volumeControllers = new ArrayList<>();
+ volumeControllers.add(use(AlarmVolumePreferenceController.class));
+ volumeControllers.add(use(MediaVolumePreferenceController.class));
+ volumeControllers.add(use(RingVolumePreferenceController.class));
+ volumeControllers.add(use(NotificationVolumePreferenceController.class));
+
+ for (VolumeSeekBarPreferenceController controller : volumeControllers) {
+ controller.setCallback(mVolumeCallback);
+ getLifecycle().addObserver(controller);
+ }
}
// === Volumes ===
@@ -205,8 +211,6 @@ public class SoundSettings extends DashboardFragment {
new DialPadTonePreferenceController(context, fragment, lifecycle);
final ScreenLockSoundPreferenceController screenLockSoundPreferenceController =
new ScreenLockSoundPreferenceController(context, fragment, lifecycle);
- final ChargingSoundPreferenceController chargingSoundPreferenceController =
- new ChargingSoundPreferenceController(context, fragment, lifecycle);
final DockingSoundPreferenceController dockingSoundPreferenceController =
new DockingSoundPreferenceController(context, fragment, lifecycle);
final TouchSoundPreferenceController touchSoundPreferenceController =
@@ -222,7 +226,6 @@ public class SoundSettings extends DashboardFragment {
controllers.add(dialPadTonePreferenceController);
controllers.add(screenLockSoundPreferenceController);
- controllers.add(chargingSoundPreferenceController);
controllers.add(dockingSoundPreferenceController);
controllers.add(touchSoundPreferenceController);
controllers.add(vibrateOnTouchPreferenceController);
@@ -233,7 +236,6 @@ public class SoundSettings extends DashboardFragment {
"other_sounds_and_vibrations_category").setChildren(
Arrays.asList(dialPadTonePreferenceController,
screenLockSoundPreferenceController,
- chargingSoundPreferenceController,
dockingSoundPreferenceController,
touchSoundPreferenceController,
vibrateOnTouchPreferenceController,
diff --git a/src/com/android/settings/notification/VolumeSeekBarPreference.java b/src/com/android/settings/notification/VolumeSeekBarPreference.java
index 8a48e95c166..d7b5e521a50 100644
--- a/src/com/android/settings/notification/VolumeSeekBarPreference.java
+++ b/src/com/android/settings/notification/VolumeSeekBarPreference.java
@@ -196,8 +196,7 @@ public class VolumeSeekBarPreference extends SeekBarPreference {
if (mSuppressionTextView != null && mSeekBar != null) {
mSuppressionTextView.setText(mSuppressionText);
final boolean showSuppression = !TextUtils.isEmpty(mSuppressionText);
- mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.INVISIBLE);
- mSeekBar.setVisibility(showSuppression ? View.INVISIBLE : View.VISIBLE);
+ mSuppressionTextView.setVisibility(showSuppression ? View.VISIBLE : View.GONE);
}
}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 1a73ea760e5..ab2cb8213ea 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -18,19 +18,26 @@ package com.android.settings.slices;
import android.app.PendingIntent;
import android.app.slice.SliceManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.provider.SettingsSlicesContract;
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.drawable.IconCompat;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.settings.R;
import com.android.settingslib.utils.ThreadUtils;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -144,11 +151,90 @@ public class SettingsSliceProvider extends SliceProvider {
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
}
+ /**
+ * Get a list of all valid Uris based on the keys indexed in the Slices database.
+ *
+ * This will return a list of {@link Uri uris} depending on {@param uri}, following:
+ * 1. Authority & Full Path -> Only {@param uri}. It is only a prefix for itself.
+ * 2. Authority & No path -> A list of authority/action/$KEY$, where
+ * {@code $KEY$} is a list of all Slice-enabled keys for the authority.
+ * 3. Authority & action path -> A list of authority/action/$KEY$, where
+ * {@code $KEY$} is a list of all Slice-enabled keys for the authority.
+ * 4. Empty authority & path -> A list of Uris with all keys for both supported authorities.
+ * 5. Else -> Empty list.
+ *
+ * Note that the authority will stay consistent with {@param uri}, and the list of valid Slice
+ * keys depends on if the authority is {@link SettingsSlicesContract#AUTHORITY} or
+ * {@link #SLICE_AUTHORITY}.
+ *
+ * @param uri The uri to look for descendants under.
+ * @returns all valid Settings uris for which {@param uri} is a prefix.
+ */
+ @Override
+ public Collection onGetSliceDescendants(Uri uri) {
+ final List descendants = new ArrayList<>();
+ final Pair pathData = SliceBuilderUtils.getPathData(uri);
+
+ if (pathData != null) {
+ // Uri has a full path and will not have any descendants.
+ descendants.add(uri);
+ return descendants;
+ }
+
+ final String authority = uri.getAuthority();
+ final String pathPrefix = uri.getPath();
+ final boolean isPathEmpty = pathPrefix.isEmpty();
+
+ // No path nor authority. Return all possible Uris.
+ if (isPathEmpty && TextUtils.isEmpty(authority)) {
+ final List platformKeys = mSlicesDatabaseAccessor.getSliceKeys(
+ true /* isPlatformSlice */);
+ final List oemKeys = mSlicesDatabaseAccessor.getSliceKeys(
+ false /* isPlatformSlice */);
+ final List allUris = buildUrisFromKeys(platformKeys,
+ SettingsSlicesContract.AUTHORITY);
+ allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY));
+
+ return allUris;
+ }
+
+ // Path is anything but empty, "action", or "intent". Return empty list.
+ if (!isPathEmpty
+ && !TextUtils.equals(pathPrefix, "/" + SettingsSlicesContract.PATH_SETTING_ACTION)
+ && !TextUtils.equals(pathPrefix,
+ "/" + SettingsSlicesContract.PATH_SETTING_INTENT)) {
+ // Invalid path prefix, there are no valid Uri descendants.
+ return descendants;
+ }
+
+ // Can assume authority belongs to the provider. Return all Uris for the authority.
+ final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY);
+ final List keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri);
+ return buildUrisFromKeys(keys, authority);
+ }
+
+ private List buildUrisFromKeys(List keys, String authority) {
+ final List descendants = new ArrayList<>();
+
+ final Uri.Builder builder = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION);
+
+ final String newUriPathPrefix = SettingsSlicesContract.PATH_SETTING_ACTION + "/";
+ for (String key : keys) {
+ builder.path(newUriPathPrefix + key);
+ descendants.add(builder.build());
+ }
+
+ return descendants;
+ }
+
@VisibleForTesting
void loadSlice(Uri uri) {
long startBuildTime = System.currentTimeMillis();
- SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
+ final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
mSliceDataCache.put(uri, sliceData);
getContext().getContentResolver().notifyChange(uri, null /* content observer */);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 80b7519430a..d2a6d101052 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -54,16 +54,16 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final String key = intent.getStringExtra(EXTRA_SLICE_KEY);
- final boolean isPlatformDefined = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
+ final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
false /* default */);
switch (action) {
case ACTION_TOGGLE_CHANGED:
- handleToggleAction(context, key, isPlatformDefined);
+ handleToggleAction(context, key, isPlatformSlice);
break;
case ACTION_SLIDER_CHANGED:
int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
- handleSliderAction(context, key, newPosition);
+ handleSliderAction(context, key, newPosition, isPlatformSlice);
break;
case ACTION_WIFI_CHANGED:
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -95,6 +95,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
if (!controller.isAvailable()) {
Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
updateUri(context, key, isPlatformSlice);
+ return;
}
// TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
@@ -107,7 +108,8 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
updateUri(context, key, isPlatformSlice);
}
- private void handleSliderAction(Context context, String key, int newPosition) {
+ private void handleSliderAction(Context context, String key, int newPosition,
+ boolean isPlatformSlice) {
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException(
"No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY);
@@ -123,6 +125,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key);
}
+ if (!controller.isAvailable()) {
+ Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
+ updateUri(context, key, isPlatformSlice);
+ return;
+ }
+
final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
final int maxSteps = sliderController.getMaxSteps();
if (newPosition < 0 || newPosition > maxSteps) {
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index a2479a2da05..6674344d576 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -113,13 +113,13 @@ public class SliceBuilderUtils {
* - key
*
* Examples of valid paths are:
- * - intent/wifi
- * - intent/bluetooth
- * - action/wifi
- * - action/accessibility/servicename
+ * - /intent/wifi
+ * - /intent/bluetooth
+ * - /action/wifi
+ * - /action/accessibility/servicename
*
* @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
- * @return Pair whose first element {@code true} if the path is prepended with "action", and
+ * @return Pair whose first element {@code true} if the path is prepended with "intent", and
* second is a key.
*/
public static Pair getPathData(Uri uri) {
@@ -130,13 +130,13 @@ public class SliceBuilderUtils {
// Example: "/action/wifi" -> [{}, "action", "wifi"]
// "/action/longer/path" -> [{}, "action", "longer/path"]
if (split.length != 3) {
- throw new IllegalArgumentException("Uri (" + uri + ") has incomplete path: " + path);
+ return null;
}
- final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
+ final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
split[1]);
- return new Pair<>(isInline, split[2]);
+ return new Pair<>(isIntent, split[2]);
}
/**
@@ -215,8 +215,8 @@ public class SliceBuilderUtils {
static Intent getContentIntent(Context context, SliceData sliceData) {
final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
- sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
- 0 /* TODO */);
+ sliceData.getFragmentClassName(), sliceData.getKey(),
+ sliceData.getScreenTitle().toString(), 0 /* TODO */);
intent.setClassName(context.getPackageName(), SubSettings.class.getName());
intent.setData(contentUri);
return intent;
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
index c02b1135699..2caf6e6be17 100644
--- a/src/com/android/settings/slices/SliceData.java
+++ b/src/com/android/settings/slices/SliceData.java
@@ -57,7 +57,7 @@ public class SliceData {
private final String mSummary;
- private final String mScreenTitle;
+ private final CharSequence mScreenTitle;
private final int mIconResource;
@@ -84,7 +84,7 @@ public class SliceData {
return mSummary;
}
- public String getScreenTitle() {
+ public CharSequence getScreenTitle() {
return mScreenTitle;
}
@@ -146,7 +146,7 @@ public class SliceData {
private String mSummary;
- private String mScreenTitle;
+ private CharSequence mScreenTitle;
private int mIconResource;
@@ -175,7 +175,7 @@ public class SliceData {
return this;
}
- public Builder setScreenTitle(String screenTitle) {
+ public Builder setScreenTitle(CharSequence screenTitle) {
mScreenTitle = screenTitle;
return this;
}
diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java
index 7cf1994f9ed..27724bfddf5 100644
--- a/src/com/android/settings/slices/SliceDataConverter.java
+++ b/src/com/android/settings/slices/SliceDataConverter.java
@@ -23,7 +23,12 @@ import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFO
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
@@ -32,9 +37,14 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
+import android.view.accessibility.AccessibilityManager;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
@@ -46,10 +56,16 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
- * Converts {@link DashboardFragment} to {@link SliceData}.
+ * Converts all Slice sources into {@link SliceData}.
+ * This includes:
+ * - All {@link DashboardFragment DashboardFragments} indexed by settings search
+ * - Accessibility services
*/
class SliceDataConverter {
@@ -101,6 +117,8 @@ class SliceDataConverter {
mSliceData.addAll(providerSliceData);
}
+ final List a11ySliceData = getAccessibilitySliceData();
+ mSliceData.addAll(a11ySliceData);
return mSliceData;
}
@@ -208,4 +226,58 @@ class SliceDataConverter {
}
return xmlSliceData;
}
+
+ private List getAccessibilitySliceData() {
+ final List sliceData = new ArrayList<>();
+
+ final String accessibilityControllerClassName =
+ AccessibilitySlicePreferenceController.class.getName();
+ final String fragmentClassName = AccessibilitySettings.class.getName();
+ final CharSequence screenTitle = mContext.getText(R.string.accessibility_settings);
+
+ final SliceData.Builder sliceDataBuilder = new SliceData.Builder()
+ .setFragmentName(fragmentClassName)
+ .setScreenTitle(screenTitle)
+ .setPreferenceControllerClassName(accessibilityControllerClassName);
+
+ final Set a11yServiceNames = new HashSet<>();
+ Collections.addAll(a11yServiceNames, mContext.getResources()
+ .getStringArray(R.array.config_settings_slices_accessibility_components));
+ final List installedServices = getAccessibilityServiceInfoList();
+ final PackageManager packageManager = mContext.getPackageManager();
+
+ for (AccessibilityServiceInfo a11yServiceInfo : installedServices) {
+ final ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ final String packageName = serviceInfo.packageName;
+ final ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
+ final String flattenedName = componentName.flattenToString();
+
+ if (!a11yServiceNames.contains(flattenedName)) {
+ continue;
+ }
+
+ final String title = resolveInfo.loadLabel(packageManager).toString();
+ int iconResource = resolveInfo.getIconResource();
+ if (iconResource == 0) {
+ iconResource = R.mipmap.ic_accessibility_generic;
+ }
+
+ sliceDataBuilder.setKey(flattenedName)
+ .setTitle(title)
+ .setIcon(iconResource)
+ .setSliceType(SliceData.SliceType.SWITCH);
+
+ sliceData.add(sliceDataBuilder.build());
+ }
+
+ return sliceData;
+ }
+
+ @VisibleForTesting
+ List getAccessibilityServiceInfoList() {
+ final AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(
+ mContext);
+ return accessibilityManager.getInstalledAccessibilityServiceList();
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index 82b3506f739..432be36b77c 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -29,6 +29,9 @@ import android.util.Pair;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
+import java.util.ArrayList;
+import java.util.List;
+
import androidx.slice.Slice;
/**
@@ -51,10 +54,12 @@ public class SlicesDatabaseAccessor {
// Cursor value for boolean true
private final int TRUE = 1;
- Context mContext;
+ private final Context mContext;
+ private final SlicesDatabaseHelper mHelper;
public SlicesDatabaseAccessor(Context context) {
mContext = context;
+ mHelper = SlicesDatabaseHelper.getInstance(mContext);
}
/**
@@ -76,19 +81,47 @@ public class SlicesDatabaseAccessor {
*/
public SliceData getSliceDataFromKey(String key) {
Cursor cursor = getIndexedSliceData(key);
- return buildSliceData(cursor, null /* uri */, false /* isInlineOnly */);
+ return buildSliceData(cursor, null /* uri */, false /* isIntentOnly */);
+ }
+
+ /**
+ * @return a list of keys in the Slices database matching on {@param isPlatformSlice}.
+ */
+ public List getSliceKeys(boolean isPlatformSlice) {
+ final String whereClause;
+
+ if (isPlatformSlice) {
+ whereClause = IndexColumns.PLATFORM_SLICE + " = 1";
+ } else {
+ whereClause = IndexColumns.PLATFORM_SLICE + " = 0";
+ }
+
+ final SQLiteDatabase database = mHelper.getReadableDatabase();
+ final String[] columns = new String[]{IndexColumns.KEY};
+ final List keys = new ArrayList<>();
+
+ try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, whereClause,
+ null /* selection */, null /* groupBy */, null /* having */, null /* orderBy */)) {
+ if (!resultCursor.moveToFirst()) {
+ return keys;
+ }
+
+ do {
+ keys.add(resultCursor.getString(0 /* key index */));
+ } while (resultCursor.moveToNext());
+ }
+
+ return keys;
}
private Cursor getIndexedSliceData(String path) {
verifyIndexing();
final String whereClause = buildKeyMatchWhereClause();
- final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
- final SQLiteDatabase database = helper.getReadableDatabase();
+ final SQLiteDatabase database = mHelper.getReadableDatabase();
final String[] selection = new String[]{path};
-
- Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL, whereClause,
- selection, null /* groupBy */, null /* having */, null /* orderBy */);
+ final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL,
+ whereClause, selection, null /* groupBy */, null /* having */, null /* orderBy */);
int numResults = resultCursor.getCount();
@@ -111,7 +144,7 @@ public class SlicesDatabaseAccessor {
.toString();
}
- private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isInlineOnly) {
+ private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isIntentOnly) {
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
@@ -127,7 +160,7 @@ public class SlicesDatabaseAccessor {
int sliceType = cursor.getInt(
cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
- if (!isInlineOnly) {
+ if (isIntentOnly) {
sliceType = SliceData.SliceType.INTENT;
}
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index d7de7bc27a9..e2ab40d407d 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -104,7 +104,7 @@ class SlicesIndexer implements Runnable {
values.put(IndexColumns.KEY, dataRow.getKey());
values.put(IndexColumns.TITLE, dataRow.getTitle());
values.put(IndexColumns.SUMMARY, dataRow.getSummary());
- values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle());
+ values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle().toString());
values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
values.put(IndexColumns.CONTROLLER, dataRow.getPreferenceController());
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index 25a0518a3f2..28ad3f5f3d3 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -193,8 +193,12 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
+ protected boolean isStreamFromOutputDevice(int streamType, int device) {
+ return mAudioManager.getDevicesForStream(streamType) == device;
+ }
+
protected boolean isOngoingCallStatus() {
- int audioMode = mAudioManager.getMode();
+ final int audioMode = mAudioManager.getMode();
return audioMode == AudioManager.MODE_RINGTONE
|| audioMode == AudioManager.MODE_IN_CALL
|| audioMode == AudioManager.MODE_IN_COMMUNICATION;
diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
index b0b3dc503d6..2f21f1b0023 100644
--- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
+++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
@@ -16,6 +16,9 @@
package com.android.settings.sound;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.support.v7.preference.Preference;
@@ -76,7 +79,7 @@ public class HandsFreeProfileOutputPreferenceController extends
// Setup devices entries, select active connected device
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
- if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothScoOn()) {
+ if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_USB_HEADSET)) {
// If wired headset is plugged in and active, select to default device.
mSelectedIndex = getDefaultDeviceIndex();
}
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index 2e52f77b066..df07dc5fa68 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -16,12 +16,13 @@
package com.android.settings.sound;
-import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.AudioManager;
-import android.media.MediaRouter;
import android.support.v7.preference.Preference;
import com.android.internal.util.ArrayUtils;
@@ -49,8 +50,7 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
return;
}
- if (mAudioManager.isMusicActiveRemotely() || isCastDevice(mMediaRouter)) {
- // TODO(76455906): Workaround for cast mode, need a solid way to identify cast mode.
+ if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) {
// In cast mode, disable switch entry.
preference.setEnabled(false);
preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable));
@@ -91,7 +91,7 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
// Setup devices entries, select active connected device
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
- if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothA2dpOn()) {
+ if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_USB_HEADSET)) {
// If wired headset is plugged in and active, select to default device.
mSelectedIndex = getDefaultDeviceIndex();
}
@@ -106,11 +106,4 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
mProfileManager.getA2dpProfile().setActiveDevice(device);
}
}
-
- private static boolean isCastDevice(MediaRouter mediaRouter) {
- final MediaRouter.RouteInfo selected = mediaRouter.getSelectedRoute(
- ROUTE_TYPE_REMOTE_DISPLAY);
- return selected != null && selected.getPresentationDisplay() != null
- && selected.getPresentationDisplay().isValid();
- }
}
diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java
index a5bab1cd980..707da000f14 100644
--- a/src/com/android/settings/widget/ValidatedEditTextPreference.java
+++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java
@@ -74,7 +74,7 @@ public class ValidatedEditTextPreference extends CustomEditTextPreference {
editText.removeTextChangedListener(mTextWatcher);
if (mIsPassword) {
editText.setInputType(
- InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
editText.setMaxLines(1);
}
editText.addTextChangedListener(mTextWatcher);
diff --git a/src/com/android/settings/wifi/WifiNoInternetDialog.java b/src/com/android/settings/wifi/WifiNoInternetDialog.java
index 6b7b2db26be..b175665a943 100644
--- a/src/com/android/settings/wifi/WifiNoInternetDialog.java
+++ b/src/com/android/settings/wifi/WifiNoInternetDialog.java
@@ -25,6 +25,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -107,14 +108,15 @@ public final class WifiNoInternetDialog extends AlertActivity implements
mCM.registerNetworkCallback(request, mNetworkCallback);
final NetworkInfo ni = mCM.getNetworkInfo(mNetwork);
- if (ni == null || !ni.isConnectedOrConnecting()) {
+ final NetworkCapabilities nc = mCM.getNetworkCapabilities(mNetwork);
+ if (ni == null || !ni.isConnectedOrConnecting() || nc == null) {
Log.d(TAG, "Network " + mNetwork + " is not connected: " + ni);
finish();
return;
}
- mNetworkName = ni.getExtraInfo();
+ mNetworkName = nc.getSSID();
if (mNetworkName != null) {
- mNetworkName = mNetworkName.replaceAll("^\"|\"$", ""); // Remove double quotes
+ mNetworkName = WifiInfo.removeDoubleQuotes(mNetworkName);
}
createDialog();
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
index b38558c1aeb..5ba0583b6ab 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -55,6 +55,7 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
mPassword = generateRandomPassword();
}
((ValidatedEditTextPreference) mPreference).setValidator(this);
+ ((ValidatedEditTextPreference) mPreference).setIsPassword(true);
((ValidatedEditTextPreference) mPreference).setIsSummaryPassword(true);
updatePasswordDisplay((EditTextPreference) mPreference);
}
diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
index 5a0999739df..d2274e65faf 100644
--- a/tests/robotests/assets/grandfather_slice_controller_not_in_xml
+++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
@@ -1,2 +1,4 @@
com.android.settings.testutils.FakeToggleController
-com.android.settings.testutils.FakeSliderController
\ No newline at end of file
+com.android.settings.testutils.FakeSliderController
+com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
+com.android.settings.accessibility.AccessibilitySlicePreferenceController
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 39620d8e0a5..cecc9c59c59 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -62,4 +62,9 @@
false
false
true
+
+
+
+ - fake_package/fake_service
+
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
new file mode 100644
index 00000000000..fe6d1a3f5fd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowAccessibilityManager;
+import org.xmlpull.v1.XmlPullParserException;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AccessibilitySlicePreferenceControllerTest {
+
+ private final String PACKAGE_NAME = "com.android.settings.fake";
+ private final String CLASS_NAME = "com.android.settings.fake.classname";
+ private final String SERVICE_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
+
+ private Context mContext;
+
+ private AccessibilitySlicePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ Settings.Secure.putInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 1 /* on */);
+ Settings.Secure.putString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ SERVICE_NAME);
+
+ // Register the fake a11y Service
+ ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
+ RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
+ shadowAccessibilityManager.setInstalledAccessibilityServiceList(getFakeServiceList());
+
+ mController = new AccessibilitySlicePreferenceController(mContext, SERVICE_NAME);
+ }
+
+ @Test
+ public void getAvailability_availableService_returnsAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_unknownService_returnsUnsupported() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
+ }
+
+ @Test
+ public void setChecked_availableService_serviceIsEnabled() {
+ mController.setChecked(true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void setNotChecked_availableService_serviceIsDisabled() {
+ mController.setChecked(false);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_serviceEnabled_returnsTrue() {
+ AccessibilityUtils.setAccessibilityServiceState(mContext,
+ ComponentName.unflattenFromString(mController.getPreferenceKey()), true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isChecked_serviceNotEnabled_returnsFalse() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.isChecked()).isFalse();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void illegalServiceName_exceptionThrown() {
+ new AccessibilitySlicePreferenceController(mContext, "not_split_by_slash");
+ }
+
+ private List getFakeServiceList() {
+ final List infoList = new ArrayList<>();
+
+ final ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = PACKAGE_NAME;
+ serviceInfo.name = CLASS_NAME;
+
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+
+ try {
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
+ mContext);
+ ComponentName componentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ info.setComponentName(componentName);
+ infoList.add(info);
+ } catch (XmlPullParserException | IOException e) {
+
+ }
+
+ return infoList;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index 4a09b408b6e..a0e5ed873bb 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -297,7 +297,7 @@ public class DashboardFeatureProviderImplTest {
"content://com.android.settings/tile_icon");
mImpl.bindIcon(preference, tile);
- assertThat(tile.icon).isNotNull();
+ assertThat(preference.getIcon()).isNotNull();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/gestures/SwipeUpPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SwipeUpPreferenceControllerTest.java
index f9a6e9cfbc1..360609bd169 100644
--- a/tests/robotests/src/com/android/settings/gestures/SwipeUpPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/SwipeUpPreferenceControllerTest.java
@@ -17,12 +17,14 @@
package com.android.settings.gestures;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.UserManager;
@@ -38,7 +40,8 @@ import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.List;
@@ -47,15 +50,35 @@ import java.util.List;
public class SwipeUpPreferenceControllerTest {
private Context mContext;
+ private ShadowPackageManager mPackageManager;
private SwipeUpPreferenceController mController;
+
+ private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
private static final String KEY_SWIPE_UP = "gesture_swipe_up";
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
+ mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
mController = new SwipeUpPreferenceController(mContext, KEY_SWIPE_UP);
}
+ @Test
+ public void testIsGestureAvailable_matchingServiceExists_shouldReturnTrue() {
+ final ComponentName recentsComponentName = ComponentName.unflattenFromString(
+ mContext.getString(com.android.internal.R.string.config_recentsComponentName));
+ final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP)
+ .setPackage(recentsComponentName.getPackageName());
+ mPackageManager.addResolveInfoForIntent(quickStepIntent, new ResolveInfo());
+
+ assertThat(SwipeUpPreferenceController.isGestureAvailable(mContext)).isTrue();
+ }
+
+ @Test
+ public void testIsGestureAvailable_noMatchingServiceExists_shouldReturnFalse() {
+ assertThat(SwipeUpPreferenceController.isGestureAvailable(mContext)).isFalse();
+ }
+
@Test
public void testIsChecked_configIsSet_shouldReturnTrue() {
// Set the setting to be enabled.
diff --git a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
index f3315e5153a..1b34fd3f98b 100644
--- a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
+++ b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -115,6 +116,24 @@ public class ApnEditorTest {
mApnEditorUT.sNotSet = "Not Set";
}
+ @Test
+ public void testApnEditor_doesNotUseManagedQuery() {
+ mApnEditorUT.getApnDataFromUri(Mockito.mock(Uri.class));
+
+ verify(mActivity, never()).managedQuery(
+ any(Uri.class),
+ any(String[].class),
+ any(String.class),
+ any(String.class));
+
+ verify(mActivity, never()).managedQuery(
+ any(Uri.class),
+ any(String[].class),
+ any(String.class),
+ any(String[].class),
+ any(String.class));
+ }
+
@Test
public void testSetStringValue_valueChanged_shouldSetValue() {
// GIVEN an APN value which is different than the APN value in database
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index d54d16fc6a4..b5399eaa951 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -17,6 +17,8 @@
package com.android.settings.slices;
+import static android.content.ContentResolver.SCHEME_CONTENT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
@@ -41,6 +43,7 @@ import org.robolectric.RuntimeEnvironment;
import androidx.slice.Slice;
+import java.util.Collection;
import java.util.HashMap;
/**
@@ -114,7 +117,190 @@ public class SettingsSliceProviderTest {
assertThat(cachedData).isNull();
}
+ @Test
+ public void getDescendantUris_fullActionUri_returnsSelf() {
+ final Uri uri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(uri);
+ }
+
+ @Test
+ public void getDescendantUris_fullIntentUri_returnsSelf() {
+ final Uri uri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(uri);
+ }
+
+ @Test
+ public void getDescendantUris_wrongPath_returnsEmpty() {
+ final Uri uri = SliceBuilderUtils.getUri("invalid_path", true);
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_invalidPath_returnsEmpty() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath("invalid")
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
+ insertSpecialCase("oem_key", false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
+ insertSpecialCase("platform_key", true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ insertSpecialCase(key, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ insertSpecialCase(key, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_noAuthorityNorPath_returnsAllUris() {
+ final String platformKey = "platform_key";
+ final String oemKey = "oemKey";
+ insertSpecialCase(platformKey, true /* isPlatformSlice */);
+ insertSpecialCase(oemKey, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .build();
+ final Uri expectedPlatformUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(platformKey)
+ .build();
+ final Uri expectedOemUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(oemKey)
+ .build();
+
+ final Collection descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri);
+ }
+
private void insertSpecialCase(String key) {
+ insertSpecialCase(key, true);
+ }
+
+ private void insertSpecialCase(String key, boolean isPlatformSlice) {
ContentValues values = new ContentValues();
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, TITLE);
@@ -123,6 +309,8 @@ public class SettingsSliceProviderTest {
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, 1234);
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, "test");
+ values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
+ values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index 0cdb2f43d59..0b6e4b5bb32 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -18,17 +18,28 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.slice.Slice;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.provider.Settings;
+import android.provider.SettingsSlicesContract;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
@@ -36,6 +47,7 @@ import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeSliderController;
import com.android.settings.testutils.FakeToggleController;
+import com.android.settings.testutils.FakeUnavailablePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
@@ -65,7 +77,7 @@ public class SliceBroadcastReceiverTest {
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
mReceiver = new SliceBroadcastReceiver();
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
@@ -192,6 +204,77 @@ public class SliceBroadcastReceiverTest {
mReceiver.onReceive(mContext, intent);
}
+ @Test
+ public void toggleUpdate_unavailableUriNotified() {
+ // Monitor the ContentResolver
+ final ContentResolver resolver = spy(mContext.getContentResolver());
+ doReturn(resolver).when(mContext).getContentResolver();
+
+ // Disable Setting
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FakeToggleController.AVAILABILITY_KEY,
+ BasePreferenceController.DISABLED_UNSUPPORTED);
+
+ // Insert Fake Toggle into Database
+ final String key = "key";
+ mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
+ insertSpecialCase(FakeToggleController.class, key);
+
+ // Turn on toggle setting
+ final FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
+ fakeToggleController.setChecked(true);
+
+ // Build Action
+ final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
+ intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
+
+ // Trigger Slice change
+ mReceiver.onReceive(mContext, intent);
+
+ // Check the value is the same and the Uri has been notified.
+ assertThat(fakeToggleController.isChecked()).isTrue();
+ final Uri expectedUri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
+ verify(resolver).notifyChange(eq(expectedUri), eq(null));
+ }
+
+ @Test
+ public void sliderUpdate_unavailableUriNotified() {
+ // Monitor the ContentResolver
+ final ContentResolver resolver = spy(mContext.getContentResolver());
+ doReturn(resolver).when(mContext).getContentResolver();
+
+ // Disable Setting
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FakeSliderController.AVAILABILITY_KEY,
+ BasePreferenceController.DISABLED_UNSUPPORTED);
+
+ // Insert Fake Slider into Database
+ final String key = "key";
+ final int position = FakeSliderController.MAX_STEPS - 1;
+ final int oldPosition = FakeSliderController.MAX_STEPS;
+ mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
+ insertSpecialCase(FakeSliderController.class, key);
+
+ // Set slider setting
+ final FakeSliderController fakeSliderController = new FakeSliderController(mContext, key);
+ fakeSliderController.setSliderPosition(oldPosition);
+
+ // Build action
+ final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
+ intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
+ intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
+
+ // Trigger Slice change
+ mReceiver.onReceive(mContext, intent);
+
+ // Check position is the same and the Uri has been notified.
+ assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
+ final Uri expectedUri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
+ verify(resolver).notifyChange(eq(expectedUri), eq(null));
+ }
+
private void insertSpecialCase(String key) {
insertSpecialCase(fakeControllerName, key);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 59eb7ceceaf..96cf1dc0bbc 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -24,7 +24,6 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +39,7 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeSliderController;
import com.android.settings.testutils.FakeToggleController;
+import com.android.settings.testutils.FakeUnavailablePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.SliceTester;
@@ -277,7 +277,7 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isFalse();
+ assertThat(pathPair.first).isTrue();
assertThat(pathPair.second).isEqualTo(KEY);
}
@@ -291,18 +291,20 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY);
}
- @Test(expected = IllegalArgumentException.class)
+ @Test
public void getPathData_noKey_returnsNull() {
final Uri uri = new Uri.Builder()
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.build();
- SliceBuilderUtils.getPathData(uri);
+ final Pair pathPair = SliceBuilderUtils.getPathData(uri);
+
+ assertThat(pathPair).isNull();
}
@Test
@@ -316,7 +318,7 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY + "/" + KEY);
}
@@ -324,7 +326,7 @@ public class SliceBuilderUtilsTest {
public void testUnsupportedSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_UNSUPPORTED);
@@ -337,7 +339,7 @@ public class SliceBuilderUtilsTest {
public void testDisabledForUserSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_FOR_USER);
@@ -350,7 +352,7 @@ public class SliceBuilderUtilsTest {
public void testDisabledDependentSettingSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.INTENT);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -372,7 +374,7 @@ public class SliceBuilderUtilsTest {
public void testUnavailableUnknownSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.UNAVAILABLE_UNKNOWN);
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index 36c27548c13..adc7a96e7e1 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -17,8 +17,22 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
@@ -32,17 +46,29 @@ import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceDataConverterTest {
- private final String fakeKey = "key";
- private final String fakeTitle = "title";
- private final String fakeSummary = "summary";
- private final String fakeScreenTitle = "screen_title";
- private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
- private final String fakeControllerName = FakePreferenceController.class.getName();
+ private final String FAKE_KEY = "key";
+ private final String FAKE_TITLE = "title";
+ private final String FAKE_SUMMARY = "summary";
+ private final String FAKE_SCREEN_TITLE = "screen_title";
+ private final String FAKE_FRAGMENT_CLASSNAME = FakeIndexProvider.class.getName();
+ private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
+
+ private final String ACCESSIBILITY_FRAGMENT = AccessibilitySettings.class.getName();
+ private final String A11Y_CONTROLLER_NAME =
+ AccessibilitySlicePreferenceController.class.getName();
+ private final String FAKE_SERVICE_NAME = "fake_service";
+ private final String FAKE_ACCESSIBILITY_PACKAGE = "fake_package";
+ private final String FAKE_A11Y_SERVICE_NAME =
+ FAKE_ACCESSIBILITY_PACKAGE + "/" + FAKE_SERVICE_NAME;
+ private final int FAKE_ICON = 1234;
+
+ private Context mContext;
private SliceDataConverter mSliceDataConverter;
private SearchFeatureProvider mSearchFeatureProvider;
@@ -50,7 +76,8 @@ public class SliceDataConverterTest {
@Before
public void setUp() {
- mSliceDataConverter = new SliceDataConverter(RuntimeEnvironment.application);
+ mContext = RuntimeEnvironment.application;
+ mSliceDataConverter = spy(new SliceDataConverter(RuntimeEnvironment.application));
mSearchFeatureProvider = new SearchFeatureProviderImpl();
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
@@ -68,20 +95,64 @@ public class SliceDataConverterTest {
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues()
.add(FakeIndexProvider.class);
+ doReturn(getFakeService()).when(mSliceDataConverter).getAccessibilityServiceInfoList();
+
List sliceDataList = mSliceDataConverter.getSliceData();
- assertThat(sliceDataList).hasSize(1);
- SliceData fakeSlice = sliceDataList.get(0);
+ assertThat(sliceDataList).hasSize(2);
+ SliceData fakeSlice0 = sliceDataList.get(0);
+ SliceData fakeSlice1 = sliceDataList.get(1);
- assertThat(fakeSlice.getKey()).isEqualTo(fakeKey);
- assertThat(fakeSlice.getTitle()).isEqualTo(fakeTitle);
- assertThat(fakeSlice.getSummary()).isEqualTo(fakeSummary);
- assertThat(fakeSlice.getScreenTitle()).isEqualTo(fakeScreenTitle);
+ // Should not assume the order of the data list.
+ if (TextUtils.equals(fakeSlice0.getKey(), FAKE_KEY)) {
+ assertFakeSlice(fakeSlice0);
+ assertFakeA11ySlice(fakeSlice1);
+ } else {
+ assertFakeSlice(fakeSlice1);
+ assertFakeA11ySlice(fakeSlice0);
+ }
+ }
+
+ private void assertFakeSlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_KEY);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
assertThat(fakeSlice.getIconResource()).isNotNull();
assertThat(fakeSlice.getUri()).isNull();
- assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
- assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName);
- assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_CLASSNAME);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
+ assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
}
+
+ private void assertFakeA11ySlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_A11Y_SERVICE_NAME);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isNull();
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(
+ mContext.getString(R.string.accessibility_settings));
+ assertThat(fakeSlice.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(fakeSlice.getUri()).isNull();
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(ACCESSIBILITY_FRAGMENT);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(A11Y_CONTROLLER_NAME);
+ }
+
+ // This is fragile. Should be replaced by a proper fake Service if possible.
+ private List getFakeService() {
+ List serviceInfoList = new ArrayList<>();
+ AccessibilityServiceInfo serviceInfo = spy(new AccessibilityServiceInfo());
+
+ ResolveInfo resolveInfo = spy(new ResolveInfo());
+ resolveInfo.serviceInfo = new ServiceInfo();
+ resolveInfo.serviceInfo.name = FAKE_SERVICE_NAME;
+ resolveInfo.serviceInfo.packageName = FAKE_ACCESSIBILITY_PACKAGE;
+ doReturn(FAKE_TITLE).when(resolveInfo).loadLabel(any(PackageManager.class));
+ doReturn(FAKE_ICON).when(resolveInfo).getIconResource();
+
+ doReturn(resolveInfo).when(serviceInfo).getResolveInfo();
+ serviceInfoList.add(serviceInfo);
+
+ return serviceInfoList;
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index 77c9891da18..45ec06430b2 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -18,6 +18,7 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.spy;
import android.content.ContentValues;
@@ -35,15 +36,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
+import java.util.List;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class SlicesDatabaseAccessorTest {
- private final String fakeTitle = "title";
- private final String fakeSummary = "summary";
- private final String fakeScreenTitle = "screen_title";
- private final int fakeIcon = 1234;
- private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
- private final String fakeControllerName = FakePreferenceController.class.getName();
+ private final String FAKE_TITLE = "title";
+ private final String FAKE_SUMMARY = "summary";
+ private final String FAKE_SCREEN_TITLE = "screen_title";
+ private final int FAKE_ICON = 1234;
+ private final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName();
+ private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
private Context mContext;
private SQLiteDatabase mDb;
@@ -70,13 +73,13 @@ public class SlicesDatabaseAccessorTest {
SliceData data = mAccessor.getSliceDataFromKey(key);
assertThat(data.getKey()).isEqualTo(key);
- assertThat(data.getTitle()).isEqualTo(fakeTitle);
- assertThat(data.getSummary()).isEqualTo(fakeSummary);
- assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
- assertThat(data.getIconResource()).isEqualTo(fakeIcon);
- assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
+ assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isNull();
- assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
+ assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
}
@Test(expected = IllegalStateException.class)
@@ -96,13 +99,13 @@ public class SlicesDatabaseAccessorTest {
SliceData data = mAccessor.getSliceDataFromUri(uri);
assertThat(data.getKey()).isEqualTo(key);
- assertThat(data.getTitle()).isEqualTo(fakeTitle);
- assertThat(data.getSummary()).isEqualTo(fakeSummary);
- assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
- assertThat(data.getIconResource()).isEqualTo(fakeIcon);
- assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
+ assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isEqualTo(uri);
- assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
+ assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
}
@Test(expected = IllegalStateException.class)
@@ -111,15 +114,62 @@ public class SlicesDatabaseAccessorTest {
mAccessor.getSliceDataFromUri(uri);
}
+ @Test
+ public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
+ final String key = "oem_key";
+ final boolean isPlatformSlice = false;
+ insertSpecialCase(key, isPlatformSlice);
+ final List keys = mAccessor.getSliceKeys(!isPlatformSlice);
+
+ assertThat(keys).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
+ final String key = "platform_key";
+ final boolean isPlatformSlice = true;
+ insertSpecialCase(key, isPlatformSlice);
+ final List keys = mAccessor.getSliceKeys(!isPlatformSlice);
+
+ assertThat(keys).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ final boolean isPlatformSlice = false;
+ insertSpecialCase(key, isPlatformSlice);
+ final List keys = mAccessor.getSliceKeys(isPlatformSlice);
+
+ assertThat(keys).containsExactly(key);
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ final boolean isPlatformSlice = true;
+ insertSpecialCase(key, isPlatformSlice);
+ final List keys = mAccessor.getSliceKeys(isPlatformSlice);
+
+ assertThat(keys).containsExactly(key);
+ }
+
private void insertSpecialCase(String key) {
+ insertSpecialCase(key, true);
+ }
+
+ private void insertSpecialCase(String key, boolean isPlatformSlice) {
ContentValues values = new ContentValues();
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
- values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
- values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
- values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
- values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
- values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
- values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
+ values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
+ values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY);
+ values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE);
+ values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON);
+ values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME);
+ values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME);
+ values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
+ values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
+
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
}
diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
index c6c4b451c23..f3f1c835787 100644
--- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
@@ -17,6 +17,8 @@
package com.android.settings.sound;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -205,10 +207,9 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
* Preference summary should be "This device"
*/
@Test
- public void hapBtDevicesAreAvailableButWiredHeadsetIsActivated_shouldSetDefaultSummary() {
+ public void updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
- mShadowAudioManager.setWiredHeadsetOn(true);
- mShadowAudioManager.setBluetoothScoOn(false);
+ mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
when(mHeadsetProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
when(mHeadsetProfile.getActiveDevice()).thenReturn(
mBluetoothDevice); // BT device is still activated in this case
@@ -226,7 +227,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
* Preference summary should be "This device"
*/
@Test
- public void noAvailableHeadsetBtDevices_preferenceEnableIsFalse_shouldSetDefaultSummary() {
+ public void updateState_noAvailableHeadsetBtDevices_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
List emptyDeviceList = new ArrayList<>();
when(mHeadsetProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index 2b15b8e0145..1c7c1c4c7b6 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -17,6 +17,9 @@
package com.android.settings.sound;
+import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -196,7 +199,7 @@ public class MediaOutputPreferenceControllerTest {
*/
@Test
public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
- mShadowAudioManager.setMusicActiveRemotely(true);
+ mShadowAudioManager.setStream(DEVICE_OUT_REMOTE_SUBMIX);
mController.updateState(mPreference);
@@ -256,8 +259,7 @@ public class MediaOutputPreferenceControllerTest {
@Test
public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_NORMAL);
- mShadowAudioManager.setWiredHeadsetOn(true);
- mShadowAudioManager.setBluetoothA2dpOn(false);
+ mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
when(mA2dpProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
when(mA2dpProfile.getActiveDevice()).thenReturn(
mBluetoothDevice); // BT device is still activated in this case
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
index f4f91ed2382..530bdee97f3 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
@@ -19,13 +19,14 @@ package com.android.settings.testutils;
import android.content.Context;
import android.provider.Settings;
-import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SliderPreferenceController;
public class FakeSliderController extends SliderPreferenceController {
private final String settingKey = "fake_slider_key";
+ public static final String AVAILABILITY_KEY = "fake_slider_availability_key";
+
public static final int MAX_STEPS = 9;
public FakeSliderController(Context context, String key) {
@@ -49,6 +50,7 @@ public class FakeSliderController extends SliderPreferenceController {
@Override
public int getAvailabilityStatus() {
- return BasePreferenceController.AVAILABLE;
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ AVAILABILITY_KEY, AVAILABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
index c984c6ceca4..d0ce76fe60a 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
@@ -26,6 +26,8 @@ public class FakeToggleController extends TogglePreferenceController {
private String settingKey = "toggle_key";
+ public static final String AVAILABILITY_KEY = "fake_toggle_availability_key";
+
private final int ON = 1;
private final int OFF = 0;
@@ -47,6 +49,7 @@ public class FakeToggleController extends TogglePreferenceController {
@Override
public int getAvailabilityStatus() {
- return AVAILABLE;
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ AVAILABILITY_KEY, AVAILABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
similarity index 82%
rename from tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java
rename to tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
index a7e5d7562aa..1ceaad864e1 100644
--- a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
@@ -1,4 +1,4 @@
-package com.android.settings.slices;
+package com.android.settings.testutils;
import android.content.Context;
import android.provider.Settings;
@@ -15,7 +15,7 @@ public class FakeUnavailablePreferenceController extends BasePreferenceControlle
@Override
public int getAvailabilityStatus() {
- return Settings.System.getInt(mContext.getContentResolver(),
+ return Settings.Global.getInt(mContext.getContentResolver(),
AVAILABILITY_KEY, 0);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
index 6817648f09b..0de2156ce38 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
@@ -16,6 +16,15 @@
package com.android.settings.testutils.shadow;
+import static android.media.AudioManager.STREAM_ACCESSIBILITY;
+import static android.media.AudioManager.STREAM_ALARM;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioManager.STREAM_NOTIFICATION;
+import static android.media.AudioManager.STREAM_RING;
+import static android.media.AudioManager.STREAM_SYSTEM;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.AudioManager.STREAM_DTMF;
+
import static org.robolectric.RuntimeEnvironment.application;
import android.media.AudioDeviceCallback;
@@ -32,6 +41,7 @@ import java.util.ArrayList;
@Implements(value = AudioManager.class, inheritImplementationMethods = true)
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
private int mRingerMode;
+ private int mStream;
private boolean mMusicActiveRemotely = false;
private ArrayList mDeviceCallbacks = new ArrayList();
@@ -48,10 +58,12 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
mRingerMode = mode;
}
+ @Implementation
public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) {
mDeviceCallbacks.add(callback);
}
+ @Implementation
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
if (mDeviceCallbacks.contains(callback)) {
mDeviceCallbacks.remove(callback);
@@ -62,10 +74,32 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
mMusicActiveRemotely = flag;
}
+ @Implementation
public boolean isMusicActiveRemotely() {
return mMusicActiveRemotely;
}
+ public void setStream(int stream) {
+ mStream = stream;
+ }
+
+ @Implementation
+ public int getDevicesForStream(int streamType) {
+ switch (streamType) {
+ case STREAM_VOICE_CALL:
+ case STREAM_SYSTEM:
+ case STREAM_RING:
+ case STREAM_MUSIC:
+ case STREAM_ALARM:
+ case STREAM_NOTIFICATION:
+ case STREAM_DTMF:
+ case STREAM_ACCESSIBILITY:
+ return mStream;
+ default:
+ return 0;
+ }
+ }
+
@Resetter
public void reset() {
mDeviceCallbacks.clear();
diff --git a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
index 5ba9f8abe58..865422c9354 100644
--- a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
@@ -116,7 +116,7 @@ public class ValidatedEditTextPreferenceTest {
mPreference.onBindDialogView(mView);
assertThat(editText.getInputType()
- & (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT))
+ & (InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_CLASS_TEXT))
.isNotEqualTo(0);
}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
index 60faa2e0702..7e757ad5f84 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
@@ -145,4 +145,21 @@ public class WifiTetherPasswordPreferenceControllerTest {
assertThat(mController.getSecuritySettingForPassword())
.isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
}
+
+ @Test
+ public void updateDisplay_shouldSetInputType() {
+ // Set controller password to anything and verify is set.
+ mController.displayPreference(mScreen);
+ mController.onPreferenceChange(mPreference, "1");
+ assertThat(mController.getPassword()).isEqualTo("1");
+
+ // Create a new config using different password
+ final WifiConfiguration config = new WifiConfiguration();
+ config.preSharedKey = "test_1234";
+ when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+ // Call updateDisplay and verify it's changed.
+ mController.updateDisplay();
+ assertThat(mPreference.isPassword()).isTrue();
+ }
}