From 1138218abe128205a4fe32a43b72fb27c11a5b32 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Thu, 10 Jan 2019 10:02:49 -0800 Subject: [PATCH 1/4] Create special case mobile data slice Build the special case mobile data slice for general use, and for the Internet Connectivity Panel. The Slice controls the default data subscription, and links to the subscriptions page. Bug: 117804089 Fixse: 119411534 Test: robotests & test app. Change-Id: I31b524a8fe3182a244d940848090e97250632f39 --- AndroidManifest.xml | 2 +- .../MobileDataPreferenceController.java | 13 +- .../network/telephony/MobileDataSlice.java | 249 ++++++++++++++++++ .../panel/InternetConnectivityPanel.java | 1 + .../settings/slices/CustomSliceManager.java | 3 +- .../settings/slices/CustomSliceRegistry.java | 10 + .../settings/slices/CustomSliceable.java | 11 +- .../slices/SettingsSliceProvider.java | 5 +- .../slices/SliceBackgroundWorker.java | 10 +- .../settings/wifi/slice/WifiSlice.java | 4 +- .../telephony/MobileDataSliceTest.java | 165 ++++++++++++ .../panel/InternetConnectivityPanelTest.java | 6 +- .../slices/SettingsSliceProviderTest.java | 3 +- 13 files changed, 463 insertions(+), 19 deletions(-) create mode 100644 src/com/android/settings/network/telephony/MobileDataSlice.java create mode 100644 tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 90aa55ff1a7..829425cfb91 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2991,7 +2991,7 @@ android:label="@string/settings_panel_title" android:theme="@style/Theme.BottomDialog" android:excludeFromRecents="true" - android:launchMode="singleTask" + android:launchMode="singleTop" android:exported="true"> diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java index 47822b6fce3..bdcc7274794 100644 --- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java +++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java @@ -122,6 +122,14 @@ public class MobileDataPreferenceController extends TogglePreferenceController && mSubId == SubscriptionManager.getDefaultDataSubscriptionId(); } + public static Uri getObservableUri(int subId) { + Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + if (TelephonyManager.getDefault().getSimCount() != 1) { + uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); + } + return uri; + } + public void init(FragmentManager fragmentManager, int subId) { mFragmentManager = fragmentManager; mSubId = subId; @@ -172,10 +180,7 @@ public class MobileDataPreferenceController extends TogglePreferenceController } public void register(Context context, int subId) { - Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); - if (TelephonyManager.getDefault().getSimCount() != 1) { - uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); - } + final Uri uri = getObservableUri(subId); context.getContentResolver().registerContentObserver(uri, false, this); } diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java new file mode 100644 index 00000000000..6efd8c3aed6 --- /dev/null +++ b/src/com/android/settings/network/telephony/MobileDataSlice.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2019 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 android.app.slice.Slice.EXTRA_TOGGLE_STATE; + +import android.annotation.ColorInt; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.network.AirplaneModePreferenceController; +import com.android.settings.slices.CustomSliceRegistry; +import com.android.settings.slices.CustomSliceable; +import com.android.settings.slices.SliceBackgroundWorker; + +import com.google.common.annotations.VisibleForTesting; + +import java.io.IOException; + +/** + * Custom {@link Slice} for Mobile Data. + *

+ * We make a custom slice instead of using {@link MobileDataPreferenceController} because the + * pref controller is generalized across any carrier, and thus does not control a specific + * subscription. We attempt to reuse any telephony-specific code from the preference controller. + * + *

+ * + */ +public class MobileDataSlice implements CustomSliceable { + + private final Context mContext; + private final SubscriptionManager mSubscriptionManager; + private final TelephonyManager mTelephonyManager; + + public MobileDataSlice(Context context) { + mContext = context; + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + } + + @Override + public Slice getSlice() { + final IconCompat icon = IconCompat.createWithResource(mContext, + R.drawable.ic_network_cell); + final String title = mContext.getText(R.string.mobile_data_settings_title).toString(); + final CharSequence summary = getSummary(); + @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); + final PendingIntent toggleAction = getBroadcastIntent(mContext); + final PendingIntent primaryAction = getPrimaryAction(); + final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon, + ListBuilder.ICON_IMAGE, title); + final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, + null /* actionTitle */, isMobileDataEnabled()); + + final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), + ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(new ListBuilder.RowBuilder() + .setTitle(title) + .setSubtitle(summary) + .addEndItem(toggleSliceAction) + .setPrimaryAction(primarySliceAction)); + return listBuilder.build(); + } + + @Override + public Uri getUri() { + return CustomSliceRegistry.MOBILE_DATA_SLICE_URI; + } + + @Override + public void onNotifyChange(Intent intent) { + // Don't make a change if we are in Airplane Mode. + if (isAirplaneModeEnabled()) { + return; + } + + final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, + isMobileDataEnabled()); + + final int defaultSubId = getDefaultSubscriptionId(mSubscriptionManager); + if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return; // No subscription - do nothing. + } + + MobileNetworkUtils.setMobileDataEnabled(mContext, defaultSubId, newState, + false /* disableOtherSubscriptions */); + // 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 WifiScanWorker} + // handle it. + } + + @Override + public IntentFilter getIntentFilter() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); + return filter; + } + + @Override + public Intent getIntent() { + return new Intent(mContext, MobileNetworkActivity.class); + } + + @Override + public Class getBackgroundWorkerClass() { + return MobileDataWorker.class; + } + + protected static int getDefaultSubscriptionId(SubscriptionManager subscriptionManager) { + final SubscriptionInfo defaultSubscription = + subscriptionManager.getDefaultDataSubscriptionInfo(); + if (defaultSubscription == null) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; // No default subscription + } + + return defaultSubscription.getSubscriptionId(); + } + + private CharSequence getSummary() { + final SubscriptionInfo defaultSubscription = + mSubscriptionManager.getDefaultDataSubscriptionInfo(); + if (defaultSubscription == null) { + return null; // no summary text + } + + return defaultSubscription.getDisplayName(); + } + + private PendingIntent getPrimaryAction() { + final Intent intent = getIntent(); + return PendingIntent.getActivity(mContext, 0 /* requestCode */, + intent, 0 /* flags */); + } + + @VisibleForTesting + boolean isAirplaneModeEnabled() { + // Generic key since we only want the method check - no UI. + AirplaneModePreferenceController controller = new AirplaneModePreferenceController(mContext, + "key" /* Key */); + return controller.isChecked(); + } + + @VisibleForTesting + boolean isMobileDataEnabled() { + if (mTelephonyManager == null) { + return false; + } + + return mTelephonyManager.isDataEnabled(); + } + + /** + * Listener for mobile data state changes. + * + *

+ * Listen to individual subscription changes since there is no framework broadcast. + * + * This worker registers a ContentObserver in the background and updates the MobileData + * Slice when the value changes. + */ + public static class MobileDataWorker extends SliceBackgroundWorker { + + DataContentObserver mMobileDataObserver; + + public MobileDataWorker(Context context, Uri uri) { + super(context, uri); + final Handler handler = new Handler(Looper.getMainLooper()); + mMobileDataObserver = new DataContentObserver(handler, this); + } + + @Override + protected void onSlicePinned() { + final SubscriptionManager subscriptionManager = + getContext().getSystemService(SubscriptionManager.class); + mMobileDataObserver.register(getContext(), + getDefaultSubscriptionId(subscriptionManager)); + } + + @Override + protected void onSliceUnpinned() { + mMobileDataObserver.unRegister(getContext()); + } + + @Override + public void close() throws IOException { + mMobileDataObserver = null; + } + + public void updateSlice() { + notifySliceChange(); + } + + public class DataContentObserver extends ContentObserver { + + private final MobileDataWorker mSliceBackgroundWorker; + + public DataContentObserver(Handler handler, MobileDataWorker backgroundWorker) { + super(handler); + mSliceBackgroundWorker = backgroundWorker; + } + + @Override + public void onChange(boolean selfChange) { + mSliceBackgroundWorker.updateSlice(); + } + + public void register(Context context, int subId) { + final Uri uri = MobileDataPreferenceController.getObservableUri(subId); + context.getContentResolver().registerContentObserver(uri, false, this); + } + + public void unRegister(Context context) { + context.getContentResolver().unregisterContentObserver(this); + } + } + } +} diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java index aae42f87e94..d20b75afce4 100644 --- a/src/com/android/settings/panel/InternetConnectivityPanel.java +++ b/src/com/android/settings/panel/InternetConnectivityPanel.java @@ -55,6 +55,7 @@ public class InternetConnectivityPanel implements PanelContent { public List getSlices() { final List uris = new ArrayList<>(); uris.add(CustomSliceRegistry.WIFI_SLICE_URI); + uris.add(CustomSliceRegistry.MOBILE_DATA_SLICE_URI); uris.add(CustomSliceRegistry.AIRPLANE_URI); return uris; } diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java index 3786c5c2ed9..c9e473a9c20 100644 --- a/src/com/android/settings/slices/CustomSliceManager.java +++ b/src/com/android/settings/slices/CustomSliceManager.java @@ -18,7 +18,6 @@ package com.android.settings.slices; import android.content.Context; import android.net.Uri; -import android.text.TextUtils; import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; @@ -35,6 +34,7 @@ import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice; import com.android.settings.location.LocationSlice; import com.android.settings.media.MediaOutputSlice; +import com.android.settings.network.telephony.MobileDataSlice; import com.android.settings.wifi.slice.ContextualWifiSlice; import com.android.settings.wifi.slice.WifiSlice; @@ -123,6 +123,7 @@ public class CustomSliceManager { mUriMap.put(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, FlashlightSlice.class); mUriMap.put(CustomSliceRegistry.LOCATION_SLICE_URI, LocationSlice.class); mUriMap.put(CustomSliceRegistry.LOW_STORAGE_SLICE_URI, LowStorageSlice.class); + mUriMap.put(CustomSliceRegistry.MOBILE_DATA_SLICE_URI, MobileDataSlice.class); mUriMap.put(CustomSliceRegistry.NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class); mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class); diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 66e85c0612d..ab1b2484828 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -164,6 +164,16 @@ public class CustomSliceRegistry { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("toggle_nfc") .build(); + + /** + * Backing Uri for Mobile Data Slice. + */ + public static final Uri MOBILE_DATA_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendEncodedPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("mobile_data") + .build(); /** * Backing Uri for Notification channel Slice. */ diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java index b538b898252..220cdc80dbf 100644 --- a/src/com/android/settings/slices/CustomSliceable.java +++ b/src/com/android/settings/slices/CustomSliceable.java @@ -71,7 +71,7 @@ public interface CustomSliceable { * * @param intent which has the action taken on a {@link Slice}. */ - void onNotifyChange(Intent intent); + default void onNotifyChange(Intent intent) {} /** * @return an {@link Intent} to the source of the Slice data. @@ -90,11 +90,12 @@ public interface CustomSliceable { } /** - * Settings Slices which can represent component lists that are updatable by the - * {@link SliceBackgroundWorker} class returned here. + * Settings Slices which require background work, such as updating lists should implement a + * {@link SliceBackgroundWorker} and return it here. An example of background work is updating + * a list of Wifi networks available in the area. * - * @return a {@link SliceBackgroundWorker} class for fetching the list of results in the - * background. + * @return a {@link Class} to perform background work for the + * slice. */ default Class getBackgroundWorkerClass() { return null; diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 80b71335646..7b9acee6cf7 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -464,8 +464,9 @@ public class SettingsSliceProvider extends SliceProvider { private List getSpecialCaseOemUris() { return Arrays.asList( - CustomSliceRegistry.ZEN_MODE_SLICE_URI, - CustomSliceRegistry.FLASHLIGHT_SLICE_URI + CustomSliceRegistry.FLASHLIGHT_SLICE_URI, + CustomSliceRegistry.MOBILE_DATA_SLICE_URI, + CustomSliceRegistry.ZEN_MODE_SLICE_URI ); } diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java index 6df45ba93e3..995394e7d41 100644 --- a/src/com/android/settings/slices/SliceBackgroundWorker.java +++ b/src/com/android/settings/slices/SliceBackgroundWorker.java @@ -59,6 +59,14 @@ public abstract class SliceBackgroundWorker implements Closeable { mUri = uri; } + protected Uri getUri() { + return mUri; + } + + protected Context getContext() { + return mContext; + } + /** * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri} * if exists @@ -151,7 +159,7 @@ public abstract class SliceBackgroundWorker implements Closeable { /** * Notify that data was updated and attempt to sync changes to the Slice. */ - protected void notifySliceChange() { + protected final void notifySliceChange() { mContext.getContentResolver().notifyChange(mUri, null); } } \ No newline at end of file diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java index 1a0ed0ce90e..bee643df363 100644 --- a/src/com/android/settings/wifi/slice/WifiSlice.java +++ b/src/com/android/settings/wifi/slice/WifiSlice.java @@ -142,7 +142,7 @@ public class WifiSlice implements CustomSliceable { .setTitle(title) .setSubtitle(!TextUtils.isEmpty(apSummary) ? apSummary - : mContext.getText(R.string.summary_placeholder)) + : null) .setPrimaryAction(SliceAction.create( getAccessPointAction(accessPoint), levelIcon, ListBuilder.ICON_IMAGE, title)); @@ -247,7 +247,7 @@ public class WifiSlice implements CustomSliceable { return mContext.getText(R.string.switch_off_text); case WifiManager.WIFI_STATE_UNKNOWN: default: - return ""; + return null; } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java new file mode 100644 index 00000000000..c497cf82665 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 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.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.provider.Settings; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.core.SliceAction; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class MobileDataSliceTest { + + private static final int SUB_ID = 2; + + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; + @Mock + private SubscriptionInfo mSubscriptionInfo; + + private Context mContext; + private MobileDataSlice mMobileDataSlice; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + doReturn(SUB_ID).when(mSubscriptionInfo).getSubscriptionId(); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + + mMobileDataSlice = spy(new MobileDataSlice(mContext)); + } + + @Test + public void getSlice_shouldHaveTitleAndToggle() { + final Slice mobileData = mMobileDataSlice.getSlice(); + + final SliceMetadata metadata = SliceMetadata.from(mContext, mobileData); + assertThat(metadata.getTitle()) + .isEqualTo(mContext.getString(R.string.mobile_data_settings_title)); + + final List toggles = metadata.getToggles(); + assertThat(toggles).hasSize(1); + + final SliceAction primaryAction = metadata.getPrimaryAction(); + final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext, + R.drawable.ic_network_cell); + assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString()); + } + + @Test + public void handleUriChange_turnedOn_updatesMobileData() { + doReturn(false).when(mMobileDataSlice).isAirplaneModeEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + final Intent intent = mMobileDataSlice.getIntent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + + mMobileDataSlice.onNotifyChange(intent); + + verify(mTelephonyManager).setDataEnabled(true); + } + + @Test + public void handleUriChange_turnedOff_updatesMobileData() { + doReturn(false).when(mMobileDataSlice).isAirplaneModeEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + final Intent intent = mMobileDataSlice.getIntent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); + + mMobileDataSlice.onNotifyChange(intent); + + verify(mTelephonyManager).setDataEnabled(false); + } + + @Test + public void handleUriChange_turnedOff_airplaneModeOn_mobileDataDoesNotUpdate() { + doReturn(true).when(mMobileDataSlice).isAirplaneModeEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + final Intent intent = mMobileDataSlice.getIntent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); + + mMobileDataSlice.onNotifyChange(intent); + + verify(mTelephonyManager, times(0)).setDataEnabled(true); + } + + @Test + public void isAirplaneModeEnabled_correctlyReturnsTrue() { + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); + + final boolean isAirplaneModeEnabled = mMobileDataSlice.isAirplaneModeEnabled(); + + assertThat(isAirplaneModeEnabled).isTrue(); + } + + @Test + public void isAirplaneModeEnabled_correctlyReturnsFalse() { + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + + final boolean isAirplaneModeEnabled = mMobileDataSlice.isAirplaneModeEnabled(); + + assertThat(isAirplaneModeEnabled).isFalse(); + } + + @Test + public void isMobileDataEnabled_mobileDataEnabled() { + final boolean seed = true; + doReturn(seed).when(mTelephonyManager).isDataEnabled(); + + final boolean isMobileDataEnabled = mMobileDataSlice.isMobileDataEnabled(); + + assertThat(isMobileDataEnabled).isEqualTo(seed); + } +} diff --git a/tests/robotests/src/com/android/settings/panel/InternetConnectivityPanelTest.java b/tests/robotests/src/com/android/settings/panel/InternetConnectivityPanelTest.java index 3a4cf7b0ba6..42867fb6ca4 100644 --- a/tests/robotests/src/com/android/settings/panel/InternetConnectivityPanelTest.java +++ b/tests/robotests/src/com/android/settings/panel/InternetConnectivityPanelTest.java @@ -46,8 +46,10 @@ public class InternetConnectivityPanelTest { public void getSlices_containsNecessarySlices() { final List uris = mPanel.getSlices(); - assertThat(uris).containsExactly(CustomSliceRegistry.WIFI_SLICE_URI, - CustomSliceRegistry.AIRPLANE_URI); + assertThat(uris).containsExactly( + CustomSliceRegistry.AIRPLANE_URI, + CustomSliceRegistry.MOBILE_DATA_SLICE_URI, + CustomSliceRegistry.WIFI_SLICE_URI); } @Test diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index 7eae3e4ad1a..efdcc264ec0 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -116,7 +116,8 @@ public class SettingsSliceProviderTest { private static final List SPECIAL_CASE_OEM_URIS = Arrays.asList( CustomSliceRegistry.ZEN_MODE_SLICE_URI, - CustomSliceRegistry.FLASHLIGHT_SLICE_URI + CustomSliceRegistry.FLASHLIGHT_SLICE_URI, + CustomSliceRegistry.MOBILE_DATA_SLICE_URI ); @Before From e6d7d3b1e740f56f4891bd3e3f8ee96fea5f6fee Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Wed, 9 Jan 2019 13:15:53 -0800 Subject: [PATCH 2/4] Update search for mobile network settings This CL make all mobile related preferences support: 1. If subId is manually set, check visibility by subId 2. If not, try find whether there is one active subId meets requirement. If so, isAvailable() will return true to enable search. Bug: 77276236 Test: RunSettingsRoboTests Change-Id: I24e2d2f5e882284ba8e997b844caee7722b6b07d --- res/xml/mobile_network_settings.xml | 3 +- .../telephony/ApnPreferenceController.java | 12 +-- .../CarrierPreferenceController.java | 14 +-- .../DataServiceSetupPreferenceController.java | 16 ++-- .../DataUsagePreferenceController.java | 9 +- ...nabledNetworkModePreferenceController.java | 28 +++--- .../Enhanced4gLtePreferenceController.java | 16 ++-- .../telephony/EuiccPreferenceController.java | 9 +- .../MobileDataPreferenceController.java | 11 +-- .../telephony/MobileNetworkSettings.java | 7 +- .../network/telephony/MobileNetworkUtils.java | 50 ++++++++++ ...ferredNetworkModePreferenceController.java | 23 +++-- .../RoamingPreferenceController.java | 11 +-- .../TelephonyAvailabilityCallback.java | 30 ++++++ .../TelephonyBasePreferenceController.java | 40 ++++++++ .../TelephonyTogglePreferenceController.java | 40 ++++++++ .../VideoCallingPreferenceController.java | 10 +- .../WifiCallingPreferenceController.java | 9 +- .../telephony/MobileNetworkUtilsTest.java | 16 +++- ...TelephonyBasePreferenceControllerTest.java | 93 +++++++++++++++++++ 20 files changed, 338 insertions(+), 109 deletions(-) create mode 100644 src/com/android/settings/network/telephony/TelephonyAvailabilityCallback.java create mode 100644 src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java create mode 100644 src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/network/telephony/TelephonyBasePreferenceControllerTest.java diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml index c6eb3e76711..16484f38edc 100644 --- a/res/xml/mobile_network_settings.xml +++ b/res/xml/mobile_network_settings.xml @@ -77,7 +77,8 @@ + android:title="@string/call_category" + settings:searchable="false"> m4gLteListeners; - private int mSubId; public Enhanced4gLtePreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); m4gLteListeners = new ArrayList<>(); mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { - final boolean isVisible = mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID - && mImsManager != null && mCarrierConfig != null + public int getAvailabilityStatus(int subId) { + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + final boolean isVisible = subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + && mImsManager != null && carrierConfig != null && mImsManager.isVolteEnabledByPlatform() && mImsManager.isVolteProvisionedOnDevice() && MobileNetworkUtils.isImsServiceStateReady(mImsManager) - && !mCarrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL); + && !carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL); return isVisible ? (is4gLtePrefEnabled() ? AVAILABLE : AVAILABLE_UNSEARCHABLE) : CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/network/telephony/EuiccPreferenceController.java b/src/com/android/settings/network/telephony/EuiccPreferenceController.java index ae207a28636..ecd20edfc57 100644 --- a/src/com/android/settings/network/telephony/EuiccPreferenceController.java +++ b/src/com/android/settings/network/telephony/EuiccPreferenceController.java @@ -18,31 +18,26 @@ package com.android.settings.network.telephony; import android.content.Context; import android.content.Intent; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import androidx.preference.Preference; -import com.android.settings.core.BasePreferenceController; - /** * Preference controller for "Euicc preference" */ -public class EuiccPreferenceController extends BasePreferenceController { +public class EuiccPreferenceController extends TelephonyBasePreferenceController { private TelephonyManager mTelephonyManager; - private int mSubId; public EuiccPreferenceController(Context context, String key) { super(context, key); mTelephonyManager = context.getSystemService(TelephonyManager.class); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { + public int getAvailabilityStatus(int subId) { return MobileNetworkUtils.showEuiccSettings(mContext) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java index 47822b6fce3..7bf01531f85 100644 --- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java +++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java @@ -40,7 +40,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop; /** * Preference controller for "Mobile data" */ -public class MobileDataPreferenceController extends TogglePreferenceController +public class MobileDataPreferenceController extends TelephonyTogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private static final String DIALOG_TAG = "MobileDataDialog"; @@ -50,7 +50,6 @@ public class MobileDataPreferenceController extends TogglePreferenceController private SubscriptionManager mSubscriptionManager; private DataContentObserver mDataContentObserver; private FragmentManager mFragmentManager; - private int mSubId; @VisibleForTesting int mDialogType; @VisibleForTesting @@ -58,15 +57,13 @@ public class MobileDataPreferenceController extends TogglePreferenceController public MobileDataPreferenceController(Context context, String key) { super(context, key); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { - return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + public int getAvailabilityStatus(int subId) { + return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @@ -74,7 +71,7 @@ public class MobileDataPreferenceController extends TogglePreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey()); + mPreference = screen.findPreference(getPreferenceKey()); } @Override diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index e05f185716a..6d29da19af8 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -114,7 +114,7 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { @Override protected List createPreferenceControllers(Context context) { mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + MobileNetworkUtils.getSearchableSubscriptionId(context)); if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2) && mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { @@ -250,11 +250,6 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { - @Override - protected boolean isPageSearchEnabled(Context context) { - return false; - } - @Override public List getXmlResourcesToIndex(Context context, boolean enabled) { diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java index c5cdd3a03ef..8e44dd418ff 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java +++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java @@ -44,6 +44,8 @@ import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.util.ArrayUtils; +import com.android.settings.core.BasePreferenceController; import java.util.Arrays; import java.util.List; @@ -403,4 +405,52 @@ public class MobileNetworkUtils { } return false; } + + + /** + * Return subId that supported by search. If there are more than one, return first one, + * otherwise return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} + */ + public static int getSearchableSubscriptionId(Context context) { + final SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + final int subIds[] = subscriptionManager.getActiveSubscriptionIdList(); + + return subIds.length >= 1 ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + /** + * Return availability for a default subscription id. If subId already been set, use it to + * check, otherwise traverse all active subIds on device to check. + * @param context context + * @param defSubId Default subId get from telephony preference controller + * @param callback Callback to check availability for a specific subId + * @return Availability + * + * @see BasePreferenceController#getAvailabilityStatus() + */ + public static int getAvailability(Context context, int defSubId, + TelephonyAvailabilityCallback callback) { + final SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + if (defSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + // If subId has been set, return the corresponding status + return callback.getAvailabilityStatus(defSubId); + } else { + // Otherwise, search whether there is one subId in device that support this preference + final int[] subIds = subscriptionManager.getActiveSubscriptionIdList(); + if (ArrayUtils.isEmpty(subIds)) { + return callback.getAvailabilityStatus( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } else { + for (final int subId : subIds) { + final int status = callback.getAvailabilityStatus(subId); + if (status == BasePreferenceController.AVAILABLE) { + return status; + } + } + return callback.getAvailabilityStatus(subIds[0]); + } + } + } } diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java index 0326f42d8c6..27a7bce5bb2 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -35,38 +35,37 @@ import com.android.settings.core.BasePreferenceController; /** * Preference controller for "Preferred network mode" */ -public class PreferredNetworkModePreferenceController extends BasePreferenceController implements - ListPreference.OnPreferenceChangeListener { +public class PreferredNetworkModePreferenceController extends TelephonyBasePreferenceController + implements ListPreference.OnPreferenceChangeListener { private CarrierConfigManager mCarrierConfigManager; private TelephonyManager mTelephonyManager; private PersistableBundle mPersistableBundle; - private int mSubId; private boolean mIsGlobalCdma; public PreferredNetworkModePreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { + public int getAvailabilityStatus(int subId) { + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); boolean visible; - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { visible = false; - } else if (mPersistableBundle == null) { + } else if (carrierConfig == null) { visible = false; - } else if (mPersistableBundle.getBoolean( + } else if (carrierConfig.getBoolean( CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)) { visible = false; - } else if (mPersistableBundle.getBoolean( + } else if (carrierConfig.getBoolean( CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL) && !mTelephonyManager.getServiceState().getRoaming() && mTelephonyManager.getServiceState().getDataRegState() == ServiceState.STATE_IN_SERVICE) { visible = false; - } else if (mPersistableBundle.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { + } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { visible = true; } else { visible = false; @@ -100,13 +99,13 @@ public class PreferredNetworkModePreferenceController extends BasePreferenceCont public void init(int subId) { mSubId = subId; - mPersistableBundle = mCarrierConfigManager.getConfigForSubId(mSubId); + final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); final boolean isLteOnCdma = mTelephonyManager.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE; mIsGlobalCdma = isLteOnCdma - && mPersistableBundle.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL); + && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL); } private int getPreferredNetworkMode() { diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java index 688268c7887..4140d5d9709 100644 --- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java +++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.java @@ -42,7 +42,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop; /** * Preference controller for "Roaming" */ -public class RoamingPreferenceController extends TogglePreferenceController implements +public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private static final String DIALOG_TAG = "MobileDataDialog"; @@ -50,7 +50,6 @@ public class RoamingPreferenceController extends TogglePreferenceController impl private RestrictedSwitchPreference mSwitchPreference; private TelephonyManager mTelephonyManager; private CarrierConfigManager mCarrierConfigManager; - private int mSubId; private DataContentObserver mDataContentObserver; @VisibleForTesting boolean mNeedDialog; @@ -59,10 +58,8 @@ public class RoamingPreferenceController extends TogglePreferenceController impl public RoamingPreferenceController(Context context, String key) { super(context, key); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override @@ -78,12 +75,12 @@ public class RoamingPreferenceController extends TogglePreferenceController impl @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - mSwitchPreference = (RestrictedSwitchPreference) screen.findPreference(getPreferenceKey()); + mSwitchPreference = screen.findPreference(getPreferenceKey()); } @Override - public int getAvailabilityStatus() { - return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + public int getAvailabilityStatus(int subId) { + return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? AVAILABLE : AVAILABLE_UNSEARCHABLE; } diff --git a/src/com/android/settings/network/telephony/TelephonyAvailabilityCallback.java b/src/com/android/settings/network/telephony/TelephonyAvailabilityCallback.java new file mode 100644 index 00000000000..d60bccdbc1f --- /dev/null +++ b/src/com/android/settings/network/telephony/TelephonyAvailabilityCallback.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 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; + +/** + * Callback to decide whether preference is available based on subscription id + */ +public interface TelephonyAvailabilityCallback { + /** + * Return availability status for a specific subId + * + * @see TelephonyBasePreferenceController + * @see TelephonyTogglePreferenceController + */ + int getAvailabilityStatus(int subId); +} diff --git a/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java new file mode 100644 index 00000000000..e4ff5c4c78e --- /dev/null +++ b/src/com/android/settings/network/telephony/TelephonyBasePreferenceController.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 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.telephony.SubscriptionManager; + +import com.android.settings.core.BasePreferenceController; + +/** + * {@link BasePreferenceController} that used by all preferences that requires subscription id. + */ +public abstract class TelephonyBasePreferenceController extends BasePreferenceController + implements TelephonyAvailabilityCallback { + protected int mSubId; + + public TelephonyBasePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + @Override + public int getAvailabilityStatus() { + return MobileNetworkUtils.getAvailability(mContext, mSubId, this::getAvailabilityStatus); + } +} diff --git a/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java b/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java new file mode 100644 index 00000000000..71efc57fb5a --- /dev/null +++ b/src/com/android/settings/network/telephony/TelephonyTogglePreferenceController.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 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.telephony.SubscriptionManager; + +import com.android.settings.core.TogglePreferenceController; + +/** + * {@link TogglePreferenceController} that used by all preferences that requires subscription id. + */ +public abstract class TelephonyTogglePreferenceController extends TogglePreferenceController + implements TelephonyAvailabilityCallback { + protected int mSubId; + + public TelephonyTogglePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + @Override + public int getAvailabilityStatus() { + return MobileNetworkUtils.getAvailability(mContext, mSubId, this::getAvailabilityStatus); + } +} diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java index 1007ef8e03a..44984e65dc3 100644 --- a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java @@ -42,7 +42,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop; /** * Preference controller for "Video Calling" */ -public class VideoCallingPreferenceController extends TogglePreferenceController implements +public class VideoCallingPreferenceController extends TelephonyTogglePreferenceController implements LifecycleObserver, OnStart, OnStop, Enhanced4gLtePreferenceController.On4gLteUpdateListener { @@ -54,21 +54,19 @@ public class VideoCallingPreferenceController extends TogglePreferenceController ImsManager mImsManager; private PhoneCallStateListener mPhoneStateListener; private DataContentObserver mDataContentObserver; - private int mSubId; public VideoCallingPreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { - return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + public int getAvailabilityStatus(int subId) { + return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && MobileNetworkUtils.isWifiCallingEnabled(mContext, - SubscriptionManager.getPhoneId(mSubId)) + SubscriptionManager.getPhoneId(subId)) && isVideoCallEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java index ec9a8412b4b..26c4d06d853 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java @@ -33,7 +33,6 @@ import androidx.preference.PreferenceScreen; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; -import com.android.settings.core.BasePreferenceController; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; @@ -43,7 +42,7 @@ import java.util.List; /** * Preference controller for "Wifi Calling" */ -public class WifiCallingPreferenceController extends BasePreferenceController implements +public class WifiCallingPreferenceController extends TelephonyBasePreferenceController implements LifecycleObserver, OnStart, OnStop { @VisibleForTesting @@ -56,19 +55,17 @@ public class WifiCallingPreferenceController extends BasePreferenceController im PhoneAccountHandle mSimCallManager; private PhoneCallStateListener mPhoneStateListener; private Preference mPreference; - private int mSubId; public WifiCallingPreferenceController(Context context, String key) { super(context, key); mTelephonyManager = context.getSystemService(TelephonyManager.class); mSimCallManager = context.getSystemService(TelecomManager.class).getSimCallManager(); mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override - public int getAvailabilityStatus() { - return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + public int getAvailabilityStatus(int subId) { + return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && MobileNetworkUtils.isWifiCallingEnabled(mContext, SubscriptionManager.getPhoneId(mSubId)) ? AVAILABLE diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java index 34e680e55f2..7dfe520b614 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java @@ -41,7 +41,6 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.telephony.PhoneConstants; -import com.android.settings.R; import org.junit.Before; import org.junit.Test; @@ -184,4 +183,19 @@ public class MobileNetworkUtilsTest { assertThat(MobileNetworkUtils.isCdmaOptions(mContext, SUB_ID_1)).isTrue(); } + + @Test + public void getSearchableSubscriptionId_oneActive_returnValid() { + when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID_1}); + + assertThat(MobileNetworkUtils.getSearchableSubscriptionId(mContext)).isEqualTo(SUB_ID_1); + } + + @Test + public void getSearchableSubscriptionId_nonActive_returnInvalid() { + when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[0]); + + assertThat(MobileNetworkUtils.getSearchableSubscriptionId(mContext)) + .isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/TelephonyBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/TelephonyBasePreferenceControllerTest.java new file mode 100644 index 00000000000..886ea177d9f --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/TelephonyBasePreferenceControllerTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 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.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.SubscriptionManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class TelephonyBasePreferenceControllerTest { + private static final int VALID_SUB_ID = 1; + + @Mock + private SubscriptionManager mSubscriptionManager; + + private TestPreferenceController mPreferenceController; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(SubscriptionManager.class)) + .thenReturn(mSubscriptionManager); + when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{}); + mPreferenceController = new TestPreferenceController(mContext, "prefKey"); + } + + @Test + public void isAvailable_validSubIdSet_returnTrue() { + mPreferenceController.init(VALID_SUB_ID); + + assertThat(mPreferenceController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_noIdSetHoweverHasDefaultOne_returnTrue() { + when(mSubscriptionManager.getActiveSubscriptionIdList()) + .thenReturn(new int[]{VALID_SUB_ID}); + + assertThat(mPreferenceController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_noDefaultAndNoSet_returnFalse() { + assertThat(mPreferenceController.isAvailable()).isFalse(); + } + + /** + * Test preference controller for {@link TelephonyBasePreferenceController} + */ + public class TestPreferenceController extends TelephonyBasePreferenceController { + public TestPreferenceController(Context context, String prefKey) { + super(context, prefKey); + } + + public void init(int subId) { + mSubId = subId; + } + + @Override + public int getAvailabilityStatus(int subId) { + return subId == VALID_SUB_ID ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + } +} From 07df08950a9805a15b5c2e90480e920c5a8c3957 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 11 Feb 2019 13:17:07 -0800 Subject: [PATCH 3/4] Don't load anything from contextual card db in legacy mode. Change-Id: I2fa1ee78bb8878c2cf46fd2f59499c9ed8eb0a09 Fixes: 124246284 Test: robotest --- .../homepage/contextualcards/ContextualCardLoader.java | 5 +++++ .../contextualcards/ContextualCardLoaderTest.java | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java index 88c489b4d7f..c0d4779445e 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java @@ -39,6 +39,7 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.slice.Slice; +import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.utils.AsyncLoaderCompat; @@ -94,6 +95,10 @@ public class ContextualCardLoader extends AsyncLoaderCompat @Override public List loadInBackground() { final List result = new ArrayList<>(); + if (mContext.getResources().getBoolean(R.bool.config_use_legacy_suggestion)) { + Log.d(TAG, "Skipping - in legacy suggestion mode"); + return result; + } try (Cursor cursor = getContextualCardsFromProvider()) { if (cursor.getCount() > 0) { for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 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 c47fa38868d..f04008b199e 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.net.Uri; +import com.android.settings.R; import com.android.settings.slices.CustomSliceRegistry; import org.junit.Before; @@ -132,6 +133,14 @@ public class ContextualCardLoaderTest { assertThat(result).hasSize(2); } + @Test + public void loadInBackground_legacyMode_shouldReturnNothing() { + assertThat(mContext.getResources().getBoolean(R.bool.config_use_legacy_suggestion)) + .isTrue(); + + assertThat(mContextualCardLoader.loadInBackground()).isEmpty(); + } + private ContextualCard getContextualCard(String sliceUri) { return new ContextualCard.Builder() .setName("test_card") From 671a39f905502d6ffcb77091b557b0d27020be2b Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 11 Feb 2019 14:38:13 -0800 Subject: [PATCH 4/4] Remove intent-filters from SettingsSliceProvider And remove unused methods from SliceDeepLinkSpringBoard. This is part 1 of b/110156445 Bug: 110156445 Test: atest Change-Id: Iab36a97332fd847ed911a9e34b505fd4a64522d3 --- AndroidManifest.xml | 11 +-- .../slices/SettingsSliceProvider.java | 14 --- .../slices/SliceDeepLinkSpringBoard.java | 10 -- .../slices/SliceDeepLinkSpringBoardTest.java | 99 ------------------- 4 files changed, 1 insertion(+), 133 deletions(-) delete mode 100644 tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 90aa55ff1a7..32a21b5983a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3021,16 +3021,7 @@ - - - - - - - - + android:grantUriPermissions="true" />