diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 8f07447cd80..0ebf8c001cb 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -18,41 +18,39 @@ package com.android.settings.slices; import static android.Manifest.permission.READ_SEARCH_INDEXABLES; -import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING; - -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.content.IntentFilter; +import android.content.Context; import android.net.Uri; -import android.net.wifi.WifiManager; -import android.provider.Settings; import android.provider.SettingsSlicesContract; import android.support.annotation.VisibleForTesting; import android.support.v4.graphics.drawable.IconCompat; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.util.Pair; -import androidx.slice.Slice; -import androidx.slice.SliceProvider; -import androidx.slice.builders.ListBuilder; -import androidx.slice.builders.SliceAction; - -import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.wifi.WifiSliceBuilder; +import com.android.settings.wifi.calling.WifiCallingSliceHelper; +import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.utils.ThreadUtils; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import androidx.slice.Slice; +import androidx.slice.SliceProvider; + /** * A {@link SliceProvider} for Settings to enabled inline results in system apps. * @@ -84,10 +82,6 @@ public class SettingsSliceProvider extends SliceProvider { */ public static final String SLICE_AUTHORITY = "com.android.settings.slices"; - public static final String PATH_WIFI = "wifi"; - public static final String ACTION_WIFI_CHANGED = - "com.android.settings.slice.action.WIFI_CHANGED"; - /** * Action passed for changes to Toggle Slices. */ @@ -121,6 +115,8 @@ public class SettingsSliceProvider extends SliceProvider { @VisibleForTesting Map mSliceDataCache; + final Set mRegisteredUris = new ArraySet<>(); + public SettingsSliceProvider() { super(READ_SEARCH_INDEXABLES); } @@ -146,28 +142,37 @@ public class SettingsSliceProvider extends SliceProvider { @Override public void onSlicePinned(Uri sliceUri) { + if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { + registerIntentToUri(WifiSliceBuilder.INTENT_FILTER , sliceUri); + // TODO (b/) Register IntentFilters for database entries. + mRegisteredUris.add(sliceUri); + return; + } + // Start warming the slice, we expect someone will want it soon. loadSliceInBackground(sliceUri); } @Override public void onSliceUnpinned(Uri sliceUri) { + if (mRegisteredUris.contains(sliceUri)) { + SliceBroadcastRelay.unregisterReceivers(getContext(), sliceUri); + mRegisteredUris.remove(sliceUri); + } mSliceDataCache.remove(sliceUri); } @Override public Slice onBindSlice(Uri sliceUri) { - String path = sliceUri.getPath(); // If adding a new Slice, do not directly match Slice URIs. // Use {@link SlicesDatabaseAccessor}. - switch (path) { - case "/" + PATH_WIFI: - return createWifiSlice(sliceUri); - case "/" + PATH_WIFI_CALLING: - return FeatureFactory.getFactory(getContext()) - .getSlicesFeatureProvider() - .getNewWifiCallingSliceHelper(getContext()) - .createWifiCallingSlice(sliceUri); + if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { + return FeatureFactory.getFactory(getContext()) + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(getContext()) + .createWifiCallingSlice(sliceUri); + } else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { + return WifiSliceBuilder.getSlice(getContext()); } SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri); @@ -223,11 +228,12 @@ public class SettingsSliceProvider extends SliceProvider { true /* isPlatformSlice */); final List oemKeys = mSlicesDatabaseAccessor.getSliceKeys( false /* isPlatformSlice */); - final List allUris = buildUrisFromKeys(platformKeys, - SettingsSlicesContract.AUTHORITY); - allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY)); + descendants.addAll(buildUrisFromKeys(platformKeys, SettingsSlicesContract.AUTHORITY)); + descendants.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY)); + descendants.addAll(getSpecialCaseUris(true /* isPlatformSlice */)); + descendants.addAll(getSpecialCaseUris(false /* isPlatformSlice */)); - return allUris; + return descendants; } // Path is anything but empty, "action", or "intent". Return empty list. @@ -242,7 +248,9 @@ public class SettingsSliceProvider extends SliceProvider { // 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); + descendants.addAll(buildUrisFromKeys(keys, authority)); + descendants.addAll(getSpecialCaseUris(isPlatformUri)); + return descendants; } private List buildUrisFromKeys(List keys, String authority) { @@ -295,55 +303,28 @@ public class SettingsSliceProvider extends SliceProvider { return new Slice.Builder(uri).build(); } - // TODO (b/70622039) remove this when the proper wifi slice is enabled. - private Slice createWifiSlice(Uri sliceUri) { - // Get wifi state - WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - int wifiState = wifiManager.getWifiState(); - boolean wifiEnabled = false; - String state; - switch (wifiState) { - case WifiManager.WIFI_STATE_DISABLED: - case WifiManager.WIFI_STATE_DISABLING: - state = getContext().getString(R.string.disconnected); - break; - case WifiManager.WIFI_STATE_ENABLED: - case WifiManager.WIFI_STATE_ENABLING: - state = wifiManager.getConnectionInfo().getSSID(); - wifiEnabled = true; - break; - case WifiManager.WIFI_STATE_UNKNOWN: - default: - state = ""; // just don't show anything? - break; + private List getSpecialCaseUris(boolean isPlatformUri) { + if (isPlatformUri) { + return getSpecialCasePlatformUris(); } - - boolean finalWifiEnabled = wifiEnabled; - return new ListBuilder(getContext(), sliceUri) - .setColor(R.color.material_blue_500) - .addRow(b -> b - .setTitle(getContext().getString(R.string.wifi_settings)) - .setTitleItem(Icon.createWithResource(getContext(), R.drawable.wifi_signal)) - .setSubtitle(state) - .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED), - null, finalWifiEnabled)) - .setPrimaryAction( - new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS), - (IconCompat) null, null))) - .build(); + return getSpecialCaseOemUris(); } - private PendingIntent getIntent(String action) { - Intent intent = new Intent(action); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0); - return pi; + private List getSpecialCasePlatformUris() { + return Arrays.asList(WifiSliceBuilder.WIFI_URI); } - private PendingIntent getBroadcastIntent(String action) { - Intent intent = new Intent(action); - intent.setClass(getContext(), SliceBroadcastReceiver.class); - return PendingIntent.getBroadcast(getContext(), 0, intent, - PendingIntent.FLAG_CANCEL_CURRENT); + private List getSpecialCaseOemUris() { + return new ArrayList<>(); + } + + @VisibleForTesting + /** + * Registers an IntentFilter in SysUI to notify changes to {@param sliceUri} when broadcasts to + * {@param intentFilter} happen. + */ + void registerIntentToUri(IntentFilter intentFilter, Uri sliceUri) { + SliceBroadcastRelay.registerReceiver(getContext(), sliceUri, SliceBroadcastReceiver.class, + intentFilter); } } diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index 04097340ed3..3e349ff9b7e 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -18,18 +18,16 @@ package com.android.settings.slices; import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED; -import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED; import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED; +import static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED; import android.app.slice.Slice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.net.wifi.WifiManager; -import android.os.Handler; import android.provider.SettingsSlicesContract; import android.text.TextUtils; import android.util.Log; @@ -40,6 +38,8 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SliderPreferenceController; import com.android.settings.core.TogglePreferenceController; 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. @@ -67,25 +67,21 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { final int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1); handleSliderAction(context, key, newPosition, isPlatformSlice); break; - case ACTION_WIFI_CHANGED: - WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - boolean newState = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, - wm.isWifiEnabled()); - wm.setWifiEnabled(newState); - // Wait a bit for wifi to update (TODO: is there a better way to do this?) - Handler h = new Handler(); - h.postDelayed(() -> { - Uri uri = SliceBuilderUtils.getUri(SettingsSliceProvider.PATH_WIFI, - false /* isPlatformSlice */); - context.getContentResolver().notifyChange(uri, null); - }, 1000); + case ACTION_WIFI_SLICE_CHANGED: + WifiSliceBuilder.handleUriChange(context, intent); break; case ACTION_WIFI_CALLING_CHANGED: FeatureFactory.getFactory(context) - .getSlicesFeatureProvider() - .getNewWifiCallingSliceHelper(context) - .handleWifiCallingChanged(intent); + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(context) + .handleWifiCallingChanged(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/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index d744fbd3924..feb7042552d 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -39,7 +39,6 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; -import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; @@ -47,6 +46,7 @@ import com.android.settings.core.SliderPreferenceController; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.DatabaseIndexingUtils; +import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.core.AbstractPreferenceController; import android.support.v4.graphics.drawable.IconCompat; @@ -54,6 +54,7 @@ import android.support.v4.graphics.drawable.IconCompat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import androidx.slice.Slice; import androidx.slice.builders.ListBuilder; @@ -345,7 +346,10 @@ public class SliceBuilderUtils { final String keywordString = data.getKeywords(); if (keywordString != null) { final String[] keywordArray = keywordString.split(","); - keywords.addAll(Arrays.asList(keywordArray)); + final List strippedKeywords = Arrays.stream(keywordArray) + .map(s -> s = s.trim()) + .collect(Collectors.toList()); + keywords.addAll(strippedKeywords); } return keywords; diff --git a/src/com/android/settings/wifi/WifiSliceBuilder.java b/src/com/android/settings/wifi/WifiSliceBuilder.java new file mode 100644 index 00000000000..2ebba67c8f5 --- /dev/null +++ b/src/com/android/settings/wifi/WifiSliceBuilder.java @@ -0,0 +1,178 @@ +/* + * 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.wifi; + +import static android.provider.SettingsSlicesContract.KEY_WIFI; + +import android.annotation.ColorInt; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; +import android.provider.SettingsSlicesContract; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.SubSettings; +import com.android.settings.Utils; +import com.android.settings.search.DatabaseIndexingUtils; +import com.android.settings.slices.SliceBroadcastReceiver; +import com.android.settings.slices.SliceBuilderUtils; + +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import android.support.v4.graphics.drawable.IconCompat; +import android.text.TextUtils; + +/** + * Utility class to build a Wifi Slice, and handle all associated actions. + */ +public class WifiSliceBuilder { + + /** + * Backing Uri for the Wifi Slice. + */ + public static final Uri WIFI_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath(KEY_WIFI) + .build(); + + /** + * Action notifying a change on the Wifi Slice. + */ + public static final String ACTION_WIFI_SLICE_CHANGED = + "com.android.settings.wifi.action.WIFI_CHANGED"; + + public static final IntentFilter INTENT_FILTER = new IntentFilter(); + + static { + INTENT_FILTER.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + INTENT_FILTER.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + } + + private WifiSliceBuilder() { + } + + /** + * Return a Wifi Slice bound to {@link #WIFI_URI}. + *

+ * Note that you should register a listener with {@link #registerIntentFilter(Context, Uri)} + * to get changes from Wifi. + */ + public static Slice getSlice(Context context) { + final boolean isWifiEnabled = isWifiEnabled(context); + final IconCompat icon = IconCompat.createWithResource(context, + R.drawable.ic_settings_wireless); + final String title = context.getString(R.string.wifi_settings); + final CharSequence summary = getSummary(context); + @ColorInt final int color = Utils.getColorAccent(context); + final PendingIntent toggleAction = getBroadcastIntent(context); + final PendingIntent primaryAction = getPrimaryAction(context); + final SliceAction primarySliceAction = new SliceAction(primaryAction, icon, title); + final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */, + isWifiEnabled); + + return new ListBuilder(context, WIFI_URI, ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(b -> b + .setTitle(title) + .setSubtitle(summary) + .addEndItem(toggleSliceAction) + .setPrimaryAction(primarySliceAction)) + .build(); + } + + /** + * Update the current wifi status to the boolean value keyed by + * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. + */ + public static void handleUriChange(Context context, Intent intent) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + final boolean newState = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, + wifiManager.isWifiEnabled()); + wifiManager.setWifiEnabled(newState); + // Do not notifyChange on Uri. The service takes longer to update the current value than it + // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay} + // handle it. + } + + private static boolean isWifiEnabled(Context context) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + + switch (wifiManager.getWifiState()) { + case WifiManager.WIFI_STATE_ENABLED: + case WifiManager.WIFI_STATE_ENABLING: + return true; + case WifiManager.WIFI_STATE_DISABLED: + case WifiManager.WIFI_STATE_DISABLING: + case WifiManager.WIFI_STATE_UNKNOWN: + default: + return false; + } + } + + private static CharSequence getSummary(Context context) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + + switch (wifiManager.getWifiState()) { + case WifiManager.WIFI_STATE_ENABLED: + final String ssid = WifiInfo.removeDoubleQuotes(wifiManager.getConnectionInfo() + .getSSID()); + if (TextUtils.equals(ssid, WifiSsid.NONE)) { + return context.getText(R.string.disconnected); + } + return ssid; + case WifiManager.WIFI_STATE_ENABLING: + return context.getText(R.string.disconnected); + case WifiManager.WIFI_STATE_DISABLED: + case WifiManager.WIFI_STATE_DISABLING: + return context.getText(R.string.switch_off_text); + case WifiManager.WIFI_STATE_UNKNOWN: + default: + return ""; + } + } + + private static PendingIntent getPrimaryAction(Context context) { + final String screenTitle = context.getText(R.string.wifi_settings).toString(); + final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build(); + final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, + WifiSettings.class.getName(), KEY_WIFI, screenTitle, + MetricsEvent.DIALOG_WIFI_AP_EDIT); + intent.setClassName(context.getPackageName(), SubSettings.class.getName()); + intent.setData(contentUri); + + return PendingIntent.getActivity(context, 0 /* requestCode */, + intent, 0 /* flags */); + } + + private static PendingIntent getBroadcastIntent(Context context) { + final Intent intent = new Intent(ACTION_WIFI_SLICE_CHANGED); + intent.setClass(context, SliceBroadcastReceiver.class); + return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + } +} diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java index 7213148e97f..a554e74352f 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java @@ -20,6 +20,7 @@ import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import android.app.PendingIntent; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -38,6 +39,7 @@ import androidx.slice.builders.SliceAction; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.slices.SettingsSliceProvider; import com.android.settings.slices.SliceBroadcastReceiver; import com.android.settings.slices.SliceBuilderUtils; @@ -76,16 +78,20 @@ public class WifiCallingSliceHelper { public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY = "android.settings.WIFI_CALLING_SETTINGS"; + /** + * Full {@link Uri} for the Wifi Calling Slice. + */ + public static final Uri WIFI_CALLING_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(PATH_WIFI_CALLING) + .build(); + /** * Timeout for querying wifi calling setting from ims manager. */ private static final int TIMEOUT_MILLIS = 2000; - /** - * Time for which data contained in the slice can remain fresh. - */ - private static final int SLICE_TTL_MILLIS = 60000; - protected SubscriptionManager mSubscriptionManager; private final Context mContext; @@ -182,7 +188,7 @@ public class WifiCallingSliceHelper { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); final String title = mContext.getString(R.string.wifi_calling_settings_title); - return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS) + return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setColor(R.color.material_blue_500) .addRow(b -> b .setTitle(title) @@ -260,7 +266,7 @@ public class WifiCallingSliceHelper { private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri, PendingIntent primaryActionIntent) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); - return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS) + return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setColor(R.color.material_blue_500) .addRow(b -> b .setTitle(title) diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index a0bd33aa6c8..60fb5f9c685 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -19,6 +19,7 @@ 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.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -31,6 +32,7 @@ import android.net.Uri; import android.os.StrictMode; import android.provider.SettingsSlicesContract; +import com.android.settings.wifi.WifiSliceBuilder; import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.FakeToggleController; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -45,6 +47,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import androidx.slice.Slice; @@ -70,6 +74,10 @@ public class SettingsSliceProviderTest { private SQLiteDatabase mDb; private SliceManager mManager; + private static final List SPECIAL_CASE_PLATFORM_URIS = Arrays.asList( + WifiSliceBuilder.WIFI_URI + ); + @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); @@ -114,7 +122,7 @@ public class SettingsSliceProviderTest { } @Test - public void testLoadSlice_doesntCacheWithoutPin() { + public void testLoadSlice_doesNotCacheWithoutPin() { insertSpecialCase(KEY); Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false); @@ -226,6 +234,7 @@ public class SettingsSliceProviderTest { .build(); final Collection descendants = mProvider.onGetSliceDescendants(uri); + descendants.removeAll(SPECIAL_CASE_PLATFORM_URIS); assertThat(descendants).isEmpty(); } @@ -293,16 +302,18 @@ public class SettingsSliceProviderTest { .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .build(); - final Uri expectedUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(key) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); } @Test @@ -313,16 +324,18 @@ public class SettingsSliceProviderTest { .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .build(); - final Uri expectedUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(key) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); } @Test @@ -334,22 +347,31 @@ public class SettingsSliceProviderTest { final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .build(); - final Uri expectedPlatformUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(platformKey) - .build(); - final Uri expectedOemUri = new Uri.Builder() + .build()); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(oemKey) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); + } + + @Test + public void bindSlice_wifiSlice_returnsWifiSlice() { + final Slice wifiSlice = mProvider.onBindSlice(WifiSliceBuilder.WIFI_URI); + + assertThat(wifiSlice.getUri()).isEqualTo(WifiSliceBuilder.WIFI_URI); } private void insertSpecialCase(String key) { diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java index 4c4b04081fa..f617aa95c8f 100644 --- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java +++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java @@ -35,6 +35,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import androidx.slice.Slice; import androidx.slice.SliceItem; @@ -211,7 +212,7 @@ public class SliceTester { assertKeywords(metadata, sliceData); } - private static void assertTitle(List sliceItems, String title) { + public static void assertTitle(List sliceItems, String title) { boolean hasTitle = false; for (SliceItem item : sliceItems) { List titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE, @@ -230,8 +231,9 @@ public class SliceTester { private static void assertKeywords(SliceMetadata metadata, SliceData data) { final List keywords = metadata.getSliceKeywords(); - final Set expectedKeywords = new HashSet<>( - Arrays.asList(data.getKeywords().split(","))); + final Set expectedKeywords = Arrays.stream(data.getKeywords().split(",")) + .map(s -> s = s.trim()) + .collect(Collectors.toSet()); expectedKeywords.add(data.getTitle()); expectedKeywords.add(data.getScreenTitle().toString()); assertThat(keywords).containsExactlyElementsIn(expectedKeywords); diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java new file mode 100644 index 00000000000..f1ac5545d30 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java @@ -0,0 +1,98 @@ +/* + * 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.wifi; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.wifi.WifiSliceBuilder; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.SliceTester; + +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.WifiManager; +import android.support.v4.graphics.drawable.IconCompat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.core.SliceAction; +import androidx.slice.widget.SliceLiveData; + +@RunWith(SettingsRobolectricTestRunner.class) +public class WifiSliceBuilderTest { + + private Context mContext; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + + // Prevent crash in SliceMetadata. + Resources resources = spy(mContext.getResources()); + doReturn(60).when(resources).getDimensionPixelSize(anyInt()); + doReturn(resources).when(mContext).getResources(); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + } + + @Test + public void getWifiSlice_correctData() { + final Slice wifiSlice = WifiSliceBuilder.getSlice(mContext); + final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice); + + + final List toggles = metadata.getToggles(); + assertThat(toggles).hasSize(1); + + final SliceAction primaryAction = metadata.getPrimaryAction(); + final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext, + R.drawable.ic_settings_wireless); + assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString()); + + final List sliceItems = wifiSlice.getItems(); + SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings)); + } + + @Test + public void handleUriChange_updatesWifi() { + final Intent intent = new Intent(WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + final WifiManager wifiManager = mContext.getSystemService(WifiManager.class); + + WifiSliceBuilder.handleUriChange(mContext, intent); + + assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED); + } +}