Snap for 4728508 from 270f608578 to pi-release

Change-Id: I0f5a3415f416511852669812b13029ff356e2bd1
This commit is contained in:
android-build-team Robot
2018-04-18 07:27:04 +00:00
62 changed files with 1224 additions and 307 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -23,4 +23,5 @@
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:paddingTop="8dp"
android:paddingBottom="8dp" />
android:paddingBottom="8dp"
android:textAlignment="viewStart"/>

View File

@@ -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">

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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"

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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;
}
}

View File

@@ -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;
}
);
});
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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 */);

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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());

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();
}
}