Merge "Add intent action for BT device detail page"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e0910f2..6cb0023 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -443,7 +443,7 @@
android:exported="true"
android:permission="android.permission.TETHER_PRIVILEGED" />
- <activity android:name="TetherProvisioningActivity"
+ <activity android:name="network.TetherProvisioningActivity"
android:exported="true"
android:permission="android.permission.TETHER_PRIVILEGED"
android:excludeFromRecents="true"
@@ -3003,7 +3003,7 @@
android:label="@string/settings_panel_title"
android:theme="@style/Theme.BottomDialog"
android:excludeFromRecents="true"
- android:launchMode="singleTask"
+ android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.settings.panel.action.INTERNET_CONNECTIVITY" />
@@ -3033,16 +3033,7 @@
<provider android:name=".slices.SettingsSliceProvider"
android:authorities="com.android.settings.slices;android.settings.slices"
android:exported="true"
- android:grantUriPermissions="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.app.slice.category.SLICE" />
- <data android:scheme="settings"
- android:host="com.android.settings.slices" />
- </intent-filter>
- </provider>
+ android:grantUriPermissions="true" />
<receiver
android:name=".slices.SliceBroadcastReceiver"
diff --git a/res/drawable/ic_system_update.xml b/res/drawable/ic_system_update.xml
deleted file mode 100644
index 3325fdd..0000000
--- a/res/drawable/ic_system_update.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
-</vector>
diff --git a/res/drawable/ic_system_update_vd_theme_24.xml b/res/drawable/ic_system_update_vd_theme_24.xml
deleted file mode 100644
index d1fc061..0000000
--- a/res/drawable/ic_system_update_vd_theme_24.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
-</vector>
diff --git a/res/values/config.xml b/res/values/config.xml
index 3023067..c2899ef 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -353,4 +353,7 @@
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
<bool name="config_enable_extra_screen_zoom_preview">true</bool>
+
+ <!-- Slice Uri to query nearby devices. -->
+ <string name="config_nearby_devices_slice_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/device_status_list_item</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6b30ab1..9281979 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10503,6 +10503,9 @@
<string name="preferred_network_mode_dialogtitle">Preferred network type</string>
<!-- Mobile network settings screen, name of the option to manage carrier profiles on devices which support embedded carrier profiles [CHAR LIMIT=NONE] -->
<string name="carrier_settings_euicc">Carrier</string>
+ <!-- Mobile network settings screen, a string showing the version of carrier settings for this
+ subscription [CHAR LIMIT=NONE] -->
+ <string name="carrier_settings_version">Settings version</string>
<!-- Mobile network settings screen, name for call settings category [CHAR LIMIT=NONE] -->
<string name="call_category">Calling</string>
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index 29c9e01..ae88d36 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -20,6 +20,12 @@
android:key="connected_devices_screen"
android:title="@string/connected_devices_dashboard_title">
+ <com.android.settings.slices.SlicePreference
+ android:key="bt_nearby_slice"
+ android:title="@string/summary_placeholder"
+ settings:controller="com.android.settings.slices.SlicePreferenceController"
+ settings:allowDividerBelow="true"/>
+
<PreferenceCategory
android:key="available_device_list"
android:title="@string/connected_device_available_media_title"
diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml
index f269fad..c3bb656 100644
--- a/res/xml/mobile_network_settings_v2.xml
+++ b/res/xml/mobile_network_settings_v2.xml
@@ -98,6 +98,12 @@
android:title="@string/carrier_settings_euicc"
settings:controller="com.android.settings.network.telephony.EuiccPreferenceController" />
+ <Preference
+ android:key="carrier_settings_version_key"
+ android:title="@string/carrier_settings_version"
+ settings:controller="com.android.settings.network.telephony.CarrierSettingsVersionPreferenceController"
+ settings:enableCopying="true" />
+
<PreferenceCategory
android:key="calling_category"
android:title="@string/call_category">
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index 3f2e55f..c4bd11d 100644
--- a/res/xml/storage_dashboard_fragment.xml
+++ b/res/xml/storage_dashboard_fragment.xml
@@ -66,7 +66,7 @@
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_system"
android:title="@string/storage_detail_system"
- android:icon="@drawable/ic_system_update_vd_theme_24"
+ android:icon="@drawable/ic_system_update"
android:order="100" />
<PreferenceCategory
android:key="pref_secondary_users"
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 93a785f..65cfdf6 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -71,6 +71,7 @@
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.Spannable;
import android.text.SpannableString;
@@ -958,6 +959,22 @@
}
/**
+ * Converts the {@link Drawable} to a {@link Bitmap}.
+ */
+ public static Bitmap drawableToBitmap(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable)drawable).getBitmap();
+ }
+
+ final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+ /**
* Get the {@link Drawable} that represents the app icon
*/
public static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory,
@@ -980,4 +997,13 @@
}
return false;
}
+
+ /** Get {@link Resources} by subscription id if subscription id is valid. */
+ public static Resources getResourcesForSubId(Context context, int subId) {
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return SubscriptionManager.getResourcesForSubId(context, subId);
+ } else {
+ return context.getResources();
+ }
+ }
}
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index b84cc26..d5cfdcc 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -17,6 +17,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.net.Uri;
import android.provider.SearchIndexableResource;
import androidx.annotation.VisibleForTesting;
@@ -24,6 +25,7 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
@@ -88,6 +90,8 @@
use(ConnectedDeviceGroupController.class).init(this);
use(PreviouslyConnectedDevicePreferenceController.class).init(this);
use(DiscoverableFooterPreferenceController.class).init(this);
+ use(SlicePreferenceController.class).setSliceUri(
+ Uri.parse(getString(R.string.config_nearby_devices_slice_uri)));
}
/**
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 998234b..15c7754 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -84,8 +84,10 @@
private PreferenceCategory mAppList;
private Drawable mIcon;
- private CharSequence mLabel;
- private String mPackageName;
+ @VisibleForTesting
+ CharSequence mLabel;
+ @VisibleForTesting
+ String mPackageName;
private CycleAdapter mCycleAdapter;
private List<NetworkCycleDataForUid> mUsageData;
@@ -133,29 +135,32 @@
mForegroundUsage = findPreference(KEY_FOREGROUND_USAGE);
mBackgroundUsage = findPreference(KEY_BACKGROUND_USAGE);
- mCycle = (SpinnerPreference) findPreference(KEY_CYCLE);
+ mCycle = findPreference(KEY_CYCLE);
mCycleAdapter = new CycleAdapter(mContext, mCycle, mCycleListener);
+ final UidDetailProvider uidDetailProvider = getUidDetailProvider();
+
if (mAppItem.key > 0) {
- if (mPackages.size() != 0) {
- try {
- ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(
- mPackages.valueAt(0), 0, UserHandle.getUserId(mAppItem.key));
- mIcon = IconDrawableFactory.newInstance(getActivity()).getBadgedIcon(info);
- mLabel = info.loadLabel(mPackageManager);
- mPackageName = info.packageName;
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
if (!UserHandle.isApp(mAppItem.key)) {
+ final UidDetail uidDetail = uidDetailProvider.getUidDetail(mAppItem.key, true);
+ mIcon = uidDetail.icon;
+ mLabel = uidDetail.label;
removePreference(KEY_UNRESTRICTED_DATA);
removePreference(KEY_RESTRICT_BACKGROUND);
} else {
- mRestrictBackground = (RestrictedSwitchPreference) findPreference(
- KEY_RESTRICT_BACKGROUND);
+ if (mPackages.size() != 0) {
+ try {
+ final ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(
+ mPackages.valueAt(0), 0, UserHandle.getUserId(mAppItem.key));
+ mIcon = IconDrawableFactory.newInstance(getActivity()).getBadgedIcon(info);
+ mLabel = info.loadLabel(mPackageManager);
+ mPackageName = info.packageName;
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ mRestrictBackground = findPreference(KEY_RESTRICT_BACKGROUND);
mRestrictBackground.setOnPreferenceChangeListener(this);
- mUnrestrictedData = (RestrictedSwitchPreference) findPreference(
- KEY_UNRESTRICTED_DATA);
+ mUnrestrictedData = findPreference(KEY_UNRESTRICTED_DATA);
mUnrestrictedData.setOnPreferenceChangeListener(this);
}
mDataSaverBackend = new DataSaverBackend(mContext);
@@ -164,7 +169,7 @@
mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
- PackageManager pm = getPackageManager();
+ final PackageManager pm = getPackageManager();
boolean matchFound = false;
for (String packageName : mPackages) {
mAppSettingsIntent.setPackage(packageName);
@@ -179,7 +184,7 @@
}
if (mPackages.size() > 1) {
- mAppList = (PreferenceCategory) findPreference(KEY_APP_LIST);
+ mAppList = findPreference(KEY_APP_LIST);
LoaderManager.getInstance(this).restartLoader(LOADER_APP_PREF, Bundle.EMPTY,
mAppPrefCallbacks);
} else {
@@ -187,7 +192,7 @@
}
} else {
final Context context = getActivity();
- UidDetail uidDetail = new UidDetailProvider(context).getUidDetail(mAppItem.key, true);
+ final UidDetail uidDetail = uidDetailProvider.getUidDetail(mAppItem.key, true);
mIcon = uidDetail.icon;
mLabel = uidDetail.label;
mPackageName = context.getPackageName();
@@ -257,6 +262,11 @@
updatePrefs(getAppRestrictBackground(), getUnrestrictData());
}
+ @VisibleForTesting
+ UidDetailProvider getUidDetailProvider() {
+ return new UidDetailProvider(mContext);
+ }
+
private void updatePrefs(boolean restrictBackground, boolean unrestrictData) {
final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfMeteredDataRestricted(
mContext, mPackageName, UserHandle.getUserId(mAppItem.key));
@@ -276,7 +286,7 @@
}
private void addUid(int uid) {
- String[] packages = getPackageManager().getPackagesForUid(uid);
+ String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
mPackages.add(packages[i]);
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index 735532a..8eeb925 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -33,6 +33,7 @@
import android.net.NetworkPolicy;
import android.net.NetworkTemplate;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -362,7 +363,8 @@
category = AppItem.CATEGORY_USER;
}
}
- } else if (uid == UID_REMOVED || uid == UID_TETHERING) {
+ } else if (uid == UID_REMOVED || uid == UID_TETHERING
+ || uid == Process.OTA_UPDATE_UID) {
collapseKey = uid;
category = AppItem.CATEGORY_APP;
} else {
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 88c489b..7a0eb0f 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.VisibleForTesting;
import androidx.slice.Slice;
+import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -51,7 +52,7 @@
@VisibleForTesting
static final int DEFAULT_CARD_COUNT = 4;
static final int CARD_CONTENT_LOADER_ID = 1;
- static final long CARD_CONTENT_LOADER_TIMEOUT_MS = DateUtils.SECOND_IN_MILLIS;
+ static final long CARD_CONTENT_LOADER_TIMEOUT_MS = DateUtils.SECOND_IN_MILLIS * 3;
private static final String TAG = "ContextualCardLoader";
@@ -94,6 +95,10 @@
@Override
public List<ContextualCard> loadInBackground() {
final List<ContextualCard> 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()) {
@@ -170,6 +175,7 @@
@VisibleForTesting
boolean isCardEligibleToDisplay(ContextualCard card) {
+ final long startTime = System.currentTimeMillis();
if (card.isCustomCard()) {
return true;
}
@@ -190,6 +196,10 @@
provider.release();
final Slice slice = Slice.bindSlice(mContext, uri, SUPPORTED_SPECS);
+ //TODO(b/123668403): remove the log here once we do the change with FutureTask
+ final long bindTime = System.currentTimeMillis() - startTime;
+ Log.d(TAG, "Binding time for " + uri + " = " + bindTime);
+
if (slice == null || slice.hasHint(HINT_ERROR)) {
Log.w(TAG, "Failed to bind slice, not eligible for display " + uri);
return false;
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index b35a38a..344c248 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -188,6 +188,8 @@
@Override
public void onFinishCardLoading(List<ContextualCard> cards) {
final long loadTime = System.currentTimeMillis() - mStartTime;
+ //TODO(b/123668403): remove the log here once we do the change with FutureTask
+ Log.d(TAG, "Total loading time = " + loadTime);
final List<ContextualCard> cardsToKeep = getCardsToKeep(cards);
//navigate back to the homepage or after card dismissal
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index ea2a308..5673948 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -21,9 +21,6 @@
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@@ -84,17 +81,6 @@
mContext = context;
}
- private static Bitmap getBitmapFromVectorDrawable(Drawable VectorDrawable) {
- final Bitmap bitmap = Bitmap.createBitmap(VectorDrawable.getIntrinsicWidth(),
- VectorDrawable.getIntrinsicHeight(), Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
-
- VectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- VectorDrawable.draw(canvas);
-
- return bitmap;
- }
-
@Override
public Uri getUri() {
return CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
@@ -234,7 +220,7 @@
.getBtClassDrawableWithDescription(mContext, device);
if (pair.first != null) {
- return IconCompat.createWithBitmap(getBitmapFromVectorDrawable(pair.first));
+ return IconCompat.createWithBitmap(Utils.drawableToBitmap(pair.first));
} else {
return IconCompat.createWithResource(mContext,
com.android.internal.R.drawable.ic_settings_bluetooth);
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
index 016aa32..692dc0a 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
@@ -142,20 +142,6 @@
mNotificationBackend = new NotificationBackend();
}
- private static Bitmap drawableToBitmap(Drawable drawable) {
- if (drawable instanceof BitmapDrawable) {
- return ((BitmapDrawable) drawable).getBitmap();
- }
-
- final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
-
- return bitmap;
- }
-
@Override
public Slice getSlice() {
final ListBuilder listBuilder =
@@ -257,7 +243,7 @@
return null;
}
- return IconCompat.createWithBitmap(drawableToBitmap(drawable));
+ return IconCompat.createWithBitmap(Utils.drawableToBitmap(drawable));
}
@VisibleForTesting
diff --git a/src/com/android/settings/TetherProvisioningActivity.java b/src/com/android/settings/network/TetherProvisioningActivity.java
similarity index 89%
rename from src/com/android/settings/TetherProvisioningActivity.java
rename to src/com/android/settings/network/TetherProvisioningActivity.java
index e842db1..b30950e 100644
--- a/src/com/android/settings/TetherProvisioningActivity.java
+++ b/src/com/android/settings/network/TetherProvisioningActivity.java
@@ -14,17 +14,21 @@
* limitations under the License.
*/
-package com.android.settings;
+package com.android.settings.network;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.os.UserHandle;
+import android.telephony.SubscriptionManager;
import android.util.Log;
+import com.android.settings.Utils;
+
/**
* Activity which acts as a proxy to the tether provisioning app for sanity checks and permission
* restrictions. Specifically, the provisioning apps require
@@ -47,7 +51,9 @@
int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE,
ConnectivityManager.TETHERING_INVALID);
- String[] provisionApp = getResources().getStringArray(
+ final int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ final Resources res = Utils.getResourcesForSubId(this, subId);
+ final String[] provisionApp = res.getStringArray(
com.android.internal.R.array.config_mobile_hotspot_provision_app);
Intent intent = new Intent(Intent.ACTION_MAIN);
diff --git a/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceController.java b/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceController.java
new file mode 100644
index 0000000..a6db773
--- /dev/null
+++ b/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceController.java
@@ -0,0 +1,54 @@
+/*
+ * 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.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class CarrierSettingsVersionPreferenceController extends BasePreferenceController {
+
+ private int mSubscriptionId;
+ private CarrierConfigManager mManager;
+
+ public CarrierSettingsVersionPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mManager = context.getSystemService(CarrierConfigManager.class);
+ mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ public void init(int subscriptionId) {
+ mSubscriptionId = subscriptionId;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ final PersistableBundle config = mManager.getConfigForSubId(mSubscriptionId);
+ if (config == null) {
+ return null;
+ }
+ return config.getString(CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index 7bf0153..f678e08 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -119,6 +119,14 @@
&& 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;
@@ -169,10 +177,7 @@
}
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 0000000..6efd8c3
--- /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.
+ * <p>
+ * 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.
+ *
+ * </p>
+ *
+ */
+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<? extends SliceBackgroundWorker> 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.
+ *
+ * <p>
+ * 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<Void> {
+
+ 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/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 6d29da1..4f9f020 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -133,6 +133,7 @@
use(CallsDefaultSubscriptionController.class).init(getLifecycle());
use(SmsDefaultSubscriptionController.class).init(getLifecycle());
use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
+ use(CarrierSettingsVersionPreferenceController.class).init(mSubId);
}
use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java
index aae42f8..d20b75a 100644
--- a/src/com/android/settings/panel/InternetConnectivityPanel.java
+++ b/src/com/android/settings/panel/InternetConnectivityPanel.java
@@ -55,6 +55,7 @@
public List<Uri> getSlices() {
final List<Uri> 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/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java
index 8e8e7bc..d7445e6 100644
--- a/src/com/android/settings/password/SetNewPasswordActivity.java
+++ b/src/com/android/settings/password/SetNewPasswordActivity.java
@@ -16,7 +16,7 @@
package com.android.settings.password;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
@@ -83,7 +83,7 @@
if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
&& getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
final boolean hasPermission = PasswordUtils.isCallingAppPermitted(
- this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ this, activityToken, REQUEST_SCREEN_LOCK_COMPLEXITY);
if (hasPermission) {
mRequestedMinComplexity =
PasswordMetrics.sanitizeComplexityLevel(getIntent()
@@ -91,7 +91,7 @@
} else {
PasswordUtils.crashCallingApplication(activityToken,
"Must have permission "
- + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY + " to use extra "
+ + REQUEST_SCREEN_LOCK_COMPLEXITY + " to use extra "
+ EXTRA_PASSWORD_COMPLEXITY);
finish();
return;
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index 33c3edb..7fbb211 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -16,7 +16,7 @@
package com.android.settings.password;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -82,10 +82,10 @@
if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
IBinder activityToken = getActivityToken();
boolean hasPermission = PasswordUtils.isCallingAppPermitted(
- this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ this, activityToken, REQUEST_SCREEN_LOCK_COMPLEXITY);
if (!hasPermission) {
PasswordUtils.crashCallingApplication(activityToken,
- "Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
+ "Must have permission " + REQUEST_SCREEN_LOCK_COMPLEXITY
+ " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
finish();
return;
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 3786c5c..c9e473a 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -18,7 +18,6 @@
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.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 @@
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 66e85c0..ab1b248 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -164,6 +164,16 @@
.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 b538b89..220cdc8 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -71,7 +71,7 @@
*
* @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 @@
}
/**
- * 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<? extends SliceBackgroundWorker>} to perform background work for the
+ * slice.
*/
default Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
return null;
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 80b7133..d1648e0 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -21,7 +21,6 @@
import android.app.slice.SliceManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.StrictMode;
@@ -46,7 +45,6 @@
import com.android.settingslib.SliceBroadcastRelay;
import com.android.settingslib.utils.ThreadUtils;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -150,18 +148,6 @@
}
@Override
- public Uri onMapIntentToUri(Intent intent) {
- try {
- return getContext().getSystemService(SliceManager.class).mapIntentToUri(
- SliceDeepLinkSpringBoard.parse(
- intent.getData(), getContext().getPackageName()));
- } catch (URISyntaxException e) {
- Log.e(TAG, "Uri syntax error, can't map intent to uri.", e);
- return null;
- }
- }
-
- @Override
public void onSlicePinned(Uri sliceUri) {
if (mCustomSliceManager.isValidUri(sliceUri)) {
final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(sliceUri);
@@ -464,8 +450,9 @@
private List<Uri> 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 6df45ba..995394e 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -59,6 +59,14 @@
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 @@
/**
* 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/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index d633b7a..f4afa16 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -21,94 +21,58 @@
import android.provider.Settings;
import android.util.Log;
-import androidx.annotation.Keep;
-
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
-import java.net.URISyntaxException;
-
public class SliceDeepLinkSpringBoard extends Activity {
private static final String TAG = "DeeplinkSpringboard";
- public static final String INTENT = "intent";
- public static final String SETTINGS = "settings";
- public static final String ACTION_VIEW_SLICE = "com.android.settings.action.VIEW_SLICE";
public static final String EXTRA_SLICE = "slice";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Uri uri = getIntent().getData();
- if (uri == null) {
+ final Uri sliceUri = parse(getIntent().getData());
+ if (sliceUri == null) {
Log.e(TAG, "No data found");
finish();
return;
}
try {
- Intent intent = parse(uri, getPackageName());
- if (ACTION_VIEW_SLICE.equals(intent.getAction())) {
- // This shouldn't matter since the slice is shown instead of the device
- // index caring about the launch uri.
- final Uri sliceUri = Uri.parse(intent.getStringExtra(EXTRA_SLICE));
- Intent launchIntent;
+ // This shouldn't matter since the slice is shown instead of the device
+ // index caring about the launch uri.
+ Intent launchIntent;
- // TODO (b/80263568) Avoid duplicating this list of Slice Uris.
- final CustomSliceManager customSliceManager = FeatureFactory.getFactory(this)
- .getSlicesFeatureProvider().getCustomSliceManager(this);
- if (customSliceManager.isValidUri(sliceUri)) {
- final CustomSliceable sliceable =
- customSliceManager.getSliceableFromUri(sliceUri);
- launchIntent = sliceable.getIntent();
- } else if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) {
- launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
- } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
- launchIntent = BluetoothSliceBuilder.getIntent(this /* context */);
- } else {
- final SlicesDatabaseAccessor slicesDatabaseAccessor =
- new SlicesDatabaseAccessor(this /* context */);
- // Sadly have to block here because we don't know where to go.
- final SliceData sliceData =
- slicesDatabaseAccessor.getSliceDataFromUri(sliceUri);
- launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData);
- }
-
- startActivity(launchIntent);
+ // TODO (b/80263568) Avoid duplicating this list of Slice Uris.
+ final CustomSliceManager customSliceManager = FeatureFactory.getFactory(this)
+ .getSlicesFeatureProvider().getCustomSliceManager(this);
+ if (customSliceManager.isValidUri(sliceUri)) {
+ final CustomSliceable sliceable =
+ customSliceManager.getSliceableFromUri(sliceUri);
+ launchIntent = sliceable.getIntent();
+ } else if (CustomSliceRegistry.ZEN_MODE_SLICE_URI.equals(sliceUri)) {
+ launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
+ } else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
+ launchIntent = BluetoothSliceBuilder.getIntent(this /* context */);
} else {
- startActivity(intent);
+ final SlicesDatabaseAccessor slicesDatabaseAccessor =
+ new SlicesDatabaseAccessor(this /* context */);
+ // Sadly have to block here because we don't know where to go.
+ final SliceData sliceData =
+ slicesDatabaseAccessor.getSliceDataFromUri(sliceUri);
+ launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData);
}
+ startActivity(launchIntent);
finish();
- } catch (URISyntaxException e) {
- Log.e(TAG, "Error decoding uri", e);
- finish();
- } catch (IllegalStateException e) {
+ } catch (Exception e) {
Log.w(TAG, "Couldn't launch Slice intent", e);
startActivity(new Intent(Settings.ACTION_SETTINGS));
finish();
}
}
- @Keep
- public static Uri createDeepLink(String s) {
- return new Uri.Builder().scheme(SETTINGS)
- .authority(SettingsSliceProvider.SLICE_AUTHORITY)
- .appendQueryParameter(INTENT, s)
- .build();
- }
-
- public static Intent parse(Uri uri, String pkg) throws URISyntaxException {
- Intent intent = Intent.parseUri(uri.getQueryParameter(INTENT),
- Intent.URI_ANDROID_APP_SCHEME);
- // Start with some really strict constraints and loosen them if we need to.
- // Don't allow components.
- intent.setComponent(null);
- // Clear out the extras.
- if (intent.getExtras() != null) {
- intent.getExtras().clear();
- }
- // Make sure this points at Settings.
- intent.setPackage(pkg);
- return intent;
+ private static Uri parse(Uri uri) {
+ return Uri.parse(uri.getQueryParameter(EXTRA_SLICE));
}
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 4aac538..65be11c 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -19,6 +19,9 @@
import android.app.ActionBar;
import android.app.settings.SettingsEnums;
import android.content.Intent;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -31,6 +34,8 @@
import com.android.settings.R;
import com.android.settings.core.InstrumentedActivity;
+import java.util.List;
+
/**
* To provision "other" device with specified Wi-Fi network.
*
@@ -78,6 +83,7 @@
/** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE */
private WifiQrCode mWifiDppQrCode;
+
/** Secret extra that allows fake networks to show in UI for testing purposes */
private boolean mIsTest;
@@ -90,6 +96,9 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.wifi_dpp_activity);
+ mFragmentManager = getSupportFragmentManager();
+
if (savedInstanceState != null) {
String qrCode = savedInstanceState.getString(KEY_QR_CODE);
@@ -103,13 +112,10 @@
mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid,
preSharedKey, hiddenSsid, networkId);
+ } else {
+ handleIntent(getIntent());
}
- setContentView(R.layout.wifi_dpp_activity);
- mFragmentManager = getSupportFragmentManager();
-
- handleIntent(getIntent());
-
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setElevation(0);
@@ -150,7 +156,13 @@
if (mWifiDppQrCode == null || !isDppSupported) {
cancelActivity = true;
} else {
- showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
+ final WifiNetworkConfig connectedConfig = getConnectedWifiNetworkConfigOrNull();
+ if (connectedConfig == null) {
+ showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
+ } else {
+ mWifiNetworkConfig = connectedConfig;
+ showAddDeviceFragment(/* addToBackStack */ false);
+ }
}
break;
default:
@@ -167,13 +179,18 @@
WifiDppQrCodeScannerFragment fragment =
(WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
- // Avoid to replace the same fragment during configuration change
- if (fragment != null && fragment.isVisible()) {
- return;
- }
if (fragment == null) {
fragment = new WifiDppQrCodeScannerFragment();
+ } else {
+ if (fragment.isVisible()) {
+ return;
+ }
+
+ // When the fragment in back stack but not on top of the stack, we can simply pop
+ // stack because current fragment transactions are arranged in an order
+ mFragmentManager.popBackStackImmediate();
+ return;
}
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
@@ -189,12 +206,19 @@
WifiDppQrCodeGeneratorFragment fragment =
(WifiDppQrCodeGeneratorFragment) mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
- // Avoid to replace the same fragment during configuration change
- if (fragment != null && fragment.isVisible()) {
+
+ if (fragment == null) {
+ fragment = new WifiDppQrCodeGeneratorFragment();
+ } else {
+ if (fragment.isVisible()) {
+ return;
+ }
+
+ // When the fragment in back stack but not on top of the stack, we can simply pop
+ // stack because current fragment transactions are arranged in an order
+ mFragmentManager.popBackStackImmediate();
return;
}
-
- fragment = new WifiDppQrCodeGeneratorFragment();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
@@ -206,10 +230,6 @@
WifiDppChooseSavedWifiNetworkFragment fragment =
(WifiDppChooseSavedWifiNetworkFragment) mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
- // Avoid to replace the same fragment during configuration change
- if (fragment != null && fragment.isVisible()) {
- return;
- }
if (fragment == null) {
fragment = new WifiDppChooseSavedWifiNetworkFragment();
@@ -218,6 +238,15 @@
bundle.putBoolean(WifiDppUtils.EXTRA_TEST, true);
fragment.setArguments(bundle);
}
+ } else {
+ if (fragment.isVisible()) {
+ return;
+ }
+
+ // When the fragment in back stack but not on top of the stack, we can simply pop
+ // stack because current fragment transactions are arranged in an order
+ mFragmentManager.popBackStackImmediate();
+ return;
}
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
@@ -234,14 +263,17 @@
(WifiDppAddDeviceFragment) mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
- // Avoid to replace the same fragment during configuration change
- if (mFragmentManager.findFragmentByTag(
- WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE) != null) {
- return;
- }
-
if (fragment == null) {
fragment = new WifiDppAddDeviceFragment();
+ } else {
+ if (fragment.isVisible()) {
+ return;
+ }
+
+ // When the fragment in back stack but not on top of the stack, we can simply pop
+ // stack because current fragment transactions are arranged in an order
+ mFragmentManager.popBackStackImmediate();
+ return;
}
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
@@ -359,4 +391,31 @@
showAddDeviceFragment(/* addToBackStack */ true);
}
+
+ private WifiNetworkConfig getConnectedWifiNetworkConfigOrNull() {
+ final WifiManager wifiManager = getSystemService(WifiManager.class);
+ if (!wifiManager.isWifiEnabled()) {
+ return null;
+ }
+
+ final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
+ if (connectionInfo == null) {
+ return null;
+ }
+
+ final int connectionNetworkId = connectionInfo.getNetworkId();
+ final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
+ for (WifiConfiguration wifiConfiguration : configs) {
+ if (wifiConfiguration.networkId == connectionNetworkId) {
+ return WifiNetworkConfig.getValidConfigOrNull(
+ WifiDppUtils.getSecurityString(wifiConfiguration),
+ wifiConfiguration.getPrintableSsid(),
+ wifiConfiguration.preSharedKey,
+ /* hiddenSsid */ false,
+ wifiConfiguration.networkId);
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
index df36ae5..143f87f 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
@@ -100,7 +100,9 @@
setContentView(R.layout.wifi_dpp_activity);
mFragmentManager = getSupportFragmentManager();
- handleIntent(getIntent());
+ if (savedInstanceState == null) {
+ handleIntent(getIntent());
+ }
ActionBar actionBar = getActionBar();
if (actionBar != null) {
@@ -122,13 +124,23 @@
}
private void showQrCodeScannerFragment(boolean addToBackStack, String ssid) {
- // Avoid to replace the same fragment during configuration change
- if (mFragmentManager.findFragmentByTag(WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER) != null) {
+ WifiDppQrCodeScannerFragment fragment =
+ (WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
+ WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
+
+ if (fragment == null) {
+ fragment = new WifiDppQrCodeScannerFragment(ssid);
+ } else {
+ if (fragment.isVisible()) {
+ return;
+ }
+
+ // When the fragment in back stack but not on top of the stack, we can simply pop
+ // stack because current fragment transactions are arranged in an order
+ mFragmentManager.popBackStackImmediate();
return;
}
-
- WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment(ssid);
- FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+ final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 9c69032..7bc80e0 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
@@ -147,6 +148,17 @@
}
}
+ static String getSecurityString(WifiConfiguration config) {
+ if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
+ return WifiQrCode.SECURITY_SAE;
+ }
+ if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ return WifiQrCode.SECURITY_WPA_PSK;
+ }
+ return (config.wepKeys[0] == null) ?
+ WifiQrCode.SECURITY_NO_PASSWORD : WifiQrCode.SECURITY_WEP;
+ }
+
/**
* Returns an intent to launch QR code generator or scanner according to the Wi-Fi network
* security. It may return null if the security is not supported by QR code generator nor
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
index 89efc31..ce92f90 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
@@ -20,7 +20,6 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
-import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
@@ -28,7 +27,6 @@
import android.view.View;
import android.widget.Toast;
-import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -64,9 +62,6 @@
private WifiManager.ActionListener mSaveListener;
private boolean mIsTest;
- @VisibleForTesting
- boolean mUseConnectedAccessPointDirectly;
-
// Container Activity must implement this interface
public interface OnChooseNetworkListener {
public void onChooseNetwork(WifiNetworkConfig wifiNetworkConfig);
@@ -123,8 +118,6 @@
}
}
};
-
- mUseConnectedAccessPointDirectly = true;
}
@Override
@@ -310,16 +303,6 @@
if (isValidForDppConfiguration(accessPoint)) {
final String key = accessPoint.getKey();
- // Check if this access point is already connected.
- if (mUseConnectedAccessPointDirectly
- && accessPoint.getDetailedState() == DetailedState.CONNECTED) {
- // Uses connected access point to start DPP in Configurator-Initiator role
- // directly.
- onPreferenceTreeClick(createAccessPointPreference(accessPoint));
- removeCachedPrefs(mAccessPointsPreferenceCategory);
- return;
- }
-
final AccessPointPreference pref = (AccessPointPreference) getCachedPreference(key);
if (pref != null) {
pref.setOrder(index);
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
index fa8c267..7a6d1fa 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -16,17 +16,26 @@
package com.android.settings.wifi.slice;
+import android.annotation.ColorInt;
import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.net.NetworkInfo.State;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
+import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
+import com.android.settingslib.wifi.AccessPoint;
/**
* {@link CustomSliceable} for Wi-Fi, used by contextual homepage.
@@ -56,6 +65,36 @@
// keep showing this card to keep UI stable, even if wifi connects to a network later.
mPreviouslyDisplayed = true;
+ // Reload theme for switching dark mode on/off
+ mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
+
return super.getSlice();
}
+
+ @Override
+ protected IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
+ final Drawable d = mContext.getDrawable(
+ com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
+
+ @ColorInt int color;
+ if (accessPoint.isActive()) {
+ final State state = accessPoint.getNetworkInfo().getState();
+ if (state == State.CONNECTED) {
+ color = Utils.getColorAccentDefaultColor(mContext);
+ } else { // connecting
+ color = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.colorControlNormal));
+ }
+ } else {
+ color = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal);
+ }
+
+ d.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+ return IconCompat.createWithBitmap(Utils.drawableToBitmap(d));
+ }
+
+ @Override
+ protected int getSliceAccentColor() {
+ return -1;
+ }
}
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 1a0ed0c..6e30b9e 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -64,8 +64,8 @@
@VisibleForTesting
static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
+ protected final Context mContext;
protected final WifiManager mWifiManager;
- private final Context mContext;
public WifiSlice(Context context) {
mContext = context;
@@ -85,7 +85,7 @@
R.drawable.ic_settings_wireless);
final String title = mContext.getString(R.string.wifi_settings);
final CharSequence summary = getSummary();
- @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
+ @ColorInt final int color = getSliceAccentColor();
final PendingIntent toggleAction = getBroadcastIntent(mContext);
final PendingIntent primaryAction = getPrimaryAction();
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
@@ -120,29 +120,22 @@
listBuilder.addRow(getAccessPointRow(results.get(i)));
} else if (needLoadingRow) {
listBuilder.addRow(new ListBuilder.RowBuilder()
- .setTitle(mContext.getText(R.string.wifi_empty_list_wifi_on))
- .setSubtitle(placeholder));
+ .setTitle(mContext.getText(R.string.wifi_empty_list_wifi_on)));
needLoadingRow = false;
} else {
listBuilder.addRow(new ListBuilder.RowBuilder()
- .setTitle(placeholder)
- .setSubtitle(placeholder));
+ .setTitle(placeholder));
}
}
return listBuilder.build();
}
private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
- final String title = accessPoint.getConfigName();
- final IconCompat levelIcon = IconCompat.createWithResource(mContext,
- com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
- final CharSequence apSummary = accessPoint.getSettingsSummary();
+ final CharSequence title = accessPoint.getConfigName();
+ final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint);
final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
.setTitle(title)
- .setSubtitle(!TextUtils.isEmpty(apSummary)
- ? apSummary
- : mContext.getText(R.string.summary_placeholder))
.setPrimaryAction(SliceAction.create(
getAccessPointAction(accessPoint), levelIcon, ListBuilder.ICON_IMAGE,
title));
@@ -154,6 +147,16 @@
return rowBuilder;
}
+ protected IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
+ return IconCompat.createWithResource(mContext,
+ com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
+ }
+
+ @ColorInt
+ protected int getSliceAccentColor() {
+ return Utils.getColorAccentDefaultColor(mContext);
+ }
+
private IconCompat getEndIcon(AccessPoint accessPoint) {
if (accessPoint.isActive()) {
return IconCompat.createWithResource(mContext, R.drawable.ic_settings);
@@ -247,7 +250,7 @@
return mContext.getText(R.string.switch_off_text);
case WifiManager.WIFI_STATE_UNKNOWN:
default:
- return "";
+ return null;
}
}
diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java
index 4b39f67..09781a8 100644
--- a/src/com/android/settings/wifi/tether/TetherService.java
+++ b/src/com/android/settings/wifi/tether/TetherService.java
@@ -32,16 +32,20 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import com.android.settings.Utils;
+
import java.util.ArrayList;
import java.util.List;
@@ -65,7 +69,7 @@
private int mCurrentTypeIndex;
private boolean mInProvisionCheck;
- private UsageStatsManagerWrapper mUsageManagerWrapper;
+ private TetherServiceWrapper mWrapper;
private ArrayList<Integer> mCurrentTethers;
private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks;
private HotspotOffReceiver mHotspotReceiver;
@@ -79,7 +83,7 @@
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "Creating TetherService");
- String provisionResponse = getResources().getString(
+ String provisionResponse = getResourceForDefaultDataSubId().getString(
com.android.internal.R.string.config_mobile_hotspot_provision_response);
registerReceiver(mReceiver, new IntentFilter(provisionResponse),
android.Manifest.permission.CONNECTIVITY_INTERNAL, null);
@@ -91,9 +95,6 @@
mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>());
mPendingCallbacks.put(
ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>());
- if (mUsageManagerWrapper == null) {
- mUsageManagerWrapper = new UsageStatsManagerWrapper(this);
- }
mHotspotReceiver = new HotspotOffReceiver(this);
}
@@ -258,7 +259,7 @@
}
private Intent getProvisionBroadcastIntent(int index) {
- String provisionAction = getResources().getString(
+ String provisionAction = getResourceForDefaultDataSubId().getString(
com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui);
Intent intent = new Intent(provisionAction);
int type = mCurrentTethers.get(index);
@@ -282,7 +283,7 @@
for (ResolveInfo resolver : resolvers) {
if (resolver.activityInfo.applicationInfo.isSystemApp()) {
String packageName = resolver.activityInfo.packageName;
- mUsageManagerWrapper.setAppInactive(packageName, false);
+ getTetherServiceWrapper().setAppInactive(packageName, false);
}
}
}
@@ -294,7 +295,7 @@
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
- int period = getResources().getInteger(
+ int period = getResourceForDefaultDataSubId().getInteger(
com.android.internal.R.integer.config_mobile_hotspot_provision_check_period);
long periodMs = period * MS_PER_HOUR;
long firstTime = SystemClock.elapsedRealtime() + periodMs;
@@ -347,7 +348,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Got provision result " + intent);
- String provisionResponse = getResources().getString(
+ String provisionResponse = getResourceForDefaultDataSubId().getString(
com.android.internal.R.string.config_mobile_hotspot_provision_response);
if (provisionResponse.equals(intent.getAction())) {
@@ -385,19 +386,27 @@
};
@VisibleForTesting
- void setUsageStatsManagerWrapper(UsageStatsManagerWrapper wrapper) {
- mUsageManagerWrapper = wrapper;
+ void setTetherServiceWrapper(TetherServiceWrapper wrapper) {
+ mWrapper = wrapper;
+ }
+
+ private TetherServiceWrapper getTetherServiceWrapper() {
+ if (mWrapper == null) {
+ mWrapper = new TetherServiceWrapper(this);
+ }
+ return mWrapper;
}
/**
- * A static helper class used for tests. UsageStatsManager cannot be mocked out becasue
- * it's marked final. This class can be mocked out instead.
+ * A static helper class used for tests. UsageStatsManager cannot be mocked out because
+ * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot
+ * be mocked. This class can be mocked out instead.
*/
@VisibleForTesting
- public static class UsageStatsManagerWrapper {
+ public static class TetherServiceWrapper {
private final UsageStatsManager mUsageStatsManager;
- UsageStatsManagerWrapper(Context context) {
+ TetherServiceWrapper(Context context) {
mUsageStatsManager = (UsageStatsManager)
context.getSystemService(Context.USAGE_STATS_SERVICE);
}
@@ -405,5 +414,15 @@
void setAppInactive(String packageName, boolean isInactive) {
mUsageStatsManager.setAppInactive(packageName, isInactive);
}
+
+ int getDefaultDataSubscriptionId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
+ }
+
+ @VisibleForTesting
+ Resources getResourceForDefaultDataSubId() {
+ final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId();
+ return Utils.getResourcesForSubId(this, subId);
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index df87761..2328375 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -15,10 +15,8 @@
*/
package com.android.settings.connecteddevice;
-import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment
- .KEY_AVAILABLE_DEVICES;
-import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment
- .KEY_CONNECTED_DEVICES;
+import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment.KEY_AVAILABLE_DEVICES;
+import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment.KEY_CONNECTED_DEVICES;
import static com.google.common.truth.Truth.assertThat;
@@ -30,6 +28,9 @@
import android.provider.SearchIndexableResource;
import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerListHelper;
+import com.android.settings.slices.SlicePreferenceController;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -49,6 +50,7 @@
@Config(shadows = {ShadowUserManager.class,
ShadowConnectivityManager.class, ShadowBluetoothAdapter.class})
public class ConnectedDeviceDashboardFragmentTest {
+ private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice";
@Mock
private PackageManager mPackageManager;
@@ -64,7 +66,7 @@
}
@Test
- public void testSearchIndexProvider_shouldIndexResource() {
+ public void searchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getXmlResourcesToIndex(mContext, true /* enabled */);
@@ -74,10 +76,24 @@
}
@Test
- public void testNonIndexableKeys_existInXmlLayout() {
+ public void nonIndexableKeys_existInXmlLayout() {
final List<String> niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
- assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_AVAILABLE_DEVICES);
+ assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_AVAILABLE_DEVICES,
+ KEY_NEARBY_DEVICES);
+ }
+
+ @Test
+ public void getPreferenceControllers_containSlicePrefController() {
+ final List<BasePreferenceController> controllers =
+ PreferenceControllerListHelper.getPreferenceControllersFromXml(mContext,
+ R.xml.connected_devices);
+
+ assertThat(controllers
+ .stream()
+ .filter(controller -> controller instanceof SlicePreferenceController)
+ .count())
+ .isEqualTo(1);
}
}
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 2855554..4561ab6 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -22,6 +22,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -31,10 +32,13 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
+import android.os.Process;
import android.telephony.SubscriptionManager;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -56,6 +60,8 @@
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.net.NetworkCycleDataForUid;
import com.android.settingslib.net.NetworkCycleDataForUidLoader;
+import com.android.settingslib.net.UidDetail;
+import com.android.settingslib.net.UidDetailProvider;
import org.junit.After;
import org.junit.Before;
@@ -96,6 +102,62 @@
}
@Test
+ public void onCreate_appUid_shouldGetAppLabelFromAppInfo() throws NameNotFoundException {
+ mFragment = spy(new AppDataUsage());
+ final FragmentActivity activity = spy(Robolectric.setupActivity(FragmentActivity.class));
+ doReturn(mPackageManager).when(activity).getPackageManager();
+ doReturn(activity).when(mFragment).getActivity();
+ doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
+ ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
+ FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
+ final String packageName = "testPackage";
+ final int uid = (Process.FIRST_APPLICATION_UID + Process.LAST_APPLICATION_UID) / 2;
+ doReturn(new String[] {packageName}).when(mPackageManager).getPackagesForUid(uid);
+ final String label = "testLabel";
+ final AppItem appItem = new AppItem(uid);
+ appItem.uids.put(uid, true);
+ final ApplicationInfo info = spy(new ApplicationInfo());
+ doReturn(label).when(info).loadLabel(mPackageManager);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(packageName), anyInt() /* flags */, anyInt() /* userId */)).thenReturn(info);
+ final Bundle args = new Bundle();
+ args.putParcelable(AppDataUsage.ARG_APP_ITEM, appItem);
+ args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
+ mFragment.setArguments(args);
+
+ mFragment.onCreate(Bundle.EMPTY);
+
+ assertThat(mFragment.mLabel).isEqualTo(label);
+ }
+
+ @Test
+ public void onCreate_notAppUid_shouldGetAppLabelFromUidDetailProvider() {
+ mFragment = spy(new AppDataUsage());
+ ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
+ FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
+ doReturn(Robolectric.setupActivity(FragmentActivity.class)).when(mFragment).getActivity();
+ doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
+ final UidDetailProvider uidDetailProvider = mock(UidDetailProvider.class);
+ doReturn(uidDetailProvider).when(mFragment).getUidDetailProvider();
+ final String label = "testLabel";
+ final int uid = Process.SYSTEM_UID;
+ final UidDetail uidDetail = new UidDetail();
+ uidDetail.label = label;
+ when(uidDetailProvider.getUidDetail(eq(uid), anyBoolean() /* blocking */)).
+ thenReturn(uidDetail);
+ final AppItem appItem = new AppItem(uid);
+ appItem.uids.put(uid, true);
+ final Bundle args = new Bundle();
+ args.putParcelable(AppDataUsage.ARG_APP_ITEM, appItem);
+ args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
+ mFragment.setArguments(args);
+
+ mFragment.onCreate(Bundle.EMPTY);
+
+ assertThat(mFragment.mLabel).isEqualTo(label);
+ }
+
+ @Test
public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
ShadowEntityHeaderController.setUseMock(mHeaderController);
when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index feb3533..73fea77 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -341,7 +341,7 @@
final StorageItemPreference apps = spy(new StorageItemPreference(mContext));
apps.setIcon(R.drawable.ic_storage_apps);
final StorageItemPreference system = spy(new StorageItemPreference(mContext));
- system.setIcon(R.drawable.ic_system_update_vd_theme_24);
+ system.setIcon(R.drawable.ic_system_update);
final StorageItemPreference files = spy(new StorageItemPreference(mContext));
files.setIcon(R.drawable.ic_folder_vd_theme_24);
final PreferenceScreen screen = mock(PreferenceScreen.class);
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 c47fa38..f04008b 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 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 @@
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")
diff --git a/tests/robotests/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceControllerTest.java
new file mode 100644
index 0000000..268c581
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/CarrierSettingsVersionPreferenceControllerTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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 android.content.Context;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowCarrierConfigManager;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowCarrierConfigManager.class)
+public class CarrierSettingsVersionPreferenceControllerTest {
+
+ private ShadowCarrierConfigManager mCarrierConfigManager;
+ private CarrierSettingsVersionPreferenceController mController;
+ private int mSubscriptionId = 1234;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final Context context = RuntimeEnvironment.application;
+ mController = new CarrierSettingsVersionPreferenceController(context, "dummy_key");
+ mController.init(mSubscriptionId);
+ mCarrierConfigManager = Shadows.shadowOf(
+ context.getSystemService(CarrierConfigManager.class));
+ }
+
+ @Test
+ public void getSummary_nullConfig_noCrash() {
+ mCarrierConfigManager.setConfigForSubId(mSubscriptionId, null);
+ assertThat(mController.getSummary()).isNull();
+ }
+
+ @Test
+ public void getSummary_nullVersionString_noCrash() {
+ mCarrierConfigManager.setConfigForSubId(mSubscriptionId, new PersistableBundle());
+ assertThat(mController.getSummary()).isNull();
+ }
+
+ @Test
+ public void getSummary_hasVersionString_correctSummary() {
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING,
+ "test_version_123");
+ mCarrierConfigManager.setConfigForSubId(mSubscriptionId, bundle);
+ assertThat(mController.getSummary()).isEqualTo("test_version_123");
+ }
+}
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 0000000..c497cf8
--- /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<SliceAction> 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 3a4cf7b..42867fb 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 void getSlices_containsNecessarySlices() {
final List<Uri> 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/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
index 4232016..48f9fb4 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
@@ -16,7 +16,7 @@
package com.android.settings.password;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
@@ -139,7 +139,7 @@
public void testLaunchChooseLock_setNewPasswordExtraWithPermission() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
@@ -169,7 +169,7 @@
public void testLaunchChooseLock_setNewPasswordExtraInvalidValue() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
@@ -197,7 +197,7 @@
public void testLaunchChooseLock_setNewPasswordExtraNoneComplexity() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
@@ -225,7 +225,7 @@
public void testLaunchChooseLock_setNewPasswordWithoutExtra() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
@@ -252,7 +252,7 @@
public void testLaunchChooseLock_setNewParentProfilePasswordExtraWithPermission() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
@@ -280,7 +280,7 @@
public void testLaunchChooseLock_setNewParentProfilePasswordWithoutExtra() {
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
ShadowPasswordUtils.setCallingAppPackageName(PKG_NAME);
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
index 63bdc38..d35b38a 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
@@ -16,7 +16,7 @@
package com.android.settings.password;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -68,7 +68,7 @@
@Test
@Config(shadows = {ShadowPasswordUtils.class})
public void setupChooseLockGenericPasswordComplexityExtraWithPermission() {
- ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ ShadowPasswordUtils.addGrantedPermission(REQUEST_SCREEN_LOCK_COMPLEXITY);
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index 7eae3e4..efdcc26 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 @@
private static final List<Uri> 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
diff --git a/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java b/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java
deleted file mode 100644
index 0c5f501..0000000
--- a/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.slices;
-
-import static com.android.settings.slices.SliceDeepLinkSpringBoard.createDeepLink;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SliceDeepLinkSpringBoardTest {
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- }
-
- @Test
- @Presubmit
- public void launchesDeepLinkIntent_shouldNotCrash() {
- final Intent deepLinkIntent = getSpringboardIntent(
- "content://com.android.settings.slices/action/test_slice");
-
- mContext.startActivity(deepLinkIntent);
- }
-
- @Test
- @Presubmit
- public void launchesDeepLinkIntent_wifiSlice_shouldNotCrash() {
- final Intent deepLinkIntent = getSpringboardIntent(
- CustomSliceRegistry.WIFI_SLICE_URI.toString());
-
- mContext.startActivity(deepLinkIntent);
- }
-
- @Test
- @Presubmit
- public void launchesDeepLinkIntent_bluetoothSlice_shouldNotCrash() {
- final Intent deepLinkIntent = getSpringboardIntent(
- CustomSliceRegistry.BLUETOOTH_URI.toString());
-
- mContext.startActivity(deepLinkIntent);
- }
-
- @Test
- @Presubmit
- public void launchesDeepLinkIntent_dndSlice_shouldNotCrash() {
- final Intent deepLinkIntent = getSpringboardIntent(
- CustomSliceRegistry.ZEN_MODE_SLICE_URI.toString());
-
- mContext.startActivity(deepLinkIntent);
- }
-
- @Test
- @Presubmit
- public void launchesDeepLinkIntent_locationSlice_shouldNotCrash() {
- final Intent deepLinkIntent = getSpringboardIntent(
- CustomSliceRegistry.LOCATION_SLICE_URI.toString());
-
- mContext.startActivity(deepLinkIntent);
- }
-
- private Intent getSpringboardIntent(String uriString) {
- final Uri uri = createDeepLink(new Intent(SliceDeepLinkSpringBoard.ACTION_VIEW_SLICE)
- .setPackage(mContext.getPackageName())
- .putExtra(SliceDeepLinkSpringBoard.EXTRA_SLICE, uriString)
- .toUri(Intent.URI_ANDROID_APP_SCHEME));
-
- return new Intent(Intent.ACTION_VIEW)
- .setData(uri)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
-}
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
index 18d62c2..c1c1d54 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
@@ -98,7 +98,6 @@
private void callOnWifiStateChanged(int state) {
mActivityRule.getActivity().getMainThreadHandler()
.post(() -> mWifiNetworkListFragment.onWifiStateChanged(state));
- mWifiNetworkListFragment.mUseConnectedAccessPointDirectly = false;
}
/** Launch the activity via an Intent with a String extra. */
@@ -173,4 +172,4 @@
onView(withText(resourceString(WIFI_DISPLAY_STATUS_CONNECTED))).check(
matches(isDisplayed()));
}
-}
\ No newline at end of file
+}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java
index 09b317c..0332092 100644
--- a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java
+++ b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java
@@ -27,6 +27,8 @@
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
@@ -83,7 +85,7 @@
private TetherService mService;
private MockResources mResources;
- private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper;
+ private MockTetherServiceWrapper mWrapper;
int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
private int mLastTetherRequestType = TETHERING_INVALID;
private int mProvisionResponse = BOGUS_RECEIVER_RESULT;
@@ -125,7 +127,7 @@
when(mPrefs.edit()).thenReturn(mPrefEditor);
when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn(
mPrefEditor);
- mUsageStatsManagerWrapper = new FakeUsageStatsManagerWrapper(mContext);
+ mWrapper = new MockTetherServiceWrapper(mContext);
ResolveInfo systemAppResolveInfo = new ResolveInfo();
ActivityInfo systemActivityInfo = new ActivityInfo();
@@ -146,6 +148,8 @@
resolvers.add(systemAppResolveInfo);
when(mPackageManager.queryBroadcastReceivers(
any(Intent.class), eq(PackageManager.MATCH_ALL))).thenReturn(resolvers);
+ setupService();
+ getService().setTetherServiceWrapper(mWrapper);
}
@Override
@@ -171,16 +175,13 @@
}
public void testStartKeepsProvisionAppActive() {
- setupService();
- getService().setUsageStatsManagerWrapper(mUsageStatsManagerWrapper);
-
runProvisioningForType(TETHERING_WIFI);
assertTrue(waitForProvisionRequest(TETHERING_WIFI));
assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
- assertFalse(mUsageStatsManagerWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME));
+ assertFalse(mWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME));
// Non-system handler of the intent action should stay idle.
- assertTrue(mUsageStatsManagerWrapper.isAppInactive(FAKE_PACKAGE_NAME));
+ assertTrue(mWrapper.isAppInactive(FAKE_PACKAGE_NAME));
}
public void testScheduleRechecks() {
@@ -419,11 +420,11 @@
}
}
- private static class FakeUsageStatsManagerWrapper
- extends TetherService.UsageStatsManagerWrapper {
+ private static class MockTetherServiceWrapper
+ extends TetherService.TetherServiceWrapper {
private final Set<String> mActivePackages;
- FakeUsageStatsManagerWrapper(Context context) {
+ MockTetherServiceWrapper(Context context) {
super(context);
mActivePackages = new HashSet<>();
}
@@ -440,5 +441,10 @@
boolean isAppInactive(String packageName) {
return !mActivePackages.contains(packageName);
}
+
+ @Override
+ int getDefaultDataSubscriptionId() {
+ return INVALID_SUBSCRIPTION_ID;
+ }
}
}