diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9a771ac9848..0c1ce65b6bb 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3140,10 +3140,15 @@ - - - + android:name=".slices.SliceBroadcastReceiver" + android:exported="false"> + + + + " + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + + + + + + + + + + + + + + + + + + + @@ -2557,7 +2649,7 @@ errorLine2=" ^"> @@ -2573,7 +2665,7 @@ errorLine2=" ^"> @@ -2589,7 +2681,7 @@ errorLine2=" ^"> @@ -2605,7 +2697,7 @@ errorLine2=" ^"> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index b77c5442f7e..a4ce9f0af7e 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -69,6 +69,8 @@ + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0c3732bd4b0..b1c94dff4e5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3167,7 +3167,7 @@ Formatting ^1\u2026 - Don\u2019t remove the ^1 while it\u2019s being formatting. + Don\u2019t remove the ^1 while it\u2019s being formatted. Move data to new storage @@ -9584,6 +9584,20 @@ To check time, notifications, and other info, pick up your device. + + Reach to check phone + + Reach to check tablet + + Reach to check device + + + To check time, notifications, and other info, reach for your phone. + + To check time, notifications, and other info, reach for your tablet. + + To check time, notifications, and other info, reach for your device. + Swipe fingerprint for notifications diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml index dd661e08872..5a55ba5dab0 100644 --- a/res/xml/app_and_notification.xml +++ b/res/xml/app_and_notification.xml @@ -71,6 +71,7 @@ android:key="special_access" android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings" android:title="@string/special_access" - android:order="20" /> + android:order="20" + settings:searchable="false"/> diff --git a/res/xml/app_default_settings.xml b/res/xml/app_default_settings.xml index 3b7c80b1925..54676679875 100644 --- a/res/xml/app_default_settings.xml +++ b/res/xml/app_default_settings.xml @@ -25,7 +25,7 @@ android:key="assist_and_voice_input" android:title="@string/assist_and_voice_input_title" android:fragment="com.android.settings.applications.assist.ManageAssist" - settings:keywords="@string/keywords_assist_input"/> + settings:searchable="false"/> + android:fragment="com.android.settings.applications.defaultapps.DefaultBrowserPicker" + settings:searchable="false"> @@ -94,7 +95,7 @@ android:key="work_default_phone_app" android:title="@string/default_phone_title" android:fragment="com.android.settings.applications.defaultapps.DefaultPhonePicker" - settings:keywords="@string/keywords_default_phone_app"> + settings:searchable="false"> diff --git a/res/xml/default_autofill_picker_settings.xml b/res/xml/default_autofill_picker_settings.xml index 26dff7eca87..da72b43fec8 100644 --- a/res/xml/default_autofill_picker_settings.xml +++ b/res/xml/default_autofill_picker_settings.xml @@ -32,7 +32,7 @@ + android:fragment="com.android.settings.development.featureflags.FeatureFlagsDashboard" + settings:searchable="false" /> + android:title="@string/assist_and_voice_input_title" + settings:keywords="@string/keywords_assist_input"> + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java index e8b7d007335..3eaed2dbdf2 100644 --- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java +++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java @@ -97,13 +97,5 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { Context context) { return buildPreferenceControllers(context, null, null /* host */); } - - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - keys.add((new SpecialAppAccessPreferenceController(context)) - .getPreferenceKey()); - return keys; - } }; } diff --git a/src/com/android/settings/applications/DefaultAppSettings.java b/src/com/android/settings/applications/DefaultAppSettings.java index 3af5bc2882f..d8fd9ebb725 100644 --- a/src/com/android/settings/applications/DefaultAppSettings.java +++ b/src/com/android/settings/applications/DefaultAppSettings.java @@ -101,16 +101,6 @@ public class DefaultAppSettings extends DashboardFragment { return Arrays.asList(sir); } - @Override - public List getNonIndexableKeys(Context context) { - List keys = super.getNonIndexableKeys(context); - keys.add(KEY_ASSIST_VOICE_INPUT); - // TODO (b/38230148) Remove these keys when we can differentiate work results - keys.add(DefaultWorkPhonePreferenceController.KEY); - keys.add(DefaultWorkBrowserPreferenceController.KEY); - return keys; - } - @Override public List createPreferenceControllers( Context context) { diff --git a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java index 1705dc578a6..b281336d0be 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java +++ b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java @@ -35,6 +35,7 @@ import android.text.Html; import android.text.TextUtils; import android.util.Log; import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceClickListener; import com.android.internal.content.PackageMonitor; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; @@ -168,11 +169,15 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment { } final Intent addNewServiceIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)); - Preference preference = new Preference(getPrefContext()); + final Context context = getPrefContext(); + final Preference preference = new Preference(context); + preference.setOnPreferenceClickListener(p -> { + context.startActivityAsUser(addNewServiceIntent, UserHandle.of(mUserId)); + return true; + }); preference.setTitle(R.string.print_menu_item_add_service); preference.setIcon(R.drawable.ic_menu_add); preference.setOrder(Integer.MAX_VALUE -1); - preference.setIntent(addNewServiceIntent); preference.setPersistent(false); return preference; } diff --git a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java index 4a99f5abed6..131a2340532 100644 --- a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java +++ b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java @@ -40,7 +40,7 @@ public class BackupSettingsActivityPreferenceController extends BasePreferenceCo @Override public int getAvailabilityStatus() { return mUm.isAdminUser() - ? AVAILABLE + ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index 2b9c2cb5565..c2e6f2f8d89 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -23,9 +23,7 @@ import android.util.Log; import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; /** @@ -45,15 +43,6 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); } - @VisibleForTesting - AvailableMediaBluetoothDeviceUpdater(DashboardFragment fragment, - DevicePreferenceCallback devicePreferenceCallback, - LocalBluetoothManager localBluetoothManager) { - super(fragment, devicePreferenceCallback, localBluetoothManager); - mAudioManager = (AudioManager) fragment.getContext(). - getSystemService(Context.AUDIO_SERVICE); - } - @Override public void onAudioModeChanged() { forceUpdate(); diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java index a26e9610429..cd452817d0e 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java @@ -149,15 +149,12 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll */ private void disableProfile(LocalBluetoothProfile profile, BluetoothDevice device, SwitchPreference profilePref) { - if (profile instanceof PbapServerProfile) { - mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED); - // We don't need to do the additional steps below for this profile. - return; - } mCachedDevice.disconnect(profile); profile.setPreferred(device, false); if (profile instanceof MapProfile) { mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED); + } else if (profile instanceof PbapServerProfile) { + mCachedDevice.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_REJECTED); } } diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java index 74a5f246fce..5f17e5f2ae6 100644 --- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java +++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java @@ -207,8 +207,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); if (cachedDevice == null) { - cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(), - mDevice); + cachedDevice = cachedDeviceManager.addDevice(mDevice); } always = cachedDevice.checkAndIncreaseMessageRejectionCount(); } diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java index bbf3fffc6c7..c452957bc14 100644 --- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java +++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java @@ -231,8 +231,7 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); if (cachedDevice == null) { - cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(), - mDevice); + cachedDevice = cachedDeviceManager.addDevice(mDevice); } String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY; diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 259a403625b..b66b286b0fd 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -24,9 +24,7 @@ import android.util.Log; import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; /** @@ -45,15 +43,6 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); } - @VisibleForTesting - ConnectedBluetoothDeviceUpdater(DashboardFragment fragment, - DevicePreferenceCallback devicePreferenceCallback, - LocalBluetoothManager localBluetoothManager) { - super(fragment, devicePreferenceCallback, localBluetoothManager); - mAudioManager = (AudioManager) fragment.getContext(). - getSystemService(Context.AUDIO_SERVICE); - } - @Override public void onAudioModeChanged() { forceUpdate(); diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java index 059a920b3d2..50de166ba65 100644 --- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java @@ -16,16 +16,13 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; /** @@ -41,13 +38,6 @@ public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater super(context, fragment, devicePreferenceCallback); } - @VisibleForTesting - SavedBluetoothDeviceUpdater(DashboardFragment fragment, - DevicePreferenceCallback devicePreferenceCallback, - LocalBluetoothManager localBluetoothManager) { - super(fragment, devicePreferenceCallback, localBluetoothManager); - } - @Override public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { final BluetoothDevice device = cachedDevice.getDevice(); diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java index 6cceaf3e518..14b8a811de8 100644 --- a/src/com/android/settings/core/BasePreferenceController.java +++ b/src/com/android/settings/core/BasePreferenceController.java @@ -274,6 +274,10 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl Log.w(TAG, "Skipping updateNonIndexableKeys due to empty key " + toString()); return; } + if (keys.contains(key)) { + Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list. " + toString()); + return; + } keys.add(key); } } diff --git a/src/com/android/settings/core/PreferenceControllerMixin.java b/src/com/android/settings/core/PreferenceControllerMixin.java index 3310df2fddf..da0b7e73d14 100644 --- a/src/com/android/settings/core/PreferenceControllerMixin.java +++ b/src/com/android/settings/core/PreferenceControllerMixin.java @@ -42,7 +42,12 @@ public interface PreferenceControllerMixin { final String key = ((AbstractPreferenceController) this).getPreferenceKey(); if (TextUtils.isEmpty(key)) { Log.w(TAG, - "Skipping updateNonIndexableKeys due to empty key " + this.toString()); + "Skipping updateNonIndexableKeys due to empty key " + toString()); + return; + } + if (keys.contains(key)) { + Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list. " + + toString()); return; } keys.add(key); diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java index ff196dcaaf6..8ef7f8dc460 100644 --- a/src/com/android/settings/core/PreferenceXmlParserUtils.java +++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java @@ -29,6 +29,9 @@ import android.util.Log; import android.util.TypedValue; import android.util.Xml; +import androidx.annotation.IntDef; +import androidx.annotation.VisibleForTesting; + import com.android.settings.R; import org.xmlpull.v1.XmlPullParser; @@ -41,9 +44,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import androidx.annotation.IntDef; -import androidx.annotation.VisibleForTesting; - /** * Utility class to parse elements of XML preferences */ @@ -53,7 +53,8 @@ public class PreferenceXmlParserUtils { @VisibleForTesting static final String PREF_SCREEN_TAG = "PreferenceScreen"; private static final List SUPPORTED_PREF_TYPES = Arrays.asList( - "Preference", "PreferenceCategory", "PreferenceScreen"); + "Preference", "PreferenceCategory", "PreferenceScreen", + "com.android.settings.widget.WorkOnlyCategory"); /** * Flag definition to indicate which metadata should be extracted when @@ -67,7 +68,8 @@ public class PreferenceXmlParserUtils { MetadataFlag.FLAG_NEED_PREF_CONTROLLER, MetadataFlag.FLAG_NEED_PREF_TITLE, MetadataFlag.FLAG_NEED_PREF_SUMMARY, - MetadataFlag.FLAG_NEED_PREF_ICON}) + MetadataFlag.FLAG_NEED_PREF_ICON, + MetadataFlag.FLAG_NEED_SEARCHABLE}) @Retention(RetentionPolicy.SOURCE) public @interface MetadataFlag { int FLAG_INCLUDE_PREF_SCREEN = 1; @@ -79,6 +81,7 @@ public class PreferenceXmlParserUtils { int FLAG_NEED_PREF_ICON = 1 << 6; int FLAG_NEED_PLATFORM_SLICE_FLAG = 1 << 7; int FLAG_NEED_KEYWORDS = 1 << 8; + int FLAG_NEED_SEARCHABLE = 1 << 9; } public static final String METADATA_PREF_TYPE = "type"; @@ -89,6 +92,7 @@ public class PreferenceXmlParserUtils { public static final String METADATA_ICON = "icon"; public static final String METADATA_PLATFORM_SLICE_FLAG = "platform_slice"; public static final String METADATA_KEYWORDS = "keywords"; + public static final String METADATA_SEARCHABLE = "searchable"; private static final String ENTRIES_SEPARATOR = "|"; @@ -154,18 +158,6 @@ public class PreferenceXmlParserUtils { R.styleable.Preference_controller); } - /** - * Call {@link #extractMetadata(Context, int, int)} with {@link #METADATA_ICON} instead. - */ - @Deprecated - public static int getDataIcon(Context context, AttributeSet attrs) { - final TypedArray ta = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.Preference); - final int dataIcon = ta.getResourceId(com.android.internal.R.styleable.Icon_icon, 0); - ta.recycle(); - return dataIcon; - } - /** * Extracts metadata from preference xml and put them into a {@link Bundle}. * @@ -232,6 +224,10 @@ public class PreferenceXmlParserUtils { if (hasFlag(flags, MetadataFlag.FLAG_NEED_KEYWORDS)) { preferenceMetadata.putString(METADATA_KEYWORDS, getKeywords(preferenceAttributes)); } + if (hasFlag(flags, MetadataFlag.FLAG_NEED_SEARCHABLE)) { + preferenceMetadata.putBoolean(METADATA_SEARCHABLE, + isSearchable(preferenceAttributes)); + } metadata.add(preferenceMetadata); preferenceAttributes.recycle(); @@ -312,6 +308,10 @@ public class PreferenceXmlParserUtils { return styledAttributes.getBoolean(R.styleable.Preference_platform_slice, false /* def */); } + private static boolean isSearchable(TypedArray styledAttributes) { + return styledAttributes.getBoolean(R.styleable.Preference_searchable, true /* default */); + } + private static String getKeywords(TypedArray styleAttributes) { return styleAttributes.getString(R.styleable.Preference_keywords); } diff --git a/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java b/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java index ae8e246b0b4..90266e03a65 100644 --- a/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java +++ b/src/com/android/settings/development/autofill/AutofillDeveloperSettingsObserver.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; @@ -30,7 +31,7 @@ final class AutofillDeveloperSettingsObserver extends ContentObserver { private final ContentResolver mResolver; public AutofillDeveloperSettingsObserver(Context context, Runnable changeCallback) { - super(new Handler()); + super(new Handler(Looper.getMainLooper())); mResolver = context.getContentResolver(); mChangeCallback = changeCallback; diff --git a/src/com/android/settings/gestures/PickupGesturePreferenceController.java b/src/com/android/settings/gestures/PickupGesturePreferenceController.java index 7460183bda0..399c047c451 100644 --- a/src/com/android/settings/gestures/PickupGesturePreferenceController.java +++ b/src/com/android/settings/gestures/PickupGesturePreferenceController.java @@ -31,8 +31,8 @@ import androidx.annotation.VisibleForTesting; public class PickupGesturePreferenceController extends GesturePreferenceController { - private final int ON = 1; - private final int OFF = 0; + private static final int ON = 1; + private static final int OFF = 0; private static final String PREF_KEY_VIDEO = "gesture_pick_up_video"; private final String mPickUpPrefKey; diff --git a/src/com/android/settings/gestures/ReachGesturePreferenceController.java b/src/com/android/settings/gestures/ReachGesturePreferenceController.java new file mode 100644 index 00000000000..e22dae42e18 --- /dev/null +++ b/src/com/android/settings/gestures/ReachGesturePreferenceController.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.gestures; + +import static android.provider.Settings.Secure.DOZE_REACH_GESTURE; + +import android.annotation.UserIdInt; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; + +import com.android.internal.hardware.AmbientDisplayConfiguration; + +public class ReachGesturePreferenceController extends GesturePreferenceController { + + private static final int ON = 1; + private static final int OFF = 0; + + private static final String PREF_KEY_VIDEO = "gesture_reach_video"; + private final String mReachUpPrefKey; + + private AmbientDisplayConfiguration mAmbientConfig; + @UserIdInt + private final int mUserId; + + public ReachGesturePreferenceController(Context context, String key) { + super(context, key); + mUserId = UserHandle.myUserId(); + mReachUpPrefKey = key; + } + + public ReachGesturePreferenceController setConfig(AmbientDisplayConfiguration config) { + mAmbientConfig = config; + return this; + } + + @Override + public int getAvailabilityStatus() { + // No hardware support for Reach Gesture + if (!getAmbientConfig().reachGestureAvailable()) { + return UNSUPPORTED_ON_DEVICE; + } + + return AVAILABLE; + } + + @Override + public boolean isSliceable() { + return TextUtils.equals(getPreferenceKey(), "gesture_reach"); + } + + @Override + protected String getVideoPrefKey() { + return PREF_KEY_VIDEO; + } + + @Override + public boolean isChecked() { + return getAmbientConfig().reachGestureEnabled(mUserId); + } + + @Override + public String getPreferenceKey() { + return mReachUpPrefKey; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), DOZE_REACH_GESTURE, + isChecked ? ON : OFF); + } + + private AmbientDisplayConfiguration getAmbientConfig() { + if (mAmbientConfig == null) { + mAmbientConfig = new AmbientDisplayConfiguration(mContext); + } + + return mAmbientConfig; + } +} diff --git a/src/com/android/settings/gestures/ReachGestureSettings.java b/src/com/android/settings/gestures/ReachGestureSettings.java new file mode 100644 index 00000000000..3df9fcfdeae --- /dev/null +++ b/src/com/android/settings/gestures/ReachGestureSettings.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.gestures; + +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.SearchIndexableResource; + +import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +import java.util.Arrays; +import java.util.List; + +@SearchIndexable +public class ReachGestureSettings extends DashboardFragment { + + private static final String TAG = "ReachGestureSettings"; + + public static final String PREF_KEY_SUGGESTION_COMPLETE = + "pref_reach_gesture_suggestion_complete"; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + SuggestionFeatureProvider suggestionFeatureProvider = FeatureFactory.getFactory(context) + .getSuggestionFeatureProvider(context); + SharedPreferences prefs = suggestionFeatureProvider.getSharedPrefs(context); + prefs.edit().putBoolean(PREF_KEY_SUGGESTION_COMPLETE, true).apply(); + + use(ReachGesturePreferenceController.class) + .setConfig(new AmbientDisplayConfiguration(context)); + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SETTINGS_GESTURE_REACH; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.reach_gesture_settings; + } + + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.reach_gesture_settings; + return Arrays.asList(sir); + } + }; + +} diff --git a/src/com/android/settings/gestures/SwipeUpPreferenceController.java b/src/com/android/settings/gestures/SwipeUpPreferenceController.java index f48d21b90d4..5e882c4e44f 100644 --- a/src/com/android/settings/gestures/SwipeUpPreferenceController.java +++ b/src/com/android/settings/gestures/SwipeUpPreferenceController.java @@ -47,6 +47,9 @@ public class SwipeUpPreferenceController extends GesturePreferenceController { final ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(R.string.config_recentsComponentName)); + if (recentsComponentName == null) { + return false; + } final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP) .setPackage(recentsComponentName.getPackageName()); if (context.getPackageManager().resolveService(quickStepIntent, diff --git a/src/com/android/settings/homepage/CardContentProvider.java b/src/com/android/settings/homepage/CardContentProvider.java index 3081ae1fa81..640a00b3683 100644 --- a/src/com/android/settings/homepage/CardContentProvider.java +++ b/src/com/android/settings/homepage/CardContentProvider.java @@ -29,6 +29,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settingslib.utils.ThreadUtils; + /** * Provider stores and manages user interaction feedback for homepage contextual cards. */ @@ -61,9 +63,7 @@ public class CardContentProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { - if (Build.IS_DEBUGGABLE) { - enableStrictMode(true); - } + maybeEnableStrictMode(); final SQLiteDatabase database = mDBHelper.getWritableDatabase(); final String table = getTableFromMatch(uri); @@ -84,10 +84,7 @@ public class CardContentProvider extends ContentProvider { public int delete(Uri uri, String selection, String[] selectionArgs) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { - if (Build.IS_DEBUGGABLE) { - enableStrictMode(true); - } - + maybeEnableStrictMode(); final SQLiteDatabase database = mDBHelper.getWritableDatabase(); final String table = getTableFromMatch(uri); final int rowsDeleted = database.delete(table, selection, selectionArgs); @@ -108,9 +105,7 @@ public class CardContentProvider extends ContentProvider { String[] selectionArgs, String sortOrder) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { - if (Build.IS_DEBUGGABLE) { - enableStrictMode(true); - } + maybeEnableStrictMode(); final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); final String table = getTableFromMatch(uri); @@ -130,9 +125,7 @@ public class CardContentProvider extends ContentProvider { public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { - if (Build.IS_DEBUGGABLE) { - enableStrictMode(true); - } + maybeEnableStrictMode(); final SQLiteDatabase database = mDBHelper.getWritableDatabase(); final String table = getTableFromMatch(uri); @@ -144,10 +137,16 @@ public class CardContentProvider extends ContentProvider { } } - private void enableStrictMode(boolean enabled) { - StrictMode.setThreadPolicy(enabled - ? new StrictMode.ThreadPolicy.Builder().detectAll().build() - : StrictMode.ThreadPolicy.LAX); + @VisibleForTesting + void maybeEnableStrictMode() { + if (Build.IS_DEBUGGABLE && ThreadUtils.isMainThread()) { + enableStrictMode(); + } + } + + @VisibleForTesting + void enableStrictMode() { + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().build()); } @VisibleForTesting diff --git a/src/com/android/settings/homepage/conditional/v2/ConditionManager.java b/src/com/android/settings/homepage/conditional/v2/ConditionManager.java index ff5d20a868f..c67b255d4f0 100644 --- a/src/com/android/settings/homepage/conditional/v2/ConditionManager.java +++ b/src/com/android/settings/homepage/conditional/v2/ConditionManager.java @@ -28,6 +28,13 @@ import com.android.settings.homepage.conditional.ConditionListener; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class ConditionManager { private static final String TAG = "ConditionManager"; @@ -37,6 +44,9 @@ public class ConditionManager { @VisibleForTesting final List mCardControllers; + private static final long DISPLAYABLE_CHECKER_TIMEOUT_MS = 20; + + private final ExecutorService mExecutorService; private final Context mAppContext; private final ConditionListener mListener; @@ -51,6 +61,7 @@ public class ConditionManager { public ConditionManager(Context context, ConditionListener listener) { mAppContext = context.getApplicationContext(); + mExecutorService = Executors.newCachedThreadPool(); mCandidates = new ArrayList<>(); mCardControllers = new ArrayList<>(); mListener = listener; @@ -62,9 +73,23 @@ public class ConditionManager { */ public List getDisplayableCards() { final List cards = new ArrayList<>(); + final List> displayableCards = new ArrayList<>(); + // Check displayable future for (ConditionalCard card : mCandidates) { - if (getController(card.getId()).isDisplayable()) { - cards.add(card); + final DisplayableChecker future = new DisplayableChecker( + card, getController(card.getId())); + displayableCards.add(mExecutorService.submit(future)); + } + // Collect future and add displayable cards + for (Future cardFuture : displayableCards) { + try { + final ConditionalCard card = cardFuture.get(DISPLAYABLE_CHECKER_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + if (card != null) { + cards.add(card); + } + } catch (InterruptedException | ExecutionException | TimeoutException e) { + Log.w(TAG, "Failed to get displayable state for card, likely timeout. Skipping", e); } } return cards; @@ -89,7 +114,6 @@ public class ConditionManager { onConditionChanged(); } - /** * Start monitoring state change for all conditions */ @@ -163,6 +187,24 @@ public class ConditionManager { mCandidates.add(new RingerMutedConditionCard(mAppContext)); mCandidates.add(new RingerVibrateConditionCard(mAppContext)); mCandidates.add(new WorkModeConditionCard(mAppContext)); + } + /** + * Returns card if controller says it's displayable. Otherwise returns null. + */ + public static class DisplayableChecker implements Callable { + + private final ConditionalCard mCard; + private final ConditionalCardController mController; + + private DisplayableChecker(ConditionalCard card, ConditionalCardController controller) { + mCard = card; + mController = controller; + } + + @Override + public ConditionalCard call() throws Exception { + return mController.isDisplayable() ? mCard : null; + } } } diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java index 6c7c0d3861c..68b1b2446bb 100644 --- a/src/com/android/settings/language/LanguageAndInputSettings.java +++ b/src/com/android/settings/language/LanguageAndInputSettings.java @@ -108,7 +108,7 @@ public class LanguageAndInputSettings extends DashboardFragment { // Pointer and Tts final TtsPreferenceController ttsPreferenceController = - new TtsPreferenceController(context, new TtsEngines(context)); + new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH); controllers.add(ttsPreferenceController); final PointerSpeedController pointerController = new PointerSpeedController(context); controllers.add(pointerController); @@ -180,7 +180,6 @@ public class LanguageAndInputSettings extends DashboardFragment { public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); // Duplicates in summary and details pages. - keys.add(KEY_TEXT_TO_SPEECH); keys.add(KEY_PHYSICAL_KEYBOARD); return keys; } diff --git a/src/com/android/settings/language/TtsPreferenceController.java b/src/com/android/settings/language/TtsPreferenceController.java index c83492c4883..7e34175ce99 100644 --- a/src/com/android/settings/language/TtsPreferenceController.java +++ b/src/com/android/settings/language/TtsPreferenceController.java @@ -19,31 +19,26 @@ package com.android.settings.language; import android.content.Context; import android.speech.tts.TtsEngines; +import androidx.annotation.VisibleForTesting; + import com.android.settings.R; -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settings.core.BasePreferenceController; -public class TtsPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin { +public class TtsPreferenceController extends BasePreferenceController { - private static final String KEY_VOICE_CATEGORY = "voice_category"; - private static final String KEY_TTS_SETTINGS = "tts_settings_summary"; + @VisibleForTesting + TtsEngines mTtsEngines; - private final TtsEngines mTtsEngines; - - public TtsPreferenceController(Context context, TtsEngines ttsEngines) { - super(context); - mTtsEngines = ttsEngines; + public TtsPreferenceController(Context context, String key) { + super(context, key); + mTtsEngines = new TtsEngines(context); } @Override - public boolean isAvailable() { + public int getAvailabilityStatus() { return !mTtsEngines.getEngines().isEmpty() && - mContext.getResources().getBoolean(R.bool.config_show_tts_settings_summary); - } - - @Override - public String getPreferenceKey() { - return KEY_TTS_SETTINGS; + mContext.getResources().getBoolean(R.bool.config_show_tts_settings_summary) + ? AVAILABLE_UNSEARCHABLE + : CONDITIONALLY_UNAVAILABLE; } } diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java index fcfa8aadb6a..efbefde5b48 100644 --- a/src/com/android/settings/search/BaseSearchIndexProvider.java +++ b/src/com/android/settings/search/BaseSearchIndexProvider.java @@ -16,14 +16,21 @@ package com.android.settings.search; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag + .FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_SEARCHABLE; + import android.annotation.XmlRes; import android.content.Context; -import android.content.res.XmlResourceParser; +import android.os.Bundle; import android.provider.SearchIndexableResource; -import android.text.TextUtils; -import android.util.AttributeSet; import android.util.Log; -import android.util.Xml; + +import androidx.annotation.CallSuper; +import androidx.annotation.VisibleForTesting; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerListHelper; @@ -31,16 +38,12 @@ import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceXmlParserUtils; import com.android.settingslib.core.AbstractPreferenceController; -import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import androidx.annotation.CallSuper; -import androidx.annotation.VisibleForTesting; - /** * A basic SearchIndexProvider that returns no data to index. */ @@ -66,11 +69,12 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { public List getNonIndexableKeys(Context context) { if (!isPageSearchEnabled(context)) { // Entire page should be suppressed, mark all keys from this page as non-indexable. - return getNonIndexableKeysFromXml(context); + return getNonIndexableKeysFromXml(context, true /* suppressAllPage */); } + final List nonIndexableKeys = new ArrayList<>(); + nonIndexableKeys.addAll(getNonIndexableKeysFromXml(context, false /* suppressAllPage */)); final List controllers = getPreferenceControllers(context); if (controllers != null && !controllers.isEmpty()) { - final List nonIndexableKeys = new ArrayList<>(); for (AbstractPreferenceController controller : controllers) { if (controller instanceof PreferenceControllerMixin) { ((PreferenceControllerMixin) controller) @@ -85,10 +89,8 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { nonIndexableKeys.add(controller.getPreferenceKey()); } } - return nonIndexableKeys; - } else { - return new ArrayList<>(); } + return nonIndexableKeys; } @Override @@ -131,7 +133,11 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { return true; } - private List getNonIndexableKeysFromXml(Context context) { + /** + * Get all non-indexable keys from xml. If {@param suppressAllPage} is set, all keys are + * considered non-indexable. Otherwise, only keys with searchable="false" are included. + */ + private List getNonIndexableKeysFromXml(Context context, boolean suppressAllPage) { final List resources = getXmlResourcesToIndex( context, true /* not used*/); if (resources == null || resources.isEmpty()) { @@ -139,27 +145,32 @@ public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider { } final List nonIndexableKeys = new ArrayList<>(); for (SearchIndexableResource res : resources) { - nonIndexableKeys.addAll(getNonIndexableKeysFromXml(context, res.xmlResId)); + nonIndexableKeys.addAll( + getNonIndexableKeysFromXml(context, res.xmlResId, suppressAllPage)); } return nonIndexableKeys; } @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) - public List getNonIndexableKeysFromXml(Context context, @XmlRes int xmlResId) { - final List nonIndexableKeys = new ArrayList<>(); - final XmlResourceParser parser = context.getResources().getXml(xmlResId); - final AttributeSet attrs = Xml.asAttributeSet(parser); + public List getNonIndexableKeysFromXml(Context context, @XmlRes int xmlResId, + boolean suppressAllPage) { + return getKeysFromXml(context, xmlResId, suppressAllPage); + } + + private List getKeysFromXml(Context context, @XmlRes int xmlResId, + boolean suppressAllPage) { + final List keys = new ArrayList<>(); try { - while (parser.next() != XmlPullParser.END_DOCUMENT) { - final String key = PreferenceXmlParserUtils.getDataKey(context, attrs); - if (!TextUtils.isEmpty(key)) { - nonIndexableKeys.add(key); + final List metadata = PreferenceXmlParserUtils.extractMetadata(context, + xmlResId, FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN | FLAG_NEED_SEARCHABLE); + for (Bundle bundle : metadata) { + if (suppressAllPage || !bundle.getBoolean(METADATA_SEARCHABLE, true)) { + keys.add(bundle.getString(METADATA_KEY)); } } } catch (IOException | XmlPullParserException e) { Log.w(TAG, "Error parsing non-indexable from xml " + xmlResId); } - return nonIndexableKeys; + return keys; } - } diff --git a/src/com/android/settings/search/DeviceIndexUpdateJobService.java b/src/com/android/settings/search/DeviceIndexUpdateJobService.java index b8f35a6baa4..3a85867f2d1 100644 --- a/src/com/android/settings/search/DeviceIndexUpdateJobService.java +++ b/src/com/android/settings/search/DeviceIndexUpdateJobService.java @@ -43,6 +43,7 @@ import androidx.slice.SliceViewManager; import androidx.slice.SliceViewManager.SliceCallback; import androidx.slice.core.SliceQuery; import androidx.slice.widget.ListContent; +import androidx.slice.widget.SliceContent; public class DeviceIndexUpdateJobService extends JobService { @@ -134,7 +135,7 @@ public class DeviceIndexUpdateJobService extends JobService { protected CharSequence findTitle(Slice loadedSlice, SliceMetadata metaData) { ListContent content = new ListContent(null, loadedSlice); - SliceItem headerItem = content.getHeaderItem(); + SliceContent headerItem = content.getHeader(); if (headerItem == null) { if (content.getRowItems().size() != 0) { headerItem = content.getRowItems().get(0); @@ -143,15 +144,15 @@ public class DeviceIndexUpdateJobService extends JobService { } } // Look for a title, then large text, then any text at all. - SliceItem title = SliceQuery.find(headerItem, FORMAT_TEXT, HINT_TITLE, null); + SliceItem title = SliceQuery.find(headerItem.getSliceItem(), FORMAT_TEXT, HINT_TITLE, null); if (title != null) { return title.getText(); } - title = SliceQuery.find(headerItem, FORMAT_TEXT, HINT_LARGE, null); + title = SliceQuery.find(headerItem.getSliceItem(), FORMAT_TEXT, HINT_LARGE, null); if (title != null) { return title.getText(); } - title = SliceQuery.find(headerItem, FORMAT_TEXT); + title = SliceQuery.find(headerItem.getSliceItem(), FORMAT_TEXT); if (title != null) { return title.getText(); } diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index f6c08ce349c..f7cbf83c9ac 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -423,7 +423,7 @@ public class SettingsSliceProvider extends SliceProvider { void registerIntentToUri(IntentFilter intentFilter, Uri sliceUri) { Log.d(TAG, "Registering Uri for broadcast relay: " + sliceUri); mRegisteredUris.add(sliceUri); - SliceBroadcastRelay.registerReceiver(getContext(), sliceUri, SliceBroadcastReceiver.class, + SliceBroadcastRelay.registerReceiver(getContext(), sliceUri, SliceRelayReceiver.class, intentFilter); } diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index a44a2cd6e0e..c72066331f8 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -55,7 +55,6 @@ import com.android.settings.flashlight.FlashlightSliceBuilder; import com.android.settings.notification.ZenModeSliceBuilder; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wifi.WifiSliceBuilder; -import com.android.settingslib.SliceBroadcastRelay; /** * Responds to actions performed on slices and notifies slices of updates in state changes. @@ -121,12 +120,6 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { case ACTION_FLASHLIGHT_SLICE_CHANGED: FlashlightSliceBuilder.handleUriChange(context, intent); break; - default: - final String uriString = intent.getStringExtra(SliceBroadcastRelay.EXTRA_URI); - if (!TextUtils.isEmpty(uriString)) { - final Uri uri = Uri.parse(uriString); - context.getContentResolver().notifyChange(uri, null /* observer */); - } } } diff --git a/src/com/android/settings/slices/SliceRelayReceiver.java b/src/com/android/settings/slices/SliceRelayReceiver.java new file mode 100644 index 00000000000..c8ec12eae85 --- /dev/null +++ b/src/com/android/settings/slices/SliceRelayReceiver.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settings.slices; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; +import com.android.settingslib.SliceBroadcastRelay; + +/** + * Receives broadcasts to notify that Settings Slices are potentially stale. + */ +public class SliceRelayReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + final String uriString = intent.getStringExtra(SliceBroadcastRelay.EXTRA_URI); + if (!TextUtils.isEmpty(uriString)) { + final Uri uri = Uri.parse(uriString); + context.getContentResolver().notifyChange(uri, null /* observer */); + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java index 52349ae6fa8..0c73e4d8913 100644 --- a/src/com/android/settings/system/SystemDashboardFragment.java +++ b/src/com/android/settings/system/SystemDashboardFragment.java @@ -101,8 +101,6 @@ public class SystemDashboardFragment extends DashboardFragment { @Override public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); - keys.add((new BackupSettingsActivityPreferenceController( - context).getPreferenceKey())); keys.add(KEY_RESET); return keys; } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 9aa56c234d3..89e9a67978c 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -49,6 +49,13 @@ import android.view.MenuItem; import android.view.View; import android.widget.SimpleAdapter; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; import com.android.internal.widget.LockPatternUtils; @@ -76,13 +83,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; -import androidx.annotation.VisibleForTesting; -import androidx.annotation.WorkerThread; -import androidx.appcompat.app.AlertDialog; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceScreen; - /** * Screen that manages the list of users on the device. * Guest user is an always visible entry, even if the guest is not currently @@ -635,8 +635,8 @@ public class UserSettings extends SettingsPreferenceFragment AlertDialog.Builder builder = new AlertDialog.Builder(context); SimpleAdapter adapter = new SimpleAdapter(builder.getContext(), data, R.layout.two_line_list_item, - new String[] {KEY_TITLE, KEY_SUMMARY}, - new int[] {R.id.title, R.id.summary}); + new String[]{KEY_TITLE, KEY_SUMMARY}, + new int[]{R.id.title, R.id.summary}); builder.setTitle(R.string.user_add_user_type_title); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @@ -1238,8 +1238,10 @@ public class UserSettings extends SettingsPreferenceFragment } @Override - public List getNonIndexableKeysFromXml(Context context, int xmlResId) { - final List niks = super.getNonIndexableKeysFromXml(context, xmlResId); + public List getNonIndexableKeysFromXml(Context context, int xmlResId, + boolean suppressAllPage) { + final List niks = super.getNonIndexableKeysFromXml(context, xmlResId, + suppressAllPage); new AddUserWhenLockedPreferenceController(context, KEY_ADD_USER_WHEN_LOCKED) .updateNonIndexableKeys(niks); new AutoSyncDataPreferenceController(context, null /* parent */) diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 10111aa7204..9e2fac32646 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -24,6 +24,7 @@ import android.app.Activity; import android.app.Dialog; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -87,7 +88,7 @@ import java.util.List; @SearchIndexable public class WifiSettings extends RestrictedSettingsFragment implements Indexable, WifiTracker.WifiListener, AccessPointListener, - WifiDialog.WifiDialogListener { + WifiDialog.WifiDialogListener, DialogInterface.OnDismissListener { private static final String TAG = "WifiSettings"; @@ -432,9 +433,8 @@ public class WifiSettings extends RestrictedSettingsFragment @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - - // If the dialog is showing, save its state. - if (mDialog != null && mDialog.isShowing()) { + // If dialog has been shown, save its state. + if (mDialog != null) { outState.putInt(SAVE_DIALOG_MODE, mDialogMode); if (mDlgAccessPoint != null) { mAccessPointSavedState = new Bundle(); @@ -443,7 +443,7 @@ public class WifiSettings extends RestrictedSettingsFragment } } - if (mWifiToNfcDialog != null && mWifiToNfcDialog.isShowing()) { + if (mWifiToNfcDialog != null) { Bundle savedState = new Bundle(); mWifiToNfcDialog.saveState(savedState); outState.putBundle(SAVED_WIFI_NFC_DIALOG_STATE, savedState); @@ -617,12 +617,24 @@ public class WifiSettings extends RestrictedSettingsFragment mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(getActivity(), mWifiNfcDialogSavedState); } - return mWifiToNfcDialog; } return super.onCreateDialog(dialogId); } + @Override + public void onDialogShowing() { + super.onDialogShowing(); + setOnDismissListener(this); + } + + @Override + public void onDismiss(DialogInterface dialog) { + // We don't keep any dialog object when dialog was dismissed. + mDialog = null; + mWifiToNfcDialog = null; + } + @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java index 3c2fa08d2f3..641c3c35b7e 100644 --- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java +++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java @@ -355,11 +355,9 @@ public class WifiP2pSettings extends DashboardFragment int textId = mWifiP2pSearching ? R.string.wifi_p2p_menu_searching : R.string.wifi_p2p_menu_search; menu.add(Menu.NONE, MENU_ID_SEARCH, 0, textId) - .setEnabled(mWifiP2pEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + .setEnabled(mWifiP2pEnabled); menu.add(Menu.NONE, MENU_ID_RENAME, 0, R.string.wifi_p2p_menu_rename) - .setEnabled(mWifiP2pEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + .setEnabled(mWifiP2pEnabled); super.onCreateOptionsMenu(menu, inflater); } diff --git a/tests/robotests/res/xml-mcc999/display_settings.xml b/tests/robotests/res/xml-mcc999/display_settings.xml index 8c5d47ad4f5..fccad7fb454 100644 --- a/tests/robotests/res/xml-mcc999/display_settings.xml +++ b/tests/robotests/res/xml-mcc999/display_settings.xml @@ -59,5 +59,6 @@ android:title="pref_title_5" android:summaryOn="summary_on" android:summaryOff="summary_off" + settings:searchable="false" settings:keywords="keywords1, keywords2, keywords3" /> \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java index 97210b332b4..c332c064da3 100644 --- a/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppAndNotificationDashboardFragmentTest.java @@ -17,6 +17,7 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -26,7 +27,6 @@ import android.os.UserManager; import com.android.settings.notification.EmergencyBroadcastPreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.XmlTestUtils; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,19 +42,16 @@ public class AppAndNotificationDashboardFragmentTest { @Test @Config(shadows = {ShadowEmergencyBroadcastPreferenceController.class}) - public void testNonIndexableKeys_existInXmlLayout() { + public void getNonIndexableKeys_shouldIncludeSpecialAppAccess() { final Context context = spy(RuntimeEnvironment.application); UserManager manager = mock(UserManager.class); when(manager.isAdminUser()).thenReturn(true); when(context.getSystemService(Context.USER_SERVICE)).thenReturn(manager); final List niks = AppAndNotificationDashboardFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(context); - AppAndNotificationDashboardFragment fragment = new AppAndNotificationDashboardFragment(); - final int xmlId = fragment.getPreferenceScreenResId(); - final List keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId); - - assertThat(keys).containsAllIn(niks); + assertThat(niks).contains( + new SpecialAppAccessPreferenceController(context).getPreferenceKey()); } @Implements(EmergencyBroadcastPreferenceController.class) diff --git a/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java b/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java index fef8eefee69..dda6b72e9f2 100644 --- a/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java +++ b/tests/robotests/src/com/android/settings/applications/DefaultAppSettingsTest.java @@ -165,7 +165,7 @@ public class DefaultAppSettingsTest { final List niks = DefaultAppSettings.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(context); - final int xmlId = (new DefaultAppSettings()).getPreferenceScreenResId(); + final int xmlId = new DefaultAppSettings().getPreferenceScreenResId(); final List keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId); diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java index e676cf4b041..14d9ca79d01 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java @@ -33,10 +33,9 @@ import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.HeadsetProfile; -import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.Before; @@ -52,7 +51,8 @@ import java.util.ArrayList; import java.util.Collection; @RunWith(SettingsRobolectricTestRunner.class) -@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class}) +@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class, + ShadowCachedBluetoothDeviceManager.class}) public class AvailableMediaBluetoothDeviceUpdaterTest { @Mock private DashboardFragment mDashboardFragment; @@ -62,21 +62,14 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { private CachedBluetoothDevice mCachedBluetoothDevice; @Mock private BluetoothDevice mBluetoothDevice; - @Mock - private LocalBluetoothManager mLocalManager; - @Mock - private LocalBluetoothProfileManager mLocalBluetoothProfileManager; - @Mock - private HeadsetProfile mHeadsetProfile; - @Mock - private CachedBluetoothDeviceManager mCachedDeviceManager; private Context mContext; private AvailableMediaBluetoothDeviceUpdater mBluetoothDeviceUpdater; - private Collection cachedDevices; + private Collection mCachedDevices; private ShadowAudioManager mShadowAudioManager; private BluetoothDevicePreference mPreference; private ShadowBluetoothAdapter mShadowBluetoothAdapter; + private ShadowCachedBluetoothDeviceManager mShadowCachedBluetoothDeviceManager; @Before public void setUp() { @@ -86,18 +79,17 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); mShadowBluetoothAdapter.setEnabled(true); mContext = RuntimeEnvironment.application; - doReturn(mContext).when(mDashboardFragment).getContext(); - cachedDevices = + mShadowCachedBluetoothDeviceManager = Shadow.extract( + Utils.getLocalBtManager(mContext).getCachedDeviceManager()); + mCachedDevices = new ArrayList(new ArrayList()); + mShadowCachedBluetoothDeviceManager.setCachedDevicesCopy(mCachedDevices); + doReturn(mContext).when(mDashboardFragment).getContext(); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mLocalManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); - when(mLocalBluetoothProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile); - when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); - when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices); - mBluetoothDeviceUpdater = spy(new AvailableMediaBluetoothDeviceUpdater(mDashboardFragment, - mDevicePreferenceCallback, mLocalManager)); + mBluetoothDeviceUpdater = spy(new AvailableMediaBluetoothDeviceUpdater(mContext, + mDashboardFragment, mDevicePreferenceCallback)); mBluetoothDeviceUpdater.setPrefContext(mContext); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, false); doNothing().when(mBluetoothDeviceUpdater).addPreference(any()); @@ -110,7 +102,7 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -123,7 +115,7 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -136,7 +128,7 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -149,7 +141,7 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java index ece71d73d9c..6faea9a2334 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java @@ -34,9 +34,8 @@ import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.LocalBluetoothManager; import org.junit.Before; import org.junit.Test; @@ -51,7 +50,8 @@ import java.util.ArrayList; import java.util.Collection; @RunWith(SettingsRobolectricTestRunner.class) -@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class}) +@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class, + ShadowCachedBluetoothDeviceManager.class}) public class ConnectedBluetoothDeviceUpdaterTest { @Mock private DashboardFragment mDashboardFragment; @@ -61,16 +61,13 @@ public class ConnectedBluetoothDeviceUpdaterTest { private CachedBluetoothDevice mCachedBluetoothDevice; @Mock private BluetoothDevice mBluetoothDevice; - @Mock - private LocalBluetoothManager mLocalManager; - @Mock - private CachedBluetoothDeviceManager mCachedDeviceManager; private Context mContext; private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater; - private Collection cachedDevices; + private Collection mCachedDevices; private ShadowAudioManager mShadowAudioManager; private ShadowBluetoothAdapter mShadowBluetoothAdapter; + private ShadowCachedBluetoothDeviceManager mShadowCachedBluetoothDeviceManager; @Before public void setUp() { @@ -80,16 +77,16 @@ public class ConnectedBluetoothDeviceUpdaterTest { mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); mShadowBluetoothAdapter.setEnabled(true); mContext = RuntimeEnvironment.application; + mShadowCachedBluetoothDeviceManager = Shadow.extract( + Utils.getLocalBtManager(mContext).getCachedDeviceManager()); doReturn(mContext).when(mDashboardFragment).getContext(); - cachedDevices = + mCachedDevices = new ArrayList(new ArrayList()); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); - when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices); - - mBluetoothDeviceUpdater = spy(new ConnectedBluetoothDeviceUpdater(mDashboardFragment, - mDevicePreferenceCallback, mLocalManager)); + mShadowCachedBluetoothDeviceManager.setCachedDevicesCopy(mCachedDevices); + mBluetoothDeviceUpdater = spy(new ConnectedBluetoothDeviceUpdater(mContext, + mDashboardFragment, mDevicePreferenceCallback)); mBluetoothDeviceUpdater.setPrefContext(mContext); doNothing().when(mBluetoothDeviceUpdater).addPreference(any()); doNothing().when(mBluetoothDeviceUpdater).removePreference(any()); @@ -101,7 +98,7 @@ public class ConnectedBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -114,7 +111,7 @@ public class ConnectedBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -127,7 +124,7 @@ public class ConnectedBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); @@ -140,7 +137,7 @@ public class ConnectedBluetoothDeviceUpdaterTest { when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - cachedDevices.add(mCachedBluetoothDevice); + mCachedDevices.add(mCachedBluetoothDevice); mBluetoothDeviceUpdater.onAudioModeChanged(); diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java index def8c4db37c..e25e4b22744 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java @@ -29,9 +29,8 @@ import android.content.Context; import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.Before; import org.junit.Test; @@ -39,8 +38,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) public class SavedBluetoothDeviceUpdaterTest { @Mock @@ -51,10 +52,6 @@ public class SavedBluetoothDeviceUpdaterTest { private CachedBluetoothDevice mCachedBluetoothDevice; @Mock private BluetoothDevice mBluetoothDevice; - @Mock - private LocalBluetoothManager mLocalManager; - @Mock - private LocalBluetoothProfileManager mLocalBluetoothProfileManager; private Context mContext; private SavedBluetoothDeviceUpdater mBluetoothDeviceUpdater; @@ -67,11 +64,10 @@ public class SavedBluetoothDeviceUpdaterTest { mContext = RuntimeEnvironment.application; doReturn(mContext).when(mDashboardFragment).getContext(); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); - when(mLocalManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); - mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mDashboardFragment, - mDevicePreferenceCallback, mLocalManager)); + mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mContext, mDashboardFragment, + mDevicePreferenceCallback)); mBluetoothDeviceUpdater.setPrefContext(mContext); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, false); doNothing().when(mBluetoothDeviceUpdater).addPreference(any()); diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java index 70cfa21df20..b3dbdab01eb 100644 --- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java +++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java @@ -16,7 +16,10 @@ package com.android.settings.core; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; @@ -247,8 +250,7 @@ public class PreferenceXmlParserUtilsTest { @Test @Config(qualifiers = "mcc999") - public void extractMetadata_requestIncludesKeywords_shouldContainKeywords() - throws IOException, XmlPullParserException { + public void extractMetadata_requestIncludesKeywords_shouldContainKeywords() throws Exception { final String expectedKeywords = "a, b, c"; final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, R.xml.location_settings, @@ -260,6 +262,32 @@ public class PreferenceXmlParserUtilsTest { assertThat(keywords).isEqualTo(expectedKeywords); } + @Test + public void extractMetadata_requestSearchable_shouldDefaultToTrue() throws Exception { + final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, + R.xml.display_settings, MetadataFlag.FLAG_NEED_SEARCHABLE); + for (Bundle bundle : metadata) { + assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isTrue(); + } + } + + @Test + @Config(qualifiers = "mcc999") + public void extractMetadata_requestSearchable_shouldReturnAttributeValue() throws Exception { + final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext, + R.xml.display_settings, + MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_SEARCHABLE); + boolean foundKey = false; + for (Bundle bundle : metadata) { + if (TextUtils.equals(bundle.getString(METADATA_KEY), "pref_key_5")) { + assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isFalse(); + foundKey = true; + break; + } + } + assertThat(foundKey).isTrue(); + } + /** * @param resId the ID for the XML preference * @return an XML resource parser that points to the start tag diff --git a/tests/robotests/src/com/android/settings/gestures/PickupGestureSettingsTest.java b/tests/robotests/src/com/android/settings/gestures/PickupGestureSettingsTest.java index d78880b4b78..72865cfd4e2 100644 --- a/tests/robotests/src/com/android/settings/gestures/PickupGestureSettingsTest.java +++ b/tests/robotests/src/com/android/settings/gestures/PickupGestureSettingsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/tests/robotests/src/com/android/settings/gestures/ReachGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/ReachGesturePreferenceControllerTest.java new file mode 100644 index 00000000000..9e24dab6261 --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/ReachGesturePreferenceControllerTest.java @@ -0,0 +1,104 @@ +/* + * 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.gestures; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ReachGesturePreferenceControllerTest { + + private static final String KEY_REACH = "gesture_reach"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private AmbientDisplayConfiguration mAmbientDisplayConfiguration; + + private ReachGesturePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new ReachGesturePreferenceController(mContext, KEY_REACH); + mController.setConfig(mAmbientDisplayConfiguration); + } + + @Test + public void testIsChecked_configIsSet_shouldReturnTrue() { + // Set the setting to be enabled. + when(mAmbientDisplayConfiguration.reachGestureEnabled(anyInt())).thenReturn(true); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void testIsChecked_configIsNotSet_shouldReturnFalse() { + // Set the setting to be disabled. + when(mAmbientDisplayConfiguration.reachGestureEnabled(anyInt())).thenReturn(false); + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void getAvailabilityStatus_gestureNotSupported_UNSUPPORTED_ON_DEVICE() { + when(mAmbientDisplayConfiguration.reachGestureAvailable()).thenReturn(false); + final int availabilityStatus = mController.getAvailabilityStatus(); + + assertThat(availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getAvailabilityStatus_gestureSupported_AVAILABLE() { + when(mAmbientDisplayConfiguration.reachGestureAvailable()).thenReturn(true); + final int availabilityStatus = mController.getAvailabilityStatus(); + + assertThat(availabilityStatus).isEqualTo(AVAILABLE); + } + + @Test + public void isSliceableCorrectKey_returnsTrue() { + final ReachGesturePreferenceController controller = + new ReachGesturePreferenceController(mContext, "gesture_reach"); + assertThat(controller.isSliceable()).isTrue(); + } + + @Test + public void isSliceableIncorrectKey_returnsFalse() { + final ReachGesturePreferenceController controller = + new ReachGesturePreferenceController(mContext, "bad_key"); + assertThat(controller.isSliceable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/gestures/ReachGestureSettingsTest.java b/tests/robotests/src/com/android/settings/gestures/ReachGestureSettingsTest.java new file mode 100644 index 00000000000..9371c71f968 --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/ReachGestureSettingsTest.java @@ -0,0 +1,51 @@ +/* + * 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.gestures; + +import static com.google.common.truth.Truth.assertThat; + +import android.provider.SearchIndexableResource; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ReachGestureSettingsTest { + + private ReachGestureSettings mSettings; + + @Before + public void setUp() { + mSettings = new ReachGestureSettings(); + } + + @Test + public void testSearchIndexProvider_shouldIndexResource() { + final List indexRes = + ReachGestureSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( + RuntimeEnvironment.application, true /* enabled */); + + assertThat(indexRes).isNotNull(); + assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId()); + } +} diff --git a/tests/robotests/src/com/android/settings/homepage/CardContentProviderTest.java b/tests/robotests/src/com/android/settings/homepage/CardContentProviderTest.java index bf1527a4a42..eec87b0286e 100644 --- a/tests/robotests/src/com/android/settings/homepage/CardContentProviderTest.java +++ b/tests/robotests/src/com/android/settings/homepage/CardContentProviderTest.java @@ -19,13 +19,19 @@ package com.android.settings.homepage; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowThreadUtils; import org.junit.After; import org.junit.Before; @@ -33,18 +39,23 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = ShadowThreadUtils.class) public class CardContentProviderTest { private Context mContext; private CardContentProvider mProvider; + private ContentResolver mResolver; private Uri mUri; @Before public void setUp() { mContext = RuntimeEnvironment.application; - mProvider = Robolectric.setupContentProvider(CardContentProvider.class); + mProvider = spy(Robolectric.setupContentProvider(CardContentProvider.class)); + mResolver = mContext.getContentResolver(); mUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CardContentProvider.CARD_AUTHORITY) @@ -54,6 +65,7 @@ public class CardContentProviderTest { @After public void cleanUp() { + ShadowThreadUtils.reset(); CardDatabaseHelper.getInstance(mContext).close(); CardDatabaseHelper.sCardDatabaseHelper = null; } @@ -61,7 +73,7 @@ public class CardContentProviderTest { @Test public void cardData_insert() { final int cnt_before_instert = getRowCount(); - mContext.getContentResolver().insert(mUri, insertOneRow()); + mResolver.insert(mUri, insertOneRow()); final int cnt_after_instert = getRowCount(); assertThat(cnt_after_instert - cnt_before_instert).isEqualTo(1); @@ -69,7 +81,7 @@ public class CardContentProviderTest { @Test public void cardData_query() { - mContext.getContentResolver().insert(mUri, insertOneRow()); + mResolver.insert(mUri, insertOneRow()); final int count = getRowCount(); assertThat(count).isGreaterThan(0); @@ -77,29 +89,27 @@ public class CardContentProviderTest { @Test public void cardData_delete() { - final ContentResolver contentResolver = mContext.getContentResolver(); - contentResolver.insert(mUri, insertOneRow()); - final int del_count = contentResolver.delete(mUri, null, null); + mResolver.insert(mUri, insertOneRow()); + final int del_count = mResolver.delete(mUri, null, null); assertThat(del_count).isGreaterThan(0); } @Test public void cardData_update() { - final ContentResolver contentResolver = mContext.getContentResolver(); - contentResolver.insert(mUri, insertOneRow()); + mResolver.insert(mUri, insertOneRow()); - final double updatingScore= 0.87; + final double updatingScore = 0.87; final ContentValues values = new ContentValues(); values.put(CardDatabaseHelper.CardColumns.SCORE, updatingScore); final String strWhere = CardDatabaseHelper.CardColumns.NAME + "=?"; final String[] selectionArgs = {"auto_rotate"}; - final int update_count = contentResolver.update(mUri, values, strWhere, selectionArgs); + final int update_count = mResolver.update(mUri, values, strWhere, selectionArgs); assertThat(update_count).isGreaterThan(0); final String[] columns = {CardDatabaseHelper.CardColumns.SCORE}; - final Cursor cr = contentResolver.query(mUri, columns, strWhere, selectionArgs, null); + final Cursor cr = mResolver.query(mUri, columns, strWhere, selectionArgs, null); cr.moveToFirst(); final double qryScore = cr.getDouble(0); @@ -107,6 +117,90 @@ public class CardContentProviderTest { assertThat(qryScore).isEqualTo(updatingScore); } + @Test + public void insert_isMainThread_shouldEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(true); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.insert(mUri, insertOneRow()); + + verify(mProvider).enableStrictMode(); + } + + @Test + public void query_isMainThread_shouldEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(true); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.query(mUri, null, null, null); + + verify(mProvider).enableStrictMode(); + } + + @Test + public void delete_isMainThread_shouldEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(true); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.delete(mUri, null, null); + + verify(mProvider).enableStrictMode(); + } + + @Test + public void update_isMainThread_shouldEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(true); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + final ContentValues values = new ContentValues(); + values.put(CardDatabaseHelper.CardColumns.SCORE, "0.01"); + + mProvider.update(mUri, values, null, null); + + verify(mProvider).enableStrictMode(); + } + + @Test + public void insert_notMainThread_shouldNotEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(false); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.insert(mUri, insertOneRow()); + + verify(mProvider, never()).enableStrictMode(); + } + + @Test + public void query_notMainThread_shouldNotEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(false); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.query(mUri, null, null, null); + + verify(mProvider, never()).enableStrictMode(); + } + + @Test + public void delete_notMainThread_shouldNotEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(false); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + + mProvider.delete(mUri, null, null); + + verify(mProvider, never()).enableStrictMode(); + } + + @Test + public void update_notMainThread_shouldNotEnableStrictMode() { + ShadowThreadUtils.setIsMainThread(false); + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", true); + final ContentValues values = new ContentValues(); + values.put(CardDatabaseHelper.CardColumns.SCORE, "0.01"); + + mProvider.update(mUri, values, null, null); + + verify(mProvider, never()).enableStrictMode(); + } + @Test(expected = UnsupportedOperationException.class) public void getType_shouldCrash() { mProvider.getType(null); @@ -138,10 +232,9 @@ public class CardContentProviderTest { } private int getRowCount() { - final ContentResolver contentResolver = mContext.getContentResolver(); - final Cursor cr = contentResolver.query(mUri, null, null, null); + final Cursor cr = mResolver.query(mUri, null, null, null); final int count = cr.getCount(); cr.close(); return count; } -} +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java index cffe9213fb4..c483b8ccc9a 100644 --- a/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/language/TtsPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.language; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -25,6 +26,9 @@ import android.content.Context; import android.speech.tts.TextToSpeech; import android.speech.tts.TtsEngines; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -38,9 +42,6 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - @RunWith(SettingsRobolectricTestRunner.class) public class TtsPreferenceControllerTest { @@ -58,7 +59,8 @@ public class TtsPreferenceControllerTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mController = new TtsPreferenceController(mContext, mTtsEngines); + mController = new TtsPreferenceController(mContext, "test_key"); + mController.mTtsEngines = mTtsEngines; mPreference = new Preference(RuntimeEnvironment.application); mPreference.setKey(mController.getPreferenceKey()); when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); diff --git a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java index df60654c1f0..0c507d9605d 100644 --- a/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/BaseSearchIndexProviderTest.java @@ -169,4 +169,24 @@ public class BaseSearchIndexProviderTest { assertThat(nonIndexableKeys).contains("status_header"); } + + @Test + @Config(qualifiers = "mcc999") + public void getNonIndexableKeys_hasSearchableAttributeInXml_shouldSuppressUnsearchable() { + final BaseSearchIndexProvider provider = new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.display_settings; + return Collections.singletonList(sir); + } + + }; + + final List nonIndexableKeys = + provider.getNonIndexableKeys(RuntimeEnvironment.application); + + assertThat(nonIndexableKeys).contains("pref_key_5"); + } } diff --git a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java index e76f43dd4b5..e3ef15e9174 100644 --- a/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java @@ -1,6 +1,7 @@ package com.android.settings.search; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -21,6 +22,9 @@ 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 SettingsSearchIndexablesProviderTest { @@ -96,16 +100,19 @@ public class SettingsSearchIndexablesProviderTest { @Test @Config(qualifiers = "mcc999") public void testNonIndexablesColumnFetched() { - Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" + + final Uri rawUri = Uri.parse("content://" + BASE_AUTHORITY + "/" + SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH); - final Cursor cursor = mProvider.query(rawUri, - SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null); + final List keys = new ArrayList<>(); - cursor.moveToFirst(); - assertThat(cursor.getCount()).isEqualTo(2); - assertThat(cursor.getString(0)).isEqualTo("pref_key_1"); - cursor.moveToNext(); - assertThat(cursor.getString(0)).isEqualTo("pref_key_3"); + try (Cursor cursor = mProvider.query(rawUri, + SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS, null, null, null)) { + while (cursor.moveToNext()) { + keys.add(cursor.getString(0)); + } + } + + assertThat(keys).hasSize(3); + assertThat(keys).containsAllOf("pref_key_1", "pref_key_3", "pref_key_5"); } } diff --git a/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java b/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java index 6e49f1e3949..9d26de2e6d3 100644 --- a/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java +++ b/tests/robotests/src/com/android/settings/security/EncryptionAndCredentialTest.java @@ -73,7 +73,7 @@ public class EncryptionAndCredentialTest { final List expectedKeys = new ArrayList<>(); for (SearchIndexableResource res : index) { expectedKeys.addAll(((BaseSearchIndexProvider) SEARCH_INDEX_DATA_PROVIDER) - .getNonIndexableKeysFromXml(mContext, res.xmlResId)); + .getNonIndexableKeysFromXml(mContext, res.xmlResId, true /* suppressAll */)); } final List keys = SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java index 955cdf107c6..6ccc5507267 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java @@ -168,6 +168,7 @@ public class SliceBroadcastReceiverTest { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(key) .build(); + verify(resolver).notifyChange(expectedUri, null); } diff --git a/tests/robotests/src/com/android/settings/slices/SliceRelayReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceRelayReceiverTest.java new file mode 100644 index 00000000000..3388a16f33f --- /dev/null +++ b/tests/robotests/src/com/android/settings/slices/SliceRelayReceiverTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.settings.slices; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.ContentResolver; +import android.content.Context; + +import android.content.Intent; +import android.net.Uri; +import android.provider.SettingsSlicesContract; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.SliceBroadcastRelay; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class SliceRelayReceiverTest { + + private Context mContext; + private SliceRelayReceiver mSliceRelayReceiver; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + mSliceRelayReceiver = new SliceRelayReceiver(); + } + + + @Test + public void onReceive_extraUri_notifiesChangeOnUri() { + // Monitor the ContentResolver + final ContentResolver resolver = spy(mContext.getContentResolver()); + doReturn(resolver).when(mContext).getContentResolver(); + + final Uri uri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath("path") + .build(); + + final Intent intent = new Intent(); + intent.putExtra(SliceBroadcastRelay.EXTRA_URI, uri.toString()); + + mSliceRelayReceiver.onReceive(mContext, intent); + + verify(resolver).notifyChange(eq(uri), any()); + + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java b/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java index 7e8493e0efe..6a96cf0cf59 100644 --- a/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/XmlTestUtils.java @@ -1,15 +1,16 @@ package com.android.settings.testutils; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag + .FLAG_INCLUDE_PREF_SCREEN; +import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY; + import android.content.Context; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; +import android.os.Bundle; import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Xml; import com.android.settings.core.PreferenceXmlParserUtils; -import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.util.ArrayList; @@ -25,30 +26,21 @@ public class XmlTestUtils { * on the screen. * * @param context of the preference screen. - * @param xmlId of the Preference Xml to be parsed. + * @param xmlId of the Preference Xml to be parsed. * @return List of all keys in the preference Xml */ public static List getKeysFromPreferenceXml(Context context, int xmlId) { - final XmlResourceParser parser = context.getResources().getXml(xmlId); - final AttributeSet attrs = Xml.asAttributeSet(parser); final List keys = new ArrayList<>(); - String key; try { - while (parser.next() != XmlPullParser.END_DOCUMENT) { - try { - key = PreferenceXmlParserUtils.getDataKey(context, attrs); - if (!TextUtils.isEmpty(key)) { - keys.add(key); - } - } catch (NullPointerException e) { - continue; - } catch (Resources.NotFoundException e) { - continue; + List metadata = PreferenceXmlParserUtils.extractMetadata(context, xmlId, + FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN); + for (Bundle bundle : metadata) { + final String key = bundle.getString(METADATA_KEY); + if (!TextUtils.isEmpty(key)) { + keys.add(key); } } - } catch (java.io.IOException e) { - return null; - } catch (XmlPullParserException e) { + } catch (java.io.IOException | XmlPullParserException e) { return null; } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCachedBluetoothDeviceManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCachedBluetoothDeviceManager.java new file mode 100644 index 00000000000..ee04c4f1d38 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCachedBluetoothDeviceManager.java @@ -0,0 +1,44 @@ +/* + * 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.testutils.shadow; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.Collection; + +/** + * Shadow class for {@link CachedBluetoothDeviceManager} to allow tests to manages the set of + * remote Bluetooth devices. + */ +@Implements(CachedBluetoothDeviceManager.class) +public class ShadowCachedBluetoothDeviceManager { + + private Collection mCachedDevices; + + public void setCachedDevicesCopy(Collection cachedDevices) { + mCachedDevices = cachedDevices; + } + + @Implementation + public synchronized Collection getCachedDevicesCopy() { + return mCachedDevices; + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java index c9c9abb7383..f7f0bce9bd4 100644 --- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java +++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSliceHelperTest.java @@ -64,6 +64,7 @@ import androidx.slice.SliceProvider; import androidx.slice.core.SliceAction; import androidx.slice.core.SliceQuery; import androidx.slice.widget.ListContent; +import androidx.slice.widget.SliceContent; import androidx.slice.widget.RowContent; import androidx.slice.widget.SliceLiveData; @@ -367,31 +368,27 @@ public class WifiCallingSliceHelperTest { // Get all the rows final ListContent listContent = new ListContent(mContext, slice); - final ArrayList rowItems = listContent.getRowItems(); + final ArrayList rowItems = listContent.getRowItems(); assertThat(rowItems.size()).isEqualTo(4 /* 4 items including header */); // First row is HEADER - SliceItem rowSliceItem = rowItems.get(0); - RowContent rowContent = new RowContent(mContext, rowSliceItem, true); + RowContent rowContent = (RowContent) rowItems.get(0); assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( R.string.wifi_calling_mode_title)); // next is WIFI_ONLY - rowSliceItem = rowItems.get(1); - rowContent = new RowContent(mContext, rowSliceItem, false); + rowContent = (RowContent) rowItems.get(1); assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( com.android.internal.R.string.wfc_mode_wifi_only_summary)); // next is WIFI_PREFERRED - rowSliceItem = rowItems.get(2); - rowContent = new RowContent(mContext, rowSliceItem, false); + rowContent = (RowContent) rowItems.get(2); assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( com.android.internal.R.string.wfc_mode_wifi_preferred_summary)); // next is CELLULAR_PREFERRED - rowSliceItem = rowItems.get(3); - rowContent = new RowContent(mContext, rowSliceItem, false); + rowContent = (RowContent) rowItems.get(3); assertThat(rowContent.getTitleItem().getText()).isEqualTo(mContext.getText( com.android.internal.R.string.wfc_mode_cellular_preferred_summary));