Slice of Provider Model: add slice structure
Implement a slice which can show/update carrier networks.
Before and after: go/b173971144screenshot
Bug: 173971144
Test: atest NetworkProviderWorkerTest (PASS)
atest ProviderModelSliceTest (PASS)
Change-Id: I3f0dab364c88723ef3185a2ff040b1fbd1b099f4
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 90e3ac4..c2881ac 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -103,8 +103,10 @@
implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener {
- private static final String TAG = "NetworkProviderSettings";
+ public static final String ACTION_NETWORK_PROVIDER_SETTINGS =
+ "android.settings.NETWORK_PROVIDER_SETTINGS";
+ private static final String TAG = "NetworkProviderSettings";
// IDs of context menu
static final int MENU_ID_CONNECT = Menu.FIRST + 1;
@VisibleForTesting
diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java
new file mode 100644
index 0000000..f6908c9
--- /dev/null
+++ b/src/com/android/settings/network/ProviderModelSlice.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 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.network;
+
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
+import static com.android.settings.slices.CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settings.network.telephony.NetworkProviderWorker;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SliceBackgroundWorker;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settings.wifi.slice.WifiSlice;
+import com.android.settings.wifi.slice.WifiSliceItem;
+import com.android.wifitrackerlib.WifiEntry;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * {@link CustomSliceable} for Wi-Fi and mobile data connection, used by generic clients.
+ */
+// ToDo If the provider model become default design in the future, the code needs to refactor
+// the whole structure and use new "data object", and then split provider model out of old design.
+public class ProviderModelSlice extends WifiSlice {
+
+ private static final String TAG = "ProviderModelSlice";
+ private final ProviderModelSliceHelper mHelper;
+
+ public ProviderModelSlice(Context context) {
+ super(context);
+ mHelper = getHelper();
+ }
+
+ @Override
+ public Uri getUri() {
+ return PROVIDER_MODEL_SLICE_URI;
+ }
+
+ private static void log(String s) {
+ Log.d(TAG, s);
+ }
+
+ protected boolean isApRowCollapsed() {
+ return false;
+ }
+
+ @Override
+ public Slice getSlice() {
+ // The provider model slice step:
+ // First section: Add a Wi-Fi item which state is connected.
+ // Second section: Add a carrier item.
+ // Third section: Add the Wi-Fi items which are not connected.
+ // Fourth section: If device has connection problem, this row show the message for user.
+
+ if (mHelper.isAirplaneModeEnabled()) {
+ log("Airplane mode is enabled.");
+ // ToDo Next CL will add the Airplane mode Message.
+ return mHelper.createListBuilder(getUri()).build();
+ }
+
+ int maxListSize = 0;
+ List<WifiSliceItem> wifiList = null;
+ final NetworkProviderWorker worker = getWorker();
+ if (worker != null) {
+ // get Wi-Fi list.
+ wifiList = worker.getResults();
+ maxListSize = worker.getApRowCount();
+ } else {
+ log("network provider worker is null.");
+ }
+
+ final boolean hasCarrier = mHelper.hasCarrier();
+ log("hasCarrier: " + hasCarrier);
+
+
+ final ListBuilder listBuilder = mHelper.createListBuilder(getUri());
+
+ // First section: Add a Wi-Fi item which state is connected.
+ final WifiSliceItem connectedWifiItem = mHelper.getConnectedWifiItem(wifiList);
+ if (connectedWifiItem != null) {
+ log("get Wi-Fi item witch is connected");
+ listBuilder.addRow(getWifiSliceItemRow(connectedWifiItem));
+ maxListSize--;
+ }
+
+ // Second section: Add a carrier item.
+ if (hasCarrier) {
+ listBuilder.addRow(mHelper.createCarrierRow());
+ maxListSize--;
+ }
+
+ // Third section: Add the Wi-Fi items which are not connected.
+ if (wifiList != null) {
+ log("get Wi-Fi items which are not connected");
+ final List<WifiSliceItem> disconnectedWifiList = wifiList.stream()
+ .filter(wifiSliceItem -> wifiSliceItem.getConnectedState()
+ != WifiEntry.CONNECTED_STATE_CONNECTED)
+ .limit(maxListSize)
+ .collect(Collectors.toList());
+ for (WifiSliceItem item : disconnectedWifiList) {
+ listBuilder.addRow(getWifiSliceItemRow(item));
+ }
+ }
+
+ // Fourth section: If device has connection problem, this row show the message for user.
+ // 1) show non_carrier_network_unavailable:
+ // - while no wifi item
+ // 2) show all_network_unavailable:
+ // - while no wifi item + no carrier
+ // - while no wifi item + no data capability
+ if (worker == null || wifiList == null) {
+ log("wifiList is null");
+ int resId = R.string.non_carrier_network_unavailable;
+ if (!hasCarrier || mHelper.isNoCarrierData()) {
+ log("No carrier item or no carrier data.");
+ resId = R.string.all_network_unavailable;
+ }
+
+ if (!hasCarrier) {
+ // If there is no item in ProviderModelItem, slice needs a header.
+ listBuilder.setHeader(mHelper.createHeader());
+ }
+ listBuilder.addGridRow(mHelper.createMessageGridRow(resId));
+ }
+
+ return listBuilder.build();
+ }
+
+ /**
+ * Update the current carrier's mobile data status.
+ */
+ @Override
+ public void onNotifyChange(Intent intent) {
+ final SubscriptionManager subscriptionManager = mHelper.getSubscriptionManager();
+ if (subscriptionManager == null) {
+ return;
+ }
+ final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
+ mHelper.isMobileDataEnabled());
+ final int defaultSubId = subscriptionManager.getDefaultDataSubscriptionId();
+ log("defaultSubId:" + defaultSubId);
+ if (!SubscriptionManager.isUsableSubscriptionId(defaultSubId)) {
+ return; // No subscription - do nothing.
+ }
+
+ MobileNetworkUtils.setMobileDataEnabled(mContext, defaultSubId, newState,
+ false /* disableOtherSubscriptions */);
+ }
+
+ @Override
+ public Intent getIntent() {
+ final String screenTitle = mContext.getText(R.string.provider_internet_settings).toString();
+ return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
+ NetworkProviderSettings.class.getName(), "" /* key */, screenTitle,
+ SettingsEnums.SLICE)
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(getUri());
+ }
+
+ @Override
+ public Class getBackgroundWorkerClass() {
+ return NetworkProviderWorker.class;
+ }
+
+ @VisibleForTesting
+ ProviderModelSliceHelper getHelper() {
+ return new ProviderModelSliceHelper(mContext, this);
+ }
+
+ @VisibleForTesting
+ NetworkProviderWorker getWorker() {
+ return SliceBackgroundWorker.getInstance(getUri());
+ }
+}
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWorker.java b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
new file mode 100644
index 0000000..bc82901
--- /dev/null
+++ b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 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.network.telephony;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyDisplayInfo;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.network.MobileDataContentObserver;
+import com.android.settings.network.MobileDataEnabledListener;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.wifi.slice.WifiScanWorker;
+
+import java.util.Collections;
+import java.util.concurrent.Executor;
+
+
+/**
+ * BackgroundWorker for Provider Model slice.
+ */
+public class NetworkProviderWorker extends WifiScanWorker implements
+ SignalStrengthListener.Callback, MobileDataEnabledListener.Client,
+ DataConnectivityListener.Client,
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "NetworkProviderWorker";
+ private static final int PROVIDER_MODEL_DEFAULT_EXPANDED_ROW_COUNT = 4;
+ private DataContentObserver mMobileDataObserver;
+ private SignalStrengthListener mSignalStrengthListener;
+ private SubscriptionsChangeListener mSubscriptionsListener;
+ private MobileDataEnabledListener mDataEnabledListener;
+ private DataConnectivityListener mConnectivityListener;
+
+ private final Context mContext;
+ @VisibleForTesting
+ final PhoneStateListener mPhoneStateListener;
+ private final SubscriptionManager mSubscriptionManager;
+ private final TelephonyManager mTelephonyManager;
+
+ public NetworkProviderWorker(Context context, Uri uri) {
+ super(context, uri);
+ // Mobile data worker
+ final Handler handler = new Handler(Looper.getMainLooper());
+ mMobileDataObserver = new DataContentObserver(handler, this);
+
+ mContext = context;
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+
+ mPhoneStateListener = new NetworkProviderPhoneStateListener(handler::post);
+ mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
+ mDataEnabledListener = new MobileDataEnabledListener(context, this);
+ mConnectivityListener = new DataConnectivityListener(context, this);
+ mSignalStrengthListener = new SignalStrengthListener(context, this);
+ }
+
+ @Override
+ protected void onSlicePinned() {
+ mMobileDataObserver.register(mContext,
+ getDefaultSubscriptionId(mSubscriptionManager));
+
+ mSubscriptionsListener.start();
+ mDataEnabledListener.start(SubscriptionManager.getDefaultDataSubscriptionId());
+ mConnectivityListener.start();
+ mSignalStrengthListener.resume();
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE
+ | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE
+ | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED);
+
+ super.onSlicePinned();
+ }
+
+ @Override
+ protected void onSliceUnpinned() {
+ mMobileDataObserver.unregister(mContext);
+ mSubscriptionsListener.stop();
+ mDataEnabledListener.stop();
+ mConnectivityListener.stop();
+ mSignalStrengthListener.pause();
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ super.onSliceUnpinned();
+ }
+
+ @Override
+ public void close() {
+ mMobileDataObserver = null;
+ super.close();
+ }
+
+ @Override
+ public int getApRowCount() {
+ return PROVIDER_MODEL_DEFAULT_EXPANDED_ROW_COUNT;
+ }
+
+ /**
+ * To update the Slice.
+ */
+ public void updateSlice() {
+ notifySliceChange();
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ Log.d(TAG, "onSubscriptionsChanged: defaultDataSubId:" + defaultDataSubId);
+
+ mSignalStrengthListener.updateSubscriptionIds(
+ SubscriptionManager.isUsableSubscriptionId(defaultDataSubId)
+ ? Collections.singleton(defaultDataSubId) : Collections.emptySet());
+ if (defaultDataSubId != mDataEnabledListener.getSubId()) {
+ mDataEnabledListener.stop();
+ mDataEnabledListener.start(defaultDataSubId);
+ }
+ updateSlice();
+ }
+
+ @Override
+ public void onSignalStrengthChanged() {
+ Log.d(TAG, "onSignalStrengthChanged");
+ updateSlice();
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ Log.d(TAG, "onAirplaneModeChanged");
+ updateSlice();
+ }
+
+ @Override
+ public void onMobileDataEnabledChange() {
+ Log.d(TAG, "onMobileDataEnabledChange");
+ updateSlice();
+ }
+
+ @Override
+ public void onDataConnectivityChange() {
+ Log.d(TAG, "onDataConnectivityChange");
+ updateSlice();
+ }
+
+ /**
+ * Listen to update of mobile data change.
+ */
+ public class DataContentObserver extends ContentObserver {
+ private final NetworkProviderWorker mNetworkProviderWorker;
+
+ public DataContentObserver(Handler handler, NetworkProviderWorker backgroundWorker) {
+ super(handler);
+ mNetworkProviderWorker = backgroundWorker;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mNetworkProviderWorker.updateSlice();
+ }
+
+ /**
+ * To register the observer for mobile data changed.
+ * @param context the Context object.
+ * @param subId the default data subscription id.
+ */
+ public void register(Context context, int subId) {
+ final Uri uri = MobileDataContentObserver.getObservableUri(context, subId);
+ context.getContentResolver().registerContentObserver(uri, false, this);
+ }
+
+ /**
+ * To unregister the observer for mobile data changed.
+ * @param context the Context object.
+ */
+ public void unregister(Context context) {
+ context.getContentResolver().unregisterContentObserver(this);
+ }
+ }
+
+ class NetworkProviderPhoneStateListener extends PhoneStateListener {
+ NetworkProviderPhoneStateListener(Executor executor) {
+ super(executor);
+ }
+
+ @Override
+ public void onServiceStateChanged(ServiceState state) {
+ Log.d(TAG, "onServiceStateChanged voiceState=" + state.getState()
+ + " dataState=" + state.getDataRegistrationState());
+ updateSlice();
+ }
+
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ Log.d(TAG, "onActiveDataSubscriptionIdChanged: subId=" + subId);
+ updateSlice();
+ }
+
+ @Override
+ public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
+ Log.d(TAG, "onDisplayInfoChanged: telephonyDisplayInfo=" + telephonyDisplayInfo);
+ updateSlice();
+ }
+ }
+
+ protected static int getDefaultSubscriptionId(SubscriptionManager subscriptionManager) {
+ final SubscriptionInfo defaultSubscription = subscriptionManager.getActiveSubscriptionInfo(
+ subscriptionManager.getDefaultDataSubscriptionId());
+
+ if (defaultSubscription == null) {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID; // No default subscription
+ }
+ return defaultSubscription.getSubscriptionId();
+ }
+}
diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java
index 6ae7089..312bf75 100644
--- a/src/com/android/settings/panel/InternetConnectivityPanel.java
+++ b/src/com/android/settings/panel/InternetConnectivityPanel.java
@@ -16,6 +16,8 @@
package com.android.settings.panel;
+import static com.android.settings.network.NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS;
+
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
@@ -51,17 +53,19 @@
@Override
public CharSequence getTitle() {
- return mContext.getText(R.string.internet_connectivity_panel_title);
+ return mContext.getText(Utils.isProviderModelEnabled(mContext)
+ ? R.string.provider_internet_settings : R.string.internet_connectivity_panel_title);
}
@Override
public List<Uri> getSlices() {
final List<Uri> uris = new ArrayList<>();
- uris.add(CustomSliceRegistry.WIFI_SLICE_URI);
- uris.add(CustomSliceRegistry.MOBILE_DATA_SLICE_URI);
if (Utils.isProviderModelEnabled(mContext)) {
+ uris.add(CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI);
uris.add(CustomSliceRegistry.AIRPLANE_SAFE_NETWORKS_SLICE_URI);
} else {
+ uris.add(CustomSliceRegistry.WIFI_SLICE_URI);
+ uris.add(CustomSliceRegistry.MOBILE_DATA_SLICE_URI);
uris.add(AirplaneModePreferenceController.SLICE_URI);
}
return uris;
@@ -69,7 +73,8 @@
@Override
public Intent getSeeMoreIntent() {
- return new Intent(Settings.ACTION_WIRELESS_SETTINGS)
+ return new Intent(Utils.isProviderModelEnabled(mContext)
+ ? ACTION_NETWORK_PROVIDER_SETTINGS : Settings.ACTION_WIRELESS_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index cf23cbd..be71b30 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -40,6 +40,7 @@
import com.android.settings.media.MediaOutputIndicatorSlice;
import com.android.settings.media.RemoteMediaSlice;
import com.android.settings.network.AirplaneSafeNetworksSlice;
+import com.android.settings.network.ProviderModelSlice;
import com.android.settings.network.telephony.MobileDataSlice;
import com.android.settings.notification.zen.ZenModeButtonPreferenceController;
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
@@ -167,6 +168,17 @@
.appendEncodedPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath("mobile_data")
.build();
+
+ /**
+ * Full {@link Uri} for the Provider Model Slice.
+ */
+ public static final Uri PROVIDER_MODEL_SLICE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendEncodedPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("provider_model")
+ .build();
+
/**
* Full {@link Uri} for the Alarm volume Slice.
*/
@@ -176,6 +188,7 @@
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath("alarm_volume")
.build();
+
/**
* Full {@link Uri} for the Call Volume Slice.
*/
@@ -319,6 +332,7 @@
sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class);
sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
+ sUriToSlice.put(PROVIDER_MODEL_SLICE_URI, ProviderModelSlice.class);
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class);
sUriToSlice.put(REMOTE_MEDIA_SLICE_URI, RemoteMediaSlice.class);
diff --git a/src/com/android/settings/wifi/slice/WifiScanWorker.java b/src/com/android/settings/wifi/slice/WifiScanWorker.java
index 16c4ebc..6c0f4aa 100644
--- a/src/com/android/settings/wifi/slice/WifiScanWorker.java
+++ b/src/com/android/settings/wifi/slice/WifiScanWorker.java
@@ -61,7 +61,7 @@
@VisibleForTesting
final LifecycleRegistry mLifecycleRegistry;
@VisibleForTesting
- WifiPickerTracker mWifiPickerTracker;
+ protected WifiPickerTracker mWifiPickerTracker;
// Worker thread used for WifiPickerTracker work
private final HandlerThread mWorkerThread;
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
new file mode 100644
index 0000000..9c16b8a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2020 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.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.GridRowBuilder;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.Utils;
+import com.android.settings.network.telephony.NetworkProviderWorker;
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settings.wifi.slice.WifiSliceItem;
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ProviderModelSliceTest {
+ private static final Uri PROVIDER_MODEL_SLICE_URI =
+ Uri.parse("content://com.android.settings.slices/action/provider_model");
+ private static final int MOCK_SLICE_LEVEL = 3;
+
+ private Context mContext;
+ private MockProviderModelSlice mMockProviderModelSlice;
+ List<WifiSliceItem> mWifiList = new ArrayList<>();
+ private ListBuilder mListBuilder;
+ private MockNetworkProviderWorker mMockNetworkProviderWorker;
+
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private WifiManager mWifiManager;
+ @Mock
+ private ProviderModelSliceHelper mProviderModelSliceHelper;
+ @Mock
+ private WifiSliceItem mMockWifiSliceItem1;
+ @Mock
+ private WifiSliceItem mMockWifiSliceItem2;
+ @Mock
+ private WifiSliceItem mMockWifiSliceItem3;
+ @Mock
+ ListBuilder.RowBuilder mMockCarrierRowBuild;
+ @Mock
+ ListBuilder.HeaderBuilder mMockHeader;
+ @Mock
+ GridRowBuilder mMockGridRowBuilderNonCarrierNetworkUnavailable;
+ @Mock
+ GridRowBuilder mMockGridRowBuilderAllNetworkUnavailable;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
+
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mMockNetworkProviderWorker = new MockNetworkProviderWorker(mContext,
+ PROVIDER_MODEL_SLICE_URI);
+ mMockProviderModelSlice = new MockProviderModelSlice(mContext, mMockNetworkProviderWorker);
+ mListBuilder = spy(new ListBuilder(mContext, PROVIDER_MODEL_SLICE_URI,
+ ListBuilder.INFINITY).setAccentColor(-1));
+ when(mProviderModelSliceHelper.createListBuilder(PROVIDER_MODEL_SLICE_URI)).thenReturn(
+ mListBuilder);
+
+ mWifiList = new ArrayList<>();
+ mMockNetworkProviderWorker.updateSelfResults(mWifiList);
+
+ mockBuilder();
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_noWorkerAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
+ mWifiList.clear();
+ mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
+ mockHelperCondition(false, false, false, null);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(1)).setHeader(mMockHeader);
+ verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_noWifiAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() {
+ mWifiList.clear();
+ mMockNetworkProviderWorker.updateSelfResults(null);
+ mockHelperCondition(false, false, false, null);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(1)).setHeader(mMockHeader);
+ verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_noWifiAndHasCarrierNoData_oneCarrierOneGridRowWithAllNetworkUnavailable() {
+ mWifiList.clear();
+ mMockNetworkProviderWorker.updateSelfResults(null);
+ mockHelperCondition(false, true, true, null);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
+ verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_noWifiAndNoCarrier_oneCarrierOneGridRowWithNonCarrierNetworkUnavailable() {
+ mWifiList.clear();
+ mMockProviderModelSlice = new MockProviderModelSlice(mContext, null);
+ mockHelperCondition(false, true, false, null);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
+ verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderNonCarrierNetworkUnavailable);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_haveTwoWifiAndOneCarrier_getCarrierAndTwoWiFi() {
+ mWifiList.clear();
+ mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1",
+ WifiEntry.CONNECTED_STATE_CONNECTED, "wifi1_key", true);
+ mWifiList.add(mMockWifiSliceItem1);
+ mockWifiItemCondition(mMockWifiSliceItem2, "wifi2", "wifi2",
+ WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi2_key", true);
+ mWifiList.add(mMockWifiSliceItem2);
+ mMockNetworkProviderWorker.updateSelfResults(mWifiList);
+ mockHelperCondition(false, true, false, mWifiList.get(0));
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
+ verify(mListBuilder, times(3)).addRow(any(ListBuilder.RowBuilder.class));
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_haveOneConnectedWifiAndTwoDisconnectedWifiAndNoCarrier_getTwoRow() {
+ mWifiList.clear();
+ mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1",
+ WifiEntry.CONNECTED_STATE_CONNECTED, "wifi1_key", true);
+ mWifiList.add(mMockWifiSliceItem1);
+ mockWifiItemCondition(mMockWifiSliceItem2, "wifi2", "wifi2",
+ WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi2_key", true);
+ mWifiList.add(mMockWifiSliceItem2);
+ mockWifiItemCondition(mMockWifiSliceItem3, "wifi3", "wifi3",
+ WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi3_key", true);
+ mWifiList.add(mMockWifiSliceItem3);
+ mMockNetworkProviderWorker.updateSelfResults(mWifiList);
+ mockHelperCondition(false, false, false, mWifiList.get(0));
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(3)).addRow(any(ListBuilder.RowBuilder.class));
+ }
+
+ @Test
+ @UiThreadTest
+ public void getSlice_haveTwoDisconnectedWifiAndNoCarrier_getTwoRow() {
+ mWifiList.clear();
+ mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1",
+ WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi1_key", true);
+ mWifiList.add(mMockWifiSliceItem1);
+ mockWifiItemCondition(mMockWifiSliceItem2, "wifi2", "wifi2",
+ WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi2_key", true);
+ mWifiList.add(mMockWifiSliceItem2);
+ mMockNetworkProviderWorker.updateSelfResults(mWifiList);
+ mockHelperCondition(false, false, false, null);
+
+ final Slice slice = mMockProviderModelSlice.getSlice();
+
+ assertThat(slice).isNotNull();
+ verify(mListBuilder, times(2)).addRow(any(ListBuilder.RowBuilder.class));
+ }
+
+ @Test
+ public void providerModelSlice_hasCorrectUri() {
+ assertThat(mMockProviderModelSlice.getUri()).isEqualTo(PROVIDER_MODEL_SLICE_URI);
+ }
+
+ private void mockHelperCondition(boolean airplaneMode, boolean hasCarrier,
+ boolean isNoCarrierData, WifiSliceItem connectedWifiItem) {
+ when(mProviderModelSliceHelper.isAirplaneModeEnabled()).thenReturn(airplaneMode);
+ when(mProviderModelSliceHelper.hasCarrier()).thenReturn(hasCarrier);
+ when(mProviderModelSliceHelper.isNoCarrierData()).thenReturn(isNoCarrierData);
+ when(mProviderModelSliceHelper.getConnectedWifiItem(any())).thenReturn(connectedWifiItem);
+ }
+
+ private void mockWifiItemCondition(WifiSliceItem mockWifiItem, String title, String summary,
+ int connectedState, String key, boolean shouldEditBeforeConnect) {
+ when(mockWifiItem.getTitle()).thenReturn(title);
+ when(mockWifiItem.getSummary()).thenReturn(summary);
+ when(mockWifiItem.getConnectedState()).thenReturn(connectedState);
+ when(mockWifiItem.getLevel()).thenReturn(MOCK_SLICE_LEVEL);
+ when(mockWifiItem.getKey()).thenReturn(key);
+ when(mockWifiItem.shouldEditBeforeConnect()).thenReturn(shouldEditBeforeConnect);
+ }
+
+ private void mockBuilder() {
+ SliceAction mockSliceAction = getPrimarySliceAction();
+ when(mMockHeader.getTitle()).thenReturn("mockHeader");
+ when(mMockHeader.getPrimaryAction()).thenReturn(mockSliceAction);
+ when(mProviderModelSliceHelper.createHeader()).thenReturn(mMockHeader);
+
+ int resId = ResourcesUtils.getResourcesId(mContext, "string",
+ "non_carrier_network_unavailable");
+ when(mProviderModelSliceHelper.createMessageGridRow(resId)).thenReturn(
+ mMockGridRowBuilderNonCarrierNetworkUnavailable);
+ resId = ResourcesUtils.getResourcesId(mContext, "string",
+ "all_network_unavailable");
+ when(mProviderModelSliceHelper.createMessageGridRow(resId)).thenReturn(
+ mMockGridRowBuilderAllNetworkUnavailable);
+
+ when(mMockCarrierRowBuild.getTitle()).thenReturn("mockRow");
+ when(mMockCarrierRowBuild.getPrimaryAction()).thenReturn(mockSliceAction);
+ when(mProviderModelSliceHelper.createCarrierRow()).thenReturn(mMockCarrierRowBuild);
+ }
+
+ private SliceAction getPrimarySliceAction() {
+ return SliceAction.createDeeplink(
+ getPrimaryAction(),
+ Utils.createIconWithDrawable(new ColorDrawable(Color.TRANSPARENT)),
+ ListBuilder.ICON_IMAGE,
+ ResourcesUtils.getResourcesString(mContext, "summary_placeholder"));
+ }
+
+ private PendingIntent getPrimaryAction() {
+ final Intent intent = new Intent("android.settings.NETWORK_PROVIDER_SETTINGS")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */,
+ intent, PendingIntent.FLAG_IMMUTABLE /* flags */);
+ }
+
+ public class MockNetworkProviderWorker extends NetworkProviderWorker {
+ MockNetworkProviderWorker(Context context, Uri uri) {
+ super(context, uri);
+ }
+
+ public void updateSelfResults(List<WifiSliceItem> results) {
+ this.updateResults(results);
+ }
+ }
+
+ public class MockProviderModelSlice extends ProviderModelSlice {
+ private MockNetworkProviderWorker mNetworkProviderWorker;
+
+ MockProviderModelSlice(Context context, MockNetworkProviderWorker networkProviderWorker) {
+ super(context);
+ mNetworkProviderWorker = networkProviderWorker;
+ }
+
+ @Override
+ ProviderModelSliceHelper getHelper() {
+ return mProviderModelSliceHelper;
+ }
+
+ @Override
+ NetworkProviderWorker getWorker() {
+ return mNetworkProviderWorker;
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java
new file mode 100644
index 0000000..a4fc745
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2020 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.network.telephony;
+
+import static com.android.settings.slices.CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyDisplayInfo;
+import android.telephony.TelephonyManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.wifitrackerlib.WifiEntry;
+import com.android.wifitrackerlib.WifiPickerTracker;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkProviderWorkerTest {
+ private Context mContext;
+ private MockNetworkProviderWorker mMockNetworkProviderWorker;
+
+ @Mock
+ WifiPickerTracker mMockWifiPickerTracker;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+
+ mMockNetworkProviderWorker = new MockNetworkProviderWorker(mContext,
+ PROVIDER_MODEL_SLICE_URI);
+ mMockNetworkProviderWorker.setWifiPickerTracker(mMockWifiPickerTracker);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onConstructor_shouldBeInCreatedState() {
+ assertThat(mMockNetworkProviderWorker.getLifecycle().getCurrentState())
+ .isEqualTo(Lifecycle.State.CREATED);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSlicePinned_shouldBeInResumedState() {
+ mMockNetworkProviderWorker.onSlicePinned();
+
+ assertThat(mMockNetworkProviderWorker.getLifecycle().getCurrentState())
+ .isEqualTo(Lifecycle.State.RESUMED);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSliceUnpinned_shouldBeInCreatedState() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.onSliceUnpinned();
+
+ assertThat(mMockNetworkProviderWorker.getLifecycle().getCurrentState())
+ .isEqualTo(Lifecycle.State.CREATED);
+ }
+
+ @Test
+ @UiThreadTest
+ public void close_shouldBeInDestroyedState() {
+ mMockNetworkProviderWorker.close();
+
+ assertThat(mMockNetworkProviderWorker.getLifecycle().getCurrentState())
+ .isEqualTo(Lifecycle.State.DESTROYED);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getWifiEntry_connectedWifiKey_shouldGetConnectedWifi() {
+ final String key = "key";
+ final WifiEntry connectedWifiEntry = mock(WifiEntry.class);
+ when(connectedWifiEntry.getKey()).thenReturn(key);
+ when(mMockWifiPickerTracker.getConnectedWifiEntry()).thenReturn(connectedWifiEntry);
+
+ assertThat(mMockNetworkProviderWorker.getWifiEntry(key)).isEqualTo(connectedWifiEntry);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getWifiEntry_reachableWifiKey_shouldGetReachableWifi() {
+ final String key = "key";
+ final WifiEntry reachableWifiEntry = mock(WifiEntry.class);
+ when(reachableWifiEntry.getKey()).thenReturn(key);
+ when(mMockWifiPickerTracker.getWifiEntries()).thenReturn(Arrays.asList(reachableWifiEntry));
+
+ assertThat(mMockNetworkProviderWorker.getWifiEntry(key)).isEqualTo(reachableWifiEntry);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSubscriptionsChanged_notifySubscriptionChanged_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onSubscriptionsChanged();
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onAirplaneModeChanged_airplaneModeOn_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onAirplaneModeChanged(false);
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onAirplaneModeChanged_airplaneModeOff_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onAirplaneModeChanged(true);
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSignalStrengthChanged_notifySignalStrengthChanged_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onSignalStrengthChanged();
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onMobileDataEnabledChange_notifyMobileDataEnabledChanged_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onMobileDataEnabledChange();
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onDataConnectivityChange_notifyDataConnectivityChanged_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.onDataConnectivityChange();
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onServiceStateChanged_notifyPhoneStateListener_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.mPhoneStateListener.onServiceStateChanged(new ServiceState());
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onActiveDataSubscriptionIdChanged_notifyPhoneStateListener_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.mPhoneStateListener.onActiveDataSubscriptionIdChanged(1);
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onDisplayInfoChanged_notifyPhoneStateListener_callUpdateSlice() {
+ mMockNetworkProviderWorker.onSlicePinned();
+ mMockNetworkProviderWorker.receiveNotification(false);
+
+ mMockNetworkProviderWorker.mPhoneStateListener.onDisplayInfoChanged(
+ new TelephonyDisplayInfo(14, 0));
+
+ assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+ }
+
+ public class MockNetworkProviderWorker extends NetworkProviderWorker {
+ private boolean mHasNotification = false;
+
+ MockNetworkProviderWorker(Context context, Uri uri) {
+ super(context, uri);
+ }
+
+ public void receiveNotification(boolean inputValue) {
+ mHasNotification = inputValue;
+ }
+
+ public boolean hasNotification() {
+ return mHasNotification;
+ }
+
+ @Override
+ public void updateSlice() {
+ super.updateSlice();
+ receiveNotification(true);
+ }
+
+ public void setWifiPickerTracker(WifiPickerTracker wifiPickerTracker) {
+ mWifiPickerTracker = wifiPickerTracker;
+ }
+ }
+}