Snap for 4728508 from 270f608578 to pi-release
Change-Id: I0f5a3415f416511852669812b13029ff356e2bd1
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2017 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="96dp"
|
||||
android:height="96dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M15.5,14h-0.79l-0.28-0.27c1.2-1.4,1.82-3.31,1.48-5.34c-0.47-2.78-2.79-5-5.59-5.34c-4.23-0.52-7.79,3.04-7.27,7.27
|
||||
c0.34,2.8,2.56,5.12,5.34,5.59c2.03,0.34,3.94-0.28,5.34-1.48L14,14.71v0.79l5.2,5.19c0.41,0.41,1.07,0.41,1.48,0l0.01-0.01
|
||||
c0.41-0.41,0.41-1.07,0-1.48L15.5,14z M9.5,14C7.01,14,5,11.99,5,9.5S7.01,5,9.5,5S14,7.01,14,9.5S11.99,14,9.5,14z" />
|
||||
</vector>
|
||||
@@ -20,8 +20,6 @@
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#F09300"
|
||||
android:pathData="M14,10.5v9.06C12.87,21,12,22,12,22S5,14.25,5,9A7,7,0,0,1,18.93,8H14.29A2.5,2.5,0,1,0,14,10.5ZM16,22h2V20H16Zm0-4h2V10H16Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM11,13h2v2h-2V13zM13,6h-2v5h2V6z"/>
|
||||
</vector>
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#4285F4"
|
||||
android:pathData="M12,2 C8.13400675,2 5,5.13400675 5,9 C5,14.25 12,22 12,22 C12,22 19,14.25 19,9
|
||||
C19,5.13400675 15.8659932,2 12,2 L12,2 Z M8.2,9.66 L9.61,8.24 L11,9.66
|
||||
L15.24,5.42 L16.65,6.83 L11,12.49 L8.2,9.66 Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM14.5,9c0,1.38 -1.12,2.5 -2.5,2.5S9.5,10.38 9.5,9s1.12,-2.5 2.5,-2.5S14.5,7.62 14.5,9z"/>
|
||||
</vector>
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#F09300"
|
||||
android:pathData="M17,1H7A2,2,0,0,0,5,3V21a2,2,0,0,0,2,2H17a2,2,0,0,0,2-2V3A2,2,0,0,0,17,1Zm0,18H7V5H17Zm-1-6H13V8H11v5H8l4,4Z" />
|
||||
android:fillColor="#FF000000"
|
||||
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,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
|
||||
</vector>
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#4285F4"
|
||||
android:pathData="M17,1H7A2,2,0,0,0,5,3V21a2,2,0,0,0,2,2H17a2,2,0,0,0,2-2V3A2,2,0,0,0,17,1ZM9.11,14.06h0l1.41,1.41,5.66-5.66-1.42-1.4-4.24,4.24L9.11,11.24,7.7,12.66ZM17,19H7V5H17Z" />
|
||||
android:fillColor="#FF000000"
|
||||
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,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16z"/>
|
||||
</vector>
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#F09300"
|
||||
android:pathData="M17,1a2,2,0,0,1,2,2V21a2,2,0,0,1-2,2H7a2,2,0,0,1-2-2V3A2,2,0,0,1,7,1Zm0,18V5H7V19ZM11,6.5h2v7H11Zm0,9h2v2H11Z" />
|
||||
android:fillColor="#FF000000"
|
||||
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,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
|
||||
</vector>
|
||||
|
||||
@@ -14,20 +14,12 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#F5A623"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M20.5515334,2.919 C15.9049774,0.613 11,0 11,0 C11,0 6.09502262,0.613
|
||||
1.44846657,2.919 C1.15485168,4.149 1,5.432 1,6.752 C1,8.109 1.16490699,9.429
|
||||
1.47561589,10.693 C2.13624937,13.382 3.45852187,15.813 5.26143791,17.807
|
||||
C6.84313725,19.559 8.79788839,20.973 11,21.926 C13.2021116,20.973
|
||||
15.1568627,19.559 16.7395676,17.807 C18.5414781,15.813 19.8637506,13.382
|
||||
20.5253896,10.693 C20.835093,9.429 21,8.109 21,6.752 C21,5.432 20.8461538,4.149
|
||||
20.5515334,2.919 M12,15.5 L10,15.5 L10,13.5 L12,13.5 L12,15.5 L12,15.5 Z M12,12
|
||||
L10,12 L10,6 L12,6 L12,12 L12,12 Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
|
||||
</vector>
|
||||
|
||||
@@ -14,22 +14,12 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#4285F4"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M20.5515334,2.92885159 C20.8461538,4.16300283 21,5.45033294 21,6.77478792
|
||||
C21,8.13636778 20.835093,9.46082277 20.5253896,10.7290888 C19.8637506,13.4271641
|
||||
18.5414781,15.8663687 16.7395676,17.8670984 C15.1568627,19.6250114
|
||||
13.2021116,21.0437836 11,22 C8.79788839,21.0437836 6.84313725,19.6250114
|
||||
5.26143791,17.8670984 C3.45852187,15.8663687 2.13624937,13.4271641
|
||||
1.47561589,10.7290888 C1.16490699,9.46082277 1,8.13636778 1,6.77478792
|
||||
C1,5.45033294 1.15485168,4.16300283 1.44846657,2.92885159
|
||||
C6.09502262,0.615068868 11,0 11,0 C11,0 15.9049774,0.615068868
|
||||
20.5515334,2.92885159 Z M15.6984615,6 L9.61538462,12.2961783 L7,10
|
||||
L5.69846154,11.3471338 L9.61538462,15 L17,7.3566879 L15.6984615,6 Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16zM12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2z"/>
|
||||
</vector>
|
||||
|
||||
@@ -14,30 +14,11 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
|
||||
<group
|
||||
android:translateX="-1"
|
||||
android:translateY="-1">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
||||
<path
|
||||
android:fillColor="#D84336"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M21.5515334,3.92885159 C21.8461538,5.16300283 22,6.45033294 22,7.77478792
|
||||
C22,9.13636778 21.835093,10.4608228 21.5253896,11.7290888 C20.8637506,14.4271641
|
||||
19.5414781,16.8663687 17.7395676,18.8670984 C16.1568627,20.6250114
|
||||
14.2021116,22.0437836 12,23 C9.79788839,22.0437836 7.84313725,20.6250114
|
||||
6.26143791,18.8670984 C4.45852187,16.8663687 3.13624937,14.4271641
|
||||
2.47561589,11.7290888 C2.16490699,10.4608228 2,9.13636778 2,7.77478792
|
||||
C2,6.45033294 2.15485168,5.16300283 2.44846657,3.92885159 C7.09502262,1.61506887
|
||||
12,1 12,1 C12,1 16.9049774,1.61506887 21.5515334,3.92885159 Z M14.6469246,7
|
||||
L11.9600359,9.71972847 L9.272253,7 L8.00878156,8.28072408 L10.6956703,11.0004526
|
||||
L8,13.720181 L9.26347144,15 L11.9600359,12.2802715 L14.7347402,15 L16,13.720181
|
||||
L13.2252957,11.0004526 L15.9121844,8.28072408 L14.6469246,7 Z" />
|
||||
</group>
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.5,9.91L14.09,8.5L12,10.59L9.91,8.5L8.5,9.91L10.59,12L8.5,14.09l1.41,1.41L12,13.42l2.09,2.08l1.41,-1.41L13.42,12L15.5,9.91zM12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2z"/>
|
||||
</vector>
|
||||
|
||||
@@ -62,35 +62,22 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/install_type"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
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"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
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"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
android:paddingBottom="8dp"
|
||||
android:textAlignment="viewStart"/>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:icon="@drawable/ic_lock"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
settings:suwFooter="@layout/choose_lock_password_footer"
|
||||
settings:suwHeaderText="@string/lockpassword_choose_your_screen_lock_header">
|
||||
|
||||
|
||||
@@ -72,9 +72,10 @@
|
||||
android:orientation="vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<SeekBar
|
||||
@@ -93,10 +94,11 @@
|
||||
android:textAlignment="viewStart"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:visibility="gone"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -55,36 +55,22 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/install_type"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
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"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
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"
|
||||
android:gravity="start"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -128,4 +128,7 @@
|
||||
doesn't interact well with scroll view -->
|
||||
<bool name="config_lock_pattern_minimal_ui">true</bool>
|
||||
|
||||
<!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
|
||||
<string-array name="config_settings_slices_accessibility_components" translatable="false"/>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -9265,6 +9265,9 @@
|
||||
<!-- [CHAR_LIMIT=NONE] Developer Settings: Title of the setting which turns on emulation of a display cutout. -->
|
||||
<string name="display_cutout_emulation">Simulate a display with a cutout</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=NONE] Developer Settings: Search keywords for the setting which turns on emulation of a display cutout. -->
|
||||
<string name="display_cutout_emulation_keywords">display cutout, notch</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off display cutout emulation. -->
|
||||
<string name="display_cutout_emulation_none">None</string>
|
||||
|
||||
|
||||
@@ -423,6 +423,15 @@
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EntityHeaderSummary"
|
||||
parent="@android:style/TextAppearance.Material.Body1">
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
<item name="android:gravity">start</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored"/>
|
||||
|
||||
<style name="ActionSecondaryButton" parent="android:Widget.DeviceDefault.Button"/>
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment"
|
||||
android:key="bluetooth_settings"
|
||||
android:title="@string/bluetooth_settings_title"
|
||||
android:icon="@drawable/ic_settings_bluetooth"
|
||||
settings:allowDividerAbove="true"/>
|
||||
android:icon="@drawable/ic_settings_bluetooth"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="dashboard_tile_placeholder" />
|
||||
|
||||
@@ -382,7 +382,8 @@
|
||||
|
||||
<ListPreference
|
||||
android:key="display_cutout_emulation"
|
||||
android:title="@string/display_cutout_emulation" />
|
||||
android:title="@string/display_cutout_emulation"
|
||||
settings:keywords="@string/display_cutout_emulation_keywords" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
@@ -141,11 +141,6 @@
|
||||
android:key="screen_locking_sounds"
|
||||
android:title="@string/screen_locking_sounds_title" />
|
||||
|
||||
<!-- Charging sounds -->
|
||||
<SwitchPreference
|
||||
android:key="charging_sounds"
|
||||
android:title="@string/charging_sounds_title" />
|
||||
|
||||
<!-- Docking sounds -->
|
||||
<SwitchPreference
|
||||
android:key="docking_sounds"
|
||||
|
||||
@@ -57,6 +57,7 @@ class EditPinPreference extends CustomEditTextPreference {
|
||||
if (editText != null) {
|
||||
editText.setInputType(InputType.TYPE_CLASS_NUMBER |
|
||||
InputType.TYPE_NUMBER_VARIATION_PASSWORD);
|
||||
editText.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,9 +32,11 @@ import android.os.Bundle;
|
||||
import android.os.RecoverySystem;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Telephony;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -151,9 +153,20 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
|
||||
ImsManager.factoryReset(context);
|
||||
restoreDefaultApn(context);
|
||||
esimFactoryReset(context, context.getPackageName());
|
||||
// There has been issues when Sms raw table somehow stores orphan
|
||||
// fragments. They lead to garbled message when new fragments come
|
||||
// in and combied with those stale ones. In case this happens again,
|
||||
// user can reset all network settings which will clean up this table.
|
||||
cleanUpSmsRawTable(context);
|
||||
}
|
||||
};
|
||||
|
||||
private void cleanUpSmsRawTable(Context context) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Uri uri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
|
||||
resolver.delete(uri, null, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void esimFactoryReset(Context context, String packageName) {
|
||||
if (mEraseEsim) {
|
||||
|
||||
@@ -342,6 +342,21 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
|
||||
boolean serviceEnabled) {
|
||||
final String serviceState = serviceEnabled
|
||||
? context.getString(R.string.accessibility_summary_state_enabled)
|
||||
: context.getString(R.string.accessibility_summary_state_disabled);
|
||||
final CharSequence serviceSummary = info.loadSummary(context.getPackageManager());
|
||||
final String stateSummaryCombo = context.getString(
|
||||
R.string.preference_summary_default_combination,
|
||||
serviceState, serviceSummary);
|
||||
|
||||
return (TextUtils.isEmpty(serviceSummary))
|
||||
? serviceState
|
||||
: stateSummaryCombo;
|
||||
}
|
||||
|
||||
private void handleToggleTextContrastPreferenceClick() {
|
||||
Settings.Secure.putInt(getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
|
||||
@@ -543,15 +558,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
preference.setSummary(R.string.accessibility_summary_state_stopped);
|
||||
description = getString(R.string.accessibility_description_state_stopped);
|
||||
} else {
|
||||
final String serviceState = serviceEnabled ?
|
||||
getString(R.string.accessibility_summary_state_enabled) :
|
||||
getString(R.string.accessibility_summary_state_disabled);
|
||||
final CharSequence serviceSummary = info.loadSummary(getPackageManager());
|
||||
final String stateSummaryCombo = getString(
|
||||
R.string.preference_summary_default_combination,
|
||||
serviceState, serviceSummary);
|
||||
preference.setSummary((TextUtils.isEmpty(serviceSummary)) ? serviceState
|
||||
: stateSummaryCombo);
|
||||
final CharSequence serviceSummary = getServiceSummary(getContext(), info,
|
||||
serviceEnabled);
|
||||
preference.setSummary(serviceSummary);
|
||||
}
|
||||
|
||||
// Disable all accessibility services that are not permitted.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilitySettings;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* PreferenceController for accessibility services to be used by Slices.
|
||||
* Wraps the common logic which enables accessibility services and checks their availability.
|
||||
* <p>
|
||||
* Should not be used in a {@link com.android.settings.dashboard.DashboardFragment}.
|
||||
*/
|
||||
public class AccessibilitySlicePreferenceController extends TogglePreferenceController {
|
||||
|
||||
private final ComponentName mComponentName;
|
||||
|
||||
private final int ON = 1;
|
||||
private final int OFF = 0;
|
||||
|
||||
public AccessibilitySlicePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mComponentName = ComponentName.unflattenFromString(getPreferenceKey());
|
||||
|
||||
if (mComponentName == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal Component Name from: " + preferenceKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo();
|
||||
return serviceInfo == null
|
||||
? "" : AccessibilitySettings.getServiceSummary(mContext, serviceInfo, isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
final ContentResolver contentResolver = mContext.getContentResolver();
|
||||
final boolean accessibilityEnabled = Settings.Secure.getInt(contentResolver,
|
||||
Settings.Secure.ACCESSIBILITY_ENABLED, OFF) == ON;
|
||||
|
||||
if (!accessibilityEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Set<ComponentName> componentNames =
|
||||
AccessibilityUtils.getEnabledServicesFromSettings(mContext);
|
||||
|
||||
return componentNames.contains(mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
if (getAccessibilityServiceInfo() == null) {
|
||||
return false;
|
||||
}
|
||||
AccessibilityUtils.setAccessibilityServiceState(mContext, mComponentName, isChecked);
|
||||
return isChecked == isChecked(); // Verify that it was probably changed.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
// Return unsupported when the service is disabled or not installed.
|
||||
return getAccessibilityServiceInfo() == null ? DISABLED_UNSUPPORTED : AVAILABLE;
|
||||
}
|
||||
|
||||
private AccessibilityServiceInfo getAccessibilityServiceInfo() {
|
||||
final AccessibilityManager accessibilityManager = mContext.getSystemService(
|
||||
AccessibilityManager.class);
|
||||
final List<AccessibilityServiceInfo> serviceList =
|
||||
accessibilityManager.getInstalledAccessibilityServiceList();
|
||||
|
||||
for (AccessibilityServiceInfo serviceInfo : serviceList) {
|
||||
if (mComponentName.equals(serviceInfo.getComponentName())) {
|
||||
return serviceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -259,8 +259,10 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
|
||||
return;
|
||||
}
|
||||
tile.icon = Icon.createWithResource(iconInfo.first, iconInfo.second);
|
||||
ThreadUtils.postOnMainThread(() ->
|
||||
preference.setIcon(tile.icon.loadDrawable(preference.getContext()))
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
preference.setIcon(tile.icon.loadDrawable(preference.getContext()));
|
||||
tile.icon = null;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package com.android.settings.gestures;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -33,6 +36,7 @@ public class SwipeUpPreferenceController extends GesturePreferenceController {
|
||||
private final int ON = 1;
|
||||
private final int OFF = 0;
|
||||
|
||||
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
|
||||
private static final String PREF_KEY_VIDEO = "gesture_swipe_up_video";
|
||||
private final UserManager mUserManager;
|
||||
|
||||
@@ -42,6 +46,14 @@ public class SwipeUpPreferenceController extends GesturePreferenceController {
|
||||
}
|
||||
|
||||
static boolean isGestureAvailable(Context context) {
|
||||
final ComponentName recentsComponentName = ComponentName.unflattenFromString(
|
||||
context.getString(com.android.internal.R.string.config_recentsComponentName));
|
||||
final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP)
|
||||
.setPackage(recentsComponentName.getPackageName());
|
||||
if (context.getPackageManager().resolveService(quickStepIntent,
|
||||
PackageManager.MATCH_SYSTEM_ONLY) == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1195,12 +1195,19 @@ public class ApnEditor extends SettingsPreferenceFragment
|
||||
}
|
||||
}
|
||||
|
||||
private ApnData getApnDataFromUri(Uri uri) {
|
||||
ApnData apnData;
|
||||
try (Cursor cursor = getActivity().managedQuery(
|
||||
uri, sProjection, null /* selection */, null /* sortOrder */)) {
|
||||
cursor.moveToFirst();
|
||||
apnData = new ApnData(uri, cursor);
|
||||
@VisibleForTesting
|
||||
ApnData getApnDataFromUri(Uri uri) {
|
||||
ApnData apnData = null;
|
||||
try (Cursor cursor = getContentResolver().query(
|
||||
uri,
|
||||
sProjection,
|
||||
null /* selection */,
|
||||
null /* selectionArgs */,
|
||||
null /* sortOrder */)) {
|
||||
if (cursor != null) {
|
||||
cursor.moveToFirst();
|
||||
apnData = new ApnData(uri, cursor);
|
||||
}
|
||||
}
|
||||
|
||||
if (apnData == null) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.settings.notification;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.arch.lifecycle.LifecycleObserver;
|
||||
import android.arch.lifecycle.OnLifecycleEvent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -31,6 +33,7 @@ import android.os.Vibrator;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -58,6 +61,7 @@ public class RingVolumePreferenceController extends VolumeSeekBarPreferenceContr
|
||||
updateRingerMode();
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -66,6 +70,7 @@ public class RingVolumePreferenceController extends VolumeSeekBarPreferenceContr
|
||||
updatePreferenceIcon();
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
@@ -118,11 +123,10 @@ public class RingVolumePreferenceController extends VolumeSeekBarPreferenceContr
|
||||
|
||||
private void updatePreferenceIcon() {
|
||||
if (mPreference != null) {
|
||||
mPreference.showIcon(mSuppressor != null
|
||||
? com.android.internal.R.drawable.ic_audio_ring_notif_mute
|
||||
: mRingerMode == AudioManager.RINGER_MODE_VIBRATE || wasRingerModeVibrate()
|
||||
? com.android.internal.R.drawable.ic_audio_ring_notif_vibrate
|
||||
: com.android.internal.R.drawable.ic_audio_ring_notif);
|
||||
mPreference.showIcon(
|
||||
mRingerMode == AudioManager.RINGER_MODE_VIBRATE || wasRingerModeVibrate()
|
||||
? com.android.internal.R.drawable.ic_audio_ring_notif_vibrate
|
||||
: com.android.internal.R.drawable.ic_audio_ring_notif);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,10 +146,16 @@ public class SoundSettings extends DashboardFragment {
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
use(AlarmVolumePreferenceController.class).setCallback(mVolumeCallback);
|
||||
use(MediaVolumePreferenceController.class).setCallback(mVolumeCallback);
|
||||
use(RingVolumePreferenceController.class).setCallback(mVolumeCallback);
|
||||
use(NotificationVolumePreferenceController.class).setCallback(mVolumeCallback);
|
||||
ArrayList<VolumeSeekBarPreferenceController> volumeControllers = new ArrayList<>();
|
||||
volumeControllers.add(use(AlarmVolumePreferenceController.class));
|
||||
volumeControllers.add(use(MediaVolumePreferenceController.class));
|
||||
volumeControllers.add(use(RingVolumePreferenceController.class));
|
||||
volumeControllers.add(use(NotificationVolumePreferenceController.class));
|
||||
|
||||
for (VolumeSeekBarPreferenceController controller : volumeControllers) {
|
||||
controller.setCallback(mVolumeCallback);
|
||||
getLifecycle().addObserver(controller);
|
||||
}
|
||||
}
|
||||
|
||||
// === Volumes ===
|
||||
@@ -205,8 +211,6 @@ public class SoundSettings extends DashboardFragment {
|
||||
new DialPadTonePreferenceController(context, fragment, lifecycle);
|
||||
final ScreenLockSoundPreferenceController screenLockSoundPreferenceController =
|
||||
new ScreenLockSoundPreferenceController(context, fragment, lifecycle);
|
||||
final ChargingSoundPreferenceController chargingSoundPreferenceController =
|
||||
new ChargingSoundPreferenceController(context, fragment, lifecycle);
|
||||
final DockingSoundPreferenceController dockingSoundPreferenceController =
|
||||
new DockingSoundPreferenceController(context, fragment, lifecycle);
|
||||
final TouchSoundPreferenceController touchSoundPreferenceController =
|
||||
@@ -222,7 +226,6 @@ public class SoundSettings extends DashboardFragment {
|
||||
|
||||
controllers.add(dialPadTonePreferenceController);
|
||||
controllers.add(screenLockSoundPreferenceController);
|
||||
controllers.add(chargingSoundPreferenceController);
|
||||
controllers.add(dockingSoundPreferenceController);
|
||||
controllers.add(touchSoundPreferenceController);
|
||||
controllers.add(vibrateOnTouchPreferenceController);
|
||||
@@ -233,7 +236,6 @@ public class SoundSettings extends DashboardFragment {
|
||||
"other_sounds_and_vibrations_category").setChildren(
|
||||
Arrays.asList(dialPadTonePreferenceController,
|
||||
screenLockSoundPreferenceController,
|
||||
chargingSoundPreferenceController,
|
||||
dockingSoundPreferenceController,
|
||||
touchSoundPreferenceController,
|
||||
vibrateOnTouchPreferenceController,
|
||||
|
||||
@@ -196,8 +196,7 @@ public class VolumeSeekBarPreference extends SeekBarPreference {
|
||||
if (mSuppressionTextView != null && mSeekBar != null) {
|
||||
mSuppressionTextView.setText(mSuppressionText);
|
||||
final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
|
||||
mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
|
||||
mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
|
||||
mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,19 +18,26 @@ package com.android.settings.slices;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.slice.SliceManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v4.graphics.drawable.IconCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
@@ -144,11 +151,90 @@ public class SettingsSliceProvider extends SliceProvider {
|
||||
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all valid Uris based on the keys indexed in the Slices database.
|
||||
* <p>
|
||||
* This will return a list of {@link Uri uris} depending on {@param uri}, following:
|
||||
* 1. Authority & Full Path -> Only {@param uri}. It is only a prefix for itself.
|
||||
* 2. Authority & No path -> A list of authority/action/$KEY$, where
|
||||
* {@code $KEY$} is a list of all Slice-enabled keys for the authority.
|
||||
* 3. Authority & action path -> A list of authority/action/$KEY$, where
|
||||
* {@code $KEY$} is a list of all Slice-enabled keys for the authority.
|
||||
* 4. Empty authority & path -> A list of Uris with all keys for both supported authorities.
|
||||
* 5. Else -> Empty list.
|
||||
* <p>
|
||||
* Note that the authority will stay consistent with {@param uri}, and the list of valid Slice
|
||||
* keys depends on if the authority is {@link SettingsSlicesContract#AUTHORITY} or
|
||||
* {@link #SLICE_AUTHORITY}.
|
||||
*
|
||||
* @param uri The uri to look for descendants under.
|
||||
* @returns all valid Settings uris for which {@param uri} is a prefix.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Uri> onGetSliceDescendants(Uri uri) {
|
||||
final List<Uri> descendants = new ArrayList<>();
|
||||
final Pair<Boolean, String> pathData = SliceBuilderUtils.getPathData(uri);
|
||||
|
||||
if (pathData != null) {
|
||||
// Uri has a full path and will not have any descendants.
|
||||
descendants.add(uri);
|
||||
return descendants;
|
||||
}
|
||||
|
||||
final String authority = uri.getAuthority();
|
||||
final String pathPrefix = uri.getPath();
|
||||
final boolean isPathEmpty = pathPrefix.isEmpty();
|
||||
|
||||
// No path nor authority. Return all possible Uris.
|
||||
if (isPathEmpty && TextUtils.isEmpty(authority)) {
|
||||
final List<String> platformKeys = mSlicesDatabaseAccessor.getSliceKeys(
|
||||
true /* isPlatformSlice */);
|
||||
final List<String> oemKeys = mSlicesDatabaseAccessor.getSliceKeys(
|
||||
false /* isPlatformSlice */);
|
||||
final List<Uri> allUris = buildUrisFromKeys(platformKeys,
|
||||
SettingsSlicesContract.AUTHORITY);
|
||||
allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY));
|
||||
|
||||
return allUris;
|
||||
}
|
||||
|
||||
// Path is anything but empty, "action", or "intent". Return empty list.
|
||||
if (!isPathEmpty
|
||||
&& !TextUtils.equals(pathPrefix, "/" + SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
&& !TextUtils.equals(pathPrefix,
|
||||
"/" + SettingsSlicesContract.PATH_SETTING_INTENT)) {
|
||||
// Invalid path prefix, there are no valid Uri descendants.
|
||||
return descendants;
|
||||
}
|
||||
|
||||
// Can assume authority belongs to the provider. Return all Uris for the authority.
|
||||
final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY);
|
||||
final List<String> keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri);
|
||||
return buildUrisFromKeys(keys, authority);
|
||||
}
|
||||
|
||||
private List<Uri> buildUrisFromKeys(List<String> keys, String authority) {
|
||||
final List<Uri> descendants = new ArrayList<>();
|
||||
|
||||
final Uri.Builder builder = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(authority)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION);
|
||||
|
||||
final String newUriPathPrefix = SettingsSlicesContract.PATH_SETTING_ACTION + "/";
|
||||
for (String key : keys) {
|
||||
builder.path(newUriPathPrefix + key);
|
||||
descendants.add(builder.build());
|
||||
}
|
||||
|
||||
return descendants;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void loadSlice(Uri uri) {
|
||||
long startBuildTime = System.currentTimeMillis();
|
||||
|
||||
SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
|
||||
final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
|
||||
mSliceDataCache.put(uri, sliceData);
|
||||
getContext().getContentResolver().notifyChange(uri, null /* content observer */);
|
||||
|
||||
|
||||
@@ -54,16 +54,16 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
final String key = intent.getStringExtra(EXTRA_SLICE_KEY);
|
||||
final boolean isPlatformDefined = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
|
||||
final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
|
||||
false /* default */);
|
||||
|
||||
switch (action) {
|
||||
case ACTION_TOGGLE_CHANGED:
|
||||
handleToggleAction(context, key, isPlatformDefined);
|
||||
handleToggleAction(context, key, isPlatformSlice);
|
||||
break;
|
||||
case ACTION_SLIDER_CHANGED:
|
||||
int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
|
||||
handleSliderAction(context, key, newPosition);
|
||||
handleSliderAction(context, key, newPosition, isPlatformSlice);
|
||||
break;
|
||||
case ACTION_WIFI_CHANGED:
|
||||
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
@@ -95,6 +95,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
if (!controller.isAvailable()) {
|
||||
Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
|
||||
updateUri(context, key, isPlatformSlice);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
|
||||
@@ -107,7 +108,8 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
updateUri(context, key, isPlatformSlice);
|
||||
}
|
||||
|
||||
private void handleSliderAction(Context context, String key, int newPosition) {
|
||||
private void handleSliderAction(Context context, String key, int newPosition,
|
||||
boolean isPlatformSlice) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY);
|
||||
@@ -123,6 +125,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key);
|
||||
}
|
||||
|
||||
if (!controller.isAvailable()) {
|
||||
Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
|
||||
updateUri(context, key, isPlatformSlice);
|
||||
return;
|
||||
}
|
||||
|
||||
final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
|
||||
final int maxSteps = sliderController.getMaxSteps();
|
||||
if (newPosition < 0 || newPosition > maxSteps) {
|
||||
|
||||
@@ -113,13 +113,13 @@ public class SliceBuilderUtils {
|
||||
* - key
|
||||
* <p>
|
||||
* Examples of valid paths are:
|
||||
* - intent/wifi
|
||||
* - intent/bluetooth
|
||||
* - action/wifi
|
||||
* - action/accessibility/servicename
|
||||
* - /intent/wifi
|
||||
* - /intent/bluetooth
|
||||
* - /action/wifi
|
||||
* - /action/accessibility/servicename
|
||||
*
|
||||
* @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
|
||||
* @return Pair whose first element {@code true} if the path is prepended with "action", and
|
||||
* @return Pair whose first element {@code true} if the path is prepended with "intent", and
|
||||
* second is a key.
|
||||
*/
|
||||
public static Pair<Boolean, String> getPathData(Uri uri) {
|
||||
@@ -130,13 +130,13 @@ public class SliceBuilderUtils {
|
||||
// Example: "/action/wifi" -> [{}, "action", "wifi"]
|
||||
// "/action/longer/path" -> [{}, "action", "longer/path"]
|
||||
if (split.length != 3) {
|
||||
throw new IllegalArgumentException("Uri (" + uri + ") has incomplete path: " + path);
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
|
||||
final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
|
||||
split[1]);
|
||||
|
||||
return new Pair<>(isInline, split[2]);
|
||||
return new Pair<>(isIntent, split[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,8 +215,8 @@ public class SliceBuilderUtils {
|
||||
static Intent getContentIntent(Context context, SliceData sliceData) {
|
||||
final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
|
||||
0 /* TODO */);
|
||||
sliceData.getFragmentClassName(), sliceData.getKey(),
|
||||
sliceData.getScreenTitle().toString(), 0 /* TODO */);
|
||||
intent.setClassName(context.getPackageName(), SubSettings.class.getName());
|
||||
intent.setData(contentUri);
|
||||
return intent;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class SliceData {
|
||||
|
||||
private final String mSummary;
|
||||
|
||||
private final String mScreenTitle;
|
||||
private final CharSequence mScreenTitle;
|
||||
|
||||
private final int mIconResource;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class SliceData {
|
||||
return mSummary;
|
||||
}
|
||||
|
||||
public String getScreenTitle() {
|
||||
public CharSequence getScreenTitle() {
|
||||
return mScreenTitle;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public class SliceData {
|
||||
|
||||
private String mSummary;
|
||||
|
||||
private String mScreenTitle;
|
||||
private CharSequence mScreenTitle;
|
||||
|
||||
private int mIconResource;
|
||||
|
||||
@@ -175,7 +175,7 @@ public class SliceData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setScreenTitle(String screenTitle) {
|
||||
public Builder setScreenTitle(CharSequence screenTitle) {
|
||||
mScreenTitle = screenTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,12 @@ import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFO
|
||||
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
|
||||
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Bundle;
|
||||
@@ -32,9 +37,14 @@ import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
|
||||
import com.android.settings.core.PreferenceXmlParserUtils;
|
||||
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilitySettings;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
@@ -46,10 +56,16 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Converts {@link DashboardFragment} to {@link SliceData}.
|
||||
* Converts all Slice sources into {@link SliceData}.
|
||||
* This includes:
|
||||
* - All {@link DashboardFragment DashboardFragments} indexed by settings search
|
||||
* - Accessibility services
|
||||
*/
|
||||
class SliceDataConverter {
|
||||
|
||||
@@ -101,6 +117,8 @@ class SliceDataConverter {
|
||||
mSliceData.addAll(providerSliceData);
|
||||
}
|
||||
|
||||
final List<SliceData> a11ySliceData = getAccessibilitySliceData();
|
||||
mSliceData.addAll(a11ySliceData);
|
||||
return mSliceData;
|
||||
}
|
||||
|
||||
@@ -208,4 +226,58 @@ class SliceDataConverter {
|
||||
}
|
||||
return xmlSliceData;
|
||||
}
|
||||
|
||||
private List<SliceData> getAccessibilitySliceData() {
|
||||
final List<SliceData> sliceData = new ArrayList<>();
|
||||
|
||||
final String accessibilityControllerClassName =
|
||||
AccessibilitySlicePreferenceController.class.getName();
|
||||
final String fragmentClassName = AccessibilitySettings.class.getName();
|
||||
final CharSequence screenTitle = mContext.getText(R.string.accessibility_settings);
|
||||
|
||||
final SliceData.Builder sliceDataBuilder = new SliceData.Builder()
|
||||
.setFragmentName(fragmentClassName)
|
||||
.setScreenTitle(screenTitle)
|
||||
.setPreferenceControllerClassName(accessibilityControllerClassName);
|
||||
|
||||
final Set<String> a11yServiceNames = new HashSet<>();
|
||||
Collections.addAll(a11yServiceNames, mContext.getResources()
|
||||
.getStringArray(R.array.config_settings_slices_accessibility_components));
|
||||
final List<AccessibilityServiceInfo> installedServices = getAccessibilityServiceInfoList();
|
||||
final PackageManager packageManager = mContext.getPackageManager();
|
||||
|
||||
for (AccessibilityServiceInfo a11yServiceInfo : installedServices) {
|
||||
final ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
|
||||
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||
final String packageName = serviceInfo.packageName;
|
||||
final ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
|
||||
final String flattenedName = componentName.flattenToString();
|
||||
|
||||
if (!a11yServiceNames.contains(flattenedName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String title = resolveInfo.loadLabel(packageManager).toString();
|
||||
int iconResource = resolveInfo.getIconResource();
|
||||
if (iconResource == 0) {
|
||||
iconResource = R.mipmap.ic_accessibility_generic;
|
||||
}
|
||||
|
||||
sliceDataBuilder.setKey(flattenedName)
|
||||
.setTitle(title)
|
||||
.setIcon(iconResource)
|
||||
.setSliceType(SliceData.SliceType.SWITCH);
|
||||
|
||||
sliceData.add(sliceDataBuilder.build());
|
||||
}
|
||||
|
||||
return sliceData;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<AccessibilityServiceInfo> getAccessibilityServiceInfoList() {
|
||||
final AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(
|
||||
mContext);
|
||||
return accessibilityManager.getInstalledAccessibilityServiceList();
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ import android.util.Pair;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
|
||||
/**
|
||||
@@ -51,10 +54,12 @@ public class SlicesDatabaseAccessor {
|
||||
// Cursor value for boolean true
|
||||
private final int TRUE = 1;
|
||||
|
||||
Context mContext;
|
||||
private final Context mContext;
|
||||
private final SlicesDatabaseHelper mHelper;
|
||||
|
||||
public SlicesDatabaseAccessor(Context context) {
|
||||
mContext = context;
|
||||
mHelper = SlicesDatabaseHelper.getInstance(mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,19 +81,47 @@ public class SlicesDatabaseAccessor {
|
||||
*/
|
||||
public SliceData getSliceDataFromKey(String key) {
|
||||
Cursor cursor = getIndexedSliceData(key);
|
||||
return buildSliceData(cursor, null /* uri */, false /* isInlineOnly */);
|
||||
return buildSliceData(cursor, null /* uri */, false /* isIntentOnly */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of keys in the Slices database matching on {@param isPlatformSlice}.
|
||||
*/
|
||||
public List<String> getSliceKeys(boolean isPlatformSlice) {
|
||||
final String whereClause;
|
||||
|
||||
if (isPlatformSlice) {
|
||||
whereClause = IndexColumns.PLATFORM_SLICE + " = 1";
|
||||
} else {
|
||||
whereClause = IndexColumns.PLATFORM_SLICE + " = 0";
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = mHelper.getReadableDatabase();
|
||||
final String[] columns = new String[]{IndexColumns.KEY};
|
||||
final List<String> keys = new ArrayList<>();
|
||||
|
||||
try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, whereClause,
|
||||
null /* selection */, null /* groupBy */, null /* having */, null /* orderBy */)) {
|
||||
if (!resultCursor.moveToFirst()) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
do {
|
||||
keys.add(resultCursor.getString(0 /* key index */));
|
||||
} while (resultCursor.moveToNext());
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
private Cursor getIndexedSliceData(String path) {
|
||||
verifyIndexing();
|
||||
|
||||
final String whereClause = buildKeyMatchWhereClause();
|
||||
final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||
final SQLiteDatabase database = helper.getReadableDatabase();
|
||||
final SQLiteDatabase database = mHelper.getReadableDatabase();
|
||||
final String[] selection = new String[]{path};
|
||||
|
||||
Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL, whereClause,
|
||||
selection, null /* groupBy */, null /* having */, null /* orderBy */);
|
||||
final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL,
|
||||
whereClause, selection, null /* groupBy */, null /* having */, null /* orderBy */);
|
||||
|
||||
int numResults = resultCursor.getCount();
|
||||
|
||||
@@ -111,7 +144,7 @@ public class SlicesDatabaseAccessor {
|
||||
.toString();
|
||||
}
|
||||
|
||||
private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isInlineOnly) {
|
||||
private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isIntentOnly) {
|
||||
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
|
||||
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
|
||||
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
|
||||
@@ -127,7 +160,7 @@ public class SlicesDatabaseAccessor {
|
||||
int sliceType = cursor.getInt(
|
||||
cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
|
||||
|
||||
if (!isInlineOnly) {
|
||||
if (isIntentOnly) {
|
||||
sliceType = SliceData.SliceType.INTENT;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class SlicesIndexer implements Runnable {
|
||||
values.put(IndexColumns.KEY, dataRow.getKey());
|
||||
values.put(IndexColumns.TITLE, dataRow.getTitle());
|
||||
values.put(IndexColumns.SUMMARY, dataRow.getSummary());
|
||||
values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle());
|
||||
values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle().toString());
|
||||
values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
|
||||
values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
|
||||
values.put(IndexColumns.CONTROLLER, dataRow.getPreferenceController());
|
||||
|
||||
@@ -193,8 +193,12 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
|
||||
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
|
||||
}
|
||||
|
||||
protected boolean isStreamFromOutputDevice(int streamType, int device) {
|
||||
return mAudioManager.getDevicesForStream(streamType) == device;
|
||||
}
|
||||
|
||||
protected boolean isOngoingCallStatus() {
|
||||
int audioMode = mAudioManager.getMode();
|
||||
final int audioMode = mAudioManager.getMode();
|
||||
return audioMode == AudioManager.MODE_RINGTONE
|
||||
|| audioMode == AudioManager.MODE_IN_CALL
|
||||
|| audioMode == AudioManager.MODE_IN_COMMUNICATION;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.settings.sound;
|
||||
|
||||
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
||||
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
@@ -76,7 +79,7 @@ public class HandsFreeProfileOutputPreferenceController extends
|
||||
// Setup devices entries, select active connected device
|
||||
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
|
||||
|
||||
if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothScoOn()) {
|
||||
if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_USB_HEADSET)) {
|
||||
// If wired headset is plugged in and active, select to default device.
|
||||
mSelectedIndex = getDefaultDeviceIndex();
|
||||
}
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package com.android.settings.sound;
|
||||
|
||||
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
|
||||
import static android.media.AudioManager.STREAM_MUSIC;
|
||||
import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaRouter;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
@@ -49,8 +50,7 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAudioManager.isMusicActiveRemotely() || isCastDevice(mMediaRouter)) {
|
||||
// TODO(76455906): Workaround for cast mode, need a solid way to identify cast mode.
|
||||
if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) {
|
||||
// In cast mode, disable switch entry.
|
||||
preference.setEnabled(false);
|
||||
preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable));
|
||||
@@ -91,7 +91,7 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
||||
// Setup devices entries, select active connected device
|
||||
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
|
||||
|
||||
if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothA2dpOn()) {
|
||||
if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_USB_HEADSET)) {
|
||||
// If wired headset is plugged in and active, select to default device.
|
||||
mSelectedIndex = getDefaultDeviceIndex();
|
||||
}
|
||||
@@ -106,11 +106,4 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
||||
mProfileManager.getA2dpProfile().setActiveDevice(device);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCastDevice(MediaRouter mediaRouter) {
|
||||
final MediaRouter.RouteInfo selected = mediaRouter.getSelectedRoute(
|
||||
ROUTE_TYPE_REMOTE_DISPLAY);
|
||||
return selected != null && selected.getPresentationDisplay() != null
|
||||
&& selected.getPresentationDisplay().isValid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class ValidatedEditTextPreference extends CustomEditTextPreference {
|
||||
editText.removeTextChangedListener(mTextWatcher);
|
||||
if (mIsPassword) {
|
||||
editText.setInputType(
|
||||
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
|
||||
editText.setMaxLines(1);
|
||||
}
|
||||
editText.addTextChangedListener(mTextWatcher);
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
@@ -107,14 +108,15 @@ public final class WifiNoInternetDialog extends AlertActivity implements
|
||||
mCM.registerNetworkCallback(request, mNetworkCallback);
|
||||
|
||||
final NetworkInfo ni = mCM.getNetworkInfo(mNetwork);
|
||||
if (ni == null || !ni.isConnectedOrConnecting()) {
|
||||
final NetworkCapabilities nc = mCM.getNetworkCapabilities(mNetwork);
|
||||
if (ni == null || !ni.isConnectedOrConnecting() || nc == null) {
|
||||
Log.d(TAG, "Network " + mNetwork + " is not connected: " + ni);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
mNetworkName = ni.getExtraInfo();
|
||||
mNetworkName = nc.getSSID();
|
||||
if (mNetworkName != null) {
|
||||
mNetworkName = mNetworkName.replaceAll("^\"|\"$", ""); // Remove double quotes
|
||||
mNetworkName = WifiInfo.removeDoubleQuotes(mNetworkName);
|
||||
}
|
||||
|
||||
createDialog();
|
||||
|
||||
@@ -55,6 +55,7 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
|
||||
mPassword = generateRandomPassword();
|
||||
}
|
||||
((ValidatedEditTextPreference) mPreference).setValidator(this);
|
||||
((ValidatedEditTextPreference) mPreference).setIsPassword(true);
|
||||
((ValidatedEditTextPreference) mPreference).setIsSummaryPassword(true);
|
||||
updatePasswordDisplay((EditTextPreference) mPreference);
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
com.android.settings.testutils.FakeToggleController
|
||||
com.android.settings.testutils.FakeSliderController
|
||||
com.android.settings.testutils.FakeSliderController
|
||||
com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
|
||||
com.android.settings.accessibility.AccessibilitySlicePreferenceController
|
||||
|
||||
@@ -62,4 +62,9 @@
|
||||
<bool name="config_show_wifi_ip_address">false</bool>
|
||||
<bool name="config_show_wifi_mac_address">false</bool>
|
||||
<bool name="config_disable_uninstall_update">true</bool>
|
||||
|
||||
<!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
|
||||
<string-array name="config_settings_slices_accessibility_components" translatable="false">
|
||||
<item>fake_package/fake_service</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class AccessibilitySlicePreferenceControllerTest {
|
||||
|
||||
private final String PACKAGE_NAME = "com.android.settings.fake";
|
||||
private final String CLASS_NAME = "com.android.settings.fake.classname";
|
||||
private final String SERVICE_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private AccessibilitySlicePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
final ContentResolver contentResolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 1 /* on */);
|
||||
Settings.Secure.putString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
SERVICE_NAME);
|
||||
|
||||
// Register the fake a11y Service
|
||||
ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
|
||||
RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
|
||||
shadowAccessibilityManager.setInstalledAccessibilityServiceList(getFakeServiceList());
|
||||
|
||||
mController = new AccessibilitySlicePreferenceController(mContext, SERVICE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailability_availableService_returnsAvailable() {
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailability_unknownService_returnsUnsupported() {
|
||||
AccessibilitySlicePreferenceController controller =
|
||||
new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
|
||||
|
||||
assertThat(controller.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChecked_availableService_serviceIsEnabled() {
|
||||
mController.setChecked(true);
|
||||
|
||||
assertThat(mController.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNotChecked_availableService_serviceIsDisabled() {
|
||||
mController.setChecked(false);
|
||||
|
||||
assertThat(mController.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isChecked_serviceEnabled_returnsTrue() {
|
||||
AccessibilityUtils.setAccessibilityServiceState(mContext,
|
||||
ComponentName.unflattenFromString(mController.getPreferenceKey()), true);
|
||||
|
||||
assertThat(mController.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isChecked_serviceNotEnabled_returnsFalse() {
|
||||
AccessibilitySlicePreferenceController controller =
|
||||
new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
|
||||
|
||||
assertThat(controller.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void illegalServiceName_exceptionThrown() {
|
||||
new AccessibilitySlicePreferenceController(mContext, "not_split_by_slash");
|
||||
}
|
||||
|
||||
private List<AccessibilityServiceInfo> getFakeServiceList() {
|
||||
final List<AccessibilityServiceInfo> infoList = new ArrayList<>();
|
||||
|
||||
final ServiceInfo serviceInfo = new ServiceInfo();
|
||||
serviceInfo.packageName = PACKAGE_NAME;
|
||||
serviceInfo.name = CLASS_NAME;
|
||||
|
||||
final ResolveInfo resolveInfo = new ResolveInfo();
|
||||
resolveInfo.serviceInfo = serviceInfo;
|
||||
|
||||
try {
|
||||
final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
|
||||
mContext);
|
||||
ComponentName componentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
|
||||
info.setComponentName(componentName);
|
||||
infoList.add(info);
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
|
||||
}
|
||||
|
||||
return infoList;
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ public class DashboardFeatureProviderImplTest {
|
||||
"content://com.android.settings/tile_icon");
|
||||
mImpl.bindIcon(preference, tile);
|
||||
|
||||
assertThat(tile.icon).isNotNull();
|
||||
assertThat(preference.getIcon()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package com.android.settings.gestures;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.UserManager;
|
||||
@@ -38,7 +40,8 @@ import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -47,15 +50,35 @@ import java.util.List;
|
||||
public class SwipeUpPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private ShadowPackageManager mPackageManager;
|
||||
private SwipeUpPreferenceController mController;
|
||||
|
||||
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
|
||||
private static final String KEY_SWIPE_UP = "gesture_swipe_up";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
|
||||
mController = new SwipeUpPreferenceController(mContext, KEY_SWIPE_UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGestureAvailable_matchingServiceExists_shouldReturnTrue() {
|
||||
final ComponentName recentsComponentName = ComponentName.unflattenFromString(
|
||||
mContext.getString(com.android.internal.R.string.config_recentsComponentName));
|
||||
final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP)
|
||||
.setPackage(recentsComponentName.getPackageName());
|
||||
mPackageManager.addResolveInfoForIntent(quickStepIntent, new ResolveInfo());
|
||||
|
||||
assertThat(SwipeUpPreferenceController.isGestureAvailable(mContext)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsGestureAvailable_noMatchingServiceExists_shouldReturnFalse() {
|
||||
assertThat(SwipeUpPreferenceController.isGestureAvailable(mContext)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsChecked_configIsSet_shouldReturnTrue() {
|
||||
// Set the setting to be enabled.
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -115,6 +116,24 @@ public class ApnEditorTest {
|
||||
mApnEditorUT.sNotSet = "Not Set";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApnEditor_doesNotUseManagedQuery() {
|
||||
mApnEditorUT.getApnDataFromUri(Mockito.mock(Uri.class));
|
||||
|
||||
verify(mActivity, never()).managedQuery(
|
||||
any(Uri.class),
|
||||
any(String[].class),
|
||||
any(String.class),
|
||||
any(String.class));
|
||||
|
||||
verify(mActivity, never()).managedQuery(
|
||||
any(Uri.class),
|
||||
any(String[].class),
|
||||
any(String.class),
|
||||
any(String[].class),
|
||||
any(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetStringValue_valueChanged_shouldSetValue() {
|
||||
// GIVEN an APN value which is different than the APN value in database
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static android.content.ContentResolver.SCHEME_CONTENT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
@@ -41,6 +43,7 @@ import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -114,7 +117,190 @@ public class SettingsSliceProviderTest {
|
||||
assertThat(cachedData).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_fullActionUri_returnsSelf() {
|
||||
final Uri uri = SliceBuilderUtils.getUri(
|
||||
SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_fullIntentUri_returnsSelf() {
|
||||
final Uri uri = SliceBuilderUtils.getUri(
|
||||
SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_wrongPath_returnsEmpty() {
|
||||
final Uri uri = SliceBuilderUtils.getUri("invalid_path", true);
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_invalidPath_returnsEmpty() {
|
||||
final String key = "platform_key";
|
||||
insertSpecialCase(key, true /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.appendPath("invalid")
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
|
||||
insertSpecialCase("oem_key", false /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
|
||||
insertSpecialCase("platform_key", true /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
|
||||
final String key = "oem_key";
|
||||
insertSpecialCase(key, false /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.build();
|
||||
final Uri expectedUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(key)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(expectedUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() {
|
||||
final String key = "oem_key";
|
||||
insertSpecialCase(key, false /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.build();
|
||||
final Uri expectedUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(key)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(expectedUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
|
||||
final String key = "platform_key";
|
||||
insertSpecialCase(key, true /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.build();
|
||||
final Uri expectedUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(key)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(expectedUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() {
|
||||
final String key = "platform_key";
|
||||
insertSpecialCase(key, true /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.build();
|
||||
final Uri expectedUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(key)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(expectedUri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_noAuthorityNorPath_returnsAllUris() {
|
||||
final String platformKey = "platform_key";
|
||||
final String oemKey = "oemKey";
|
||||
insertSpecialCase(platformKey, true /* isPlatformSlice */);
|
||||
insertSpecialCase(oemKey, false /* isPlatformSlice */);
|
||||
final Uri uri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.build();
|
||||
final Uri expectedPlatformUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSlicesContract.AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(platformKey)
|
||||
.build();
|
||||
final Uri expectedOemUri = new Uri.Builder()
|
||||
.scheme(SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(oemKey)
|
||||
.build();
|
||||
|
||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
|
||||
|
||||
assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
insertSpecialCase(key, true);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key, boolean isPlatformSlice) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, TITLE);
|
||||
@@ -123,6 +309,8 @@ public class SettingsSliceProviderTest {
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, 1234);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, "test");
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
|
||||
|
||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||
}
|
||||
|
||||
@@ -18,17 +18,28 @@
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.slice.Slice;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.search.FakeIndexProvider;
|
||||
import com.android.settings.search.SearchFeatureProvider;
|
||||
import com.android.settings.search.SearchFeatureProviderImpl;
|
||||
@@ -36,6 +47,7 @@ import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.FakeSliderController;
|
||||
import com.android.settings.testutils.FakeToggleController;
|
||||
import com.android.settings.testutils.FakeUnavailablePreferenceController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -65,7 +77,7 @@ public class SliceBroadcastReceiverTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
mReceiver = new SliceBroadcastReceiver();
|
||||
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||
@@ -192,6 +204,77 @@ public class SliceBroadcastReceiverTest {
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toggleUpdate_unavailableUriNotified() {
|
||||
// Monitor the ContentResolver
|
||||
final ContentResolver resolver = spy(mContext.getContentResolver());
|
||||
doReturn(resolver).when(mContext).getContentResolver();
|
||||
|
||||
// Disable Setting
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeToggleController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.DISABLED_UNSUPPORTED);
|
||||
|
||||
// Insert Fake Toggle into Database
|
||||
final String key = "key";
|
||||
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
|
||||
insertSpecialCase(FakeToggleController.class, key);
|
||||
|
||||
// Turn on toggle setting
|
||||
final FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
|
||||
fakeToggleController.setChecked(true);
|
||||
|
||||
// Build Action
|
||||
final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
|
||||
|
||||
// Trigger Slice change
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
|
||||
// Check the value is the same and the Uri has been notified.
|
||||
assertThat(fakeToggleController.isChecked()).isTrue();
|
||||
final Uri expectedUri = SliceBuilderUtils.getUri(
|
||||
SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
|
||||
verify(resolver).notifyChange(eq(expectedUri), eq(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sliderUpdate_unavailableUriNotified() {
|
||||
// Monitor the ContentResolver
|
||||
final ContentResolver resolver = spy(mContext.getContentResolver());
|
||||
doReturn(resolver).when(mContext).getContentResolver();
|
||||
|
||||
// Disable Setting
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeSliderController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.DISABLED_UNSUPPORTED);
|
||||
|
||||
// Insert Fake Slider into Database
|
||||
final String key = "key";
|
||||
final int position = FakeSliderController.MAX_STEPS - 1;
|
||||
final int oldPosition = FakeSliderController.MAX_STEPS;
|
||||
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
|
||||
insertSpecialCase(FakeSliderController.class, key);
|
||||
|
||||
// Set slider setting
|
||||
final FakeSliderController fakeSliderController = new FakeSliderController(mContext, key);
|
||||
fakeSliderController.setSliderPosition(oldPosition);
|
||||
|
||||
// Build action
|
||||
final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
|
||||
intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
|
||||
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
|
||||
|
||||
// Trigger Slice change
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
|
||||
// Check position is the same and the Uri has been notified.
|
||||
assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
|
||||
final Uri expectedUri = SliceBuilderUtils.getUri(
|
||||
SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
|
||||
verify(resolver).notifyChange(eq(expectedUri), eq(null));
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
insertSpecialCase(fakeControllerName, key);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -40,6 +39,7 @@ import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.FakeSliderController;
|
||||
import com.android.settings.testutils.FakeToggleController;
|
||||
import com.android.settings.testutils.FakeUnavailablePreferenceController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.SliceTester;
|
||||
|
||||
@@ -277,7 +277,7 @@ public class SliceBuilderUtilsTest {
|
||||
|
||||
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
|
||||
|
||||
assertThat(pathPair.first).isFalse();
|
||||
assertThat(pathPair.first).isTrue();
|
||||
assertThat(pathPair.second).isEqualTo(KEY);
|
||||
}
|
||||
|
||||
@@ -291,18 +291,20 @@ public class SliceBuilderUtilsTest {
|
||||
|
||||
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
|
||||
|
||||
assertThat(pathPair.first).isTrue();
|
||||
assertThat(pathPair.first).isFalse();
|
||||
assertThat(pathPair.second).isEqualTo(KEY);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void getPathData_noKey_returnsNull() {
|
||||
final Uri uri = new Uri.Builder()
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.build();
|
||||
|
||||
SliceBuilderUtils.getPathData(uri);
|
||||
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
|
||||
|
||||
assertThat(pathPair).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -316,7 +318,7 @@ public class SliceBuilderUtilsTest {
|
||||
|
||||
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
|
||||
|
||||
assertThat(pathPair.first).isTrue();
|
||||
assertThat(pathPair.first).isFalse();
|
||||
assertThat(pathPair.second).isEqualTo(KEY + "/" + KEY);
|
||||
}
|
||||
|
||||
@@ -324,7 +326,7 @@ public class SliceBuilderUtilsTest {
|
||||
public void testUnsupportedSlice_validTitleSummary() {
|
||||
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
|
||||
SliceData.SliceType.SWITCH);
|
||||
Settings.System.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.DISABLED_UNSUPPORTED);
|
||||
|
||||
@@ -337,7 +339,7 @@ public class SliceBuilderUtilsTest {
|
||||
public void testDisabledForUserSlice_validTitleSummary() {
|
||||
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
|
||||
SliceData.SliceType.SWITCH);
|
||||
Settings.System.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.DISABLED_FOR_USER);
|
||||
|
||||
@@ -350,7 +352,7 @@ public class SliceBuilderUtilsTest {
|
||||
public void testDisabledDependentSettingSlice_validTitleSummary() {
|
||||
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
|
||||
SliceData.SliceType.INTENT);
|
||||
Settings.System.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.DISABLED_DEPENDENT_SETTING);
|
||||
|
||||
@@ -372,7 +374,7 @@ public class SliceBuilderUtilsTest {
|
||||
public void testUnavailableUnknownSlice_validTitleSummary() {
|
||||
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
|
||||
SliceData.SliceType.SWITCH);
|
||||
Settings.System.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
|
||||
BasePreferenceController.UNAVAILABLE_UNKNOWN);
|
||||
|
||||
|
||||
@@ -17,8 +17,22 @@
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilitySettings;
|
||||
import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
|
||||
import com.android.settings.search.FakeIndexProvider;
|
||||
import com.android.settings.search.SearchFeatureProvider;
|
||||
import com.android.settings.search.SearchFeatureProviderImpl;
|
||||
@@ -32,17 +46,29 @@ import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class SliceDataConverterTest {
|
||||
|
||||
private final String fakeKey = "key";
|
||||
private final String fakeTitle = "title";
|
||||
private final String fakeSummary = "summary";
|
||||
private final String fakeScreenTitle = "screen_title";
|
||||
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||
private final String fakeControllerName = FakePreferenceController.class.getName();
|
||||
private final String FAKE_KEY = "key";
|
||||
private final String FAKE_TITLE = "title";
|
||||
private final String FAKE_SUMMARY = "summary";
|
||||
private final String FAKE_SCREEN_TITLE = "screen_title";
|
||||
private final String FAKE_FRAGMENT_CLASSNAME = FakeIndexProvider.class.getName();
|
||||
private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
|
||||
|
||||
private final String ACCESSIBILITY_FRAGMENT = AccessibilitySettings.class.getName();
|
||||
private final String A11Y_CONTROLLER_NAME =
|
||||
AccessibilitySlicePreferenceController.class.getName();
|
||||
private final String FAKE_SERVICE_NAME = "fake_service";
|
||||
private final String FAKE_ACCESSIBILITY_PACKAGE = "fake_package";
|
||||
private final String FAKE_A11Y_SERVICE_NAME =
|
||||
FAKE_ACCESSIBILITY_PACKAGE + "/" + FAKE_SERVICE_NAME;
|
||||
private final int FAKE_ICON = 1234;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private SliceDataConverter mSliceDataConverter;
|
||||
private SearchFeatureProvider mSearchFeatureProvider;
|
||||
@@ -50,7 +76,8 @@ public class SliceDataConverterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mSliceDataConverter = new SliceDataConverter(RuntimeEnvironment.application);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mSliceDataConverter = spy(new SliceDataConverter(RuntimeEnvironment.application));
|
||||
mSearchFeatureProvider = new SearchFeatureProviderImpl();
|
||||
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
|
||||
@@ -68,20 +95,64 @@ public class SliceDataConverterTest {
|
||||
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues()
|
||||
.add(FakeIndexProvider.class);
|
||||
|
||||
doReturn(getFakeService()).when(mSliceDataConverter).getAccessibilityServiceInfoList();
|
||||
|
||||
List<SliceData> sliceDataList = mSliceDataConverter.getSliceData();
|
||||
|
||||
assertThat(sliceDataList).hasSize(1);
|
||||
SliceData fakeSlice = sliceDataList.get(0);
|
||||
assertThat(sliceDataList).hasSize(2);
|
||||
SliceData fakeSlice0 = sliceDataList.get(0);
|
||||
SliceData fakeSlice1 = sliceDataList.get(1);
|
||||
|
||||
assertThat(fakeSlice.getKey()).isEqualTo(fakeKey);
|
||||
assertThat(fakeSlice.getTitle()).isEqualTo(fakeTitle);
|
||||
assertThat(fakeSlice.getSummary()).isEqualTo(fakeSummary);
|
||||
assertThat(fakeSlice.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||
// Should not assume the order of the data list.
|
||||
if (TextUtils.equals(fakeSlice0.getKey(), FAKE_KEY)) {
|
||||
assertFakeSlice(fakeSlice0);
|
||||
assertFakeA11ySlice(fakeSlice1);
|
||||
} else {
|
||||
assertFakeSlice(fakeSlice1);
|
||||
assertFakeA11ySlice(fakeSlice0);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertFakeSlice(SliceData fakeSlice) {
|
||||
assertThat(fakeSlice.getKey()).isEqualTo(FAKE_KEY);
|
||||
assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(fakeSlice.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(fakeSlice.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
|
||||
assertThat(fakeSlice.getIconResource()).isNotNull();
|
||||
assertThat(fakeSlice.getUri()).isNull();
|
||||
assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||
assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||
assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML
|
||||
assertThat(fakeSlice.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_CLASSNAME);
|
||||
assertThat(fakeSlice.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
|
||||
assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
|
||||
assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
|
||||
}
|
||||
|
||||
private void assertFakeA11ySlice(SliceData fakeSlice) {
|
||||
assertThat(fakeSlice.getKey()).isEqualTo(FAKE_A11Y_SERVICE_NAME);
|
||||
assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(fakeSlice.getSummary()).isNull();
|
||||
assertThat(fakeSlice.getScreenTitle()).isEqualTo(
|
||||
mContext.getString(R.string.accessibility_settings));
|
||||
assertThat(fakeSlice.getIconResource()).isEqualTo(FAKE_ICON);
|
||||
assertThat(fakeSlice.getUri()).isNull();
|
||||
assertThat(fakeSlice.getFragmentClassName()).isEqualTo(ACCESSIBILITY_FRAGMENT);
|
||||
assertThat(fakeSlice.getPreferenceController()).isEqualTo(A11Y_CONTROLLER_NAME);
|
||||
}
|
||||
|
||||
// This is fragile. Should be replaced by a proper fake Service if possible.
|
||||
private List<AccessibilityServiceInfo> getFakeService() {
|
||||
List<AccessibilityServiceInfo> serviceInfoList = new ArrayList<>();
|
||||
AccessibilityServiceInfo serviceInfo = spy(new AccessibilityServiceInfo());
|
||||
|
||||
ResolveInfo resolveInfo = spy(new ResolveInfo());
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
resolveInfo.serviceInfo.name = FAKE_SERVICE_NAME;
|
||||
resolveInfo.serviceInfo.packageName = FAKE_ACCESSIBILITY_PACKAGE;
|
||||
doReturn(FAKE_TITLE).when(resolveInfo).loadLabel(any(PackageManager.class));
|
||||
doReturn(FAKE_ICON).when(resolveInfo).getIconResource();
|
||||
|
||||
doReturn(resolveInfo).when(serviceInfo).getResolveInfo();
|
||||
serviceInfoList.add(serviceInfo);
|
||||
|
||||
return serviceInfoList;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.ContentValues;
|
||||
@@ -35,15 +36,17 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class SlicesDatabaseAccessorTest {
|
||||
|
||||
private final String fakeTitle = "title";
|
||||
private final String fakeSummary = "summary";
|
||||
private final String fakeScreenTitle = "screen_title";
|
||||
private final int fakeIcon = 1234;
|
||||
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||
private final String fakeControllerName = FakePreferenceController.class.getName();
|
||||
private final String FAKE_TITLE = "title";
|
||||
private final String FAKE_SUMMARY = "summary";
|
||||
private final String FAKE_SCREEN_TITLE = "screen_title";
|
||||
private final int FAKE_ICON = 1234;
|
||||
private final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName();
|
||||
private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
|
||||
|
||||
private Context mContext;
|
||||
private SQLiteDatabase mDb;
|
||||
@@ -70,13 +73,13 @@ public class SlicesDatabaseAccessorTest {
|
||||
SliceData data = mAccessor.getSliceDataFromKey(key);
|
||||
|
||||
assertThat(data.getKey()).isEqualTo(key);
|
||||
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||
assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
|
||||
assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
|
||||
assertThat(data.getUri()).isNull();
|
||||
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||
assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@@ -96,13 +99,13 @@ public class SlicesDatabaseAccessorTest {
|
||||
SliceData data = mAccessor.getSliceDataFromUri(uri);
|
||||
|
||||
assertThat(data.getKey()).isEqualTo(key);
|
||||
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||
assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
|
||||
assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
|
||||
assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
|
||||
assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
|
||||
assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
|
||||
assertThat(data.getUri()).isEqualTo(uri);
|
||||
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||
assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@@ -111,15 +114,62 @@ public class SlicesDatabaseAccessorTest {
|
||||
mAccessor.getSliceDataFromUri(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
|
||||
final String key = "oem_key";
|
||||
final boolean isPlatformSlice = false;
|
||||
insertSpecialCase(key, isPlatformSlice);
|
||||
final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice);
|
||||
|
||||
assertThat(keys).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
|
||||
final String key = "platform_key";
|
||||
final boolean isPlatformSlice = true;
|
||||
insertSpecialCase(key, isPlatformSlice);
|
||||
final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice);
|
||||
|
||||
assertThat(keys).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
|
||||
final String key = "oem_key";
|
||||
final boolean isPlatformSlice = false;
|
||||
insertSpecialCase(key, isPlatformSlice);
|
||||
final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice);
|
||||
|
||||
assertThat(keys).containsExactly(key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
|
||||
final String key = "platform_key";
|
||||
final boolean isPlatformSlice = true;
|
||||
insertSpecialCase(key, isPlatformSlice);
|
||||
final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice);
|
||||
|
||||
assertThat(keys).containsExactly(key);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key) {
|
||||
insertSpecialCase(key, true);
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String key, boolean isPlatformSlice) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
|
||||
values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
|
||||
|
||||
|
||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.settings.sound;
|
||||
|
||||
|
||||
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -205,10 +207,9 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
|
||||
* Preference summary should be "This device"
|
||||
*/
|
||||
@Test
|
||||
public void hapBtDevicesAreAvailableButWiredHeadsetIsActivated_shouldSetDefaultSummary() {
|
||||
public void updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary() {
|
||||
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
mShadowAudioManager.setWiredHeadsetOn(true);
|
||||
mShadowAudioManager.setBluetoothScoOn(false);
|
||||
mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
|
||||
when(mHeadsetProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
|
||||
when(mHeadsetProfile.getActiveDevice()).thenReturn(
|
||||
mBluetoothDevice); // BT device is still activated in this case
|
||||
@@ -226,7 +227,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
|
||||
* Preference summary should be "This device"
|
||||
*/
|
||||
@Test
|
||||
public void noAvailableHeadsetBtDevices_preferenceEnableIsFalse_shouldSetDefaultSummary() {
|
||||
public void updateState_noAvailableHeadsetBtDevices_shouldSetDefaultSummary() {
|
||||
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
|
||||
when(mHeadsetProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
package com.android.settings.sound;
|
||||
|
||||
|
||||
import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
|
||||
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -196,7 +199,7 @@ public class MediaOutputPreferenceControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
|
||||
mShadowAudioManager.setMusicActiveRemotely(true);
|
||||
mShadowAudioManager.setStream(DEVICE_OUT_REMOTE_SUBMIX);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
@@ -256,8 +259,7 @@ public class MediaOutputPreferenceControllerTest {
|
||||
@Test
|
||||
public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
|
||||
mShadowAudioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
mShadowAudioManager.setWiredHeadsetOn(true);
|
||||
mShadowAudioManager.setBluetoothA2dpOn(false);
|
||||
mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
|
||||
when(mA2dpProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
|
||||
when(mA2dpProfile.getActiveDevice()).thenReturn(
|
||||
mBluetoothDevice); // BT device is still activated in this case
|
||||
|
||||
@@ -19,13 +19,14 @@ package com.android.settings.testutils;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SliderPreferenceController;
|
||||
|
||||
public class FakeSliderController extends SliderPreferenceController {
|
||||
|
||||
private final String settingKey = "fake_slider_key";
|
||||
|
||||
public static final String AVAILABILITY_KEY = "fake_slider_availability_key";
|
||||
|
||||
public static final int MAX_STEPS = 9;
|
||||
|
||||
public FakeSliderController(Context context, String key) {
|
||||
@@ -49,6 +50,7 @@ public class FakeSliderController extends SliderPreferenceController {
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return BasePreferenceController.AVAILABLE;
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
AVAILABILITY_KEY, AVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ public class FakeToggleController extends TogglePreferenceController {
|
||||
|
||||
private String settingKey = "toggle_key";
|
||||
|
||||
public static final String AVAILABILITY_KEY = "fake_toggle_availability_key";
|
||||
|
||||
private final int ON = 1;
|
||||
private final int OFF = 0;
|
||||
|
||||
@@ -47,6 +49,7 @@ public class FakeToggleController extends TogglePreferenceController {
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
AVAILABILITY_KEY, AVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.android.settings.slices;
|
||||
package com.android.settings.testutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
@@ -15,7 +15,7 @@ public class FakeUnavailablePreferenceController extends BasePreferenceControlle
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return Settings.System.getInt(mContext.getContentResolver(),
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
AVAILABILITY_KEY, 0);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,15 @@
|
||||
|
||||
package com.android.settings.testutils.shadow;
|
||||
|
||||
import static android.media.AudioManager.STREAM_ACCESSIBILITY;
|
||||
import static android.media.AudioManager.STREAM_ALARM;
|
||||
import static android.media.AudioManager.STREAM_MUSIC;
|
||||
import static android.media.AudioManager.STREAM_NOTIFICATION;
|
||||
import static android.media.AudioManager.STREAM_RING;
|
||||
import static android.media.AudioManager.STREAM_SYSTEM;
|
||||
import static android.media.AudioManager.STREAM_VOICE_CALL;
|
||||
import static android.media.AudioManager.STREAM_DTMF;
|
||||
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.media.AudioDeviceCallback;
|
||||
@@ -32,6 +41,7 @@ import java.util.ArrayList;
|
||||
@Implements(value = AudioManager.class, inheritImplementationMethods = true)
|
||||
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
|
||||
private int mRingerMode;
|
||||
private int mStream;
|
||||
private boolean mMusicActiveRemotely = false;
|
||||
private ArrayList<AudioDeviceCallback> mDeviceCallbacks = new ArrayList();
|
||||
|
||||
@@ -48,10 +58,12 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
|
||||
mRingerMode = mode;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) {
|
||||
mDeviceCallbacks.add(callback);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
|
||||
if (mDeviceCallbacks.contains(callback)) {
|
||||
mDeviceCallbacks.remove(callback);
|
||||
@@ -62,10 +74,32 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
|
||||
mMusicActiveRemotely = flag;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public boolean isMusicActiveRemotely() {
|
||||
return mMusicActiveRemotely;
|
||||
}
|
||||
|
||||
public void setStream(int stream) {
|
||||
mStream = stream;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
public int getDevicesForStream(int streamType) {
|
||||
switch (streamType) {
|
||||
case STREAM_VOICE_CALL:
|
||||
case STREAM_SYSTEM:
|
||||
case STREAM_RING:
|
||||
case STREAM_MUSIC:
|
||||
case STREAM_ALARM:
|
||||
case STREAM_NOTIFICATION:
|
||||
case STREAM_DTMF:
|
||||
case STREAM_ACCESSIBILITY:
|
||||
return mStream;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public void reset() {
|
||||
mDeviceCallbacks.clear();
|
||||
|
||||
@@ -116,7 +116,7 @@ public class ValidatedEditTextPreferenceTest {
|
||||
mPreference.onBindDialogView(mView);
|
||||
|
||||
assertThat(editText.getInputType()
|
||||
& (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT))
|
||||
& (InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_CLASS_TEXT))
|
||||
.isNotEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,4 +145,21 @@ public class WifiTetherPasswordPreferenceControllerTest {
|
||||
assertThat(mController.getSecuritySettingForPassword())
|
||||
.isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateDisplay_shouldSetInputType() {
|
||||
// Set controller password to anything and verify is set.
|
||||
mController.displayPreference(mScreen);
|
||||
mController.onPreferenceChange(mPreference, "1");
|
||||
assertThat(mController.getPassword()).isEqualTo("1");
|
||||
|
||||
// Create a new config using different password
|
||||
final WifiConfiguration config = new WifiConfiguration();
|
||||
config.preSharedKey = "test_1234";
|
||||
when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
|
||||
|
||||
// Call updateDisplay and verify it's changed.
|
||||
mController.updateDisplay();
|
||||
assertThat(mPreference.isPassword()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user