From 0db4ead2b3c7cbc38b81f3f7d5f70ad6e1aa5119 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 17 Dec 2018 13:22:42 -0800 Subject: [PATCH] Hide wifi card sometimes. When there is a connected wifi, we now hide the wifi slice card. However, if we initially shows this card but later wifi is connected while the card is visible, we keep showing this card to avoid janky animation. The card will be gone if user nagivates to a different UI and comes back. - Create a new slice ContextualWifiSlice for homepage use case, all special logic for homepage are added here. - Change reference for WIFI_SLICE to CONTEXTUAL_WIFI_SLICE where make sense. Change-Id: Ibd87f88058f357aabef0f7d68a5bf48350d75b06 Fixes: 121040746 Test: robotests --- .../contextualcards/ContextualCardLoader.java | 4 +- .../SettingsContextualCardProvider.java | 4 +- .../settings/slices/CustomSliceManager.java | 4 +- .../settings/slices/CustomSliceRegistry.java | 12 ++ .../settings/wifi/WifiDialogActivity.java | 5 +- .../wifi/slice/ContextualWifiSlice.java | 61 +++++++++++ .../settings/wifi/{ => slice}/WifiSlice.java | 19 +++- .../ContextualCardLoaderTest.java | 2 +- .../SettingsContextualCardProviderTest.java | 5 +- .../slices/SettingsSliceProviderTest.java | 2 +- .../wifi/slice/ContextualWifiSliceTest.java | 103 ++++++++++++++++++ .../wifi/{ => slice}/WifiSliceTest.java | 6 +- 12 files changed, 207 insertions(+), 20 deletions(-) create mode 100644 src/com/android/settings/wifi/slice/ContextualWifiSlice.java rename src/com/android/settings/wifi/{ => slice}/WifiSlice.java (95%) create mode 100644 tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java rename tests/robotests/src/com/android/settings/wifi/{ => slice}/WifiSliceTest.java (96%) diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java index 71b262de7d7..6d4bd205190 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java @@ -21,7 +21,7 @@ import static android.app.slice.Slice.HINT_ERROR; import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS; import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI; -import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI; +import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -204,7 +204,7 @@ public class ContextualCardLoader extends AsyncLoaderCompat } private boolean isLargeCard(ContextualCard card) { - return card.getSliceUri().equals(WIFI_SLICE_URI) + return card.getSliceUri().equals(CONTEXTUAL_WIFI_SLICE_URI) || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI); } diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java index d5500fb37e3..57970433150 100644 --- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java +++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java @@ -34,8 +34,8 @@ public class SettingsContextualCardProvider extends ContextualCardProvider { public ContextualCardList getContextualCards() { final ContextualCard wifiCard = ContextualCard.newBuilder() - .setSliceUri(CustomSliceRegistry.WIFI_SLICE_URI.toString()) - .setCardName(CustomSliceRegistry.WIFI_SLICE_URI.toString()) + .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()) + .setCardName(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString()) .setCardCategory(ContextualCard.Category.IMPORTANT) .build(); final ContextualCard connectedDeviceCard = diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java index 4a9de15d841..bb47df28622 100644 --- a/src/com/android/settings/slices/CustomSliceManager.java +++ b/src/com/android/settings/slices/CustomSliceManager.java @@ -32,7 +32,8 @@ import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice; import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice; import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; import com.android.settings.location.LocationSlice; -import com.android.settings.wifi.WifiSlice; +import com.android.settings.wifi.slice.ContextualWifiSlice; +import com.android.settings.wifi.slice.WifiSlice; import java.util.Map; import java.util.WeakHashMap; @@ -107,6 +108,7 @@ public class CustomSliceManager { mUriMap.put(CustomSliceRegistry.BATTERY_FIX_SLICE_URI, BatteryFixSlice.class); mUriMap.put(CustomSliceRegistry.BATTERY_INFO_SLICE_URI, BatterySlice.class); mUriMap.put(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class); + mUriMap.put(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class); mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class); mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class); mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class); diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 1b8cffef509..bdf8b35ebda 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -80,6 +80,17 @@ public class CustomSliceRegistry { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("bluetooth_devices") .build(); + + /** + * Backing Uri for the Wifi Slice. + */ + public static final Uri CONTEXTUAL_WIFI_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("contextual_wifi") + .build(); + /** * Backing Uri for the Data usage Slice. */ @@ -216,6 +227,7 @@ public class CustomSliceRegistry { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(KEY_WIFI) .build(); + /** * Backing Uri for the Zen Mode Slice. */ diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java index 9ef6a39a028..c32bcf3d0c6 100644 --- a/src/com/android/settings/wifi/WifiDialogActivity.java +++ b/src/com/android/settings/wifi/WifiDialogActivity.java @@ -38,6 +38,8 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo private static final String TAG = "WifiDialogActivity"; + public static final String KEY_ACCESS_POINT_STATE = "access_point_state"; + /** * Boolean extra indicating whether this activity should connect to an access point on the * caller's behalf. If this is set to false, the caller should check @@ -46,9 +48,8 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo */ @VisibleForTesting static final String KEY_CONNECT_FOR_CALLER = "connect_for_caller"; - static final String KEY_ACCESS_POINT_STATE = "access_point_state"; - private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; + private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; private static final int RESULT_CONNECTED = RESULT_FIRST_USER; private static final int RESULT_FORGET = RESULT_FIRST_USER + 1; diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java new file mode 100644 index 00000000000..fa8c2678e29 --- /dev/null +++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java @@ -0,0 +1,61 @@ +/* + * 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.slice; + +import android.content.Context; +import android.net.Uri; +import android.net.wifi.WifiSsid; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.slice.Slice; + +import com.android.settings.slices.CustomSliceRegistry; +import com.android.settings.slices.CustomSliceable; + +/** + * {@link CustomSliceable} for Wi-Fi, used by contextual homepage. + */ +public class ContextualWifiSlice extends WifiSlice { + + private static final String TAG = "ContextualWifiSlice"; + @VisibleForTesting + boolean mPreviouslyDisplayed; + + public ContextualWifiSlice(Context context) { + super(context); + } + + @Override + public Uri getUri() { + return CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI; + } + + @Override + public Slice getSlice() { + if (!mPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) { + Log.d(TAG, "Wifi is connected, no point showing any suggestion."); + return null; + } + // Set mPreviouslyDisplayed to true - we will show *something* on the screen. So we should + // keep showing this card to keep UI stable, even if wifi connects to a network later. + mPreviouslyDisplayed = true; + + return super.getSlice(); + } +} diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java similarity index 95% rename from src/com/android/settings/wifi/WifiSlice.java rename to src/com/android/settings/wifi/slice/WifiSlice.java index 9f05783421f..4d3a95ad217 100644 --- a/src/com/android/settings/wifi/WifiSlice.java +++ b/src/com/android/settings/wifi/slice/WifiSlice.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.wifi; +package com.android.settings.wifi.slice; import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import static android.provider.SettingsSlicesContract.KEY_WIFI; @@ -46,6 +46,8 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.slices.CustomSliceable; import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBuilderUtils; +import com.android.settings.wifi.WifiDialogActivity; +import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.details.WifiNetworkDetailsFragment; import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.wifi.WifiTracker; @@ -54,15 +56,15 @@ import java.util.ArrayList; import java.util.List; /** - * Utility class to build a Wifi Slice, and handle all associated actions. + * {@link CustomSliceable} for Wi-Fi, used by generic clients. */ public class WifiSlice implements CustomSliceable { @VisibleForTesting static final int DEFAULT_EXPANDED_ROW_COUNT = 3; + protected final WifiManager mWifiManager; private final Context mContext; - private final WifiManager mWifiManager; public WifiSlice(Context context) { mContext = context; @@ -77,6 +79,7 @@ public class WifiSlice implements CustomSliceable { @Override public Slice getSlice() { final boolean isWifiEnabled = isWifiEnabled(); + final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_wireless); final String title = mContext.getString(R.string.wifi_settings); @@ -208,6 +211,13 @@ public class WifiSlice implements CustomSliceable { return intent; } + protected String getActiveSSID() { + if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) { + return WifiSsid.NONE; + } + return WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo().getSSID()); + } + private boolean isWifiEnabled() { switch (mWifiManager.getWifiState()) { case WifiManager.WIFI_STATE_ENABLED: @@ -221,8 +231,7 @@ public class WifiSlice implements CustomSliceable { private CharSequence getSummary() { switch (mWifiManager.getWifiState()) { case WifiManager.WIFI_STATE_ENABLED: - final String ssid = WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo() - .getSSID()); + final String ssid = getActiveSSID(); if (TextUtils.equals(ssid, WifiSsid.NONE)) { return mContext.getText(R.string.disconnected); } diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java index 101ca75ec2d..c62a6bbbfdb 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java @@ -145,7 +145,7 @@ public class ContextualCardLoaderTest { cards.add(new ContextualCard.Builder() .setName("test_wifi") .setCardType(ContextualCard.CardType.SLICE) - .setSliceUri(CustomSliceRegistry.WIFI_SLICE_URI) + .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI) .build()); cards.add(new ContextualCard.Builder() .setName("test_flashlight") diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java index 8f36ea59652..d4b67f51ef1 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java @@ -70,11 +70,12 @@ public class SettingsContextualCardProviderTest { } @Test - public void getContextualCards_wifiSlice_shouldGetCorrectCategory() { + public void getContextualCards_wifiSlice_shouldGetImportantCategory() { final ContextualCardList cards = mProvider.getContextualCards(); ContextualCard wifiCard = null; for (ContextualCard card : cards.getCardList()) { - if (card.getSliceUri().equals(CustomSliceRegistry.WIFI_SLICE_URI.toString())) { + if (card.getSliceUri().equals( + CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString())) { wifiCard = card; } } diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index b1292677898..7eae3e4ad1a 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -55,7 +55,7 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowThreadUtils; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUtils; -import com.android.settings.wifi.WifiSlice; +import com.android.settings.wifi.slice.WifiSlice; import com.android.settingslib.wifi.WifiTracker; import org.junit.After; diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java new file mode 100644 index 00000000000..bf5fba83cc0 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java @@ -0,0 +1,103 @@ +/* + * 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.slice; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +import android.content.ContentResolver; +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; + +import androidx.core.graphics.drawable.IconCompat; +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; + +import com.android.settings.R; +import com.android.settings.testutils.SliceTester; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class ContextualWifiSliceTest { + + private Context mContext; + private ContentResolver mResolver; + private WifiManager mWifiManager; + private ContextualWifiSlice mWifiSlice; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + mResolver = mock(ContentResolver.class); + doReturn(mResolver).when(mContext).getContentResolver(); + mWifiManager = mContext.getSystemService(WifiManager.class); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + mWifiManager.setWifiEnabled(true); + + mWifiSlice = new ContextualWifiSlice(mContext); + } + + @Test + public void getWifiSlice_hasActiveConnection_shouldReturnNull() { + final WifiConfiguration config = new WifiConfiguration(); + config.SSID = "123"; + mWifiManager.connect(config, null /* listener */); + + final Slice wifiSlice = mWifiSlice.getSlice(); + + assertThat(wifiSlice).isNull(); + } + + @Test + public void getWifiSlice_previousDisplayed_hasActiveConnection_shouldHaveTitleAndToggle() { + mWifiSlice.mPreviouslyDisplayed = true; + final WifiConfiguration config = new WifiConfiguration(); + config.SSID = "123"; + mWifiManager.connect(config, null /* listener */); + + final Slice wifiSlice = mWifiSlice.getSlice(); + 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)); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java similarity index 96% rename from tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java rename to tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java index 2d4dd045f38..3c78749ddfb 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java @@ -12,16 +12,15 @@ * 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; +package com.android.settings.wifi.slice; import static android.app.slice.Slice.HINT_LIST_ITEM; import static android.app.slice.SliceItem.FORMAT_SLICE; import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI; -import static com.android.settings.wifi.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT; +import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT; import static com.google.common.truth.Truth.assertThat; @@ -29,7 +28,6 @@ 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 static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context;