Snap for 5124112 from 3c7841c94a to qt-release

Change-Id: I226eea6f2a8d9f3d2caeb69ebeeaef6496dce78f
This commit is contained in:
android-build-team Robot
2018-11-11 04:13:16 +00:00
95 changed files with 2458 additions and 1244 deletions

View File

@@ -911,7 +911,7 @@
<activity android:name=".Settings$MyDeviceInfoActivity"
android:label="@string/about_settings"
android:icon="@drawable/ic_settings_about"
android:icon="@drawable/ic_homepage_about"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="android.settings.DEVICE_INFO_SETTINGS" />
@@ -922,14 +922,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<intent-filter>
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.order" android:value="-270"/>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.system" />
<meta-data android:name="com.android.settings.title"
android:resource="@string/about_settings" />
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
@@ -2962,16 +2954,6 @@
android:value="true" />
</activity>
<activity android:name="Settings$DirectoryAccessSettingsActivity"
android:label="@string/directory_access">
<intent-filter>
<action android:name="android.settings.STORAGE_VOLUME_ACCESS_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.manageapplications.ManageApplications" />
</activity>
<provider android:name=".slices.SettingsSliceProvider"
android:authorities="com.android.settings.slices;android.settings.slices"
android:exported="true"

View File

@@ -1029,7 +1029,7 @@
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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;homepage_connected_device_background&quot;>#71A234&lt;/color>"
errorLine1=" &lt;color name=&quot;homepage_connected_device_background&quot;>#72B70F&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
@@ -1077,7 +1077,7 @@
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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;homepage_display_background&quot;>#FFB600&lt;/color>"
errorLine1=" &lt;color name=&quot;homepage_display_background&quot;>#FFA727&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
@@ -1173,7 +1173,7 @@
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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;homepage_system_background&quot;>#757575&lt;/color>"
errorLine1=" &lt;color name=&quot;homepage_system_background&quot;>#9E9E9E&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
@@ -1229,6 +1229,22 @@
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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;homepage_about_background&quot;>#9FA8DA&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="129"
column="5"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
@@ -1241,7 +1257,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="133"
line="134"
column="5"/>
</issue>
@@ -1257,7 +1273,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="134"
line="135"
column="5"/>
</issue>
@@ -1273,7 +1289,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="135"
line="136"
column="5"/>
</issue>
@@ -1289,7 +1305,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="136"
line="137"
column="5"/>
</issue>
@@ -1305,7 +1321,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="137"
line="138"
column="5"/>
</issue>
@@ -1321,7 +1337,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="138"
line="139"
column="5"/>
</issue>
@@ -1337,7 +1353,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="141"
line="142"
column="5"/>
</issue>
@@ -1353,7 +1369,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="142"
line="143"
column="5"/>
</issue>
@@ -1369,7 +1385,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="143"
line="144"
column="5"/>
</issue>
@@ -1385,7 +1401,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="144"
line="145"
column="5"/>
</issue>
@@ -1401,7 +1417,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="145"
line="146"
column="5"/>
</issue>
@@ -1693,6 +1709,22 @@
column="9"/>
</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.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" android:color=&quot;@color/homepage_about_background&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/ic_homepage_about.xml"
line="23"
column="17"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid
android:color="@color/homepage_about_background" />
<size
android:width="@dimen/dashboard_tile_image_size"
android:height="@dimen/dashboard_tile_image_size" />
</shape>
</item>
<item
android:width="@dimen/dashboard_tile_foreground_image_size"
android:height="@dimen/dashboard_tile_foreground_image_size"
android:start="@dimen/dashboard_tile_foreground_image_inset"
android:top="@dimen/dashboard_tile_foreground_image_inset"
android:drawable="@drawable/ic_phone_info" />
</layer-list>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7v-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,7h2v2h-2V7zM11,11h2v6h-2V11z"/>
</vector>

View File

@@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 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.
-->
<!-- Entity header -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/entity_header"
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="24dp"
android:paddingBottom="24dp">
<LinearLayout
android:id="@+id/entity_header_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="56dp">
<ImageView
android:id="@+id/entity_header_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="fitCenter"
android:layout_gravity="center_horizontal"
android:antialias="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/entity_header_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="false"
android:ellipsize="marquee"
android:gravity="start"
android:textDirection="locale" />
<TextView
android:id="@+id/install_type"
style="@style/TextAppearance.EntityHeaderSummary"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/entity_header_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/entity_header_second_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entity_header_links"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageButton
android:id="@android:id/button1"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@null"
android:tint="?android:attr/colorAccent" />
<ImageButton
android:id="@android:id/button2"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@null"
android:tint="?android:attr/colorAccent" />
</LinearLayout>
</LinearLayout>

View File

@@ -27,8 +27,6 @@
<ImageView android:id="@+id/admin_support_icon"
android:layout_width="@dimen/admin_details_dialog_icon_size"
android:layout_height="@dimen/admin_details_dialog_icon_size"
android:tint="?android:attr/colorAccent"
android:src="@*android:drawable/ic_info"
android:scaleType="fitCenter"
android:contentDescription="@null" />
<TextView android:id="@+id/admin_support_dialog_title"

View File

@@ -24,16 +24,18 @@
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="@dimen/homepage_condition_full_card_height"
android:layout_height="wrap_content"
android:paddingStart="@dimen/homepage_card_padding_start"
android:paddingEnd="@dimen/homepage_card_padding_end"
android:paddingTop="@dimen/homepage_condition_full_card_padding_top"
android:paddingBottom="@dimen/homepage_condition_full_card_padding_bottom"
android:orientation="horizontal"
android:gravity="center_vertical">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/suggestion_card_icon_size"
android:layout_height="@dimen/suggestion_card_icon_size"
android:layout_width="@dimen/homepage_card_icon_size"
android:layout_height="@dimen/homepage_card_icon_size"
android:tint="?android:attr/colorAccent"/>
<LinearLayout
@@ -59,13 +61,7 @@
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="@dimen/homepage_condition_full_card_divider_width"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/homepage_condition_full_card_divider_padding_top"
android:layout_marginBottom="@dimen/homepage_condition_full_card_divider_padding_bottom"
android:background="?android:attr/dividerVertical" />
<include layout="@layout/vertical_divider"/>
<Button
android:id="@+id/first_action"

View File

@@ -32,14 +32,16 @@
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/suggestion_card_icon_size"
android:layout_height="@dimen/suggestion_card_icon_size"
android:layout_width="@dimen/homepage_card_icon_size"
android:layout_height="@dimen/homepage_card_icon_size"
android:tint="?android:attr/colorAccent"/>
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:layout_marginTop="@dimen/homepage_condition_half_card_title_margin_top"
android:layout_marginBottom="@dimen/homepage_condition_card_title_margin_bottom"
style="@style/TextAppearance.ConditionCardTitle"/>
@@ -48,6 +50,9 @@
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:layout_marginBottom="@dimen/homepage_condition_half_card_summary_margin_bottom"
style="@style/TextAppearance.ConditionCardSummary"/>
<include layout="@layout/horizontal_divider"/>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suggestion_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/ContextualCardStyle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="112dp"
android:paddingBottom="8dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/homepage_card_icon_size"
android:layout_height="@dimen/homepage_card_icon_size"
style="@style/SuggestionCardIcon"
android:layout_marginTop="16dp"
android:layout_marginBottom="6dp"/>
</RelativeLayout>
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.SuggestionTitle"
android:fadingEdge="horizontal"/>
<TextView
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.SuggestionSummary"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -16,60 +16,58 @@
-->
<!-- Entity header -->
<LinearLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/entity_header"
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/preference_no_icon_padding_start"
android:paddingTop="24dp"
android:paddingBottom="32dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/entity_header_content"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/entity_header_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="16dp"
android:scaleType="fitXY"
android:antialias="true" />
android:antialias="true"/>
<TextView
android:id="@+id/entity_header_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="false"
android:ellipsize="marquee"
android:gravity="start"
android:textDirection="locale" />
android:textDirection="locale"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/install_type"
style="@style/TextAppearance.EntityHeaderSummary"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"/>
<TextView
android:id="@+id/entity_header_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"/>
<TextView
android:id="@+id/entity_header_second_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
@@ -78,6 +76,8 @@
android:id="@+id/entity_header_links"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:orientation="vertical">
<ImageButton
@@ -102,4 +102,4 @@
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +15,9 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="directory_access_details"
android:title="@string/directory_access"/>
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/divider"
android:layout_width="@dimen/vertical_divider_width"
android:layout_height="match_parent"
android:background="?android:attr/dividerVertical"/>

View File

@@ -215,10 +215,12 @@
<string-array name="wifi_security">
<!-- The Wi-Fi network does not have any security. -->
<item>@string/wifi_security_none</item>
<item translatable="false">@string/wifi_security_owe</item>
<item translatable="false">@string/wifi_security_wep</item>
<item translatable="false">@string/wifi_security_psk_generic</item>
<item translatable="false">@string/wifi_security_sae</item>
<item translatable="false">@string/wifi_security_eap</item>
<item translatable="false">@string/wifi_security_eap_suiteb</item>
</string-array>
<!-- Match this with the constants in AccessPoint. --> <skip />
@@ -228,6 +230,7 @@
<item>@string/wifi_security_none</item>
<item translatable="false">@string/wifi_security_wep</item>
<item translatable="false">@string/wifi_security_psk_generic</item>
<item translatable="false">@string/wifi_security_sae</item>
</string-array>
<!-- Security types for wireless tether -->

View File

@@ -113,19 +113,20 @@
<!-- Dashboard/homepage icon background colors -->
<color name="homepage_network_background">#2196F3</color>
<color name="homepage_connected_device_background">#71A234</color>
<color name="homepage_connected_device_background">#72B70F</color>
<color name="homepage_app_and_notification_background">#FF7E0F</color>
<color name="homepage_battery_background">#258982</color>
<color name="homepage_display_background">#FFB600</color>
<color name="homepage_display_background">#FFA727</color>
<color name="homepage_sound_background">#01B1AF</color>
<color name="homepage_storage_background">#C14CE6</color>
<color name="homepage_security_background">#0F9D58</color>
<color name="homepage_accounts_background">#F15B8D</color>
<color name="homepage_accessibility_background">#5011C1</color>
<color name="homepage_system_background">#757575</color>
<color name="homepage_system_background">#9E9E9E</color>
<color name="homepage_support_background">#26459C</color>
<color name="homepage_generic_icon_background">#1A73E8</color>
<color name="homepage_location_background">#2EC7DC</color>
<color name="homepage_about_background">#9FA8DA</color>
<!-- End of dashboard/homepage icon background colors -->
<color name="glif_error_color">@*android:color/material_red_A700</color>

View File

@@ -134,14 +134,15 @@
have distinct intensity levels -->
<bool name="config_vibration_supports_multiple_intensities">false</bool>
<!--
Whether or not the homepage should be powered by legacy suggestion (versus contextual cards)
Default to true as not all devices support contextual cards.
-->
<bool name="config_use_legacy_suggestion">true</bool>
<!-- Whether or not homepage should display user's account avatar -->
<bool name="config_show_avatar_in_homepage">false</bool>
<!-- Whether or not TopLevelSettings should force rounded icon for injected tiles -->
<bool name="config_force_rounded_icon_TopLevelSettings">true</bool>
<!-- TODO(b/115429501): move those 3 configs to framework-->
<!-- Show enabled lte option for lte device -->
<bool name="config_enabled_lte" translatable="false">false</bool>
<!-- Show enabled tdscdma option for device -->
<bool name="config_support_tdscdma" translatable="false">false</bool>
<!-- Show enabled tdscdma option for device when connect roaming network -->
<string-array name="config_support_tdscdma_roaming_on_networks" translatable="false"></string-array>
</resources>

View File

@@ -303,17 +303,6 @@
<dimen name="suggestion_condition_header_padding_expanded">5dp</dimen>
<dimen name="condition_header_height">36dp</dimen>
<!-- Suggestion cards size and padding -->
<dimen name="suggestion_card_icon_size">24dp</dimen>
<dimen name="suggestion_card_outer_margin">14dp</dimen>
<dimen name="suggestion_card_inner_margin">12dp</dimen>
<dimen name="suggestion_card_padding_bottom_one_card">16dp</dimen>
<dimen name="suggestion_card_corner_radius">2dp</dimen>
<dimen name="suggestion_card_icon_side_margin">12dp</dimen>
<dimen name="suggestion_card_button_side_margin">8dp</dimen>
<dimen name="suggestion_card_button_top_margin">16dp</dimen>
<dimen name="suggestion_card_button_bottom_margin">18dp</dimen>
<!-- Condition cards size and padding -->
<dimen name="condition_card_elevation">2dp</dimen>
@@ -331,6 +320,7 @@
<dimen name="homepage_bottombar_fab_cradle">68dp</dimen>
<!-- Homepage cards size and padding -->
<dimen name="homepage_card_icon_size">24dp</dimen>
<dimen name="homepage_card_corner_radius">8dp</dimen>
<dimen name="homepage_card_elevation">2dp</dimen>
<dimen name="homepage_card_vertical_margin">4dp</dimen>
@@ -343,6 +333,9 @@
<dimen name="horizontal_divider_margin_bottom">8dp</dimen>
<dimen name="horizontal_divider_height">.75dp</dimen>
<!-- Vertical divider size -->
<dimen name="vertical_divider_width">.75dp</dimen>
<!-- Signal icon in NetworkSelectSetting -->
<dimen name="signal_strength_icon_size">24dp</dimen>
@@ -351,11 +344,10 @@
<dimen name="homepage_condition_half_card_height">150dp</dimen>
<dimen name="homepage_condition_half_card_padding_top">12dp</dimen>
<dimen name="homepage_condition_half_card_title_margin_top">12dp</dimen>
<dimen name="homepage_condition_full_card_height">72dp</dimen>
<dimen name="homepage_condition_half_card_summary_margin_bottom">12dp</dimen>
<dimen name="homepage_condition_full_card_padding_start">24dp</dimen>
<dimen name="homepage_condition_full_card_padding_end">24dp</dimen>
<dimen name="homepage_condition_full_card_divider_width">.75dp</dimen>
<dimen name="homepage_condition_full_card_divider_padding_top">12dp</dimen>
<dimen name="homepage_condition_full_card_divider_padding_bottom">12dp</dimen>
<dimen name="homepage_condition_full_card_padding_top">12dp</dimen>
<dimen name="homepage_condition_full_card_padding_bottom">12dp</dimen>
</resources>

View File

@@ -678,7 +678,7 @@
<!-- check box to allow data usage when roaming [CHAR LIMIT=41] -->
<string name="allow_data_usage_title">Allow data usage when roaming</string>
<!-- mobile network settings screen, setting check box title -->
<string name="roaming">Data roaming</string>
<string name="roaming">Roaming</string>
<!-- mobile network settings screen, setting option summary text when check box is selected -->
<string name="roaming_enable">Connect to data services when roaming</string>
<!-- mobile network settings screen, setting option summary text when check box is clear -->
@@ -9964,14 +9964,12 @@
<!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] -->
<string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
<!-- Title for Directory Access settings -->
<string name="directory_access">Directory access</string>
<!-- Keywords for Directory Access settings -->
<string name="keywords_directory_access">directory access</string>
<!-- String used to describe the name of a directory in a volume; it must
show both names, with the directory name wrapped in parenthesis -->
<string name="directory_on_volume"><xliff:g id="volume" example="SD Card">%1$s</xliff:g> (<xliff:g id="directory" example="Movies">%2$s</xliff:g>)</string>
<!-- UI debug setting: select an app to use updated graphics driver [CHAR LIMIT=100] -->
<string name="updated_gfx_driver_dev_opt_in_app">Select app to use updated graphics driver</string>
<!-- UI debug setting: no app selected to use updated GPU driver [CHAR LIMIT=100] -->
<string name="updated_gfx_driver_dev_opt_in_app_not_set">No selected app to use updated graphics driver</string>
<!-- UI debug setting: app selected to use updated graphics driver [CHAR LIMIT=NONE] -->
<string name="updated_gfx_driver_dev_opt_in_app_set">Opt in application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
<!-- Slices Strings -->
@@ -10010,11 +10008,6 @@
<!-- Title for preference showing the name of the device. [CHAR LIMIT=60]-->
<string name="my_device_info_device_name_preference_title">Device name</string>
<!-- Settings item title for automatic Bluetooth on while driving preference [CHAR LIMIT=35] -->
<string name="bluetooth_on_while_driving_pref">Use Bluetooth when driving</string>
<!-- Settings item summary for automatic Bluetooth on while driving preference [CHAR LIMIT=100] -->
<string name="bluetooth_on_while_driving_summary">Turn on Bluetooth automatically when driving</string>
<!-- Title for Wifi Access settings [CHAR LIMIT=35] -->
<string name="change_wifi_state_title">Wi-Fi control</string>
@@ -10187,9 +10180,6 @@
<!-- Text for Network global [CHAR LIMIT=NONE] -->
<string name="network_global">Global</string>
<!-- Configuration setting for world mode Format is <true;GID if any to be checked> [CHAR LIMIT=NONE] -->
<string translatable="false" name="config_world_mode"/>
<!-- Available networks screen title/heading [CHAR LIMIT=NONE] -->
<string name="label_available">Available networks</string>
<!-- Mobile network settings screen, toast when searching for available networks [CHAR LIMIT=NONE] -->
@@ -10260,6 +10250,8 @@
<string name="mobile_data_usage_title">App data usage</string>
<!-- Summary to show the current network mode is invalid. [CHAR LIMIT=NONE]-->
<string name="mobile_network_mode_error">Invalid Network Mode <xliff:g id="networkModeId" example="0">%1$d</xliff:g>. Ignore.</string>
<!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] -->
<string name="mobile_network_apn_title">Access Point Names</string>
<!-- Available networks screen, summary when button disallowed due to permanent automatic mode [CHAR LIMIT=NONE] -->
<string name="manual_mode_disallowed_summary">Unavailable when connected to <xliff:g id="carrier" example="verizon">%1$s</xliff:g></string>
@@ -10281,4 +10273,9 @@
</plurals>
<!-- Title for no connected devices in connected device slice. [CHAR LIMIT=NONE] -->
<string name="no_connected_devices">No connected devices</string>
<!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
<string name="force_desktop_mode">Force desktop mode</string>
<!-- UI debug setting: force desktop mode summary [CHAR LIMIT=150] -->
<string name="force_desktop_mode_summary">Force experimental desktop mode on secondary displays</string>
</resources>

View File

@@ -320,8 +320,9 @@
<style name="TextAppearance.EntityHeaderTitle"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">16sp</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.EntityHeaderSummary"
@@ -331,6 +332,7 @@
<item name="android:gravity">start</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">marquee</item>
<item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.ZenOnboardingButton">
@@ -350,16 +352,8 @@
<style name="SuggestionCardIcon">
<item name="android:layout_centerHorizontal">false</item>
<item name="android:layout_alignParentStart">true</item>
<item name="android:layout_marginStart">@dimen/suggestion_card_icon_side_margin</item>
<item name="android:layout_marginEnd">@dimen/suggestion_card_icon_side_margin</item>
</style>
<style name="SuggestionCardButton">
<item name="android:layout_gravity">start</item>
<item name="android:layout_marginStart">@dimen/suggestion_card_button_side_margin</item>
<item name="android:layout_marginEnd">@dimen/suggestion_card_button_side_margin</item>
<item name="android:layout_marginTop">@dimen/suggestion_card_button_top_margin</item>
<item name="android:layout_marginBottom">@dimen/suggestion_card_button_bottom_margin</item>
<item name="android:layout_marginStart">12dp</item>
<item name="android:layout_marginEnd">12dp</item>
</style>
<style name="FingerprintLayoutTheme">
@@ -405,12 +399,10 @@
</style>
<style name="EntityHeader">
<item name="android:background">?android:attr/colorPrimary</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:paddingTop">16dp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:background">?android:attr/colorPrimaryDark</item>
<item name="android:paddingTop">24dp</item>
<item name="android:paddingBottom">16dp</item>
<item name="android:paddingEnd">16dp</item>
<item name="android:paddingBottom">8dp</item>
</style>
<style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored"/>

View File

@@ -44,14 +44,6 @@
android:icon="@drawable/ic_android"
android:order="-6"/>
<SwitchPreference
android:key="bluetooth_on_while_driving"
android:title="@string/bluetooth_on_while_driving_pref"
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_on_while_driving_summary"
settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
android:order="-4"/>
<com.android.settingslib.RestrictedPreference
android:key="connected_device_printing"
android:title="@string/print_settings"

View File

@@ -422,6 +422,10 @@
<Preference android:key="angle_enabled_app"
android:title="@string/angle_enabled_app" />
<Preference android:key="updated_gfx_driver_dev_opt_in_app"
android:summary="@string/updated_gfx_driver_dev_opt_in_app_summary"
android:title="@string/updated_gfx_driver_dev_opt_in_app" />
</PreferenceCategory>
<PreferenceCategory
@@ -510,6 +514,11 @@
android:title="@string/enable_freeform_support"
android:summary="@string/enable_freeform_support_summary" />
<SwitchPreference
android:key="force_desktop_mode_on_external_displays"
android:title="@string/force_desktop_mode"
android:summary="@string/force_desktop_mode_summary" />
<Preference
android:key="reset_shortcut_manager_throttling"
android:title="@string/reset_shortcut_manager_throttling" />

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!--We want separate APN setting from reset of settings because-->
<!--we want user to change it with caution.-->
<PreferenceCategory
android:key="category_gsm_apn_key"
android:layout="@layout/preference_category_no_label">
<com.android.settingslib.RestrictedPreference
android:key="button_gsm_apn_key"
android:title="@string/apn_settings"
android:persistent="false" />
</PreferenceCategory>
<PreferenceScreen
android:key="carrier_settings_key"
android:title="@string/carrier_settings_title">
<!-- b/114749736, create a preference controller to build intent -->
</PreferenceScreen>
</PreferenceScreen>

View File

@@ -138,7 +138,7 @@
<com.android.settingslib.RestrictedPreference
android:key="telephony_apn_key"
android:persistent="false"
android:title="@string/apn_settings"
android:title="@string/mobile_network_apn_title"
settings:allowDividerAbove="true"
settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/>

View File

@@ -19,13 +19,16 @@
android:title="@string/print_print_job">
<Preference
android:key="print_job_preference">
android:key="print_job_preference"
android:title="@string/print_print_job"
settings:controller="com.android.settings.print.PrintJobPreferenceController">
</Preference>
<Preference
android:key="print_job_message_preference"
android:layout="@layout/print_job_summary"
android:selectable="false">
android:selectable="false"
settings:controller="com.android.settings.print.PrintJobMessagePreferenceController">
</Preference>
</PreferenceScreen>

View File

@@ -120,16 +120,6 @@
android:value="com.android.settings.Settings$VrListenersSettingsActivity" />
</Preference>
<Preference
android:key="special_app_directory_access"
android:title="@string/directory_access"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
settings:keywords="@string/keywords_directory_access">
<extra
android:name="classname"
android:value="com.android.settings.Settings$DirectoryAccessSettingsActivity" />
</Preference>
<Preference
android:key="change_wifi_state"
android:title="@string/change_wifi_state_title"

View File

@@ -124,6 +124,15 @@
android:order="10"
android:fragment="com.android.settings.system.SystemDashboardFragment"/>
<Preference
android:key="top_level_about_device"
android:title="@string/about_settings"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_about"
android:order="20"
android:fragment="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment"
settings:controller="com.android.settings.deviceinfo.aboutphone.TopLevelAboutDevicePreferenceController"/>
<Preference
android:key="top_level_support"
android:summary="@string/support_summary"

View File

@@ -120,7 +120,6 @@ public class Settings extends SettingsActivity {
public static class PhotosStorageActivity extends SettingsActivity {
/* empty */
}
public static class DirectoryAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiCallingSettingsActivity extends SettingsActivity { /* empty */ }

View File

@@ -18,8 +18,10 @@ package com.android.settings.accounts;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
public interface AccountFeatureProvider {
String getAccountType();
Account[] getAccounts(Context context);
Intent getAccountSettingsDeeplinkIntent();
}

View File

@@ -2,6 +2,7 @@ package com.android.settings.accounts;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
public class AccountFeatureProviderImpl implements AccountFeatureProvider {
@Override
@@ -13,4 +14,9 @@ public class AccountFeatureProviderImpl implements AccountFeatureProvider {
public Account[] getAccounts(Context context) {
return new Account[0];
}
@Override
public Intent getAccountSettingsDeeplinkIntent() {
return null;
}
}

View File

@@ -17,35 +17,81 @@
package com.android.settings.accounts;
import android.accounts.Account;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.OnLifecycleEvent;
import com.android.settings.R;
import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.ThreadUtils;
import java.util.List;
/**
* Avatar related work to the onStart method of registered observable classes
* in {@link SettingsHomepageActivity}.
*/
public class AvatarViewMixin implements LifecycleObserver {
private Context mContext;
private ImageView mAvatarView;
private static final String TAG = "AvatarViewMixin";
public AvatarViewMixin(Context context, ImageView avatarView) {
mContext = context.getApplicationContext();
@VisibleForTesting
static final Intent INTENT_GET_ACCOUNT_DATA =
new Intent("android.content.action.SETTINGS_ACCOUNT_DATA");
private static final String METHOD_GET_ACCOUNT_AVATAR = "getAccountAvatar";
private static final String KEY_AVATAR_BITMAP = "account_avatar";
private static final int REQUEST_CODE = 1013;
private final Context mContext;
private final ImageView mAvatarView;
private final MutableLiveData<Bitmap> mAvatarImage;
public AvatarViewMixin(SettingsHomepageActivity activity, ImageView avatarView) {
mContext = activity.getApplicationContext();
mAvatarView = avatarView;
mAvatarView.setOnClickListener(v -> {
if (hasAccount()) {
//TODO(b/117509285) launch the new page of the MeCard
} else {
final Intent intent = FeatureFactory.getFactory(mContext)
.getAccountFeatureProvider()
.getAccountSettingsDeeplinkIntent();
if (intent != null) {
activity.startActivityForResult(intent, REQUEST_CODE);
}
}
});
mAvatarImage = new MutableLiveData<>();
mAvatarImage.observe(activity, bitmap -> {
avatarView.setImageBitmap(bitmap);
});
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
if (!mContext.getResources().getBoolean(R.bool.config_show_avatar_in_homepage)) {
Log.d(TAG, "Feature disabled. Skipping");
return;
}
if (hasAccount()) {
//TODO(b/117509285): To migrate account icon on search bar
loadAvatar();
} else {
mAvatarView.setImageResource(R.drawable.ic_account_circle_24dp);
}
@@ -57,4 +103,34 @@ public class AvatarViewMixin implements LifecycleObserver {
mContext).getAccountFeatureProvider().getAccounts(mContext);
return (accounts != null) && (accounts.length > 0);
}
private void loadAvatar() {
final String authority = queryProviderAuthority();
if (TextUtils.isEmpty(authority)) {
return;
}
ThreadUtils.postOnBackgroundThread(() -> {
final Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority)
.build();
final Bundle bundle = mContext.getContentResolver().call(uri,
METHOD_GET_ACCOUNT_AVATAR, null /* arg */, null /* extras */);
final Bitmap bitmap = bundle.getParcelable(KEY_AVATAR_BITMAP);
mAvatarImage.postValue(bitmap);
});
}
@VisibleForTesting
String queryProviderAuthority() {
final List<ResolveInfo> providers =
mContext.getPackageManager().queryIntentContentProviders(INTENT_GET_ACCOUNT_DATA,
PackageManager.MATCH_SYSTEM_ONLY);
if (providers.size() == 1) {
return providers.get(0).providerInfo.authority;
} else {
Log.w(TAG, "The size of the provider is " + providers.size());
return null;
}
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.ArraySet;
import android.util.Log;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import java.util.Set;
// TODO(b/72055774): add unit tests
public class AppStateDirectoryAccessBridge extends AppStateBaseBridge {
private static final String TAG = "DirectoryAccessBridge";
// TODO(b/72055774): set to false once feature is ready (or use Log.isLoggable)
static final boolean DEBUG = true;
static final boolean VERBOSE = true;
public AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback) {
super(appState, callback);
}
@Override
protected void loadAllExtraInfo() { }
@Override
protected void updateExtraInfo(AppEntry app, String pkg, int uid) { }
public static final AppFilter FILTER_APP_HAS_DIRECTORY_ACCESS = new AppFilter() {
private Set<String> mPackages;
@Override
public void init() {
throw new UnsupportedOperationException("Need to call constructor that takes context");
}
@Override
public void init(Context context) {
mPackages = null;
final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*")
.build();
try (Cursor cursor = context.getContentResolver().query(providerUri,
TABLE_PACKAGES_COLUMNS, null, null)) {
if (cursor == null) {
Log.w(TAG, "Didn't get cursor for " + providerUri);
return;
}
final int count = cursor.getCount();
if (count == 0) {
if (DEBUG) {
Log.d(TAG, "No packages anymore (was " + mPackages + ")");
}
return;
}
mPackages = new ArraySet<>(count);
while (cursor.moveToNext()) {
mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE));
}
if (DEBUG) {
Log.d(TAG, "init(): " + mPackages);
}
}
}
@Override
public boolean filterApp(AppEntry info) {
return mPackages != null && mPackages.contains(info.info.packageName);
}
};
}

View File

@@ -18,13 +18,10 @@ package com.android.settings.applications;
import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.GrantedUriPermission;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -32,7 +29,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -461,17 +457,6 @@ public class AppStorageSettings extends AppInfoWithHeader
Context.ACTIVITY_SERVICE);
am.clearGrantedUriPermissions(packageName);
// Also update the Scoped Directory Access UI permissions
final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
.build();
Log.v(TAG, "Asking " + providerUri + " to delete permissions for " + packageName);
final int deleted = context.getContentResolver().delete(providerUri, null, new String[] {
packageName
});
Log.d(TAG, "Deleted " + deleted + " entries for package " + packageName);
// Update UI
refreshGrantedUriPermissions();
}

View File

@@ -1,323 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_GRANTED;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract
.TABLE_PERMISSIONS_COLUMNS;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract
.TABLE_PERMISSIONS_COL_DIRECTORY;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract
.TABLE_PERMISSIONS_COL_GRANTED;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract
.TABLE_PERMISSIONS_COL_PACKAGE;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract
.TABLE_PERMISSIONS_COL_VOLUME_UUID;
import static com.android.settings.applications.AppStateDirectoryAccessBridge.DEBUG;
import static com.android.settings.applications.AppStateDirectoryAccessBridge.VERBOSE;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Pair;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.widget.EntityHeaderController;
import com.android.settings.widget.EntityHeaderController.ActionType;
import com.android.settingslib.applications.AppUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access).
*
* <p>Currently, it shows the entry for which the user denied access with the "Do not ask again"
* flag checked on: the user than can use the settings toggle to reset that deniel.
*
* <p>This fragments dynamically lists all such permissions, starting with one preference per
* directory in the primary storage, then adding additional entries for the external volumes (one
* entry for the whole volume).
*/
// TODO(b/72055774): add unit tests
public class DirectoryAccessDetails extends AppInfoBase {
@SuppressWarnings("hiding")
private static final String TAG = "DirectoryAccessDetails";
private boolean mCreated;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mCreated) {
Log.w(TAG, "onActivityCreated(): ignoring duplicate call");
return;
}
mCreated = true;
if (mPackageInfo == null) {
Log.w(TAG, "onActivityCreated(): no package info");
return;
}
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this, /* header= */ null )
.setRecyclerView(getListView(), getSettingsLifecycle())
.setIcon(IconDrawableFactory.newInstance(getPrefContext())
.getBadgedIcon(mPackageInfo.applicationInfo))
.setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
.setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo))
.setPackageName(mPackageName)
.setUid(mPackageInfo.applicationInfo.uid)
.setHasAppInfoLink(false)
.setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
.done(activity, getPrefContext());
getPreferenceScreen().addPreference(pref);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.directory_access_details);
}
@Override
protected boolean refreshUi() {
final Context context = getPrefContext();
final PreferenceScreen prefsGroup = getPreferenceScreen();
prefsGroup.removeAll();
final Map<String, ExternalVolume> externalVolumes = new HashMap<>();
final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
.build();
// Query provider for entries.
try (Cursor cursor = context.getContentResolver().query(providerUri,
TABLE_PERMISSIONS_COLUMNS, null, new String[] { mPackageName }, null)) {
if (cursor == null) {
Log.w(TAG, "Didn't get cursor for " + mPackageName);
return true;
}
final int count = cursor.getCount();
if (count == 0) {
// This setting screen should not be reached if there was no permission, so just
// ignore it
Log.w(TAG, "No permissions for " + mPackageName);
return true;
}
while (cursor.moveToNext()) {
final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE);
final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY);
final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1;
if (VERBOSE) {
Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir
+ " granted:" + granted);
}
if (!mPackageName.equals(pkg)) {
// Sanity check, shouldn't happen
Log.w(TAG, "Ignoring " + uuid + "/" + dir + " due to package mismatch: "
+ "expected " + mPackageName + ", got " + pkg);
continue;
}
if (uuid == null) {
if (dir == null) {
// Sanity check, shouldn't happen
Log.wtf(TAG, "Ignoring permission on primary storage root");
} else {
// Primary storage entry: add right away
prefsGroup.addPreference(newPreference(context, dir, providerUri,
/* uuid= */ null, dir, granted, /* children= */ null));
}
} else {
// External volume entry: save it for later.
ExternalVolume externalVolume = externalVolumes.get(uuid);
if (externalVolume == null) {
externalVolume = new ExternalVolume(uuid);
externalVolumes.put(uuid, externalVolume);
}
if (dir == null) {
// Whole volume
externalVolume.granted = granted;
} else {
// Directory only
externalVolume.children.add(new Pair<>(dir, granted));
}
}
}
}
if (VERBOSE) {
Log.v(TAG, "external volumes: " + externalVolumes);
}
if (externalVolumes.isEmpty()) {
// We're done!
return true;
}
// Add entries from external volumes
// Query StorageManager to get the user-friendly volume names.
final StorageManager sm = context.getSystemService(StorageManager.class);
final List<VolumeInfo> volumes = sm.getVolumes();
if (volumes.isEmpty()) {
Log.w(TAG, "StorageManager returned no secondary volumes");
return true;
}
final Map<String, String> volumeNames = new HashMap<>(volumes.size());
for (VolumeInfo volume : volumes) {
final String uuid = volume.getFsUuid();
if (uuid == null) continue; // Primary storage; not used.
String name = sm.getBestVolumeDescription(volume);
if (name == null) {
Log.w(TAG, "No description for " + volume + "; using uuid instead: " + uuid);
name = uuid;
}
volumeNames.put(uuid, name);
}
if (VERBOSE) {
Log.v(TAG, "UUID -> name mapping: " + volumeNames);
}
for (ExternalVolume volume : externalVolumes.values()) {
final String volumeName = volumeNames.get(volume.uuid);
if (volumeName == null) {
Log.w(TAG, "Ignoring entry for invalid UUID: " + volume.uuid);
continue;
}
// First add the pref for the whole volume...
final PreferenceCategory category = new PreferenceCategory(context);
prefsGroup.addPreference(category);
final Set<SwitchPreference> children = new HashSet<>(volume.children.size());
category.addPreference(newPreference(context, volumeName, providerUri, volume.uuid,
/* dir= */ null, volume.granted, children));
// ... then the children prefs
volume.children.forEach((pair) -> {
final String dir = pair.first;
final String name = context.getResources()
.getString(R.string.directory_on_volume, volumeName, dir);
final SwitchPreference childPref =
newPreference(context, name, providerUri, volume.uuid, dir, pair.second,
/* children= */ null);
category.addPreference(childPref);
children.add(childPref);
});
}
return true;
}
private SwitchPreference newPreference(Context context, String title, Uri providerUri,
String uuid, String dir, boolean granted, @Nullable Set<SwitchPreference> children) {
final SwitchPreference pref = new SwitchPreference(context);
pref.setKey(String.format("%s:%s", uuid, dir));
pref.setTitle(title);
pref.setChecked(granted);
pref.setOnPreferenceChangeListener((unused, value) -> {
if (!Boolean.class.isInstance(value)) {
// Sanity check
Log.wtf(TAG, "Invalid value from switch: " + value);
return true;
}
final boolean newValue = ((Boolean) value).booleanValue();
resetDoNotAskAgain(context, newValue, providerUri, uuid, dir);
if (children != null) {
// When parent is granted, children should be hidden; and vice versa
final boolean newChildValue = !newValue;
for (SwitchPreference child : children) {
child.setVisible(newChildValue);
}
}
return true;
});
return pref;
}
private void resetDoNotAskAgain(Context context, boolean newValue, Uri providerUri,
@Nullable String uuid, @Nullable String directory) {
if (DEBUG) {
Log.d(TAG, "Asking " + providerUri + " to update " + uuid + "/" + directory + " to "
+ newValue);
}
final ContentValues values = new ContentValues(1);
values.put(COL_GRANTED, newValue);
final int updated = context.getContentResolver().update(providerUri, values,
null, new String[] { mPackageName, uuid, directory });
if (DEBUG) {
Log.d(TAG, "Updated " + updated + " entries for " + uuid + "/" + directory);
}
}
@Override
protected AlertDialog createDialog(int id, int errorCode) {
return null;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL;
}
private static class ExternalVolume {
final String uuid;
final List<Pair<String, Boolean>> children = new ArrayList<>();
boolean granted;
ExternalVolume(String uuid) {
this.uuid = uuid;
}
@Override
public String toString() {
return "ExternalVolume: [uuid=" + uuid + ", granted=" + granted +
", children=" + children + "]";
}
}
}

View File

@@ -90,12 +90,9 @@ public class AppHeaderViewPreferenceController extends BasePreferenceController
private void setAppLabelAndIcon(PackageInfo pkgInfo, AppEntry appEntry) {
final Activity activity = mParent.getActivity();
final boolean isInstantApp = AppUtils.isInstant(pkgInfo.applicationInfo);
final CharSequence summary = isInstantApp
? null : mContext.getString(Utils.getInstallationStatus(appEntry.info));
mEntityHeaderController
.setLabel(appEntry)
.setIcon(appEntry)
.setSummary(summary)
.setIsInstantApp(isInstantApp)
.done(activity, false /* rebindActions */);
}

View File

@@ -19,7 +19,6 @@ package com.android.settings.applications.manageapplications;
import androidx.annotation.IntDef;
import com.android.settings.R;
import com.android.settings.applications.AppStateDirectoryAccessBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateOverlayBridge;
@@ -70,7 +69,6 @@ public class AppFilterRegistry {
public static final int FILTER_APPS_WITH_OVERLAY = 11;
public static final int FILTER_APPS_WRITE_SETTINGS = 12;
public static final int FILTER_APPS_INSTALL_SOURCES = 13;
public static final int FILTER_APP_HAS_DIRECTORY_ACCESS = 14;
public static final int FILTER_APP_CAN_CHANGE_WIFI_STATE = 15;
public static final int FILTER_APPS_BLOCKED = 16;
// Next id: 17
@@ -170,12 +168,6 @@ public class AppFilterRegistry {
FILTER_APPS_INSTALL_SOURCES,
R.string.filter_install_sources_apps);
// Apps that interacted with directory access permissions (A.K.A. Scoped Directory Access)
mFilters[FILTER_APP_HAS_DIRECTORY_ACCESS] = new AppFilterItem(
AppStateDirectoryAccessBridge.FILTER_APP_HAS_DIRECTORY_ACCESS,
FILTER_APP_HAS_DIRECTORY_ACCESS,
R.string.filter_install_sources_apps);
mFilters[FILTER_APP_CAN_CHANGE_WIFI_STATE] = new AppFilterItem(
AppStateChangeWifiStateBridge.FILTER_CHANGE_WIFI_STATE,
FILTER_APP_CAN_CHANGE_WIFI_STATE,
@@ -208,8 +200,6 @@ public class AppFilterRegistry {
return FILTER_APPS_WRITE_SETTINGS;
case ManageApplications.LIST_TYPE_MANAGE_SOURCES:
return FILTER_APPS_INSTALL_SOURCES;
case ManageApplications.LIST_TYPE_DIRECTORY_ACCESS:
return FILTER_APP_HAS_DIRECTORY_ACCESS;
case ManageApplications.LIST_TYPE_WIFI_ACCESS:
return FILTER_APP_CAN_CHANGE_WIFI_STATE;
case ManageApplications.LIST_TYPE_NOTIFICATION:

View File

@@ -90,7 +90,6 @@ import com.android.settings.SettingsActivity;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.AppStateDirectoryAccessBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState;
@@ -101,7 +100,6 @@ import com.android.settings.applications.AppStateUsageBridge.UsageState;
import com.android.settings.applications.AppStateWriteSettingsBridge;
import com.android.settings.applications.AppStorageSettings;
import com.android.settings.applications.DefaultAppSettings;
import com.android.settings.applications.DirectoryAccessDetails;
import com.android.settings.applications.InstalledAppCounter;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
@@ -218,7 +216,6 @@ public class ManageApplications extends InstrumentedFragment
public static final int LIST_TYPE_GAMES = 9;
public static final int LIST_TYPE_MOVIES = 10;
public static final int LIST_TYPE_PHOTOGRAPHY = 11;
public static final int LIST_TYPE_DIRECTORY_ACCESS = 12;
public static final int LIST_TYPE_WIFI_ACCESS = 13;
// List types that should show instant apps.
@@ -293,9 +290,6 @@ public class ManageApplications extends InstrumentedFragment
mListType = LIST_TYPE_PHOTOGRAPHY;
mSortOrder = R.id.sort_order_size;
mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);
} else if (className.equals(Settings.DirectoryAccessSettingsActivity.class.getName())) {
mListType = LIST_TYPE_DIRECTORY_ACCESS;
screenTitle = R.string.directory_access;
} else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {
mListType = LIST_TYPE_WIFI_ACCESS;
screenTitle = R.string.change_wifi_state_title;
@@ -479,8 +473,6 @@ public class ManageApplications extends InstrumentedFragment
return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS;
case LIST_TYPE_MANAGE_SOURCES:
return MetricsEvent.MANAGE_EXTERNAL_SOURCES;
case LIST_TYPE_DIRECTORY_ACCESS:
return MetricsEvent.DIRECTORY_ACCESS;
case LIST_TYPE_WIFI_ACCESS:
return MetricsEvent.CONFIGURE_WIFI;
default:
@@ -578,9 +570,6 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_PHOTOGRAPHY:
startAppInfoFragment(AppStorageSettings.class, R.string.storage_photos_videos);
break;
case LIST_TYPE_DIRECTORY_ACCESS:
startAppInfoFragment(DirectoryAccessDetails.class, R.string.directory_access);
break;
case LIST_TYPE_WIFI_ACCESS:
startAppInfoFragment(ChangeWifiStateDetails.class,
R.string.change_wifi_state_title);
@@ -916,8 +905,6 @@ public class ManageApplications extends InstrumentedFragment
mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) {
mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_DIRECTORY_ACCESS) {
mExtraInfoBridge = new AppStateDirectoryAccessBridge(mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_WIFI_ACCESS) {
mExtraInfoBridge = new AppStateChangeWifiStateBridge(mContext, mState, this);
} else {
@@ -1360,9 +1347,6 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_MANAGE_SOURCES:
holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));
break;
case LIST_TYPE_DIRECTORY_ACCESS:
holder.setSummary(null);
break;
case LIST_TYPE_WIFI_ACCESS:
holder.setSummary(ChangeWifiStateDetails.getSummary(mContext, entry));
break;

View File

@@ -74,7 +74,6 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new BluetoothFilesPreferenceController(context));
controllers.add(new BluetoothOnWhileDrivingPreferenceController(context));
final PrintSettingPreferenceController printerController =
new PrintSettingPreferenceController(context);

View File

@@ -1,59 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.connecteddevice;
import android.content.Context;
import android.provider.Settings;
import android.util.FeatureFlagUtils;
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.TogglePreferenceController;
/** Handles a toggle for a setting to turn on Bluetooth while driving. * */
public class BluetoothOnWhileDrivingPreferenceController extends TogglePreferenceController
implements PreferenceControllerMixin {
static final String KEY_BLUETOOTH_ON_DRIVING = "bluetooth_on_while_driving";
public BluetoothOnWhileDrivingPreferenceController(Context context) {
super(context, KEY_BLUETOOTH_ON_DRIVING);
}
@Override
public int getAvailabilityStatus() {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.BLUETOOTH_WHILE_DRIVING)) {
return AVAILABLE;
}
return CONDITIONALLY_UNAVAILABLE;
}
@Override
public boolean isChecked() {
return Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
0)
!= 0;
}
@Override
public boolean setChecked(boolean isChecked) {
final int value = isChecked ? 1 : 0;
return Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, value);
}
}

View File

@@ -20,7 +20,6 @@ package com.android.settings.core;
* This class keeps track of all feature flags in Settings.
*/
public class FeatureFlags {
public static final String BLUETOOTH_WHILE_DRIVING = "settings_bluetooth_while_driving";
public static final String AUDIO_SWITCHER_SETTINGS = "settings_audio_switcher";
public static final String DYNAMIC_HOMEPAGE = "settings_dynamic_homepage";
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";

View File

@@ -34,7 +34,6 @@ import com.android.settings.accounts.ChooseAccountFragment;
import com.android.settings.accounts.ManagedProfileSettings;
import com.android.settings.applications.AppAndNotificationDashboardFragment;
import com.android.settings.applications.DefaultAppSettings;
import com.android.settings.applications.DirectoryAccessDetails;
import com.android.settings.applications.ProcessStatsSummary;
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.applications.UsageAccessDetails;
@@ -258,7 +257,6 @@ public class SettingsGateway {
LockscreenDashboardFragment.class.getName(),
BluetoothDeviceDetailsFragment.class.getName(),
DataUsageList.class.getName(),
DirectoryAccessDetails.class.getName(),
ToggleBackupSettingFragment.class.getName(),
PreviouslyConnectedDeviceDashboardFragment.class.getName(),
};

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class DesktopModePreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String FORCE_DESKTOP_MODE_KEY = "force_desktop_mode_on_external_displays";
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
public DesktopModePreferenceController(Context context) {
super(context);
}
@Override
public String getPreferenceKey() {
return FORCE_DESKTOP_MODE_KEY;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (Boolean) newValue;
Settings.Global.putInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@Override
public void updateState(Preference preference) {
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
Settings.Global.putInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}
@VisibleForTesting
String getBuildType() {
return Build.TYPE;
}
}

View File

@@ -27,4 +27,6 @@ public interface DevelopmentOptionsActivityRequestCodes {
int REQUEST_MOCK_LOCATION_APP = 2;
int REQUEST_CODE_ANGLE_ENABLED_APP = 3;
int REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP = 4;
}

View File

@@ -406,6 +406,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new WaitForDebuggerPreferenceController(context));
controllers.add(new EnableGpuDebugLayersPreferenceController(context));
controllers.add(new AngleEnabledAppPreferenceController(context, fragment));
controllers.add(new UpdatedGfxDriverDevOptInPreferenceController(context, fragment));
controllers.add(new VerifyAppsOverUsbPreferenceController(context));
controllers.add(new LogdSizePreferenceController(context));
controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle));
@@ -458,6 +459,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new AllowAppsOnExternalPreferenceController(context));
controllers.add(new ResizableActivityPreferenceController(context));
controllers.add(new FreeformWindowsPreferenceController(context));
controllers.add(new DesktopModePreferenceController(context));
controllers.add(new SmsAccessRestrictionPreferenceController(context));
controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));

View File

@@ -19,7 +19,6 @@ package com.android.settings.development;
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -37,18 +36,11 @@ public class FreeformWindowsPreferenceController extends DeveloperOptionsPrefere
static final int SETTING_VALUE_OFF = 0;
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final String USER_BUILD_TYPE = "user";
public FreeformWindowsPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return !TextUtils.equals(USER_BUILD_TYPE, getBuildType());
}
@Override
public String getPreferenceKey() {
return ENABLE_FREEFORM_SUPPORT_KEY;

View File

@@ -0,0 +1,124 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
.REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
// TODO(b/119221883): Need to override isAvailable() to return false when updatable graphics driver is not supported.
public class UpdatedGfxDriverDevOptInPreferenceController
extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin, OnActivityResultListener {
private static final String UPDATED_GFX_DRIVER_DEV_OPT_IN_APP_KEY =
"updated_gfx_driver_dev_opt_in_app";
private final DevelopmentSettingsDashboardFragment mFragment;
private final PackageManager mPackageManager;
public UpdatedGfxDriverDevOptInPreferenceController(Context context,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mPackageManager = mContext.getPackageManager();
}
@Override
public String getPreferenceKey() {
return UPDATED_GFX_DRIVER_DEV_OPT_IN_APP_KEY;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (UPDATED_GFX_DRIVER_DEV_OPT_IN_APP_KEY.equals(preference.getKey())) {
// pass it on to settings
final Intent intent = getActivityStartIntent();
mFragment.startActivityForResult(intent,
REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
return true;
}
return false;
}
@Override
public void updateState(Preference preference) {
updatePreferenceSummary();
}
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP
|| resultCode != Activity.RESULT_OK) {
return false;
}
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP, data.getAction());
updatePreferenceSummary();
return true;
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
mPreference.setSummary(mContext.getResources().getString(
R.string.updated_gfx_driver_dev_opt_in_app_not_set));
}
@VisibleForTesting
Intent getActivityStartIntent() {
Intent intent = new Intent(mContext, AppPicker.class);
intent.putExtra(AppPicker.EXTRA_NON_SYSTEM, true /* value */);
return intent;
}
private void updatePreferenceSummary() {
final String updatedGfxDriverDevOptInApp = Settings.Global.getString(
mContext.getContentResolver(), Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
if (updatedGfxDriverDevOptInApp != null && !updatedGfxDriverDevOptInApp.isEmpty()) {
mPreference.setSummary(mContext.getResources().getString(
R.string.updated_gfx_driver_dev_opt_in_app_set,
getAppLabel(updatedGfxDriverDevOptInApp)));
} else {
mPreference.setSummary(mContext.getResources().getString(
R.string.updated_gfx_driver_dev_opt_in_app_not_set));
}
}
private String getAppLabel(String applicationPackageName) {
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfo(applicationPackageName,
PackageManager.GET_DISABLED_COMPONENTS);
final CharSequence lab = mPackageManager.getApplicationLabel(ai);
return lab != null ? lab.toString() : applicationPackageName;
} catch (PackageManager.NameNotFoundException e) {
return applicationPackageName;
}
}
}

View File

@@ -79,12 +79,7 @@ public class DeviceModelPreferenceController extends BasePreferenceController {
}
public static String getDeviceModel() {
FutureTask<String> msvSuffixTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() {
return DeviceInfoUtils.getMsvSuffix();
}
});
FutureTask<String> msvSuffixTask = new FutureTask<>(() -> DeviceInfoUtils.getMsvSuffix());
msvSuffixTask.run();
try {

View File

@@ -181,25 +181,6 @@ public class MyDeviceInfoFragment extends DashboardFragment
controller.updateDeviceName(confirm);
}
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
private final SummaryLoader mSummaryLoader;
public SummaryProvider(SummaryLoader summaryLoader) {
mSummaryLoader = summaryLoader;
}
@Override
public void setListening(boolean listening) {
if (listening) {
mSummaryLoader.setSummary(this, DeviceModelPreferenceController.getDeviceModel());
}
}
}
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
= (activity, summaryLoader) -> new SummaryProvider(summaryLoader);
/**
* For Search.
*/

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo.aboutphone;
import android.content.Context;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.deviceinfo.DeviceModelPreferenceController;
public class TopLevelAboutDevicePreferenceController extends BasePreferenceController {
public TopLevelAboutDevicePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public CharSequence getSummary() {
return DeviceModelPreferenceController.getDeviceModel();
}
}

View File

@@ -23,6 +23,8 @@ import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
@@ -109,16 +111,24 @@ public class ActionDisabledByAdminDialogHelper {
if (admin == null) {
return;
}
ImageView supportIconView = root.requireViewById(R.id.admin_support_icon);
if (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
|| !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId)) {
admin = null;
supportIconView.setImageDrawable(
mActivity.getDrawable(com.android.internal.R.drawable.ic_info));
TypedArray ta = mActivity.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
supportIconView.setImageTintList(ColorStateList.valueOf(ta.getColor(0, 0)));
ta.recycle();
} else {
final Drawable badgedIcon = Utils.getBadgedIcon(
IconDrawableFactory.newInstance(mActivity),
mActivity.getPackageManager(),
admin.getPackageName(),
userId);
((ImageView) root.findViewById(R.id.admin_support_icon)).setImageDrawable(badgedIcon);
supportIconView.setImageDrawable(badgedIcon);
}
setAdminSupportTitle(root, restriction);

View File

@@ -235,10 +235,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
controller.setLabel(mAppEntry);
controller.setIcon(mAppEntry);
boolean isInstantApp = AppUtils.isInstant(mAppEntry.info);
CharSequence summary = isInstantApp
? null : getString(Utils.getInstallationStatus(mAppEntry.info));
controller.setIsInstantApp(AppUtils.isInstant(mAppEntry.info));
controller.setSummary(summary);
}
controller.done(context, true /* rebindActions */);

View File

@@ -201,7 +201,7 @@ public class CardDatabaseHelper extends SQLiteOpenHelper {
final String selection = CardColumns.CARD_DISMISSED + "=0";
Cursor cursor = db.query(CARD_TABLE, null /* columns */, selection,
null /* selectionArgs */, null /* groupBy */, null /* having */,
null /* orderBy */);
CardColumns.SCORE + " DESC" /* orderBy */);
return cursor;
}

View File

@@ -33,12 +33,12 @@ public class ContextualCard {
/**
* Flags indicating the type of the ContextualCard.
*/
@IntDef({CardType.DEFAULT, CardType.SLICE, CardType.SUGGESTION, CardType.CONDITIONAL})
@IntDef({CardType.DEFAULT, CardType.SLICE, CardType.LEGACY_SUGGESTION, CardType.CONDITIONAL})
@Retention(RetentionPolicy.SOURCE)
public @interface CardType {
int DEFAULT = 0;
int SLICE = 1;
int SUGGESTION = 2;
int LEGACY_SUGGESTION = 2;
int CONDITIONAL = 3;
}

View File

@@ -18,11 +18,16 @@ package com.android.settings.homepage.contextualcards;
import android.util.Log;
import androidx.annotation.LayoutRes;
import androidx.annotation.VisibleForTesting;
import com.android.settings.homepage.contextualcards.ContextualCard.CardType;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.legacysuggestion
.LegacySuggestionContextualCardController;
import com.android.settings.homepage.contextualcards.legacysuggestion
.LegacySuggestionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
@@ -34,6 +39,7 @@ import java.util.stream.Collectors;
public class ContextualCardLookupTable {
private static final String TAG = "ContextualCardLookup";
static class ControllerRendererMapping implements Comparable<ControllerRendererMapping> {
@CardType
final int mCardType;
@@ -41,7 +47,7 @@ public class ContextualCardLookupTable {
final Class<? extends ContextualCardController> mControllerClass;
final Class<? extends ContextualCardRenderer> mRendererClass;
ControllerRendererMapping(@CardType int cardType, int viewType,
ControllerRendererMapping(@CardType int cardType, @LayoutRes int viewType,
Class<? extends ContextualCardController> controllerClass,
Class<? extends ContextualCardRenderer> rendererClass) {
mCardType = cardType;
@@ -69,6 +75,10 @@ public class ContextualCardLookupTable {
ConditionContextualCardRenderer.FULL_WIDTH_VIEW_TYPE,
ConditionContextualCardController.class,
ConditionContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.LEGACY_SUGGESTION,
LegacySuggestionContextualCardRenderer.VIEW_TYPE,
LegacySuggestionContextualCardController.class,
LegacySuggestionContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.SLICE,
SliceContextualCardRenderer.VIEW_TYPE,
SliceContextualCardController.class,

View File

@@ -16,7 +16,8 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader
.CARD_CONTENT_LOADER_ID;
import static java.util.stream.Collectors.groupingBy;
@@ -57,8 +58,8 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
private static final String TAG = "ContextualCardManager";
//The list for Settings Custom Card
@ContextualCard.CardType
private static final int[] SETTINGS_CARDS = {ContextualCard.CardType.CONDITIONAL};
private static final int[] SETTINGS_CARDS =
{ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION};
private final Context mContext;
private final ControllerRendererPool mControllerRendererPool;
@@ -68,14 +69,14 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
private ContextualCardUpdateListener mListener;
public ContextualCardManager(Context context, @NonNull Lifecycle lifecycle) {
public ContextualCardManager(Context context, Lifecycle lifecycle) {
mContext = context;
mLifecycle = lifecycle;
mContextualCards = new ArrayList<>();
mLifecycleObservers = new ArrayList<>();
mControllerRendererPool = new ControllerRendererPool();
//for data provided by Settings
for (int cardType : SETTINGS_CARDS) {
for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
setupController(cardType);
}
}
@@ -94,7 +95,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
}
}
private void setupController(int cardType) {
private void setupController(@ContextualCard.CardType int cardType) {
final ContextualCardController controller = mControllerRendererPool.getController(mContext,
cardType);
if (controller == null) {

View File

@@ -18,6 +18,7 @@ package com.android.settings.homepage.contextualcards;
import android.view.View;
import androidx.annotation.LayoutRes;
import androidx.recyclerview.widget.RecyclerView;
/**
@@ -28,6 +29,7 @@ public interface ContextualCardRenderer {
/**
* The layout type of the renderer.
*/
@LayoutRes
int getViewType(boolean isHalfWidth);
/**

View File

@@ -16,6 +16,8 @@
package com.android.settings.homepage.contextualcards;
import androidx.annotation.MainThread;
import java.util.List;
import java.util.Map;
@@ -31,5 +33,6 @@ public interface ContextualCardUpdateListener {
* null, which means all cards from corresponding {@link
* ContextualCard.CardType} are removed.
*/
@MainThread
void onContextualCardUpdated(Map<Integer, List<ContextualCard>> cards);
}

View File

@@ -26,6 +26,10 @@ import androidx.lifecycle.LifecycleOwner;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardController;
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.legacysuggestion
.LegacySuggestionContextualCardController;
import com.android.settings.homepage.contextualcards.legacysuggestion
.LegacySuggestionContextualCardRenderer;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardController;
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
@@ -111,6 +115,8 @@ public class ControllerRendererPool {
return new ConditionContextualCardController(context);
} else if (SliceContextualCardController.class == clz) {
return new SliceContextualCardController();
} else if (LegacySuggestionContextualCardController.class == clz) {
return new LegacySuggestionContextualCardController(context);
}
return null;
}
@@ -118,9 +124,12 @@ public class ControllerRendererPool {
private ContextualCardRenderer createCardRenderer(Context context,
LifecycleOwner lifecycleOwner, Class<?> clz) {
if (ConditionContextualCardRenderer.class == clz) {
return new ConditionContextualCardRenderer(context, this /*controllerRendererPool*/);
return new ConditionContextualCardRenderer(context, this /* controllerRendererPool */);
} else if (SliceContextualCardRenderer.class == clz) {
return new SliceContextualCardRenderer(context, lifecycleOwner);
} else if (LegacySuggestionContextualCardRenderer.class == clz) {
return new LegacySuggestionContextualCardRenderer(context,
this /* controllerRendererPool */);
}
return null;
}

View File

@@ -23,6 +23,7 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.logging.nano.MetricsProto;
@@ -37,7 +38,9 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
* Card renderer for {@link ConditionalContextualCard}.
*/
public class ConditionContextualCardRenderer implements ContextualCardRenderer {
@LayoutRes
public static final int HALF_WIDTH_VIEW_TYPE = R.layout.homepage_condition_half_tile;
@LayoutRes
public static final int FULL_WIDTH_VIEW_TYPE = R.layout.homepage_condition_full_tile;
private final Context mContext;

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import android.app.PendingIntent;
import com.android.settings.homepage.contextualcards.ContextualCard;
public class LegacySuggestionContextualCard extends ContextualCard {
private final PendingIntent mPendingIntent;
public LegacySuggestionContextualCard(Builder builder) {
super(builder);
mPendingIntent = builder.mPendingIntent;
}
@Override
public int getCardType() {
return CardType.LEGACY_SUGGESTION;
}
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
public static class Builder extends ContextualCard.Builder {
private PendingIntent mPendingIntent;
public Builder setPendingIntent(PendingIntent pendingIntent) {
mPendingIntent = pendingIntent;
return this;
}
@Override
public Builder setCardType(int cardType) {
throw new IllegalArgumentException(
"Cannot change card type for " + getClass().getName());
}
public LegacySuggestionContextualCard build() {
return new LegacySuggestionContextualCard(this);
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.service.settings.suggestions.Suggestion;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardController;
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.suggestions.SuggestionController;
import com.android.settingslib.suggestions.SuggestionController.ServiceConnectionListener;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class LegacySuggestionContextualCardController implements ContextualCardController,
LifecycleObserver, OnStart, OnStop, ServiceConnectionListener {
private static final String TAG = "LegacySuggestCardCtrl";
@VisibleForTesting
SuggestionController mSuggestionController;
private ContextualCardUpdateListener mCardUpdateListener;
private final Context mContext;
public LegacySuggestionContextualCardController(Context context) {
mContext = context;
if (!mContext.getResources().getBoolean(R.bool.config_use_legacy_suggestion)) {
Log.w(TAG, "Legacy suggestion contextual card disabled, skipping.");
return;
}
final ComponentName suggestionServiceComponent =
FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider(mContext)
.getSuggestionServiceComponent();
mSuggestionController = new SuggestionController(
mContext, suggestionServiceComponent, this /* listener */);
}
@Override
public int getCardType() {
return ContextualCard.CardType.LEGACY_SUGGESTION;
}
@Override
public void onPrimaryClick(ContextualCard card) {
try {
((LegacySuggestionContextualCard) card).getPendingIntent().send();
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Failed to start suggestion " + card.getTitleText());
}
}
@Override
public void onActionClick(ContextualCard card) {
}
@Override
public void setCardUpdateListener(ContextualCardUpdateListener listener) {
mCardUpdateListener = listener;
}
@Override
public void onStart() {
if (mSuggestionController == null) {
return;
}
mSuggestionController.start();
}
@Override
public void onStop() {
if (mSuggestionController == null) {
return;
}
mSuggestionController.stop();
}
@Override
public void onServiceConnected() {
loadSuggestions();
}
@Override
public void onServiceDisconnected() {
}
private void loadSuggestions() {
ThreadUtils.postOnBackgroundThread(() -> {
if (mSuggestionController == null || mCardUpdateListener == null) {
return;
}
final List<Suggestion> suggestions = mSuggestionController.getSuggestions();
Log.d(TAG, "Loaded suggests: "
+ suggestions == null ? "null" : String.valueOf(suggestions.size()));
final List<ContextualCard> cards = new ArrayList<>();
if (suggestions != null) {
// Convert suggestion to ContextualCard
for (Suggestion suggestion : suggestions) {
final LegacySuggestionContextualCard.Builder cardBuilder =
new LegacySuggestionContextualCard.Builder();
if (suggestion.getIcon() != null) {
cardBuilder.setIconDrawable(suggestion.getIcon().loadDrawable(mContext));
}
cardBuilder
.setPendingIntent(suggestion.getPendingIntent())
.setName(suggestion.getId())
.setTitleText(suggestion.getTitle().toString())
.setSummaryText(suggestion.getSummary().toString());
cards.add(cardBuilder.build());
}
}
// Update adapter
final Map<Integer, List<ContextualCard>> suggestionCards = new ArrayMap<>();
suggestionCards.put(ContextualCard.CardType.LEGACY_SUGGESTION, cards);
ThreadUtils.postOnMainThread(
() -> mCardUpdateListener.onContextualCardUpdated(suggestionCards));
});
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
public class LegacySuggestionContextualCardRenderer implements ContextualCardRenderer {
@LayoutRes
public static final int VIEW_TYPE = R.layout.homepage_suggestion_tile;
private final Context mContext;
private final ControllerRendererPool mControllerRendererPool;
public LegacySuggestionContextualCardRenderer(Context context,
ControllerRendererPool controllerRendererPool) {
mContext = context;
mControllerRendererPool = controllerRendererPool;
}
@Override
public int getViewType(boolean isHalfWidth) {
return VIEW_TYPE;
}
@Override
public RecyclerView.ViewHolder createViewHolder(View view) {
return new LegacySuggestionViewHolder(view);
}
@Override
public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
final LegacySuggestionViewHolder vh = (LegacySuggestionViewHolder) holder;
vh.icon.setImageDrawable(card.getIconDrawable());
vh.title.setText(card.getTitleText());
vh.summary.setText(card.getSummaryText());
vh.itemView.setOnClickListener(v ->
mControllerRendererPool.getController(mContext,
card.getCardType()).onPrimaryClick(card));
}
private static class LegacySuggestionViewHolder extends RecyclerView.ViewHolder {
public final ImageView icon;
public final TextView title;
public final TextView summary;
public LegacySuggestionViewHolder(View itemView) {
super(itemView);
icon = itemView.findViewById(android.R.id.icon);
title = itemView.findViewById(android.R.id.title);
summary = itemView.findViewById(android.R.id.summary);
}
}
}

View File

@@ -25,18 +25,15 @@ import android.telephony.SubscriptionManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
public class ApnPreference extends Preference implements
CompoundButton.OnCheckedChangeListener, OnClickListener {
public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener {
final static String TAG = "ApnPreference";
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -82,11 +79,6 @@ public class ApnPreference extends Preference implements
rb.setVisibility(View.GONE);
}
}
View textLayout = view.findViewById(R.id.text_layout);
if ((textLayout != null) && textLayout instanceof RelativeLayout) {
textLayout.setOnClickListener(this);
}
}
public boolean isChecked() {
@@ -116,16 +108,16 @@ public class ApnPreference extends Preference implements
}
}
public void onClick(android.view.View v) {
if ((v != null) && (R.id.text_layout == v.getId())) {
Context context = getContext();
if (context != null) {
int pos = Integer.parseInt(getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
context.startActivity(editIntent);
}
@Override
protected void onClick() {
super.onClick();
Context context = getContext();
if (context != null) {
int pos = Integer.parseInt(getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
context.startActivity(editIntent);
}
}

View File

@@ -21,7 +21,6 @@ import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -65,8 +64,7 @@ import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import java.util.ArrayList;
public class ApnSettings extends RestrictedSettingsFragment implements
Preference.OnPreferenceChangeListener {
public class ApnSettings extends RestrictedSettingsFragment {
static final String TAG = "ApnSettings";
public static final String EXTRA_POSITION = "position";
@@ -313,7 +311,6 @@ public class ApnSettings extends RestrictedSettingsFragment implements
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(this);
pref.setSubId(subId);
boolean selectable = ((type == null) || !type.equals("mms"));
@@ -405,14 +402,6 @@ public class ApnSettings extends RestrictedSettingsFragment implements
startActivity(intent);
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
int pos = Integer.parseInt(preference.getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
startActivity(new Intent(Intent.ACTION_EDIT, url));
return true;
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.d(TAG, "onPreferenceChange(): Preference - " + preference
+ ", newValue - " + newValue + ", newValue type - "

View File

@@ -180,7 +180,7 @@ public class EnabledNetworkModePreferenceController extends BasePreferenceContro
preference.setEntryValues(
R.array.enabled_networks_tdscdma_values);
} else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)
&& !resources.getBoolean(R.bool.config_enabled_lte)) {
&& !carrierConfig.getBoolean(CarrierConfigManager.KEY_LTE_ENABLED_BOOL)) {
preference.setEntries(R.array.enabled_networks_except_gsm_lte_choices);
preference.setEntryValues(R.array.enabled_networks_except_gsm_lte_values);
} else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
@@ -190,7 +190,7 @@ public class EnabledNetworkModePreferenceController extends BasePreferenceContro
preference.setEntries(select);
preference.setEntryValues(
R.array.enabled_networks_except_gsm_values);
} else if (!resources.getBoolean(R.bool.config_enabled_lte)) {
} else if (!carrierConfig.getBoolean(CarrierConfigManager.KEY_LTE_ENABLED_BOOL)) {
preference.setEntries(
R.array.enabled_networks_except_lte_choices);
preference.setEntryValues(

View File

@@ -27,6 +27,7 @@ import android.database.Cursor;
import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.provider.Settings;
import android.service.carrier.CarrierMessagingService;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
@@ -329,28 +330,11 @@ public class MobileNetworkUtils {
* settings
*/
public static boolean isWorldMode(Context context, int subId) {
final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
.createForSubscriptionId(subId);
boolean worldModeOn = false;
final String configString = context.getString(R.string.config_world_mode);
if (!TextUtils.isEmpty(configString)) {
String[] configArray = configString.split(";");
// Check if we have World mode configuration set to True only or config is set to True
// and SIM GID value is also set and matches to the current SIM GID.
if (configArray != null &&
((configArray.length == 1 && configArray[0].equalsIgnoreCase("true"))
|| (configArray.length == 2 && !TextUtils.isEmpty(configArray[1])
&& telephonyManager != null
&& configArray[1].equalsIgnoreCase(
telephonyManager.getGroupIdLevel1())))) {
worldModeOn = true;
}
}
Log.d(TAG, "isWorldMode=" + worldModeOn);
return worldModeOn;
final PersistableBundle carrierConfig = context.getSystemService(
CarrierConfigManager.class).getConfigForSubId(subId);
return carrierConfig == null
? false
: carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL);
}
/**
@@ -396,14 +380,21 @@ public class MobileNetworkUtils {
//TODO(b/117651939): move it to telephony
private static boolean isTdscdmaSupported(Context context, TelephonyManager telephonyManager) {
if (context.getResources().getBoolean(R.bool.config_support_tdscdma)) {
final PersistableBundle carrierConfig = context.getSystemService(
CarrierConfigManager.class).getConfig();
if (carrierConfig == null) {
return false;
}
if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) {
return true;
}
String operatorNumeric = telephonyManager.getServiceState().getOperatorNumeric();
String[] numericArray = context.getResources().getStringArray(
R.array.config_support_tdscdma_roaming_on_networks);
if (numericArray.length == 0 || operatorNumeric == null) {
String[] numericArray = carrierConfig.getStringArray(
CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY);
if (numericArray == null || operatorNumeric == null) {
return false;
}
for (String numeric : numericArray) {
@@ -413,4 +404,4 @@ public class MobileNetworkUtils {
}
return false;
}
}
}

View File

@@ -264,6 +264,10 @@ public class ChooseLockGeneric extends SettingsActivity {
return false;
}
protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
return ChooseLockGeneric.InternalActivity.class;
}
protected void addHeaderView() {
if (mForFingerprint) {
setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
@@ -291,7 +295,7 @@ public class ChooseLockGeneric extends SettingsActivity {
return true;
} else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)) {
Intent chooseLockGenericIntent = new Intent(getActivity(),
ChooseLockGeneric.InternalActivity.class);
getInternalActivityClass());
chooseLockGenericIntent.setAction(getIntent().getAction());
// Forward the target user id to ChooseLockGeneric.
chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);

View File

@@ -27,6 +27,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.recyclerview.widget.RecyclerView;
@@ -135,6 +136,11 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
return true;
}
@Override
protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
return SetupChooseLockGeneric.InternalActivity.class;
}
/***
* Disables preferences that are less secure than required quality and shows only secure
* screen lock options here.
@@ -207,4 +213,25 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
return intent;
}
}
public static class InternalActivity extends ChooseLockGeneric.InternalActivity {
@Override
protected boolean isValidFragment(String fragmentName) {
return InternalSetupChooseLockGenericFragment.class.getName().equals(fragmentName);
}
@Override
/* package */ Class<? extends Fragment> getFragmentClass() {
return InternalSetupChooseLockGenericFragment.class;
}
public static class InternalSetupChooseLockGenericFragment
extends ChooseLockGenericFragment {
@Override
protected boolean canRunBeforeDeviceProvisioned() {
return true;
}
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.settings.print;
import android.content.Context;
import android.print.PrintJob;
import android.print.PrintJobInfo;
import android.text.TextUtils;
public class PrintJobMessagePreferenceController extends PrintJobPreferenceControllerBase {
public PrintJobMessagePreferenceController(Context context, String key) {
super(context, key);
}
@Override
protected void updateUi() {
final PrintJob printJob = getPrintJob();
if (printJob == null) {
mFragment.finish();
return;
}
if (printJob.isCancelled() || printJob.isCompleted()) {
mFragment.finish();
return;
}
final PrintJobInfo info = printJob.getInfo();
final CharSequence status = info.getStatus(mContext.getPackageManager());
mPreference.setVisible(!TextUtils.isEmpty(status));
mPreference.setSummary(status);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.settings.print;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.print.PrintJob;
import android.print.PrintJobInfo;
import android.text.format.DateUtils;
import com.android.settings.R;
import java.text.DateFormat;
public class PrintJobPreferenceController extends PrintJobPreferenceControllerBase {
public PrintJobPreferenceController(Context context, String key) {
super(context, key);
}
@Override
protected void updateUi() {
final PrintJob printJob = getPrintJob();
if (printJob == null) {
mFragment.finish();
return;
}
if (printJob.isCancelled() || printJob.isCompleted()) {
mFragment.finish();
return;
}
PrintJobInfo info = printJob.getInfo();
switch (info.getState()) {
case PrintJobInfo.STATE_CREATED: {
mPreference.setTitle(mContext.getString(
R.string.print_configuring_state_title_template, info.getLabel()));
}
break;
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
if (!printJob.getInfo().isCancelling()) {
mPreference.setTitle(mContext.getString(
R.string.print_printing_state_title_template, info.getLabel()));
} else {
mPreference.setTitle(mContext.getString(
R.string.print_cancelling_state_title_template, info.getLabel()));
}
}
break;
case PrintJobInfo.STATE_FAILED: {
mPreference.setTitle(mContext.getString(
R.string.print_failed_state_title_template, info.getLabel()));
}
break;
case PrintJobInfo.STATE_BLOCKED: {
if (!printJob.getInfo().isCancelling()) {
mPreference.setTitle(mContext.getString(
R.string.print_blocked_state_title_template, info.getLabel()));
} else {
mPreference.setTitle(mContext.getString(
R.string.print_cancelling_state_title_template, info.getLabel()));
}
}
break;
}
mPreference.setSummary(mContext.getString(R.string.print_job_summary,
info.getPrinterName(), DateUtils.formatSameDayTime(
info.getCreationTime(), info.getCreationTime(), DateFormat.SHORT,
DateFormat.SHORT)));
TypedArray a = mContext.obtainStyledAttributes(new int[]{
android.R.attr.colorControlNormal});
int tintColor = a.getColor(0, 0);
a.recycle();
switch (info.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
Drawable icon = mContext.getDrawable(com.android.internal.R.drawable.ic_print);
icon.setTint(tintColor);
mPreference.setIcon(icon);
break;
}
case PrintJobInfo.STATE_FAILED:
case PrintJobInfo.STATE_BLOCKED: {
Drawable icon = mContext.getDrawable(
com.android.internal.R.drawable.ic_print_error);
icon.setTint(tintColor);
mPreference.setIcon(icon);
break;
}
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.settings.print;
import android.content.Context;
import android.print.PrintJob;
import android.print.PrintJobId;
import android.print.PrintManager;
import android.util.Log;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
public abstract class PrintJobPreferenceControllerBase extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, PrintManager.PrintJobStateChangeListener {
private static final String TAG = "PrintJobPrefCtrlBase";
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
private final PrintManager mPrintManager;
protected Preference mPreference;
protected PrintJobSettingsFragment mFragment;
protected PrintJobId mPrintJobId;
public PrintJobPreferenceControllerBase(Context context, String key) {
super(context, key);
mPrintManager = ((PrintManager) mContext.getSystemService(
Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(mContext.getUserId());
}
@Override
public void onStart() {
mPrintManager.addPrintJobStateChangeListener(this);
updateUi();
}
@Override
public void onStop() {
mPrintManager.removePrintJobStateChangeListener(this);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void onPrintJobStateChanged(PrintJobId printJobId) {
updateUi();
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
public void init(PrintJobSettingsFragment fragment) {
mFragment = fragment;
processArguments();
}
protected PrintJob getPrintJob() {
return mPrintManager.getPrintJob(mPrintJobId);
}
protected abstract void updateUi();
private void processArguments() {
String printJobId = mFragment.getArguments().getString(EXTRA_PRINT_JOB_ID);
if (printJobId == null) {
printJobId = mFragment.getActivity().getIntent().getStringExtra(EXTRA_PRINT_JOB_ID);
if (printJobId == null) {
Log.w(TAG, EXTRA_PRINT_JOB_ID + " not set");
mFragment.finish();
return;
}
}
mPrintJobId = PrintJobId.unflattenFromString(printJobId);
}
}

View File

@@ -17,114 +17,59 @@
package com.android.settings.print;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.print.PrintJob;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrintManager.PrintJobStateChangeListener;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.preference.Preference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import java.text.DateFormat;
import com.android.settings.dashboard.DashboardFragment;
/**
* Fragment for management of a print job.
*/
public class PrintJobSettingsFragment extends SettingsPreferenceFragment {
private static final String LOG_TAG = PrintJobSettingsFragment.class.getSimpleName();
public class PrintJobSettingsFragment extends DashboardFragment {
private static final String TAG = "PrintJobSettingsFragment";
private static final int MENU_ITEM_ID_CANCEL = 1;
private static final int MENU_ITEM_ID_RESTART = 2;
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
@Override
protected int getPreferenceScreenResId() {
return R.xml.print_job_settings;
}
private static final String PRINT_JOB_PREFERENCE = "print_job_preference";
private static final String PRINT_JOB_MESSAGE_PREFERENCE = "print_job_message_preference";
@Override
protected String getLogTag() {
return TAG;
}
private final PrintJobStateChangeListener mPrintJobStateChangeListener =
new PrintJobStateChangeListener() {
@Override
public void onPrintJobStateChanged(PrintJobId printJobId) {
updateUi();
}
};
private PrintManager mPrintManager;
private Preference mPrintJobPreference;
private Preference mMessagePreference;
private PrintJobId mPrintJobId;
@Override
public void onAttach(Context context) {
super.onAttach(context);
use(PrintJobPreferenceController.class).init(this);
use(PrintJobMessagePreferenceController.class).init(this);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.PRINT_JOB_SETTINGS;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
addPreferencesFromResource(R.xml.print_job_settings);
mPrintJobPreference = findPreference(PRINT_JOB_PREFERENCE);
mMessagePreference = findPreference(PRINT_JOB_MESSAGE_PREFERENCE);
mPrintManager = ((PrintManager) getActivity().getSystemService(
Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
getActivity().getUserId());
getActivity().getActionBar().setTitle(R.string.print_print_job);
processArguments();
setHasOptionsMenu(true);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getListView().setEnabled(false);
}
@Override
public void onStart() {
super.onStart();
mPrintManager.addPrintJobStateChangeListener(
mPrintJobStateChangeListener);
updateUi();
}
@Override
public void onStop() {
super.onStop();
mPrintManager.removePrintJobStateChangeListener(
mPrintJobStateChangeListener);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
PrintJob printJob = getPrintJob();
final PrintJob printJob = use(PrintJobPreferenceController.class).getPrintJob();
if (printJob == null) {
return;
}
@@ -144,7 +89,7 @@ public class PrintJobSettingsFragment extends SettingsPreferenceFragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
PrintJob printJob = getPrintJob();
final PrintJob printJob = use(PrintJobPreferenceController.class).getPrintJob();
if (printJob != null) {
switch (item.getItemId()) {
@@ -164,113 +109,4 @@ public class PrintJobSettingsFragment extends SettingsPreferenceFragment {
return super.onOptionsItemSelected(item);
}
private void processArguments() {
String printJobId = getArguments().getString(EXTRA_PRINT_JOB_ID);
if (printJobId == null) {
printJobId = getIntent().getStringExtra(EXTRA_PRINT_JOB_ID);
if (printJobId == null) {
Log.w(LOG_TAG, EXTRA_PRINT_JOB_ID + " not set");
finish();
return;
}
}
mPrintJobId = PrintJobId.unflattenFromString(printJobId);
}
private PrintJob getPrintJob() {
return mPrintManager.getPrintJob(mPrintJobId);
}
private void updateUi() {
PrintJob printJob = getPrintJob();
if (printJob == null) {
finish();
return;
}
if (printJob.isCancelled() || printJob.isCompleted()) {
finish();
return;
}
PrintJobInfo info = printJob.getInfo();
switch (info.getState()) {
case PrintJobInfo.STATE_CREATED: {
mPrintJobPreference.setTitle(getString(
R.string.print_configuring_state_title_template, info.getLabel()));
} break;
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
if (!printJob.getInfo().isCancelling()) {
mPrintJobPreference.setTitle(getString(
R.string.print_printing_state_title_template, info.getLabel()));
} else {
mPrintJobPreference.setTitle(getString(
R.string.print_cancelling_state_title_template, info.getLabel()));
}
} break;
case PrintJobInfo.STATE_FAILED: {
mPrintJobPreference.setTitle(getString(
R.string.print_failed_state_title_template, info.getLabel()));
} break;
case PrintJobInfo.STATE_BLOCKED: {
if (!printJob.getInfo().isCancelling()) {
mPrintJobPreference.setTitle(getString(
R.string.print_blocked_state_title_template, info.getLabel()));
} else {
mPrintJobPreference.setTitle(getString(
R.string.print_cancelling_state_title_template, info.getLabel()));
}
} break;
}
mPrintJobPreference.setSummary(getString(R.string.print_job_summary,
info.getPrinterName(), DateUtils.formatSameDayTime(
info.getCreationTime(), info.getCreationTime(), DateFormat.SHORT,
DateFormat.SHORT)));
TypedArray a = getActivity().obtainStyledAttributes(new int[]{
android.R.attr.colorControlNormal});
int tintColor = a.getColor(0, 0);
a.recycle();
switch (info.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
Drawable icon = getActivity().getDrawable(com.android.internal.R.drawable.ic_print);
icon.setTint(tintColor);
mPrintJobPreference.setIcon(icon);
break;
}
case PrintJobInfo.STATE_FAILED:
case PrintJobInfo.STATE_BLOCKED: {
Drawable icon = getActivity().getDrawable(
com.android.internal.R.drawable.ic_print_error);
icon.setTint(tintColor);
mPrintJobPreference.setIcon(icon);
break;
}
}
CharSequence status = info.getStatus(getPackageManager());
if (!TextUtils.isEmpty(status)) {
if (getPreferenceScreen().findPreference(PRINT_JOB_MESSAGE_PREFERENCE) == null) {
getPreferenceScreen().addPreference(mMessagePreference);
}
mMessagePreference.setSummary(status);
} else {
getPreferenceScreen().removePreference(mMessagePreference);
}
getActivity().invalidateOptionsMenu();
}
}

View File

@@ -454,6 +454,13 @@ public class WifiConfigController implements TextWatcher,
return false;
}
boolean isValidSaePassword(String password) {
if (password.length() >= 1 && password.length() <= 63) {
return true;
}
return false;
}
boolean isSubmittable() {
boolean enabled = false;
boolean passwordInvalid = false;
@@ -461,7 +468,9 @@ public class WifiConfigController implements TextWatcher,
&& ((mAccessPointSecurity == AccessPoint.SECURITY_WEP
&& mPasswordView.length() == 0)
|| (mAccessPointSecurity == AccessPoint.SECURITY_PSK
&& !isValidPsk(mPasswordView.getText().toString())))) {
&& !isValidPsk(mPasswordView.getText().toString()))
|| (mAccessPointSecurity == AccessPoint.SECURITY_SAE
&& !isValidSaePassword(mPasswordView.getText().toString())))) {
passwordInvalid = true;
}
if ((mSsidView != null && mSsidView.length() == 0)
@@ -475,7 +484,9 @@ public class WifiConfigController implements TextWatcher,
} else {
enabled = ipAndProxyFieldsAreValid();
}
if (mAccessPointSecurity == AccessPoint.SECURITY_EAP && mEapCaCertSpinner != null
if ((mAccessPointSecurity == AccessPoint.SECURITY_EAP ||
mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B)
&& mEapCaCertSpinner != null
&& mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem();
if (caCertSelection.equals(mUnspecifiedCertString)) {
@@ -492,7 +503,9 @@ public class WifiConfigController implements TextWatcher,
enabled = false;
}
}
if (mAccessPointSecurity == AccessPoint.SECURITY_EAP && mEapUserCertSpinner != null
if ((mAccessPointSecurity == AccessPoint.SECURITY_EAP ||
mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B)
&& mEapUserCertSpinner != null
&& mView.findViewById(R.id.l_user_cert).getVisibility() != View.GONE
&& mEapUserCertSpinner.getSelectedItem().equals(mUnspecifiedCertString)) {
// Disallow submit if the user has not selected a user certificate for an EAP network
@@ -590,8 +603,18 @@ public class WifiConfigController implements TextWatcher,
break;
case AccessPoint.SECURITY_EAP:
case AccessPoint.SECURITY_EAP_SUITE_B:
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
if (mAccessPointSecurity == AccessPoint.SECURITY_EAP_SUITE_B) {
config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
config.requirePMF = true;
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
config.allowedGroupMgmtCiphers.set(WifiConfiguration.GroupMgmtCipher
.BIP_GMAC_256);
config.allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
}
config.enterpriseConfig = new WifiEnterpriseConfig();
int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
int phase2Method = mPhase2Spinner.getSelectedItemPosition();
@@ -700,6 +723,20 @@ public class WifiConfigController implements TextWatcher,
config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
}
break;
case AccessPoint.SECURITY_SAE:
config.allowedKeyManagement.set(KeyMgmt.SAE);
config.requirePMF = true;
if (mPasswordView.length() != 0) {
String password = mPasswordView.getText().toString();
config.preSharedKey = '"' + password + '"';
}
break;
case AccessPoint.SECURITY_OWE:
config.allowedKeyManagement.set(KeyMgmt.OWE);
config.requirePMF = true;
break;
default:
return null;
}
@@ -851,7 +888,8 @@ public class WifiConfigController implements TextWatcher,
}
private void showSecurityFields() {
if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
if (mAccessPointSecurity == AccessPoint.SECURITY_NONE ||
mAccessPointSecurity == AccessPoint.SECURITY_OWE) {
mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
return;
}
@@ -870,7 +908,8 @@ public class WifiConfigController implements TextWatcher,
}
}
if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
if (mAccessPointSecurity != AccessPoint.SECURITY_EAP &&
mAccessPointSecurity != AccessPoint.SECURITY_EAP_SUITE_B) {
mView.findViewById(R.id.eap).setVisibility(View.GONE);
return;
}

View File

@@ -488,7 +488,8 @@ public class WifiSettings extends RestrictedSettingsFragment
menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && nfcAdapter.isEnabled() &&
mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
(!(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE))) {
// Only allow writing of NFC tags for password-protected networks.
menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
}
@@ -506,7 +507,8 @@ public class WifiSettings extends RestrictedSettingsFragment
boolean isSavedNetwork = mSelectedAccessPoint.isSaved();
if (isSavedNetwork) {
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
} else if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
} else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
/** Bypass dialog for unsecured networks */
mSelectedAccessPoint.generateOpenNetworkConfig();
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
@@ -552,7 +554,8 @@ public class WifiSettings extends RestrictedSettingsFragment
* networks, or Passpoint provided networks.
*/
WifiConfiguration config = mSelectedAccessPoint.getConfig();
if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
mSelectedAccessPoint.generateOpenNetworkConfig();
connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
} else if (mSelectedAccessPoint.isSaved() && config != null
@@ -772,7 +775,8 @@ public class WifiSettings extends RestrictedSettingsFragment
preference.setKey(key);
preference.setOrder(index);
if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
&& accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
&& (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE &&
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
onPreferenceTreeClick(preference);
mOpenSsid = null;

View File

@@ -67,7 +67,7 @@ public class WifiPrivacyPreferenceController extends BasePreferenceController im
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mWifiConfiguration != null) {
//TODO(b/117957974): update MAC randomization level to WifiManager
mWifiConfiguration.macRandomizationSetting = Integer.parseInt((String) newValue);
mWifiManager.updateNetwork(mWifiConfiguration);
}
updateSummary((DropDownPreference) preference, Integer.parseInt((String) newValue));
@@ -77,10 +77,9 @@ public class WifiPrivacyPreferenceController extends BasePreferenceController im
@VisibleForTesting
int getRandomizationValue() {
if (mWifiConfiguration != null) {
//TODO(b/117957974): get real MAC randomization level from WifiManager
return 0;
return mWifiConfiguration.macRandomizationSetting;
}
return 0;
return WifiConfiguration.RANDOMIZATION_PERSISTENT;
}
private void updateSummary(DropDownPreference preference, int macRandomized) {

View File

@@ -15,7 +15,6 @@ com.android.settings.applications.appinfo.WriteSettingsDetails
com.android.settings.applications.AppLaunchSettings
com.android.settings.applications.AppStorageSettings
com.android.settings.applications.ConfirmConvertToFbe
com.android.settings.applications.DirectoryAccessDetails
com.android.settings.applications.ProcessStatsDetail
com.android.settings.applications.ProcessStatsSummary
com.android.settings.applications.ProcessStatsUi
@@ -59,6 +58,7 @@ com.android.settings.notification.RedactionInterstitial$RedactionInterstitialFra
com.android.settings.notification.ZenModeEventRuleSettings
com.android.settings.notification.ZenModeScheduleRuleSettings
com.android.settings.password.ChooseLockGeneric$ChooseLockGenericFragment
com.android.settings.password.SetupChooseLockGeneric$InternalActivity$InternalSetupChooseLockGenericFragment
com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
com.android.settings.print.PrintJobSettingsFragment
com.android.settings.print.PrintServiceSettingsFragment

View File

@@ -62,6 +62,8 @@
<bool name="config_show_wifi_mac_address">false</bool>
<bool name="config_disable_uninstall_update">true</bool>
<bool name="config_show_device_name">false</bool>
<bool name="config_use_legacy_suggestion">false</bool>
<bool name="config_show_avatar_in_homepage">true</bool>
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
<bool name="config_enable_extra_screen_zoom_preview">false</bool>

View File

@@ -18,18 +18,22 @@ package com.android.settings.accounts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.accounts.Account;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.widget.ImageView;
import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@@ -39,50 +43,92 @@ import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowPackageManager;
@RunWith(SettingsRobolectricTestRunner.class)
public class AvatarViewMixinTest {
private static final String DUMMY_ACCOUNT = "test@domain.com";
private static final String DUMMY_DOMAIN = "domain.com";
private static final String DUMMY_AUTHORITY = "authority.domain.com";
private Context mContext;
private ImageView mImageView;
private ActivityController mController;
private SettingsHomepageActivity mActivity;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mImageView = new ImageView(mContext);
mController = Robolectric.buildActivity(SettingsHomepageActivity.class).create();
mActivity = (SettingsHomepageActivity) mController.get();
}
@Test
public void hasAccount_useDefaultAccountData_returnFalse() {
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mContext, mImageView);
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
assertThat(avatarViewMixin.hasAccount()).isFalse();
}
@Test
@Config(shadows = ShadowAccountFeatureProviderImpl.class)
public void hasAccount_useShadowAccountData_returnTrue() {
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mContext, mImageView);
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
assertThat(avatarViewMixin.hasAccount()).isTrue();
}
@Test
public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {
final AvatarViewMixin mockAvatar = spy(new AvatarViewMixin(mContext, mImageView));
public void onStart_configDisabled_doNothing() {
final AvatarViewMixin mixin = spy(new AvatarViewMixin(mActivity, mImageView));
mixin.onStart();
final ActivityController controller = Robolectric.buildActivity(
SettingsHomepageActivity.class).create();
final SettingsHomepageActivity settingsHomepageActivity =
(SettingsHomepageActivity) controller.get();
settingsHomepageActivity.getLifecycle().addObserver(mockAvatar);
controller.start();
verify(mockAvatar).onStart();
verify(mixin, never()).hasAccount();
}
@Implements(AccountFeatureProviderImpl.class)
@Test
@Config(qualifiers = "mcc999")
public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {
final AvatarViewMixin mockAvatar = spy(new AvatarViewMixin(mActivity, mImageView));
mActivity.getLifecycle().addObserver(mockAvatar);
mController.start();
verify(mockAvatar).hasAccount();
}
@Test
public void queryProviderAuthority_useShadowPackagteManager_returnNull() {
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
assertThat(avatarViewMixin.queryProviderAuthority()).isNull();
}
@Test
public void queryProviderAuthority_useNewShadowPackagteManager_returnAuthority() {
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(mActivity, mImageView);
ShadowPackageManager shadowPackageManager = Shadow.extract(mContext.getPackageManager());
final PackageInfo accountProvider = new PackageInfo();
accountProvider.packageName = "test.pkg";
accountProvider.applicationInfo = new ApplicationInfo();
accountProvider.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
accountProvider.applicationInfo.packageName = accountProvider.packageName;
accountProvider.providers = new ProviderInfo[1];
accountProvider.providers[0] = new ProviderInfo();
accountProvider.providers[0].authority = DUMMY_AUTHORITY;
accountProvider.providers[0].packageName = accountProvider.packageName;
accountProvider.providers[0].name = "test.class";
accountProvider.providers[0].applicationInfo = accountProvider.applicationInfo;
final ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.providerInfo = accountProvider.providers[0];
shadowPackageManager.addResolveInfoForIntent(AvatarViewMixin.INTENT_GET_ACCOUNT_DATA,
resolveInfo);
assertThat(avatarViewMixin.queryProviderAuthority()).isEqualTo(DUMMY_AUTHORITY);
}
@Implements(value = AccountFeatureProviderImpl.class)
public static class ShadowAccountFeatureProviderImpl {
@Implementation

View File

@@ -106,15 +106,12 @@ public class AppHeaderViewPreferenceControllerTest {
final TextView title = mHeader.findViewById(R.id.entity_header_title);
final TextView summary = mHeader.findViewById(R.id.entity_header_summary);
mController.displayPreference(mScreen);
mController.refreshUi();
assertThat(title).isNotNull();
assertThat(title.getText()).isEqualTo(appLabel);
assertThat(summary).isNotNull();
assertThat(summary.getText()).isEqualTo(mContext.getString(R.string.installed));
}
@Test

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.connecteddevice;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.FeatureFlagUtils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class BluetoothOnWhileDrivingPreferenceControllerTest {
private BluetoothOnWhileDrivingPreferenceController mController;
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new BluetoothOnWhileDrivingPreferenceController(mContext);
}
@Test
public void getAvailabilityStatus_onWhenEnabled() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlags.BLUETOOTH_WHILE_DRIVING, true);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_offWhenDisabled() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
@Test
public void setChecked_togglesSettingSecure() {
mController.setChecked(true);
final String name = Secure.BLUETOOTH_ON_WHILE_DRIVING;
assertThat(Settings.Secure.getInt(mContext.getContentResolver(), name, 0)).isEqualTo(1);
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static com.android.settings.development.DesktopModePreferenceController.SETTING_VALUE_OFF;
import static com.android.settings.development.DesktopModePreferenceController.SETTING_VALUE_ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class DesktopModePreferenceControllerTest {
private static final String ENG_BUILD_TYPE = "eng";
private static final String USER_BUILD_TYPE = "user";
@Mock
private SwitchPreference mPreference;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private DesktopModePreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new DesktopModePreferenceController(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mController.displayPreference(mScreen);
}
@Test
public void isAvailable_engBuild_shouldBeTrue() {
mController = spy(mController);
doReturn(ENG_BUILD_TYPE).when(mController).getBuildType();
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvaiable_userBuild_shouldBeTrue() {
mController = spy(mController);
doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void onPreferenceChange_switchEnabled_shouldEnableFreeformWindows() {
mController.onPreferenceChange(mPreference, true /* new value */);
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_ON);
}
@Test
public void onPreferenceChange_switchDisabled_shouldDisableFreeformWindows() {
mController.onPreferenceChange(mPreference, false /* new value */);
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
}
@Test
public void updateState_settingEnabled_preferenceShouldBeChecked() {
Settings.Global.putInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_ON);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
Settings.Global.putInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, SETTING_VALUE_OFF);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
mController.onDeveloperOptionsSwitchDisabled();
final int mode = Settings.Global.getInt(mContext.getContentResolver(),
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, -1 /* default */);
assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
verify(mPreference).setEnabled(false);
}
}

View File

@@ -19,7 +19,6 @@ package com.android.settings.development;
import static com.android.settings.development.FreeformWindowsPreferenceController
.SETTING_VALUE_OFF;
import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON;
import static com.android.settings.development.FreeformWindowsPreferenceController.USER_BUILD_TYPE;
import static com.google.common.truth.Truth.assertThat;
@@ -47,6 +46,7 @@ import org.robolectric.RuntimeEnvironment;
public class FreeformWindowsPreferenceControllerTest {
private static final String ENG_BUILD_TYPE = "eng";
private static final String USER_BUILD_TYPE = "user";
@Mock
private SwitchPreference mPreference;
@@ -74,11 +74,11 @@ public class FreeformWindowsPreferenceControllerTest {
}
@Test
public void isAvaiable_userBuild_shouldBeFalse() {
public void isAvaiable_userBuild_shouldBeTrue() {
mController = spy(mController);
doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.isAvailable()).isTrue();
}
@Test

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class UpdatedGfxDriverDevOptInPreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
private Context mContext;
private Preference mPreference;
private UpdatedGfxDriverDevOptInPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = spy(new UpdatedGfxDriverDevOptInPreferenceController(mContext, mFragment));
mPreference = new Preference(mContext);
mPreference.setKey(mController.getPreferenceKey());
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void handlePreferenceTreeClick_preferenceClicked_launchActivity() {
final Intent activityStartIntent = new Intent(mContext, AppPicker.class);
final String preferenceKey = mController.getPreferenceKey();
doReturn(activityStartIntent).when(mController).getActivityStartIntent();
mController.handlePreferenceTreeClick(mPreference);
verify(mFragment).startActivityForResult(activityStartIntent,
REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
}
@Test
public void updateState_foobarAppSelected_shouldUpdateSummaryWithUpdatedDriverDevOptInAppLabel() {
final String selectedApp = "foobar";
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver,
Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP, selectedApp);
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo(mContext.getString(R.string.updated_gfx_driver_dev_opt_in_app_set, selectedApp));
}
@Test
public void updateState_noAppSelected_shouldUpdateSummaryWithNoAppSelected() {
final String selectedApp = null;
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver,
Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP, selectedApp);
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo(mContext.getString(R.string.updated_gfx_driver_dev_opt_in_app_not_set));
}
@Test
public void onActivityResult_foobarAppSelected_shouldUpdateSummaryWithUpdatedDriverDevOptInLabel() {
Intent activityResultIntent = new Intent(mContext, AppPicker.class);
final String appLabel = "foobar";
activityResultIntent.setAction(appLabel);
final boolean result = mController
.onActivityResult(REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP, Activity.RESULT_OK,
activityResultIntent);
assertThat(result).isTrue();
assertThat(mPreference.getSummary()).isEqualTo(mContext.getString(R.string.updated_gfx_driver_dev_opt_in_app_set, appLabel));
}
@Test
public void onActivityResult_badRequestCode_shouldReturnFalse() {
assertThat(mController.onActivityResult(
-1 /* requestCode */, -1 /* resultCode */, null /* intent */)).isFalse();
}
@Test
public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getSummary()).isEqualTo(mContext.getString(R.string.updated_gfx_driver_dev_opt_in_app_not_set));
}
}

View File

@@ -1,4 +1,20 @@
package com.android.settings.deviceinfo.deviceinfo;
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo.aboutphone;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -6,8 +22,6 @@ import static org.mockito.Mockito.verify;
import android.content.DialogInterface;
import com.android.settings.deviceinfo.aboutphone.DeviceNameWarningDialog;
import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.deviceinfo;
package com.android.settings.deviceinfo.aboutphone;
import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
@@ -35,7 +35,7 @@ import android.util.ArrayMap;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceScreen;
import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
import com.android.settings.deviceinfo.BuildNumberPreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo.aboutphone;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.Build;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class TopLevelAboutDevicePreferenceControllerTest {
private Context mContext;
private TopLevelAboutDevicePreferenceController mController;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new TopLevelAboutDevicePreferenceController(mContext, "test_key");
}
@Test
public void getAvailabilityState_shouldBeAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getSummary_shouldReturnDeviceModel() {
assertThat(mController.getSummary().toString()).isEqualTo(Build.MODEL);
}
}

View File

@@ -258,7 +258,6 @@ public class AdvancedPowerUsageDetailTest {
verify(mEntityHeaderController).setIcon(mAppEntry);
verify(mEntityHeaderController).setLabel(mAppEntry);
verify(mEntityHeaderController).setIsInstantApp(true);
verify(mEntityHeaderController).setSummary((CharSequence) null);
}
@Test

View File

@@ -18,10 +18,12 @@ package com.android.settings.homepage.contextualcards;
import static com.google.common.truth.Truth.assertThat;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.android.settings.intelligence.ContextualCardProto;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
@@ -30,6 +32,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class CardDatabaseHelperTest {
@@ -80,4 +85,38 @@ public class CardDatabaseHelperTest {
assertThat(columnNames).isEqualTo(expectedNames);
cursor.close();
}
@Test
public void getContextualCards_shouldSortByScore() {
insertFakeCard(mDatabase, "card1", 1, "uri1");
insertFakeCard(mDatabase, "card2", 0, "uri2");
insertFakeCard(mDatabase, "card3", 10, "uri3");
// Should sort as 3,1,2
try (final Cursor cursor = CardDatabaseHelper.getInstance(mContext).getContextualCards()) {
assertThat(cursor.getCount()).isEqualTo(3);
final List<ContextualCard> cards = new ArrayList<>();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
cards.add(new ContextualCard(cursor));
}
assertThat(cards.get(0).getName()).isEqualTo("card3");
assertThat(cards.get(1).getName()).isEqualTo("card1");
assertThat(cards.get(2).getName()).isEqualTo("card2");
}
}
private static void insertFakeCard(SQLiteDatabase db, String name, double score, String uri) {
final ContentValues value = new ContentValues();
value.put(CardDatabaseHelper.CardColumns.NAME, name);
value.put(CardDatabaseHelper.CardColumns.SCORE, score);
value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
value.put(CardDatabaseHelper.CardColumns.CATEGORY,
ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
RuntimeEnvironment.application.getPackageName());
value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
}
}

View File

@@ -30,7 +30,7 @@ public class ConditionalContextualCardTest {
@Test(expected = IllegalArgumentException.class)
public void newInstance_changeCardType_shouldCrash() {
new ConditionalContextualCard.Builder()
.setCardType(ContextualCard.CardType.SUGGESTION)
.setCardType(ContextualCard.CardType.LEGACY_SUGGESTION)
.build();
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import android.content.Context;
import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settingslib.suggestions.SuggestionController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = ShadowThreadUtils.class)
public class LegacySuggestionContextualCardControllerTest {
@Mock
private SuggestionController mSuggestionController;
@Mock
private ContextualCardUpdateListener mCardUpdateListener;
private Context mContext;
private LegacySuggestionContextualCardController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
mContext = RuntimeEnvironment.application;
mController = new LegacySuggestionContextualCardController(mContext);
}
@Test
public void init_configOn_shouldCreateSuggestionController() {
final LegacySuggestionContextualCardController controller =
new LegacySuggestionContextualCardController(mContext);
assertThat(controller.mSuggestionController).isNotNull();
}
@Test
@Config(qualifiers = "mcc999")
public void init_configOff_shouldNotCreateSuggestionController() {
final LegacySuggestionContextualCardController controller =
new LegacySuggestionContextualCardController(mContext);
assertThat(controller.mSuggestionController).isNull();
}
@Test
public void goThroughLifecycle_hasSuggestionController_shouldStartStopController() {
mController.mSuggestionController = mSuggestionController;
mController.onStart();
verify(mSuggestionController).start();
mController.onStop();
verify(mSuggestionController).stop();
}
@Test
public void onServiceConnected_shouldLoadSuggestion() {
mController.mSuggestionController = mSuggestionController;
mController.setCardUpdateListener(mCardUpdateListener);
mController.onServiceConnected();
verify(mSuggestionController).getSuggestions();
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class LegacySuggestionContextualCardRendererTest {
@Mock
private ControllerRendererPool mControllerRendererPool;
@Mock
private LegacySuggestionContextualCardController mController;
private Context mContext;
private LegacySuggestionContextualCardRenderer mRenderer;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mRenderer = new LegacySuggestionContextualCardRenderer(mContext, mControllerRendererPool);
}
@Test
public void bindView_shouldSetListener() {
final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
final RecyclerView recyclerView = new RecyclerView(mContext);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
when(mControllerRendererPool.getController(mContext,
ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
mRenderer.bindView(viewHolder, buildContextualCard());
assertThat(card).isNotNull();
assertThat(card.hasOnClickListeners()).isTrue();
}
@Test
public void viewClick_shouldInvokeControllerPrimaryClick() {
final int viewType = mRenderer.getViewType(true /* isHalfWidth */);
final RecyclerView recyclerView = new RecyclerView(mContext);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
final View card = LayoutInflater.from(mContext).inflate(viewType, recyclerView, false);
final RecyclerView.ViewHolder viewHolder = mRenderer.createViewHolder(card);
when(mControllerRendererPool.getController(mContext,
ContextualCard.CardType.LEGACY_SUGGESTION)).thenReturn(mController);
mRenderer.bindView(viewHolder, buildContextualCard());
assertThat(card).isNotNull();
card.performClick();
verify(mController).onPrimaryClick(any(ContextualCard.class));
}
private ContextualCard buildContextualCard() {
return new LegacySuggestionContextualCard.Builder()
.setName("test_name")
.setTitleText("test_title")
.setSummaryText("test_summary")
.setIconDrawable(mContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
.build();
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.homepage.contextualcards.legacysuggestion;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.app.PendingIntent;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SettingsRobolectricTestRunner.class)
public class LegacySuggestionContextualCardTest {
@Test(expected = IllegalArgumentException.class)
public void newInstance_changeCardType_shouldCrash() {
new LegacySuggestionContextualCard.Builder()
.setCardType(ContextualCard.CardType.CONDITIONAL)
.build();
}
@Test
public void getCardType_shouldAlwaysBeSuggestionType() {
assertThat(new LegacySuggestionContextualCard.Builder().build().getCardType())
.isEqualTo(ContextualCard.CardType.LEGACY_SUGGESTION);
}
@Test
public void build_shouldSetPendingIntent() {
assertThat(new LegacySuggestionContextualCard.Builder()
.setPendingIntent(mock(PendingIntent.class))
.build()
.getPendingIntent()).isNotNull();
}
}

View File

@@ -165,7 +165,8 @@ public class MobileNetworkUtilsTest {
@Test
public void isCdmaOptions_worldModeWithGsmWcdma_returnTrue() {
when(mTelephonyManager.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
when(mContext.getString(R.string.config_world_mode)).thenReturn("true");
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, true);
Settings.Global.putInt(mContext.getContentResolver(),
android.provider.Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID_1,
TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.print;
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.print.PrintJob;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class PrintJobMessagePreferenceControllerTest {
private static final String PREF_KEY = "print_job_message_preference";
@Mock
private PrintManager mPrintManager;
@Mock
private PrintJob mPrintJob;
@Mock
private PrintJobInfo mPrintJobInfo;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private PrintJobMessagePreferenceController mController;
private Preference mPreference;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mPreference = new Preference(mContext);
when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
mController = new PrintJobMessagePreferenceController(mContext, PREF_KEY);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mController.displayPreference(mScreen);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mLifecycle.addObserver(mController);
}
@Test
public void onStartStop_shouldRegisterPrintStateListener() {
mLifecycle.handleLifecycleEvent(ON_START);
mLifecycle.handleLifecycleEvent(ON_STOP);
verify(mPrintManager).addPrintJobStateChangeListener(mController);
verify(mPrintManager).removePrintJobStateChangeListener(mController);
}
@Test
public void updateUi_visiblePreference() {
when(mPrintJobInfo.getStatus(anyObject())).thenReturn("TestPrint");
mLifecycle.handleLifecycleEvent(ON_START);
assertThat(mPreference.isVisible()).isTrue();
mLifecycle.handleLifecycleEvent(ON_STOP);
}
@Test
public void updateUi_invisiblePreference() {
when(mPrintJobInfo.getStatus(anyObject())).thenReturn(null);
mLifecycle.handleLifecycleEvent(ON_START);
assertThat(mPreference.isVisible()).isFalse();
mLifecycle.handleLifecycleEvent(ON_STOP);
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.print;
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.print.PrintJob;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class PrintJobPreferenceControllerTest {
private static final String PREF_KEY = "print_job_preference";
@Mock
private PrintManager mPrintManager;
@Mock
private PrintJob mPrintJob;
@Mock
private PrintJobInfo mPrintJobInfo;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private PrintJobPreferenceController mController;
private Preference mPreference;
private String mTestLabel;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mPreference = new Preference(mContext);
mTestLabel = "PrintTest";
when(mContext.getSystemService(Context.PRINT_SERVICE)).thenReturn(mPrintManager);
when(mPrintManager.getGlobalPrintManagerForUser(anyInt())).thenReturn(mPrintManager);
when(mPrintManager.getPrintJob(anyObject())).thenReturn(mPrintJob);
when(mPrintJob.getInfo()).thenReturn(mPrintJobInfo);
mController = new PrintJobPreferenceController(mContext, PREF_KEY);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mPrintJobInfo.getLabel()).thenReturn(mTestLabel);
mController.displayPreference(mScreen);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mLifecycle.addObserver(mController);
}
@Test
public void onStartStop_shouldRegisterPrintStateListener() {
mLifecycle.handleLifecycleEvent(ON_START);
mLifecycle.handleLifecycleEvent(ON_STOP);
verify(mPrintManager).addPrintJobStateChangeListener(mController);
verify(mPrintManager).removePrintJobStateChangeListener(mController);
}
@Test
public void updateUi_jobState_STATE_CREATED() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_CREATED);
mController.onStart();
String title = mContext.getString(
R.string.print_configuring_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_QUEUED() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_QUEUED);
mController.onStart();
String title = mContext.getString(
R.string.print_printing_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_STARTED() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_STARTED);
mController.onStart();
String title = mContext.getString(
R.string.print_printing_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_QUEUED_and_jobInfo_CANCELLING() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_QUEUED);
when(mPrintJobInfo.isCancelling()).thenReturn(true);
mController.onStart();
String title = mContext.getString(
R.string.print_cancelling_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_STARTED_and_jobInfo_CANCELLING() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_STARTED);
when(mPrintJobInfo.isCancelling()).thenReturn(true);
mController.onStart();
String title = mContext.getString(
R.string.print_cancelling_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_FAILED() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_FAILED);
mController.onStart();
String title = mContext.getString(
R.string.print_failed_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_BLOCKED() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_BLOCKED);
mController.onStart();
String title = mContext.getString(
R.string.print_blocked_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
@Test
public void updateUi_jobState_STATE_BLOCKED_and_jobInfo_CANCELLING() {
when(mPrintJobInfo.getState()).thenReturn(PrintJobInfo.STATE_BLOCKED);
when(mPrintJobInfo.isCancelling()).thenReturn(true);
mController.onStart();
String title = mContext.getString(
R.string.print_cancelling_state_title_template, mTestLabel);
assertThat(mPreference.getTitle()).isEqualTo(title);
}
}

View File

@@ -66,7 +66,7 @@ public class WifiTetherSecurityPreferenceControllerTest {
public void onPreferenceChange_securityValueUpdated() {
mController.onPreferenceChange(mPreference, WPA2_PSK);
assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
mController.onPreferenceChange(mPreference, NONE);
assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE);
@@ -75,11 +75,11 @@ public class WifiTetherSecurityPreferenceControllerTest {
@Test
public void updateDisplay_preferenceUpdated() {
// test defaulting to WPA2 PSK on new config
// test defaulting to WPA2-Personal on new config
when(mWifiManager.getWifiApConfiguration()).thenReturn(null);
mController.updateDisplay();
assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
// test open tether network
when(mWifiManager.getWifiApConfiguration()).thenReturn(mConfig);
@@ -89,11 +89,11 @@ public class WifiTetherSecurityPreferenceControllerTest {
assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.NONE);
assertThat(mPreference.getSummary()).isEqualTo("None");
// test WPA2 PSK tether network
// test WPA2-Personal tether network
mConfig.allowedKeyManagement.clear();
mConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
mController.updateDisplay();
assertThat(mController.getSecurityType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
assertThat(mPreference.getSummary()).isEqualTo("WPA2 PSK");
assertThat(mPreference.getSummary()).isEqualTo("WPA2-Personal");
}
}

View File

@@ -166,7 +166,6 @@ Device name;device_name
Device security;security_category
Device theme;theme
Dial pad tones;dial_pad_tones
Directory access;special_app_directory_access
Disable Bluetooth A2DP hardware offload;bluetooth_disable_a2dp_hw_offload
Disable HW overlays;disable_overlays
Disable USB audio routing;usb_audio
@@ -236,6 +235,7 @@ Force 4x MSAA;force_msaa
Force RTL layout direction;force_rtl_layout_all_locales
Force activities to be resizable;force_resizable_activities
Force allow apps on external;force_allow_on_external
Force desktop mode;force_desktop_mode_on_external_displays
Force full GNSS measurements;enable_gnss_raw_meas_full_tracking
Free up space;storage_settings_free_space
Games;pref_games
@@ -620,4 +620,4 @@ Your access to this device;device_access_category
 ;auto_brightness_video
 ;battery_header
 ;battery_tip
 ;feature_flag_category
 ;feature_flag_category

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.password;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static com.google.common.truth.Truth.assertThat;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import android.support.test.runner.lifecycle.Stage;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiSelector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Collection;
/**
* Tests for {@link SetupChooseLockGenericTest}
*
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SetupChooseLockGenericTest {
private UiDevice mDevice;
private Context mContext;
@Before
public void setUp() throws Exception {
mDevice = UiDevice.getInstance(getInstrumentation());
mContext = getInstrumentation().getTargetContext();
Settings.Global.putInt(
mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
}
@After
public void tearDown() {
Settings.Global.putInt(
mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
}
@Test
public void clickSkipFigerprintPreference_deviceNotProvisioned_shouldBeAbleToProceed()
throws Throwable {
final Intent newPasswordIntent =
new Intent(getTargetContext(), SetupChooseLockGeneric.class)
.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true)
.setAction(ACTION_SET_NEW_PASSWORD)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
getInstrumentation().getContext().startActivity(newPasswordIntent);
mDevice.waitForIdle();
mDevice.findObject(new UiSelector().textContains("Continue without ")).click();
final Activity activity = getCurrentActivity();
assertThat(activity).isInstanceOf(SetupChooseLockGeneric.InternalActivity.class);
}
private Activity getCurrentActivity() throws Throwable {
getInstrumentation().waitForIdleSync();
final Activity[] activity = new Activity[1];
getInstrumentation().runOnMainSync(() -> {
Collection<Activity> activities = ActivityLifecycleMonitorRegistry.getInstance()
.getActivitiesInStage(Stage.RESUMED);
activity[0] = activities.iterator().next();
});
return activity[0];
}
}