From e6baedd917e041576c04687cf20d8d56dd2980fc Mon Sep 17 00:00:00 2001
From: Inseob Kim
Date: Thu, 8 Nov 2018 12:44:47 +0900
Subject: [PATCH 01/26] Schematize vold system properties
Properties accessed across partitions are now schematized and will
become APIs to make explicit interfaces among partitions.
Bug: 117924132
Test: m -j
Change-Id: Id2a696c621015d46015d5de0e7aef987e9e01b54
Merged-In: Id2a696c621015d46015d5de0e7aef987e9e01b54
---
src/com/android/settings/CryptKeeper.java | 11 +++++------
src/com/android/settings/MasterClear.java | 3 ++-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1f331d7a635..ca54b07dcd5 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -33,11 +33,11 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
+import android.sysprop.VoldProperties;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.text.Editable;
@@ -400,7 +400,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
super.onCreate(savedInstanceState);
// If we are not encrypted or encrypting, get out quickly.
- final String state = SystemProperties.get("vold.decrypt");
+ final String state = VoldProperties.decrypt().orElse("");
if (!isDebugView() && ("".equals(state) || DECRYPT_STATE.equals(state))) {
disableCryptKeeperComponent(this);
// Typically CryptKeeper is launched as the home app. We didn't
@@ -468,7 +468,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
return;
}
- final String progress = SystemProperties.get("vold.encrypt_progress");
+ final String progress = VoldProperties.encrypt_progress().orElse("");
if (!"".equals(progress) || isDebugView(FORCE_VIEW_PROGRESS)) {
setContentView(R.layout.crypt_keeper_progress);
encryptionProgressInit();
@@ -636,7 +636,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
}
private void updateProgress() {
- final String state = SystemProperties.get("vold.encrypt_progress");
+ final String state = VoldProperties.encrypt_progress().orElse("");
if ("error_partially_encrypted".equals(state)) {
showFactoryReset(false);
@@ -657,8 +657,7 @@ public class CryptKeeper extends Activity implements TextView.OnEditorActionList
// Now try to get status as time remaining and replace as appropriate
Log.v(TAG, "Encryption progress: " + progress);
try {
- final String timeProperty = SystemProperties.get("vold.encrypt_time_remaining");
- int time = Integer.parseInt(timeProperty);
+ int time = VoldProperties.encrypt_time_remaining().get();
if (time >= 0) {
// Round up to multiple of 10 - this way display is less jerky
time = (time + 9) / 10 * 10;
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index a7da41692fa..182081c6335 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -39,6 +39,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
+import android.sysprop.VoldProperties;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
@@ -404,7 +405,7 @@ public class MasterClear extends InstrumentedFragment implements OnGlobalLayoutL
}
private boolean isExtStorageEncrypted() {
- String state = SystemProperties.get("vold.decrypt");
+ String state = VoldProperties.decrypt().orElse("");
return !"".equals(state);
}
From 3b76d0f9eff5a24552bbc0c437b193ba7434db38 Mon Sep 17 00:00:00 2001
From: chen xu
Date: Wed, 28 Nov 2018 00:22:42 -0800
Subject: [PATCH 02/26] address API council feedbacks for Telephony.Carriers
Bug: 118296421
Test: telephony unit test
Change-Id: Idf8bcad4fe9d765a73563e9b0c1c659175835447
---
src/com/android/settings/network/ApnEditor.java | 4 ++--
src/com/android/settings/network/ApnSettings.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java
index 633fc45cb3c..a16be66c27c 100644
--- a/src/com/android/settings/network/ApnEditor.java
+++ b/src/com/android/settings/network/ApnEditor.java
@@ -167,7 +167,7 @@ public class ApnEditor extends SettingsPreferenceFragment
Telephony.Carriers.ROAMING_PROTOCOL, // 20
Telephony.Carriers.MVNO_TYPE, // 21
Telephony.Carriers.MVNO_MATCH_DATA, // 22
- Telephony.Carriers.EDITED, // 23
+ Telephony.Carriers.EDITED_STATUS, // 23
Telephony.Carriers.USER_EDITABLE //24
};
@@ -1035,7 +1035,7 @@ public class ApnEditor extends SettingsPreferenceFragment
callUpdate,
CARRIER_ENABLED_INDEX);
- values.put(Telephony.Carriers.EDITED, Telephony.Carriers.USER_EDITED);
+ values.put(Telephony.Carriers.EDITED_STATUS, Telephony.Carriers.USER_EDITED);
if (callUpdate) {
final Uri uri = mApnData.getUri() == null ? mCarrierUri : mApnData.getUri();
diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java
index 3b1e14c93f8..5c3882ca015 100755
--- a/src/com/android/settings/network/ApnSettings.java
+++ b/src/com/android/settings/network/ApnSettings.java
@@ -85,7 +85,7 @@ public class ApnSettings extends RestrictedSettingsFragment {
Telephony.Carriers.TYPE,
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
- Telephony.Carriers.EDITED,
+ Telephony.Carriers.EDITED_STATUS,
};
private static final int ID_INDEX = 0;
From 54d5a727c1829872c37bd983dd4f45c2efa091c2 Mon Sep 17 00:00:00 2001
From: chen xu
Date: Wed, 28 Nov 2018 00:22:42 -0800
Subject: [PATCH 03/26] address API council feedbacks for Telephony.Carriers
Bug: 118296421
Test: telephony unit test
Change-Id: Idf8bcad4fe9d765a73563e9b0c1c659175835447
Merged-in: Idf8bcad4fe9d765a73563e9b0c1c659175835447
---
src/com/android/settings/network/ApnEditor.java | 4 ++--
src/com/android/settings/network/ApnSettings.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java
index 86e9f7b8c3c..0cc88b340e6 100644
--- a/src/com/android/settings/network/ApnEditor.java
+++ b/src/com/android/settings/network/ApnEditor.java
@@ -166,7 +166,7 @@ public class ApnEditor extends SettingsPreferenceFragment
Telephony.Carriers.ROAMING_PROTOCOL, // 20
Telephony.Carriers.MVNO_TYPE, // 21
Telephony.Carriers.MVNO_MATCH_DATA, // 22
- Telephony.Carriers.EDITED, // 23
+ Telephony.Carriers.EDITED_STATUS, // 23
Telephony.Carriers.USER_EDITABLE //24
};
@@ -1030,7 +1030,7 @@ public class ApnEditor extends SettingsPreferenceFragment
callUpdate,
CARRIER_ENABLED_INDEX);
- values.put(Telephony.Carriers.EDITED, Telephony.Carriers.USER_EDITED);
+ values.put(Telephony.Carriers.EDITED_STATUS, Telephony.Carriers.USER_EDITED);
if (callUpdate) {
final Uri uri = mApnData.getUri() == null ? mCarrierUri : mApnData.getUri();
diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java
index ad7f463b231..3b39e383ddc 100755
--- a/src/com/android/settings/network/ApnSettings.java
+++ b/src/com/android/settings/network/ApnSettings.java
@@ -84,7 +84,7 @@ public class ApnSettings extends RestrictedSettingsFragment {
Telephony.Carriers.TYPE,
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
- Telephony.Carriers.EDITED,
+ Telephony.Carriers.EDITED_STATUS,
};
private static final int ID_INDEX = 0;
From 72e54c8f85576da873d6edf57c0d82d8977d2f31 Mon Sep 17 00:00:00 2001
From: Yi-Ling Chuang
Date: Tue, 4 Dec 2018 17:44:04 +0800
Subject: [PATCH 04/26] Stop observing a slice view when a slice is dismissed.
In order to receive updates of slices, we make sliceLiveData observes
slice views. When a slice is dismissed, it should stop observing
the view so the view can be recycled and reused.
Fixes: 120465506
Test: robotests
Change-Id: Ie4f12e9a3e6e0e7d59d3346ab17282707047bf16
---
.../slices/SliceContextualCardRenderer.java | 9 +++----
.../SliceContextualCardRendererTest.java | 25 ++++++++++++++++---
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 4df2a04cd9e..267fe4dce25 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -60,7 +60,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
private static final String TAG = "SliceCardRenderer";
@VisibleForTesting
- final Map> mSliceLiveDataMap;
+ final Map> mSliceLiveDataMap;
@VisibleForTesting
final Set mFlippedCardSet;
@@ -95,8 +95,6 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
final SliceViewHolder cardHolder = (SliceViewHolder) holder;
final Uri uri = card.getSliceUri();
- //TODO(b/116063073): The URI check should be done earlier when we are performing final
- // filtering after having the full list.
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Log.w(TAG, "Invalid uri, skipping slice: " + uri);
return;
@@ -106,11 +104,11 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
cardHolder.sliceView.setTag(uri);
//TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
- LiveData sliceLiveData = mSliceLiveDataMap.get(uri.toString());
+ LiveData sliceLiveData = mSliceLiveDataMap.get(uri);
if (sliceLiveData == null) {
sliceLiveData = SliceLiveData.fromUri(mContext, uri);
- mSliceLiveDataMap.put(uri.toString(), sliceLiveData);
+ mSliceLiveDataMap.put(uri, sliceLiveData);
}
mCardSet.add(card);
@@ -146,6 +144,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
cardHolder.resetCard();
mFlippedCardSet.remove(cardHolder);
+ mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
});
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index 11d0106565c..7d71302c4c6 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -52,7 +52,7 @@ import org.robolectric.android.controller.ActivityController;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceContextualCardRendererTest {
- private static final String TEST_SLICE_URI = "content://test/test";
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
@Mock
private LiveData mSliceLiveData;
@@ -91,7 +91,7 @@ public class SliceContextualCardRendererTest {
@Test
public void bindView_invalidScheme_sliceShouldBeNull() {
- final String sliceUri = "contet://com.android.settings.slices/action/flashlight";
+ final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
@@ -191,6 +191,23 @@ public class SliceContextualCardRendererTest {
assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
}
+ @Test
+ public void viewClick_removeCard_sliceLiveDataShouldRemoveObservers() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
+ final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
+ mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
+ mRenderer.bindView(viewHolder, contextualCard);
+ doReturn(mController).when(mControllerRendererPool).getController(mActivity,
+ ContextualCard.CardType.SLICE);
+
+ card.performLongClick();
+ btnRemove.performClick();
+
+ assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isFalse();
+ }
+
@Test
public void onStop_cardIsFlipped_shouldFlipBack() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
@@ -213,11 +230,11 @@ public class SliceContextualCardRendererTest {
return mRenderer.createViewHolder(view);
}
- private ContextualCard buildContextualCard(String sliceUri) {
+ private ContextualCard buildContextualCard(Uri sliceUri) {
return new ContextualCard.Builder()
.setName("test_name")
.setCardType(ContextualCard.CardType.SLICE)
- .setSliceUri(Uri.parse(sliceUri))
+ .setSliceUri(sliceUri)
.build();
}
}
From 7b0dc688c272d87b0458ed194ac8d739865a4a96 Mon Sep 17 00:00:00 2001
From: Yanting Yang
Date: Tue, 4 Dec 2018 22:57:07 +0800
Subject: [PATCH 05/26] Correct metrics category in ConnectedDeviceSlice
The used category METRICS_CATEGORY_UNKNOWN in Bluetooth detail intent is
not matched. Correct the category to BLUETOOTH_DEVICE_DETAILS.
Bug: 114807655
Test: robotest
Change-Id: I941db81164ac2b3a09b6d3c0d97f14c5e65fb6ed
---
.../homepage/contextualcards/slices/ConnectedDeviceSlice.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
index 0c79b6b37d5..1a52853c0df 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards.slices;
import android.app.PendingIntent;
+import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
@@ -48,7 +49,6 @@ import com.android.settings.slices.SliceBuilderUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.ArrayList;
import java.util.Collection;
@@ -193,7 +193,7 @@ public class ConnectedDeviceSlice implements CustomSliceable {
subSettingLauncher.setDestination(BluetoothDeviceDetailsFragment.class.getName())
.setArguments(args)
.setTitleRes(R.string.device_details_title)
- .setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN);
+ .setSourceMetricsCategory(SettingsEnums.BLUETOOTH_DEVICE_DETAILS);
// The requestCode should be unique, use the hashcode of device as request code.
return PendingIntent
From 66b2b91d724aace26025541a61e34600fb265ba2 Mon Sep 17 00:00:00 2001
From: Yanting Yang
Date: Wed, 5 Dec 2018 21:10:47 +0800
Subject: [PATCH 06/26] Fix deep link issue of Slice cards in home page
Add setData(uri) back to intent to fix deep link launching error.
Change-Id: Ibffce43ddeb9a1388d001515d8d3b320c5b45520
Fixes: 120473478
Test: robotests, visual
---
.../contextualcards/deviceinfo/BatterySlice.java | 11 ++++++-----
.../contextualcards/deviceinfo/DataUsageSlice.java | 3 ++-
.../contextualcards/deviceinfo/DeviceInfoSlice.java | 3 ++-
.../contextualcards/deviceinfo/StorageSlice.java | 3 ++-
.../contextualcards/slices/ConnectedDeviceSlice.java | 3 ++-
.../contextualcards/slices/LowStorageSlice.java | 3 ++-
6 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
index b0d69630a0f..5271e128502 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
@@ -16,8 +16,6 @@
package com.android.settings.homepage.contextualcards.deviceinfo;
-import static com.android.settings.slices.CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
-
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -37,6 +35,7 @@ import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.PowerUsageSummary;
+import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBuilderUtils;
@@ -66,7 +65,8 @@ public class BatterySlice implements CustomSliceable {
final CharSequence title = mContext.getText(R.string.power_usage_summary_title);
final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
ListBuilder.ICON_IMAGE, title);
- final Slice slice = new ListBuilder(mContext, BATTERY_INFO_SLICE_URI, ListBuilder.INFINITY)
+ final Slice slice = new ListBuilder(mContext, CustomSliceRegistry.BATTERY_INFO_SLICE_URI,
+ ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
.setHeader(new ListBuilder.HeaderBuilder().setTitle(title))
.addRow(new ListBuilder.RowBuilder()
@@ -81,7 +81,7 @@ public class BatterySlice implements CustomSliceable {
@Override
public Uri getUri() {
- return BATTERY_INFO_SLICE_URI;
+ return CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
}
@Override
@@ -95,7 +95,8 @@ public class BatterySlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
PowerUsageSummary.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.BATTERY_INFO_SLICE_URI);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
index bb7858633d0..6e94f6dd80c 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
@@ -94,7 +94,8 @@ public class DataUsageSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
DataUsageSummary.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.DATA_USAGE_SLICE_URI);
}
private PendingIntent getPrimaryAction() {
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
index 694336d19ca..1f75ab14e17 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
@@ -85,7 +85,8 @@ public class DeviceInfoSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
MyDeviceInfoFragment.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.DEVICE_INFO_SLICE_URI);
}
private PendingIntent getPrimaryAction() {
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
index eba831ac23b..799a7019d64 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
@@ -80,7 +80,8 @@ public class StorageSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
StorageDashboardFragment.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.STORAGE_SLICE_URI);
}
private PendingIntent getPrimaryAction() {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
index 0c79b6b37d5..d6cb42e516e 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
@@ -147,7 +147,8 @@ public class ConnectedDeviceSlice implements CustomSliceable {
ConnectedDeviceDashboardFragment.class.getName(), "" /* key */,
screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
index 3cbbb0c98f8..e0f31165c5f 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
@@ -110,7 +110,8 @@ public class LowStorageSlice implements CustomSliceable {
StorageSettings.class.getName(), "" /* key */,
screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.LOW_STORAGE_SLICE_URI);
}
private RowBuilder buildRowBuilder(CharSequence title, String summary, IconCompat icon) {
From 6020a3da1e923956f318b7bc594247d9e4805348 Mon Sep 17 00:00:00 2001
From: Mill Chen
Date: Wed, 5 Dec 2018 21:07:06 +0800
Subject: [PATCH 07/26] Disable scrollbar of the button in conditional card
The scrollbar of the button will be enabled if changing font size
to large or above. It is fixed by disabling scrollbar of the button.
Change-Id: Ia66afac962c7b0d431007382dc6a2c7456fc915d
Fixes: 120085679
Test: visual, rebuild
---
res/layout/homepage_condition_half_tile.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/res/layout/homepage_condition_half_tile.xml b/res/layout/homepage_condition_half_tile.xml
index fb8338926af..eff167abb9f 100644
--- a/res/layout/homepage_condition_half_tile.xml
+++ b/res/layout/homepage_condition_half_tile.xml
@@ -61,6 +61,7 @@
android:id="@+id/first_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:scrollbars="none"
style="@style/ConditionHalfCardBorderlessButton"/>
From fdebb9632b63354edd026751290ceb0dcf9c442f Mon Sep 17 00:00:00 2001
From: Beverly
Date: Wed, 5 Dec 2018 12:33:02 -0500
Subject: [PATCH 08/26] Update DND strings
Fixes: 120497233
Bug: 111475013
Test: manually flash and check strings
Test: make RunSettingsRoboTests -j40
Change-Id: I0a8971226a485f8ec41d83c167e51dac1a9c8107
---
res/values/arrays.xml | 11 ++-
res/values/strings.xml | 76 +++++++++----------
res/xml/zen_mode_calls_settings.xml | 6 +-
res/xml/zen_mode_messages_settings.xml | 6 +-
res/xml/zen_mode_sound_vibration_settings.xml | 4 +-
...odeAutomaticRulesPreferenceController.java | 3 +-
.../settings/notification/ZenModeBackend.java | 26 ++++---
.../ZenModeMessagesPreferenceController.java | 7 +-
...ModePriorityCallsPreferenceController.java | 9 ++-
...ePriorityMessagesPreferenceController.java | 9 ++-
.../notification/ZenModeSettings.java | 44 +++--------
.../notification/ZenRulePreference.java | 33 ++++----
...utomaticRulesPreferenceControllerTest.java | 2 +-
...PriorityCallsPreferenceControllerTest.java | 14 ++--
...orityMessagesPreferenceControllerTest.java | 14 ++--
.../notification/ZenModeSettingsTest.java | 8 +-
16 files changed, 131 insertions(+), 141 deletions(-)
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 33976a6b86b..f95809ea3d2 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1077,11 +1077,18 @@
- never
-
+
- @string/zen_mode_from_anyone
- @string/zen_mode_from_contacts
- @string/zen_mode_from_starred
- - @string/zen_mode_from_none
+ - @string/zen_mode_from_none_calls
+
+
+
+ - @string/zen_mode_from_anyone
+ - @string/zen_mode_from_contacts
+ - @string/zen_mode_from_starred
+ - @string/zen_mode_from_none_messages
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4aa09515ca0..44d43c3b9c5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -670,7 +670,7 @@
Mobile data
- Calls
+ Allow calls
SMS messages
@@ -7083,8 +7083,8 @@
- - 1 rule
- - %d rules
+ - 1 enabled
+ - %d enabled
@@ -7124,10 +7124,10 @@
Delete
- Do Not Disturb
+ Schedules
- Automatic rule
+ Schedule
Schedule
@@ -7142,7 +7142,7 @@
Schedule
- Use rule
+ Use schedule
Priority only
@@ -7166,7 +7166,7 @@
When Do Not Disturb is on
- Notification restrictions
+ Restrict notifications
No sound from notifications
@@ -7272,7 +7272,7 @@
On / %1$s
- Off / %1$s
+ Off / %1$s
Off
@@ -7297,12 +7297,12 @@
- - 1 rule can turn on automatically
- - %d rules can turn on automatically
+ - 1 schedule can turn on automatically
+ - %d schedules can turn on automatically
- Mute phone, but allow exceptions
+ Mute device but allow exceptions
Exceptions
@@ -7753,28 +7753,28 @@
Rename
- Rule name
+ Schedule name
- Enter rule name
+ Enter schedule name
- Rule name already in use
+ Schedule name already in use
Add more
- Add event rule
+ Add event schedule
- Add time rule
+ Add time schedule
- Delete rule
+ Delete schedule
- Choose rule type
+ Choose schedule type
Delete \u201c%1$s\u201d rule?
@@ -7855,7 +7855,7 @@
Alarm can override end time
- Stop at the end time or next alarm, whichever comes first
+ Schedule turns off when an alarm rings
Do Not Disturb behavior
@@ -7876,10 +7876,10 @@
%1$s to %2$s
- Calls
+ Allow calls
- Allow calls
+ Calls
When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.
@@ -7894,25 +7894,13 @@
- Messages
+ Allow text messages
When Do Not Disturb is on, incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.
-
- Allow messages
-
-
- Messages
-
-
- messages
-
-
- Some messages
-
-
- some messages
+
+ Text messages
From anyone
@@ -7932,9 +7920,15 @@
From repeat callers only
-
+
None
+
+ Don\u2019t allow any calls
+
+
+ Don\u2019t allow any messages
+
Allow alarms
@@ -7942,7 +7936,7 @@
alarms
- Allow media
+ Allow media sounds
media
@@ -7966,7 +7960,7 @@
Allow apps to override
- Overrides Do Not Disturb
+ App exceptions
@@ -7997,10 +7991,10 @@
Allow repeat callers
- From %1$s
+ Allow from %1$s
- From %1$s and %2$s
+ Allow from %1$s and %2$s
If the same person calls a second time within a %d minute period
diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml
index 74b6986f3cc..4616cf8c61d 100644
--- a/res/xml/zen_mode_calls_settings.xml
+++ b/res/xml/zen_mode_calls_settings.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="zen_mode_calls_settings_page"
- android:title="@string/zen_mode_calls" >
+ android:title="@string/zen_mode_calls_title" >
+ android:title="@string/zen_mode_messages_title" >
diff --git a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
index 615b26c35d9..7da90c8de9d 100644
--- a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
@@ -73,8 +73,7 @@ public class ZenModeAutomaticRulesPreferenceController extends
// 2. rule was added or deleted, so reload the entire list
if (Objects.equals(pref.mId, sortedRules[i].getKey())) {
AutomaticZenRule rule = sortedRules[i].getValue();
- pref.setName(rule.getName());
- pref.setChecked(rule.isEnabled());
+ pref.updatePreference(rule);
} else {
reloadAllRules(sortedRules);
break;
diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java
index 4824825aa91..a75f51c423d 100644
--- a/src/com/android/settings/notification/ZenModeBackend.java
+++ b/src/com/android/settings/notification/ZenModeBackend.java
@@ -250,15 +250,17 @@ public class ZenModeBackend {
}
}
+ protected int getAlarmsTotalSilenceCallsMessagesSummary(int category) {
+ if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
+ return R.string.zen_mode_from_none_messages;
+ } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){
+ return R.string.zen_mode_from_none_calls;
+ }
+ return 0;
+ }
+
protected int getContactsSummary(int category) {
int contactType = -1;
-
- // SOURCE_NONE can be used when in total silence or alarms only
- // (policy is based on user's preferences but the UI displayed is based on zenMode)
- if (category == SOURCE_NONE) {
- return R.string.zen_mode_from_none;
- }
-
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
if (isPriorityCategoryEnabled(category)) {
contactType = getPriorityMessageSenders();
@@ -273,12 +275,16 @@ public class ZenModeBackend {
case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
return R.string.zen_mode_from_anyone;
case NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS:
- return R.string.zen_mode_from_contacts;
+ return R.string.zen_mode_from_contacts;
case NotificationManager.Policy.PRIORITY_SENDERS_STARRED:
- return R.string.zen_mode_from_starred;
+ return R.string.zen_mode_from_starred;
case SOURCE_NONE:
default:
- return R.string.zen_mode_from_none;
+ if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
+ return R.string.zen_mode_from_none_messages;
+ } else {
+ return R.string.zen_mode_from_none_calls;
+ }
}
}
diff --git a/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java b/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
index 19ee809732b..2e41f205f58 100644
--- a/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
@@ -18,11 +18,11 @@ package com.android.settings.notification;
import android.content.Context;
+import androidx.preference.Preference;
+
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
-import androidx.preference.Preference;
-
public class ZenModeMessagesPreferenceController extends
AbstractZenModePreferenceController implements PreferenceControllerMixin {
@@ -48,6 +48,7 @@ public class ZenModeMessagesPreferenceController extends
@Override
public void updateState(Preference preference) {
super.updateState(preference);
- // TODO: (b/111475013 - beverlyt) set messages summary
+
+ preference.setSummary(mSummaryBuilder.getMessagesSettingSummary(getPolicy()));
}
}
diff --git a/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java b/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
index 44b6c2474f8..9872188744f 100644
--- a/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
@@ -21,14 +21,14 @@ import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
public class ZenModePriorityCallsPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
@@ -80,7 +80,8 @@ public class ZenModePriorityCallsPreferenceController extends AbstractZenModePre
case Settings.Global.ZEN_MODE_ALARMS:
mPreference.setEnabled(false);
mPreference.setValue(ZenModeBackend.ZEN_MODE_FROM_NONE);
- mPreference.setSummary(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE));
+ mPreference.setSummary(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
+ NotificationManager.Policy.PRIORITY_CATEGORY_CALLS));
break;
default:
preference.setEnabled(true);
diff --git a/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java b/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
index 56829a74acb..cfda367f617 100644
--- a/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
@@ -21,14 +21,14 @@ import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
public class ZenModePriorityMessagesPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
@@ -80,7 +80,8 @@ public class ZenModePriorityMessagesPreferenceController extends AbstractZenMode
case Settings.Global.ZEN_MODE_ALARMS:
mPreference.setEnabled(false);
mPreference.setValue(ZenModeBackend.ZEN_MODE_FROM_NONE);
- mPreference.setSummary(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE));
+ mPreference.setSummary(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
+ NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES));
break;
default:
preference.setEnabled(true);
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 293c429b17a..a3f59c680d5 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -145,7 +145,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|| PRIORITY_CATEGORY_REPEAT_CALLERS == category, false);
int numCategories = enabledCategories.size();
if (numCategories == 0) {
- return mContext.getString(R.string.zen_mode_no_exceptions);
+ return mContext.getString(R.string.zen_mode_from_none_calls);
} else if (numCategories == 1) {
return mContext.getString(R.string.zen_mode_calls_summary_one,
enabledCategories.get(0));
@@ -156,34 +156,14 @@ public class ZenModeSettings extends ZenModeSettingsBase {
}
}
- String getMsgEventReminderSettingSummary(Policy policy) {
+ String getMessagesSettingSummary(Policy policy) {
List enabledCategories = getEnabledCategories(policy,
- category -> PRIORITY_CATEGORY_EVENTS == category
- || PRIORITY_CATEGORY_REMINDERS == category
- || PRIORITY_CATEGORY_MESSAGES == category, true);
+ category -> PRIORITY_CATEGORY_MESSAGES == category, false);
int numCategories = enabledCategories.size();
if (numCategories == 0) {
- return mContext.getString(R.string.zen_mode_no_exceptions);
- } else if (numCategories == 1) {
- return enabledCategories.get(0);
- } else if (numCategories == 2) {
- return mContext.getString(R.string.join_two_items, enabledCategories.get(0),
- enabledCategories.get(1));
- } else if (numCategories == 3){
- final List summaries = new ArrayList<>();
- summaries.add(enabledCategories.get(0));
- summaries.add(enabledCategories.get(1));
- summaries.add(enabledCategories.get(2));
-
- return ListFormatter.getInstance().format(summaries);
+ return mContext.getString(R.string.zen_mode_from_none_messages);
} else {
- final List summaries = new ArrayList<>();
- summaries.add(enabledCategories.get(0));
- summaries.add(enabledCategories.get(1));
- summaries.add(enabledCategories.get(2));
- summaries.add(mContext.getString(R.string.zen_mode_other_options));
-
- return ListFormatter.getInstance().format(summaries);
+ return enabledCategories.get(0);
}
}
@@ -292,17 +272,11 @@ public class ZenModeSettings extends ZenModeSettingsBase {
}
} else if (category == Policy.PRIORITY_CATEGORY_MESSAGES) {
if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) {
- if (isFirst) {
- return mContext.getString(R.string.zen_mode_all_messages);
- } else {
- return mContext.getString(R.string.zen_mode_all_messages_list);
- }
+ return mContext.getString(R.string.zen_mode_from_anyone);
+ } else if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_CONTACTS){
+ return mContext.getString(R.string.zen_mode_from_contacts);
} else {
- if (isFirst) {
- return mContext.getString(R.string.zen_mode_selected_messages);
- } else {
- return mContext.getString(R.string.zen_mode_selected_messages_list);
- }
+ return mContext.getString(R.string.zen_mode_from_starred);
}
} else if (category == Policy.PRIORITY_CATEGORY_EVENTS) {
if (isFirst) {
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index 48a879b6dfa..10b49eb73dd 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -31,6 +31,7 @@ import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
@@ -122,17 +123,17 @@ public class ZenRulePreference extends TwoTargetPreference {
return mChecked;
}
- public void setChecked(boolean checked) {
- mChecked = checked;
- if (mCheckBox != null) {
- mCheckBox.setChecked(checked);
- }
- }
-
- public void setName(String name) {
- if (!Objects.equals(mName, name)) {
- mName = name;
+ public void updatePreference(AutomaticZenRule rule) {
+ if (!mRule.getName().equals(rule.getName())) {
+ mName = rule.getName();
setTitle(mName);
+ mRule.setName(mName.toString());
+ }
+
+ if (mRule.isEnabled() != rule.isEnabled()) {
+ mRule.setEnabled(rule.isEnabled());
+ setChecked(mRule.isEnabled());
+ setSummary(computeRuleSummary(mRule));
}
}
@@ -141,6 +142,13 @@ public class ZenRulePreference extends TwoTargetPreference {
mOnCheckBoxClickListener.onClick(null);
}
+ private void setChecked(boolean checked) {
+ mChecked = checked;
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(checked);
+ }
+ }
+
private View.OnClickListener mOnCheckBoxClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -159,7 +167,7 @@ public class ZenRulePreference extends TwoTargetPreference {
try {
ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
- setSummary(computeRuleSummary(rule, mIsSystemRule, info.loadLabel(mPm)));
+ setSummary(computeRuleSummary(rule));
} catch (PackageManager.NameNotFoundException e) {
appExists = false;
return;
@@ -179,8 +187,7 @@ public class ZenRulePreference extends TwoTargetPreference {
setKey(mId);
}
- private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
- CharSequence providerLabel) {
+ private String computeRuleSummary(AutomaticZenRule rule) {
return (rule == null || !rule.isEnabled())
? mContext.getResources().getString(R.string.switch_off_text)
: mContext.getResources().getString(R.string.switch_on_text);
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
index 3eae2667973..b431c0a65f2 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
@@ -144,7 +144,7 @@ public class ZenModeAutomaticRulesPreferenceControllerTest {
mockGetAutomaticZenRules(NUM_RULES, rMap);
FieldSetter.setField(mZenRulePreference, ZenRulePreference.class.getDeclaredField("mId"), testId);
mController.updateState(mockPref);
- verify(mZenRulePreference, times(1)).setChecked(false);
+ verify(mZenRulePreference, times(1)).updatePreference(any());
verify(mController, never()).reloadAllRules(any());
}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
index 36a1382d7c6..7131250442e 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
@@ -30,6 +30,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -43,9 +46,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
-import androidx.preference.ListPreference;
-import androidx.preference.PreferenceScreen;
-
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModePriorityCallsPreferenceControllerTest {
@@ -86,8 +86,8 @@ public class ZenModePriorityCallsPreferenceControllerTest {
when(mBackend.getPriorityCallSenders())
.thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
- when(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE))
- .thenCallRealMethod();
+ when(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
+ NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)).thenCallRealMethod();
when(mBackend.getContactsSummary(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
.thenCallRealMethod();
@@ -110,7 +110,7 @@ public class ZenModePriorityCallsPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
- verify(mockPref).setSummary(R.string.zen_mode_from_none);
+ verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
}
@Test
@@ -121,7 +121,7 @@ public class ZenModePriorityCallsPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
- verify(mockPref).setSummary(R.string.zen_mode_from_none);
+ verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
index 75605a4d2f0..7b6698dc693 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
@@ -30,6 +30,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -43,9 +46,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
-import androidx.preference.ListPreference;
-import androidx.preference.PreferenceScreen;
-
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModePriorityMessagesPreferenceControllerTest {
@@ -86,8 +86,8 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
when(mBackend.getPriorityMessageSenders())
.thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
- when(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE))
- .thenCallRealMethod();
+ when(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
+ NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenCallRealMethod();
when(mBackend.getContactsSummary(NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES))
.thenCallRealMethod();
@@ -110,7 +110,7 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
- verify(mockPref).setSummary(R.string.zen_mode_from_none);
+ verify(mockPref).setSummary(R.string.zen_mode_from_none_messages);
}
@Test
@@ -121,7 +121,7 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
- verify(mockPref).setSummary(R.string.zen_mode_from_none);
+ verify(mockPref).setSummary(R.string.zen_mode_from_none_messages);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
index 4fc7d57f5fb..53032ac789c 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
@@ -71,20 +71,20 @@ public class ZenModeSettingsTest {
@Test
public void testGetCallsSettingSummary_none() {
Policy policy = new Policy(0, 0, 0, 0);
- assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("None");
+ assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Don\u2019t allow any calls");
}
@Test
public void testGetCallsSettingSummary_contacts() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS,
Policy.PRIORITY_SENDERS_CONTACTS, 0, 0);
- assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From contacts");
+ assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from contacts");
}
@Test
public void testGetCallsSettingSummary_repeatCallers() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0);
- assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From repeat callers");
+ assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from repeat callers");
}
@Test
@@ -93,7 +93,7 @@ public class ZenModeSettingsTest {
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | Policy.PRIORITY_CATEGORY_CALLS,
Policy.PRIORITY_SENDERS_STARRED, 0, 0);
assertThat(mBuilder.getCallsSettingSummary(policy))
- .isEqualTo("From starred contacts and repeat callers");
+ .isEqualTo("Allow from starred contacts and repeat callers");
}
@Test
From 11b7c7f2546ecf18fe20d3ccfde4e550e927a29c Mon Sep 17 00:00:00 2001
From: Antony Sargent
Date: Wed, 5 Dec 2018 09:30:30 -0800
Subject: [PATCH 09/26] Layout changes in v2 Network & internet page
This adds the skeleton of a header section which will only appear when
the device has two or more active mobile subscriptions. Subsequent CL's
will add the actual logic implementing it.
Also this moves up the airplane mode toggle higher up on the page, and
removes the proxy selector entry (which has been unconditionally
disabled by the ProxyPreferenceController for a while).
Bug: 116349402
Test: manual (this is mostly a layout change - subsequent changes will
have actual logic to test for the subscriptions header)
Change-Id: Iaee338d5c13e05d3c2d9d04872a94cf90e5da588
---
res/xml/network_and_internet_v2.xml | 48 ++++++++++---------
.../network/MultiNetworkHeaderController.java | 36 ++++++++++++++
2 files changed, 61 insertions(+), 23 deletions(-)
create mode 100644 src/com/android/settings/network/MultiNetworkHeaderController.java
diff --git a/res/xml/network_and_internet_v2.xml b/res/xml/network_and_internet_v2.xml
index 680b268d1df..974739d3c0e 100644
--- a/res/xml/network_and_internet_v2.xml
+++ b/res/xml/network_and_internet_v2.xml
@@ -21,13 +21,20 @@
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
+
+
+ android:order="-30"
+ settings:allowDividerAbove="true">
@@ -44,16 +51,15 @@
settings:useAdminDisabledSummary="true">
-
+ settings:controller="com.android.settings.network.AirplaneModePreferenceController"
+ settings:platform_slice="true"
+ settings:userRestriction="no_airplane_mode"/>
-
-
-
+ android:summary="@string/summary_placeholder"
+ settings:keywords="@string/keywords_hotspot_tethering"
+ settings:userRestriction="no_config_tethering"
+ settings:useAdminDisabledSummary="true" />
Date: Tue, 4 Dec 2018 15:40:34 -0800
Subject: [PATCH 10/26] Add search to app info list.
- add a search option menu to the manage applications page.
- add a search filter to the app list adapter to remove any app whose
app name does not contain the search query.
Change-Id: Ie749daeef2cdc4a22fade45422ae90f44d00ceb2
Fixes: 119598311
Test: make RunSettingsRoboTests
---
res/drawable/ic_find_in_page_24px.xml | 27 +++++
res/menu/manage_apps.xml | 7 ++
.../ManageApplications.java | 74 +++++++++++-
.../ManageApplicationsTest.java | 114 +++++++++++++++++-
4 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 res/drawable/ic_find_in_page_24px.xml
diff --git a/res/drawable/ic_find_in_page_24px.xml b/res/drawable/ic_find_in_page_24px.xml
new file mode 100644
index 00000000000..18895e49a1c
--- /dev/null
+++ b/res/drawable/ic_find_in_page_24px.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
diff --git a/res/menu/manage_apps.xml b/res/menu/manage_apps.xml
index 99dba37d3a4..51189a0722d 100644
--- a/res/menu/manage_apps.xml
+++ b/res/menu/manage_apps.xml
@@ -15,6 +15,13 @@
-->
+ */
+ private class SearchFilter extends Filter {
+ @WorkerThread
+ @Override
+ protected FilterResults performFiltering(CharSequence query) {
+ final ArrayList matchedEntries;
+ if (TextUtils.isEmpty(query)) {
+ matchedEntries = mOriginalEntries;
+ } else {
+ matchedEntries = new ArrayList<>();
+ for (ApplicationsState.AppEntry entry : mOriginalEntries) {
+ if (entry.label.toLowerCase().contains(query.toString().toLowerCase())) {
+ matchedEntries.add(entry);
+ }
+ }
+ }
+ final FilterResults results = new FilterResults();
+ results.values = matchedEntries;
+ results.count = matchedEntries.size();
+ return results;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ mEntries = (ArrayList) results.values;
+ notifyDataSetChanged();
+ }
+ }
}
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index b3f5b5e72e8..4c9cacb6926 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -28,11 +28,12 @@ import static com.android.settings.applications.manageapplications.ManageApplica
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -48,9 +49,11 @@ import android.os.Looper;
import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.SearchView;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
@@ -158,6 +161,35 @@ public class ManageApplicationsTest {
verify(loadingContainer, never()).setVisibility(View.VISIBLE);
}
+ @Test
+ public void onCreateOptionsMenu_shouldSetSearchQueryListener() {
+ final SearchView searchView = mock(SearchView.class);
+ final MenuItem searchMenu = mock(MenuItem.class);
+ final MenuItem helpMenu = mock(MenuItem.class);
+ when(searchMenu.getActionView()).thenReturn(searchView);
+ when(mMenu.findItem(R.id.search_app_list_menu)).thenReturn(searchMenu);
+ when(mMenu.add(anyInt() /* groupId */, anyInt() /* itemId */, anyInt() /* order */,
+ anyInt() /* titleRes */)).thenReturn(helpMenu);
+ doReturn("Test").when(mFragment).getText(anyInt() /* resId */);
+ doNothing().when(mFragment).updateOptionsMenu();
+
+ mFragment.onCreateOptionsMenu(mMenu, mock(MenuInflater.class));
+
+ verify(searchView).setOnQueryTextListener(mFragment);
+ }
+
+ @Test
+ public void onQueryTextChange_shouldFilterSearchInApplicationsAdapter() {
+ final ManageApplications.ApplicationsAdapter adapter =
+ mock(ManageApplications.ApplicationsAdapter.class);
+ final String query = "Test App";
+ ReflectionHelpers.setField(mFragment, "mApplications", adapter);
+
+ mFragment.onQueryTextChange(query);
+
+ verify(adapter).filterSearch(query);
+ }
+
@Test
public void updateLoading_appLoaded_shouldNotDelayCallToHandleLoadingContainer() {
ReflectionHelpers.setField(mFragment, "mLoadingContainer", mock(View.class));
@@ -249,6 +281,34 @@ public class ManageApplicationsTest {
verify(loadingViewController).showContent(true /* animate */);
}
+ @Test
+ public void onRebuildComplete_hasSearchQuery_shouldFilterSearch() {
+ final String query = "Test";
+ final RecyclerView recyclerView = mock(RecyclerView.class);
+ final View emptyView = mock(View.class);
+ ReflectionHelpers.setField(mFragment, "mRecyclerView", recyclerView);
+ ReflectionHelpers.setField(mFragment, "mEmptyView", emptyView);
+ final SearchView searchView = mock(SearchView.class);
+ ReflectionHelpers.setField(mFragment, "mSearchView", searchView);
+ when(searchView.isVisibleToUser()).thenReturn(true);
+ when(searchView.getQuery()).thenReturn(query);
+ final View listContainer = mock(View.class);
+ when(listContainer.getVisibility()).thenReturn(View.VISIBLE);
+ ReflectionHelpers.setField(mFragment, "mListContainer", listContainer);
+ ReflectionHelpers.setField(
+ mFragment, "mFilterAdapter", mock(ManageApplications.FilterSpinnerAdapter.class));
+ final ArrayList appList = new ArrayList<>();
+ appList.add(mock(ApplicationsState.AppEntry.class));
+ final ManageApplications.ApplicationsAdapter adapter =
+ spy(new ManageApplications.ApplicationsAdapter(mState, mFragment,
+ AppFilterRegistry.getInstance().get(FILTER_APPS_ALL),
+ null /* savedInstanceState */));
+
+ adapter.onRebuildComplete(appList);
+
+ verify(adapter).filterSearch(query);
+ }
+
@Test
public void notifyItemChange_recyclerViewIdle_shouldNotify() {
final RecyclerView recyclerView = mock(RecyclerView.class);
@@ -343,6 +403,48 @@ public class ManageApplicationsTest {
verify(holder, never()).updateSwitch(any(), anyBoolean(), anyBoolean());
}
+ @Test
+ public void applicationsAdapter_filterSearch_emptyQuery_shouldShowFullList() {
+ final ManageApplications.ApplicationsAdapter adapter =
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
+ ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
+
+ adapter.filterSearch("");
+
+ assertThat(adapter.getItemCount()).isEqualTo(5);
+ }
+
+ @Test
+ public void applicationsAdapter_filterSearch_noMatch_shouldShowEmptyList() {
+ final ManageApplications.ApplicationsAdapter adapter =
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
+ ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
+
+ adapter.filterSearch("orange");
+
+ assertThat(adapter.getItemCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void applicationsAdapter_filterSearch_shouldShowMatchedItemsOnly() {
+ final ManageApplications.ApplicationsAdapter adapter =
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
+ ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
+
+ adapter.filterSearch("an");
+
+ assertThat(adapter.getItemCount()).isEqualTo(3);
+ assertThat(adapter.getAppEntry(0).label).isEqualTo("Banana");
+ assertThat(adapter.getAppEntry(1).label).isEqualTo("Cantaloupe");
+ assertThat(adapter.getAppEntry(2).label).isEqualTo("Mango");
+ }
+
@Test
public void sortOrderSavedOnRebuild() {
when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
@@ -375,4 +477,14 @@ public class ManageApplicationsTest {
return new RoboMenuItem(id);
});
}
+
+ private ArrayList getTestAppList(String[] appNames) {
+ final ArrayList appList = new ArrayList<>();
+ for (String name : appNames) {
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.label = name;
+ appList.add(appEntry);
+ }
+ return appList;
+ }
}
From d7fa2fa64e9da3495088173650aa26075fcb7a8d Mon Sep 17 00:00:00 2001
From: Fan Zhang
Date: Wed, 5 Dec 2018 14:42:53 -0800
Subject: [PATCH 11/26] Make a few custom slices implement CustomSliceable.
Bug: 80263568
Test: robotests, slice-browser
Change-Id: Id809a347d77448917154c2d1144fd2517e70829a
---
.../EmergencyInfoPreferenceController.java | 5 +-
...SliceBuilder.java => FlashlightSlice.java} | 74 ++++++++++---------
.../deviceinfo/EmergencyInfoSlice.java | 49 ++++++++----
...onSliceBuilder.java => LocationSlice.java} | 49 +++++++-----
.../settings/slices/CustomSliceManager.java | 6 ++
.../slices/SettingsSliceProvider.java | 15 ----
.../slices/SliceBroadcastReceiver.java | 5 --
.../slices/SliceDeepLinkSpringBoard.java | 3 -
...lderTest.java => FlashlightSliceTest.java} | 4 +-
...uilderTest.java => LocationSliceTest.java} | 4 +-
10 files changed, 119 insertions(+), 95 deletions(-)
rename src/com/android/settings/flashlight/{FlashlightSliceBuilder.java => FlashlightSlice.java} (67%)
rename src/com/android/settings/location/{LocationSliceBuilder.java => LocationSlice.java} (66%)
rename tests/robotests/src/com/android/settings/flashlight/{FlashlightSliceBuilderTest.java => FlashlightSliceTest.java} (94%)
rename tests/robotests/src/com/android/settings/location/{LocationSliceBuilderTest.java => LocationSliceTest.java} (93%)
diff --git a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
index 408db09c230..33e77715b4e 100644
--- a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
+++ b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
@@ -36,8 +36,9 @@ import java.util.List;
public class EmergencyInfoPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
+ public static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
+
private static final String KEY_EMERGENCY_INFO = "emergency_info";
- private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
private static final String PACKAGE_NAME_EMERGENCY = "com.android.emergency";
public EmergencyInfoPreferenceController(Context context) {
@@ -57,7 +58,7 @@ public class EmergencyInfoPreferenceController extends AbstractPreferenceControl
public void updateState(Preference preference) {
UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
- UserHandle.myUserId());
+ UserHandle.myUserId());
preference.setSummary(mContext.getString(R.string.emergency_info_summary, info.name));
}
diff --git a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java b/src/com/android/settings/flashlight/FlashlightSlice.java
similarity index 67%
rename from src/com/android/settings/flashlight/FlashlightSliceBuilder.java
rename to src/com/android/settings/flashlight/FlashlightSlice.java
index 5833229a546..a2c4561c1d5 100644
--- a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java
+++ b/src/com/android/settings/flashlight/FlashlightSlice.java
@@ -28,6 +28,7 @@ import android.content.IntentFilter;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
+import android.net.Uri;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Log;
@@ -41,69 +42,78 @@ import androidx.slice.builders.SliceAction;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.slices.CustomSliceRegistry;
-import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.CustomSliceable;
/**
* Utility class to build a Flashlight Slice, and handle all associated actions.
*/
-public class FlashlightSliceBuilder {
+public class FlashlightSlice implements CustomSliceable {
- private static final String TAG = "FlashlightSliceBuilder";
-
- /**
- * Action notifying a change on the Flashlight Slice.
- */
- public static final String ACTION_FLASHLIGHT_SLICE_CHANGED =
- "com.android.settings.flashlight.action.FLASHLIGHT_SLICE_CHANGED";
+ private static final String TAG = "FlashlightSlice";
/**
* Action broadcasting a change on whether flashlight is on or off.
*/
- public static final String ACTION_FLASHLIGHT_CHANGED =
+ private static final String ACTION_FLASHLIGHT_CHANGED =
"com.android.settings.flashlight.action.FLASHLIGHT_CHANGED";
- public static final IntentFilter INTENT_FILTER = new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
+ private final Context mContext;
- private FlashlightSliceBuilder() {
+ public FlashlightSlice(Context context) {
+ mContext = context;
}
- public static Slice getSlice(Context context) {
- if (!isFlashlightAvailable(context)) {
+ @Override
+ public Slice getSlice() {
+ if (!isFlashlightAvailable(mContext)) {
return null;
}
- final PendingIntent toggleAction = getBroadcastIntent(context);
- @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
+ final PendingIntent toggleAction = getBroadcastIntent(mContext);
+ @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
final IconCompat icon =
- IconCompat.createWithResource(context, R.drawable.ic_signal_flashlight);
- return new ListBuilder(context, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
+ IconCompat.createWithResource(mContext, R.drawable.ic_signal_flashlight);
+ return new ListBuilder(mContext, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(new RowBuilder()
- .setTitle(context.getText(R.string.power_flashlight))
+ .setTitle(mContext.getText(R.string.power_flashlight))
.setTitleItem(icon, ICON_IMAGE)
.setPrimaryAction(
- SliceAction.createToggle(toggleAction, null, isFlashlightEnabled(context))))
+ SliceAction.createToggle(toggleAction, null,
+ isFlashlightEnabled(mContext))))
.build();
}
- /**
- * Update the current flashlight status to the boolean value keyed by
- * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
- */
- public static void handleUriChange(Context context, Intent intent) {
+ @Override
+ public Uri getUri() {
+ return CustomSliceRegistry.FLASHLIGHT_SLICE_URI;
+ }
+
+ @Override
+ public IntentFilter getIntentFilter() {
+ return new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
try {
- final String cameraId = getCameraId(context);
+ final String cameraId = getCameraId(mContext);
if (cameraId != null) {
final boolean state = intent.getBooleanExtra(
- EXTRA_TOGGLE_STATE, isFlashlightEnabled(context));
- final CameraManager cameraManager = context.getSystemService(CameraManager.class);
+ EXTRA_TOGGLE_STATE, isFlashlightEnabled(mContext));
+ final CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
cameraManager.setTorchMode(cameraId, state);
}
} catch (CameraAccessException e) {
Log.e(TAG, "Camera couldn't set torch mode.", e);
}
- context.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
+ mContext.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
+ }
+
+ @Override
+ public Intent getIntent() {
+ return null;
}
private static String getCameraId(Context context) throws CameraAccessException {
@@ -121,12 +131,6 @@ public class FlashlightSliceBuilder {
return null;
}
- private static PendingIntent getBroadcastIntent(Context context) {
- final Intent intent = new Intent(ACTION_FLASHLIGHT_SLICE_CHANGED);
- intent.setClass(context, SliceBroadcastReceiver.class);
- return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
- }
private static boolean isFlashlightAvailable(Context context) {
return Settings.Secure.getInt(
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
index 2484e53b18f..f8be2d656aa 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
@@ -16,9 +16,12 @@
package com.android.settings.homepage.contextualcards.deviceinfo;
+import static com.android.settings.accounts.EmergencyInfoPreferenceController.ACTION_EDIT_EMERGENCY_INFO;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -27,37 +30,57 @@ import androidx.slice.builders.SliceAction;
import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
// This is a slice helper class for EmergencyInfo
-public class EmergencyInfoSlice {
+public class EmergencyInfoSlice implements CustomSliceable {
- private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
+ private final Context mContext;
- public static Slice getSlice(Context context) {
- final ListBuilder listBuilder = new ListBuilder(context,
+ public EmergencyInfoSlice(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Slice getSlice() {
+ final ListBuilder listBuilder = new ListBuilder(mContext,
CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI,
ListBuilder.INFINITY);
listBuilder.addRow(
new ListBuilder.RowBuilder()
- .setTitle(context.getText(R.string.emergency_info_title))
+ .setTitle(mContext.getText(R.string.emergency_info_title))
.setSubtitle(
- context.getText(R.string.emergency_info_contextual_card_summary))
- .setPrimaryAction(createPrimaryAction(context)));
+ mContext.getText(R.string.emergency_info_contextual_card_summary))
+ .setPrimaryAction(createPrimaryAction()));
return listBuilder.build();
}
- private static SliceAction createPrimaryAction(Context context) {
- PendingIntent pendingIntent =
+ @Override
+ public Uri getUri() {
+ return CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI;
+ }
+
+ @Override
+ public Intent getIntent() {
+ return new Intent(ACTION_EDIT_EMERGENCY_INFO);
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
+ }
+
+ private SliceAction createPrimaryAction() {
+ final PendingIntent pendingIntent =
PendingIntent.getActivity(
- context,
+ mContext,
0 /* requestCode */,
- new Intent(ACTION_EDIT_EMERGENCY_INFO),
+ getIntent(),
PendingIntent.FLAG_UPDATE_CURRENT);
return SliceAction.createDeeplink(
pendingIntent,
- IconCompat.createWithResource(context, R.drawable.empty_icon),
+ IconCompat.createWithResource(mContext, R.drawable.empty_icon),
ListBuilder.ICON_IMAGE,
- context.getText(R.string.emergency_info_title));
+ mContext.getText(R.string.emergency_info_title));
}
}
diff --git a/src/com/android/settings/location/LocationSliceBuilder.java b/src/com/android/settings/location/LocationSlice.java
similarity index 66%
rename from src/com/android/settings/location/LocationSliceBuilder.java
rename to src/com/android/settings/location/LocationSlice.java
index f70d09b27b7..6dc4241865e 100644
--- a/src/com/android/settings/location/LocationSliceBuilder.java
+++ b/src/com/android/settings/location/LocationSlice.java
@@ -38,29 +38,31 @@ import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBuilderUtils;
/**
* Utility class to build an intent-based Location Slice.
*/
-public class LocationSliceBuilder {
+public class LocationSlice implements CustomSliceable {
- private LocationSliceBuilder() {
+ private final Context mContext;
+
+ public LocationSlice(Context context) {
+ mContext = context;
}
- /**
- * Return a Location Slice bound to {@link CustomSliceRegistry#LOCATION_SLICE_URI}.
- */
- public static Slice getSlice(Context context) {
- final IconCompat icon = IconCompat.createWithResource(context,
+ @Override
+ public Slice getSlice() {
+ final IconCompat icon = IconCompat.createWithResource(mContext,
R.drawable.ic_signal_location);
- final String title = context.getString(R.string.location_settings_title);
- @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
- final PendingIntent primaryAction = getPrimaryAction(context);
+ final CharSequence title = mContext.getText(R.string.location_settings_title);
+ @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
+ final PendingIntent primaryAction = getPrimaryAction();
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
ListBuilder.ICON_IMAGE, title);
- return new ListBuilder(context, CustomSliceRegistry.LOCATION_SLICE_URI,
+ return new ListBuilder(mContext, CustomSliceRegistry.LOCATION_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(new RowBuilder()
@@ -70,19 +72,30 @@ public class LocationSliceBuilder {
.build();
}
- public static Intent getIntent(Context context) {
- final String screenTitle = context.getText(R.string.location_settings_title).toString();
+ @Override
+ public Uri getUri() {
+ return CustomSliceRegistry.LOCATION_SLICE_URI;
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
+
+ }
+
+ @Override
+ public Intent getIntent() {
+ final String screenTitle = mContext.getText(R.string.location_settings_title).toString();
final Uri contentUri = new Uri.Builder().appendPath(KEY_LOCATION).build();
- return SliceBuilderUtils.buildSearchResultPageIntent(context,
+ return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
LocationSettings.class.getName(), KEY_LOCATION, screenTitle,
MetricsEvent.LOCATION)
- .setClassName(context.getPackageName(), SubSettings.class.getName())
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(contentUri);
}
- private static PendingIntent getPrimaryAction(Context context) {
- final Intent intent = getIntent(context);
- return PendingIntent.getActivity(context, 0 /* requestCode */,
+ private PendingIntent getPrimaryAction() {
+ final Intent intent = getIntent();
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */,
intent, 0 /* flags */);
}
}
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index bef72b75c2a..8f8ee967fc4 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -22,13 +22,16 @@ import android.util.ArrayMap;
import androidx.annotation.VisibleForTesting;
+import com.android.settings.flashlight.FlashlightSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
+import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
+import com.android.settings.location.LocationSlice;
import com.android.settings.wifi.WifiSlice;
import java.util.Map;
@@ -106,6 +109,9 @@ public class CustomSliceManager {
mUriMap.put(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI, ConnectedDeviceSlice.class);
mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
+ mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
+ 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.STORAGE_SLICE_URI, StorageSlice.class);
mUriMap.put(CustomSliceRegistry.WIFI_SLICE_URI, WifiSlice.class);
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 109f02ef61d..80b71335646 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -41,9 +41,6 @@ import androidx.slice.SliceProvider;
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.flashlight.FlashlightSliceBuilder;
-import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
-import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.SliceBroadcastRelay;
@@ -182,12 +179,6 @@ public class SettingsSliceProvider extends SliceProvider {
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
registerIntentToUri(BluetoothSliceBuilder.INTENT_FILTER, sliceUri);
return;
- } else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
- registerIntentToUri(FlashlightSliceBuilder.INTENT_FILTER, sliceUri);
- mRegisteredUris.add(sliceUri);
- return;
- } else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
- return;
}
// Start warming the slice, we expect someone will want it soon.
@@ -240,8 +231,6 @@ public class SettingsSliceProvider extends SliceProvider {
return ZenModeSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
return BluetoothSliceBuilder.getSlice(getContext());
- } else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
- return LocationSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.ENHANCED_4G_SLICE_URI.equals(sliceUri)) {
return FeatureFactory.getFactory(getContext())
.getSlicesFeatureProvider()
@@ -252,10 +241,6 @@ public class SettingsSliceProvider extends SliceProvider {
.getSlicesFeatureProvider()
.getNewWifiCallingSliceHelper(getContext())
.createWifiCallingPreferenceSlice(sliceUri);
- } else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
- return FlashlightSliceBuilder.getSlice(getContext());
- } else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
- return EmergencyInfoSlice.getSlice(getContext());
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 2860e9a7544..823c7294adc 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -17,7 +17,6 @@
package com.android.settings.slices;
import static com.android.settings.bluetooth.BluetoothSliceBuilder.ACTION_BLUETOOTH_SLICE_CHANGED;
-import static com.android.settings.flashlight.FlashlightSliceBuilder.ACTION_FLASHLIGHT_SLICE_CHANGED;
import static com.android.settings.network.telephony.Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED;
import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY;
@@ -46,7 +45,6 @@ import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.core.TogglePreferenceController;
-import com.android.settings.flashlight.FlashlightSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
@@ -108,9 +106,6 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
.getNewWifiCallingSliceHelper(context)
.handleWifiCallingPreferenceChanged(intent);
break;
- case ACTION_FLASHLIGHT_SLICE_CHANGED:
- FlashlightSliceBuilder.handleUriChange(context, intent);
- break;
case ACTION_COPY:
handleCopyAction(context, key, isPlatformSlice);
break;
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index 01708af87d9..d633b7af16e 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -24,7 +24,6 @@ import android.util.Log;
import androidx.annotation.Keep;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
-import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
@@ -66,8 +65,6 @@ public class SliceDeepLinkSpringBoard extends Activity {
launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
launchIntent = BluetoothSliceBuilder.getIntent(this /* context */);
- } else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
- launchIntent = LocationSliceBuilder.getIntent(this /* context */);
} else {
final SlicesDatabaseAccessor slicesDatabaseAccessor =
new SlicesDatabaseAccessor(this /* context */);
diff --git a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
index 56a84bb08e2..4af57545642 100644
--- a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
@@ -42,7 +42,7 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
-public class FlashlightSliceBuilderTest {
+public class FlashlightSliceTest {
private Context mContext;
@@ -58,7 +58,7 @@ public class FlashlightSliceBuilderTest {
public void getFlashlightSlice_correctData() {
Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
- final Slice slice = FlashlightSliceBuilder.getSlice(mContext);
+ final Slice slice = new FlashlightSlice(mContext).getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
final List toggles = metadata.getToggles();
diff --git a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
similarity index 93%
rename from tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/location/LocationSliceTest.java
index ecbf858095a..8f1045ad0ee 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
@@ -24,7 +24,7 @@ import org.robolectric.RuntimeEnvironment;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
-public class LocationSliceBuilderTest {
+public class LocationSliceTest {
private Context mContext;
@@ -38,7 +38,7 @@ public class LocationSliceBuilderTest {
@Test
public void getLocationSlice_correctSliceContent() {
- final Slice LocationSlice = LocationSliceBuilder.getSlice(mContext);
+ final Slice LocationSlice = new LocationSlice(mContext).getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, LocationSlice);
final List toggles = metadata.getToggles();
From 42055cbe50b80e58ca3e886f6a8c92fe0249f67b Mon Sep 17 00:00:00 2001
From: Malcolm Chen
Date: Wed, 5 Dec 2018 12:48:00 -0800
Subject: [PATCH 12/26] Only enable data for one SIM in DSDS.
Only enable mobile data for one SIM for simplicity. Which means When
turning on mobile data on non-default sub, pop a notification to user
that it will turn off data of the other one.
Bug: 120515679
Test: manual and unittest
Change-Id: I7c190bb70d771b7f280c246038a380e4fc7338a3
---
.../telephony/MobileDataPreferenceController.java | 13 ++++---------
.../network/telephony/MobileNetworkUtils.java | 3 ++-
.../MobileDataPreferenceControllerTest.java | 4 ++--
3 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index b1124f8eee1..9ebeda0fb4f 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -22,7 +22,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -131,16 +130,12 @@ public class MobileDataPreferenceController extends TogglePreferenceController
@VisibleForTesting
boolean isDialogNeeded() {
final boolean enableData = !mTelephonyManager.isDataEnabled();
- final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
- mSubId);
- final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1);
- final boolean isMultipleDataOnCapable =
- (mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1);
- final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null
- && currentSir.getSubscriptionId() == nextSir.getSubscriptionId());
+ final int defaultSubId = mSubscriptionManager.getDefaultDataSubscriptionId();
+ final boolean needToDisableOthers = mSubscriptionManager
+ .isActiveSubscriptionId(defaultSubId) && defaultSubId != mSubId;
if (enableData) {
- if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) {
+ if (isMultiSim && needToDisableOthers) {
mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG;
return true;
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index dc184d3df3f..27cc3673061 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -230,7 +230,8 @@ public class MobileNetworkUtils {
subscriptionManager.getActiveSubscriptionInfoList();
if (subInfoList != null) {
for (SubscriptionInfo subInfo : subInfoList) {
- if (subInfo.getSubscriptionId() != subId) {
+ // We never disable mobile data for opportunistic subscriptions.
+ if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) {
context.getSystemService(TelephonyManager.class).createForSubscriptionId(
subInfo.getSubscriptionId()).setDataEnabled(false);
}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
index 2fc3d987463..e1ad93bdb8e 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
@@ -20,6 +20,7 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -104,9 +105,8 @@ public class MobileDataPreferenceControllerTest {
public void isDialogNeeded_enableNonDefaultSimInMultiSimMode_returnTrue() {
doReturn(false).when(mTelephonyManager).isDataEnabled();
doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID);
- doReturn(null).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(anyInt());
doReturn(2).when(mTelephonyManager).getSimCount();
- doReturn(1).when(mTelephonyManager).getNumberOfModemsWithSimultaneousDataConnections();
assertThat(mController.isDialogNeeded()).isTrue();
assertThat(mController.mDialogType).isEqualTo(
From 2f7f14f08c9da1cd497eccfa6cf8ee6abc7ea396 Mon Sep 17 00:00:00 2001
From: Sunny Shao
Date: Wed, 5 Dec 2018 16:10:00 +0800
Subject: [PATCH 13/26] Added FloatingAppBarScrollingViewBehavior
-Added FloatingAppBarScrollingViewBehavior for search bar. It can be scolling,
transparent and overlapped the scrolling child view.
-Exchanged the position of NestedScrollView and AppBarLayout in
settings_homepage_container.xml.
-Set the app bar height.
Change-Id: I6ef4c9001a1f893292fcbc825a0a9f2069b7286b
Fixes: 118886724
Test: robotest
---
res/layout/settings_homepage_container.xml | 17 +++--
res/values/dimens.xml | 2 +
.../FloatingAppBarScrollingViewBehavior.java | 61 ++++++++++++++++++
...oatingAppBarScrollingViewBehaviorTest.java | 63 +++++++++++++++++++
4 files changed, 134 insertions(+), 9 deletions(-)
create mode 100644 src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
create mode 100644 tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index 8d81e824642..75d449fe889 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -21,24 +21,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
-
-
+ app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
+
+
+
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 83848af419b..a6c6c37df50 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -105,6 +105,8 @@
32dp
4dp
16dp
+
+ 80dp
16dp
diff --git a/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
new file mode 100644
index 00000000000..23f6ccd4b92
--- /dev/null
+++ b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * This scrolling view behavior will set the background of the {@link AppBarLayout} as
+ * transparent and without the elevation. Also make header overlapped the scrolling child view.
+ */
+public class FloatingAppBarScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
+ private boolean initialized;
+
+ public FloatingAppBarScrollingViewBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
+ boolean changed = super.onDependentViewChanged(parent, child, dependency);
+ if (!initialized && dependency instanceof AppBarLayout) {
+ initialized = true;
+ AppBarLayout appBarLayout = (AppBarLayout) dependency;
+ setAppBarLayoutTransparent(appBarLayout);
+ }
+ return changed;
+ }
+
+ @VisibleForTesting
+ void setAppBarLayoutTransparent(AppBarLayout appBarLayout) {
+ appBarLayout.setBackgroundColor(Color.TRANSPARENT);
+ appBarLayout.setTargetElevation(0);
+ }
+
+ @Override
+ protected boolean shouldHeaderOverlapScrollingChild() {
+ return true;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
new file mode 100644
index 00000000000..6acc4d984fe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class FloatingAppBarScrollingViewBehaviorTest {
+
+ private FloatingAppBarScrollingViewBehavior mScrollingViewBehavior;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mScrollingViewBehavior = new FloatingAppBarScrollingViewBehavior(mContext,
+ Robolectric.buildAttributeSet().build());
+ }
+
+ @Test
+ public void shouldHeaderOverlapScrollingChild_returnTrue() {
+ assertThat(mScrollingViewBehavior.shouldHeaderOverlapScrollingChild()).isTrue();
+ }
+
+ @Test
+ public void setAppBarLayoutTransparent_backgroundDefaultAsWhite_shouldBeTransparent() {
+ mContext.setTheme(R.style.Theme_Settings_Home);
+ final AppBarLayout appBarLayout = new AppBarLayout(mContext);
+ appBarLayout.setBackgroundColor(Color.WHITE);
+ mScrollingViewBehavior.setAppBarLayoutTransparent(appBarLayout);
+ assertThat(((ColorDrawable) appBarLayout.getBackground()).getColor()).isEqualTo(
+ Color.TRANSPARENT);
+ }
+}
From eda2987b86c97a1c241e7854854d2f2117776cd1 Mon Sep 17 00:00:00 2001
From: Chienyuan
Date: Wed, 7 Nov 2018 16:55:24 +0800
Subject: [PATCH 14/26] Show reboot dialog when tunring off developer option
The toggle button "Disable Bluetooth A2DP hardware offload" in developer
options need reboot to take effect when value changed. Otherwise, the
A2DP will not work until user reboot the device.
If we want this toggle button change back to default value when turning
off developer options, we need reboot device as well.
This patch will check the property value of A2DP hardware offload. If
turning off developer options will change the value, show a dialog to
force the user to reboot device.
Bug: 80449594
Test: make -j50 RunSettingsRoboTests
Change-Id: Ibace1ff72c1b41bd55444242a74e3f0b49187668
---
...oothA2dpHwOffloadPreferenceController.java | 19 ++++
.../DevelopmentSettingsDashboardFragment.java | 20 ++++-
.../DisableDevSettingsDialogFragment.java | 88 +++++++++++++++++++
...elopmentSettingsDashboardFragmentTest.java | 44 +++++++++-
4 files changed, 169 insertions(+), 2 deletions(-)
create mode 100644 src/com/android/settings/development/DisableDevSettingsDialogFragment.java
diff --git a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
index 0fcec05bd43..95e663bf50f 100644
--- a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
@@ -66,6 +66,25 @@ public class BluetoothA2dpHwOffloadPreferenceController extends DeveloperOptions
}
}
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ final boolean offloadSupported =
+ SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
+ if (offloadSupported) {
+ ((SwitchPreference) mPreference).setChecked(false);
+ SystemProperties.set(A2DP_OFFLOAD_DISABLED_PROPERTY, "false");
+ }
+ }
+
+ public boolean isDefaultValue() {
+ final boolean offloadSupported =
+ SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
+ final boolean offloadDisabled =
+ SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
+ return offloadSupported ? !offloadDisabled : true;
+ }
+
public void onA2dpHwDialogConfirmed() {
final boolean offloadDisabled =
SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 762686ad51f..4ddcc364c6d 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -221,7 +221,16 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
if (isChecked) {
EnableDevelopmentSettingWarningDialog.show(this /* host */);
} else {
- disableDeveloperOptions();
+ final BluetoothA2dpHwOffloadPreferenceController controller =
+ getDevelopmentOptionsController(
+ BluetoothA2dpHwOffloadPreferenceController.class);
+ // If A2DP hardware offload isn't default value, we must reboot after disable
+ // developer options. Show a dialog for the user to confirm.
+ if (controller == null || controller.isDefaultValue()) {
+ disableDeveloperOptions();
+ } else {
+ DisableDevSettingsDialogFragment.show(this /* host */);
+ }
}
}
}
@@ -380,6 +389,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
mSwitchBar.setChecked(false);
}
+ void onDisableDevelopmentOptionsConfirmed() {
+ disableDeveloperOptions();
+ }
+
+ void onDisableDevelopmentOptionsRejected() {
+ // Reset the toggle
+ mSwitchBar.setChecked(true);
+ }
+
private static List buildPreferenceControllers(Context context,
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
diff --git a/src/com/android/settings/development/DisableDevSettingsDialogFragment.java b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
new file mode 100644
index 00000000000..9b3ba588256
--- /dev/null
+++ b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
@@ -0,0 +1,88 @@
+/*
+ * 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.development;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class DisableDevSettingsDialogFragment extends InstrumentedDialogFragment
+ implements DialogInterface.OnClickListener {
+
+ public static final String TAG = "DisableDevSettingDlg";
+
+ @VisibleForTesting
+ static DisableDevSettingsDialogFragment newInstance() {
+ final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
+ return dialog;
+ }
+
+ public static void show(DevelopmentSettingsDashboardFragment host) {
+ final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
+ dialog.setTargetFragment(host, 0 /* requestCode */);
+ final FragmentManager manager = host.getActivity().getSupportFragmentManager();
+ dialog.show(manager, TAG);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.DIALOG_DISABLE_DEVELOPMENT_OPTIONS;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Reuse the same text of disable_a2dp_hw_offload_dialog.
+ // The text is generic enough to be used for turning off Dev options.
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message)
+ .setTitle(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title)
+ .setPositiveButton(
+ R.string.bluetooth_disable_a2dp_hw_offload_dialog_confirm, this)
+ .setNegativeButton(
+ R.string.bluetooth_disable_a2dp_hw_offload_dialog_cancel, this)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Fragment fragment = getTargetFragment();
+ if (!(fragment instanceof DevelopmentSettingsDashboardFragment)){
+ Log.e(TAG, "getTargetFragment return unexpected type");
+ }
+
+ final DevelopmentSettingsDashboardFragment host =
+ (DevelopmentSettingsDashboardFragment) fragment;
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ host.onDisableDevelopmentOptionsConfirmed();
+ PowerManager pm = getContext().getSystemService(PowerManager.class);
+ pm.reboot(null);
+ } else {
+ host.onDisableDevelopmentOptionsRejected();
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index d2c9b65455d..5eb21bdadc6 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -28,10 +28,15 @@ import android.content.Context;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch;
@@ -47,12 +52,14 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
import org.robolectric.util.ReflectionHelpers;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = ShadowUserManager.class)
+@Config(shadows = {ShadowUserManager.class, ShadowAlertDialogCompat.class,
+ SettingsShadowResourcesImpl.class})
public class DevelopmentSettingsDashboardFragmentTest {
private ToggleSwitch mSwitch;
@@ -178,6 +185,29 @@ public class DevelopmentSettingsDashboardFragmentTest {
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
}
+ @Test
+ @Config(shadows = ShadowDisableDevSettingsDialogFragment.class)
+ public void onSwitchChanged_turnOff_andOffloadIsNotDefaultValue_shouldShowWarningDialog() {
+ final BluetoothA2dpHwOffloadPreferenceController controller =
+ mock(BluetoothA2dpHwOffloadPreferenceController.class);
+ when(mDashboard.getContext()).thenReturn(mContext);
+ when(mDashboard.getDevelopmentOptionsController(
+ BluetoothA2dpHwOffloadPreferenceController.class)).thenReturn(controller);
+ when(controller.isDefaultValue()).thenReturn(false);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+
+ mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+
+ AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(dialog).isNotNull();
+ ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
+ assertThat(shadowDialog.getTitle()).isEqualTo(
+ mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title));
+ assertThat(shadowDialog.getMessage()).isEqualTo(
+ mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message));
+ }
+
@Test
public void onOemUnlockDialogConfirmed_shouldCallControllerOemConfirmed() {
final OemUnlockPreferenceController controller = mock(OemUnlockPreferenceController.class);
@@ -264,6 +294,18 @@ public class DevelopmentSettingsDashboardFragmentTest {
}
}
+ @Implements(DisableDevSettingsDialogFragment.class)
+ public static class ShadowDisableDevSettingsDialogFragment {
+
+ @Implementation
+ public static void show(DevelopmentSettingsDashboardFragment host) {
+ DisableDevSettingsDialogFragment mFragment =
+ spy(DisableDevSettingsDialogFragment.newInstance());
+ FragmentController.setupFragment(mFragment, FragmentActivity.class,
+ 0 /* containerViewId */, null /* bundle */);
+ }
+ }
+
@Implements(PictureColorModePreferenceController.class)
public static class ShadowPictureColorModePreferenceController {
@Implementation
From 064600b9128bbfb5bd14e99b7d2e3080db1e59b5 Mon Sep 17 00:00:00 2001
From: Leon Liao
Date: Thu, 6 Dec 2018 16:39:09 +0800
Subject: [PATCH 15/26] Update a11y timeout UI
Update UI with moving descriptive text to bottom(FooterPreference) and
adding video controller.
Test: atest AccessibilityTimeoutControllerTest
Test: make RunSettingsRoboTests
Test: atest UniquePreferenceTest
Change-Id: Ib3d4a88aa633539691ea902f6d41ceb55b55caef
---
...accessibility_content_timeout_settings.xml | 20 +++++++++----------
...accessibility_control_timeout_settings.xml | 20 +++++++++----------
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/res/xml/accessibility_content_timeout_settings.xml b/res/xml/accessibility_content_timeout_settings.xml
index d4504495342..2d9072b222d 100644
--- a/res/xml/accessibility_content_timeout_settings.xml
+++ b/res/xml/accessibility_content_timeout_settings.xml
@@ -17,27 +17,23 @@
-
-
+
+
diff --git a/res/xml/accessibility_control_timeout_settings.xml b/res/xml/accessibility_control_timeout_settings.xml
index 6d8e1d010b0..ea8d8c64580 100644
--- a/res/xml/accessibility_control_timeout_settings.xml
+++ b/res/xml/accessibility_control_timeout_settings.xml
@@ -17,27 +17,23 @@
-
-
+
+
From 69a56b42a1ed4fb8162deebbe5f17278720267f6 Mon Sep 17 00:00:00 2001
From: Fan Zhang
Date: Thu, 6 Dec 2018 12:02:05 -0800
Subject: [PATCH 16/26] Catch error when we fail to get slice icon.
Change-Id: Ia8bdf1ef8a090d2f939abf27b2308eafde7d8928
Fixes: 120588243
Test: robotests
---
.../android/settings/slices/SliceBuilderUtils.java | 8 +++++++-
.../settings/slices/SliceBuilderUtilsTest.java | 13 +++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index c16a8ba2c1f..d75eaa2e1a2 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -449,6 +449,12 @@ public class SliceBuilderUtils {
if (iconResource == 0) {
iconResource = R.drawable.ic_settings;
}
- return IconCompat.createWithResource(context, iconResource);
+ try {
+ return IconCompat.createWithResource(context, iconResource);
+ } catch (Exception e) {
+ Log.w(TAG, "Falling back to settings icon because there is an error getting slice icon "
+ + data.getUri(), e);
+ return IconCompat.createWithResource(context, R.drawable.ic_settings);
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index f9937f4dd5a..821d3830992 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -505,6 +505,19 @@ public class SliceBuilderUtilsTest {
assertThat(actualIconResource).isEqualTo(settingsIcon);
}
+ @Test
+ public void getSafeIcon_invalidResource_shouldFallbackToSettingsIcon() {
+ final int settingsIcon = R.drawable.ic_settings;
+ final int badIcon = 0x12345678;
+ final SliceData data = getDummyData(TOGGLE_CONTROLLER, SliceData.SliceType.SWITCH,
+ badIcon);
+
+ final IconCompat actualIcon = SliceBuilderUtils.getSafeIcon(mContext, data);
+
+ final int actualIconResource = actualIcon.toIcon().getResId();
+ assertThat(actualIconResource).isEqualTo(settingsIcon);
+ }
+
private SliceData getDummyData() {
return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
ICON, IS_DYNAMIC_SUMMARY_ALLOWED);
From 42e9d266359fc438cbef992b0f4f0eb7351ad513 Mon Sep 17 00:00:00 2001
From: Salvador Martinez
Date: Tue, 4 Dec 2018 14:13:10 -0800
Subject: [PATCH 17/26] Allow appending static preferences to
RadioButtonPickerFragment
This makes it so that static preferences can also be added after
the candidates so they can show up on the bottom of the screen.
This is done via a new xml tag for the preference screen that
is usually mostly empty that RaiodButtonPickerFragments use
Test: robotests
Bug: 111450127
Change-Id: I0fe2f480f0ff59b9bf9269e94b33ab4b008b47b8
---
res/values/attrs.xml | 8 +++++
res/values/strings.xml | 6 ++++
res/xml/battery_saver_schedule_settings.xml | 23 ++++++++++++++
.../core/PreferenceXmlParserUtils.java | 28 ++++++++++++++---
.../widget/RadioButtonPickerFragment.java | 31 +++++++++++++++++--
.../battery_saver_schedule_settings.xml | 23 ++++++++++++++
.../core/PreferenceXmlParserUtilsTest.java | 27 ++++++++++++++++
.../ColorModePreferenceFragmentTest.java | 1 +
.../widget/RadioButtonPickerFragmentTest.java | 23 ++++++++++++++
9 files changed, 163 insertions(+), 7 deletions(-)
create mode 100644 res/xml/battery_saver_schedule_settings.xml
create mode 100644 tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 752fd3dada5..86763b77169 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -72,6 +72,14 @@
+
+
+
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4aa09515ca0..4aab4e0fceb 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5406,6 +5406,12 @@
Turn on automatically
+
+ No schedule
+
+
+ Set a schedule
+
At %1$s
diff --git a/res/xml/battery_saver_schedule_settings.xml b/res/xml/battery_saver_schedule_settings.xml
new file mode 100644
index 00000000000..f91e4ca25d1
--- /dev/null
+++ b/res/xml/battery_saver_schedule_settings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java
index 9fdeeefbe5a..ce5c5051f5a 100644
--- a/src/com/android/settings/core/PreferenceXmlParserUtils.java
+++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java
@@ -55,6 +55,8 @@ public class PreferenceXmlParserUtils {
private static final List SUPPORTED_PREF_TYPES = Arrays.asList(
"Preference", "PreferenceCategory", "PreferenceScreen",
"com.android.settings.widget.WorkOnlyCategory");
+ public static final int PREPEND_VALUE = 0;
+ public static final int APPEND_VALUE = 1;
/**
* Flag definition to indicate which metadata should be extracted when
@@ -84,6 +86,7 @@ public class PreferenceXmlParserUtils {
int FLAG_NEED_KEYWORDS = 1 << 8;
int FLAG_NEED_SEARCHABLE = 1 << 9;
int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10;
+ int FLAG_NEED_PREF_APPEND = 1 << 11;
}
public static final String METADATA_PREF_TYPE = "type";
@@ -97,6 +100,7 @@ public class PreferenceXmlParserUtils {
public static final String METADATA_SEARCHABLE = "searchable";
public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE =
"allow_dynamic_summary_in_slice";
+ public static final String METADATA_APPEND = "staticPreferenceLocation";
private static final String ENTRIES_SEPARATOR = "|";
@@ -184,14 +188,13 @@ public class PreferenceXmlParserUtils {
// Parse next until start tag is found
}
final int outerDepth = parser.getDepth();
-
+ final boolean hasPrefScreenFlag = hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN);
do {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String nodeName = parser.getName();
- if (!hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN)
- && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) {
+ if (!hasPrefScreenFlag && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) {
continue;
}
if (!SUPPORTED_PREF_TYPES.contains(nodeName) && !nodeName.endsWith("Preference")) {
@@ -199,8 +202,14 @@ public class PreferenceXmlParserUtils {
}
final Bundle preferenceMetadata = new Bundle();
final AttributeSet attrs = Xml.asAttributeSet(parser);
+
final TypedArray preferenceAttributes = context.obtainStyledAttributes(attrs,
R.styleable.Preference);
+ TypedArray preferenceScreenAttributes = null;
+ if (hasPrefScreenFlag) {
+ preferenceScreenAttributes = context.obtainStyledAttributes(
+ attrs, R.styleable.PreferenceScreen);
+ }
if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_TYPE)) {
preferenceMetadata.putString(METADATA_PREF_TYPE, nodeName);
@@ -236,6 +245,10 @@ public class PreferenceXmlParserUtils {
preferenceMetadata.putBoolean(METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
isDynamicSummaryAllowed(preferenceAttributes));
}
+ if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_APPEND) && hasPrefScreenFlag) {
+ preferenceMetadata.putBoolean(METADATA_APPEND,
+ isAppended(preferenceScreenAttributes));
+ }
metadata.add(preferenceMetadata);
preferenceAttributes.recycle();
@@ -325,7 +338,12 @@ public class PreferenceXmlParserUtils {
false /* default */);
}
- private static String getKeywords(TypedArray styleAttributes) {
- return styleAttributes.getString(R.styleable.Preference_keywords);
+ private static String getKeywords(TypedArray styledAttributes) {
+ return styledAttributes.getString(R.styleable.Preference_keywords);
+ }
+
+ private static boolean isAppended(TypedArray styledAttributes) {
+ return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation,
+ PREPEND_VALUE) == APPEND_VALUE;
}
}
diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java
index 89df487200e..50c1b58442f 100644
--- a/src/com/android/settings/widget/RadioButtonPickerFragment.java
+++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java
@@ -22,10 +22,12 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Toast;
import androidx.annotation.LayoutRes;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -34,16 +36,23 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.core.PreferenceXmlParserUtils;
+import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import com.android.settingslib.widget.CandidateInfo;
+import java.io.IOException;
import java.util.List;
import java.util.Map;
+import org.xmlpull.v1.XmlPullParserException;
public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements
RadioButtonPreference.OnClickListener {
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ @VisibleForTesting
static final String EXTRA_FOR_WORK = "for_work";
+ private static final String TAG = "RadioButtonPckrFrgmt";
+ @VisibleForTesting
+ boolean mAppendStaticPreferences = false;
private final Map mCandidates = new ArrayMap<>();
@@ -69,6 +78,19 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
+ try {
+ // Check if the xml specifies if static preferences should go on the top or bottom
+ final List metadata = PreferenceXmlParserUtils.extractMetadata(getContext(),
+ getPreferenceScreenResId(),
+ MetadataFlag.FLAG_INCLUDE_PREF_SCREEN |
+ MetadataFlag.FLAG_NEED_PREF_APPEND);
+ mAppendStaticPreferences = metadata.get(0)
+ .getBoolean(PreferenceXmlParserUtils.METADATA_APPEND);
+ } catch (IOException e) {
+ Log.e(TAG, "Error trying to open xml file", e);
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Error parsing xml", e);
+ }
updateCandidates();
}
@@ -142,7 +164,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
final String systemDefaultKey = getSystemDefaultKey();
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
- addStaticPreferences(screen);
+ if (!mAppendStaticPreferences) {
+ addStaticPreferences(screen);
+ }
final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId();
if (shouldShowItemNone()) {
@@ -168,6 +192,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
}
}
mayCheckOnlyRadioButton();
+ if (mAppendStaticPreferences) {
+ addStaticPreferences(screen);
+ }
}
@VisibleForTesting
diff --git a/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml b/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml
new file mode 100644
index 00000000000..f91e4ca25d1
--- /dev/null
+++ b/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
index 3b1b5afc3ab..ebf325273a0 100644
--- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
@@ -18,6 +18,7 @@ package com.android.settings.core;
import static com.android.settings.core.PreferenceXmlParserUtils
.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE;
@@ -315,6 +316,32 @@ public class PreferenceXmlParserUtilsTest {
}
}
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void extractMetadata_requestAppendProperty_shouldDefaultToFalse()
+ throws Exception {
+ final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
+ R.xml.display_settings,
+ MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
+
+ for (Bundle bundle : metadata) {
+ assertThat(bundle.getBoolean(METADATA_APPEND)).isFalse();
+ }
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue()
+ throws Exception {
+ final List metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
+ R.xml.battery_saver_schedule_settings,
+ MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
+
+ for (Bundle bundle : metadata) {
+ assertThat(bundle.getBoolean(METADATA_APPEND)).isTrue();
+ }
+ }
+
/**
* @param resId the ID for the XML preference
* @return an XML resource parser that points to the start tag
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
index 859912aa71c..57f0ebbc6a0 100644
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
@@ -209,6 +209,7 @@ public class ColorModePreferenceFragmentTest {
@Test
public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() {
+ when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
doNothing().when(mFragment).addPreferencesFromResource(anyInt());
doNothing().when(mFragment).updateCandidates();
diff --git a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
index 64352d96638..55d212ffef1 100644
--- a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
@@ -18,6 +18,7 @@ package com.android.settings.widget;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -37,7 +38,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -98,6 +101,26 @@ public class RadioButtonPickerFragmentTest {
assertThat(mFragment.setDefaultKeyCalled).isTrue();
}
+ @Test
+ public void staticPreferencesPrepended_addedFirst() {
+ mFragment.mAppendStaticPreferences = false;
+ mFragment.updateCandidates();
+
+ InOrder inOrder = Mockito.inOrder(mFragment);
+ inOrder.verify(mFragment).addStaticPreferences(any());
+ inOrder.verify(mFragment).getRadioButtonPreferenceCustomLayoutResId();
+ }
+
+ @Test
+ public void staticPreferencesAppended_addedLast() {
+ mFragment.mAppendStaticPreferences = true;
+ mFragment.updateCandidates();
+
+ InOrder inOrder = Mockito.inOrder(mFragment);
+ inOrder.verify(mFragment).mayCheckOnlyRadioButton();
+ inOrder.verify(mFragment).addStaticPreferences(any());
+ }
+
@Test
public void shouldHaveNoCustomPreferenceLayout() {
assertThat(mFragment.getRadioButtonPreferenceCustomLayoutResId()).isEqualTo(0);
From e58e0c6e0ec2587bca6058e4d8a09d03dd5cfe71 Mon Sep 17 00:00:00 2001
From: Raff Tsai
Date: Wed, 5 Dec 2018 19:13:46 +0800
Subject: [PATCH 18/26] Log contextual card is visible and homepage is
displayed event
Bug: 79698338
Test: Robolectric
Change-Id: I89ac5ed2765729d8571e84d3a050f0aa07385caa
---
.../ContextualCardFeatureProviderImpl.java | 37 +++++++++--
.../contextualcards/ContextualCardLoader.java | 62 +++++++++++++------
.../ContextualCardManager.java | 10 ++-
...ContextualCardFeatureProviderImplTest.java | 45 +++++++++++++-
4 files changed, 126 insertions(+), 28 deletions(-)
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index e437e2b37f9..32a86e84389 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -16,8 +16,10 @@
package com.android.settings.homepage.contextualcards;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -25,6 +27,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.slice.widget.EventInfo;
import com.android.settings.R;
+import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import java.util.List;
@@ -38,10 +41,6 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
// Contextual card shows, log card name and rank
private static final int CONTEXTUAL_CARD_SHOW = 39;
- // Contextual card is eligible to be shown, but doesn't rank high
- // enough, log card name and score
- private static final int CONTEXTUAL_CARD_NOT_SHOW = 40;
-
// Contextual card is dismissed, log card name
private static final int CONTEXTUAL_CARD_DISMISS = 41;
@@ -67,6 +66,11 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
// log type
private static final String EXTRA_CONTEXTUALCARD_ACTION_TYPE = "type";
+ // displayed contextual cards
+ private static final String EXTRA_CONTEXTUALCARD_VISIBLE = "visible";
+
+ // hidden contextual cards
+ private static final String EXTRA_CONTEXTUALCARD_HIDDEN = "hidden";
// Contextual card tap target
private static final int TARGET_DEFAULT = 0;
@@ -82,6 +86,10 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
@Override
public void logHomepageDisplay(Context context, Long latency) {
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW);
+ intent.putExtra(EXTRA_LATENCY, latency);
+ sendBroadcast(context, intent);
}
@Override
@@ -94,8 +102,13 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
}
@Override
- public void logContextualCardDisplay(Context context, List showCards,
+ public void logContextualCardDisplay(Context context, List visibleCards,
List hiddenCards) {
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_SHOW);
+ intent.putExtra(EXTRA_CONTEXTUALCARD_VISIBLE, serialize(visibleCards));
+ intent.putExtra(EXTRA_CONTEXTUALCARD_HIDDEN, serialize(hiddenCards));
+ sendBroadcast(context, intent);
}
@Override
@@ -116,7 +129,7 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
final String action = context.getString(R.string.config_settingsintelligence_log_action);
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
- context.sendBroadcast(intent);
+ context.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
@@ -133,4 +146,16 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
return TARGET_DEFAULT;
}
}
+
+ @VisibleForTesting
+ @NonNull
+ byte[] serialize(List cards) {
+ final ContextualCardList.Builder builder = ContextualCardList.newBuilder();
+ cards.stream().forEach(card -> builder.addCard(
+ com.android.settings.intelligence.ContextualCardProto.ContextualCard.newBuilder()
+ .setSliceUri(card.getSliceUri().toString())
+ .setCardName(card.getName())
+ .build()));
+ return builder.build().toByteArray();
+ }
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 3ef465333fd..6373519c770 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -20,6 +20,9 @@ import static android.app.slice.Slice.HINT_ERROR;
import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
+import static com.android.settings.slices.CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI;
+import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
+
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
@@ -34,7 +37,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.slice.Slice;
-import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList;
@@ -103,27 +106,50 @@ public class ContextualCardLoader extends AsyncLoaderCompat
return getFinalDisplayableCards(result);
}
+ // Get final displayed cards and log what cards will be displayed/hidden
@VisibleForTesting
List getFinalDisplayableCards(List candidates) {
- List eligibleCards = filterEligibleCards(candidates);
- eligibleCards = eligibleCards.stream().limit(DEFAULT_CARD_COUNT).collect(
- Collectors.toList());
+ final List eligibleCards = filterEligibleCards(candidates);
+ final List visibleCards = new ArrayList<>();
+ final List hiddenCards = new ArrayList<>();
- if (eligibleCards.size() <= 2 || getNumberOfLargeCard(eligibleCards) == 0) {
- return eligibleCards;
+ final int size = eligibleCards.size();
+ for (int i = 0; i < size; i++) {
+ if (i < DEFAULT_CARD_COUNT) {
+ visibleCards.add(eligibleCards.get(i));
+ } else {
+ hiddenCards.add(eligibleCards.get(i));
+ }
}
- if (eligibleCards.size() == DEFAULT_CARD_COUNT) {
- eligibleCards.remove(eligibleCards.size() - 1);
+ try {
+ // The maximum cards are four small cards OR
+ // one large card with two small cards OR
+ // two large cards
+ if (visibleCards.size() <= 2 || getNumberOfLargeCard(visibleCards) == 0) {
+ // four small cards
+ return visibleCards;
+ }
+
+ if (visibleCards.size() == DEFAULT_CARD_COUNT) {
+ hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
+ }
+
+ if (getNumberOfLargeCard(visibleCards) == 1) {
+ // One large card with two small cards
+ return visibleCards;
+ }
+
+ hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
+
+ // Two large cards
+ return visibleCards;
+ } finally {
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
+ contextualCardFeatureProvider.logContextualCardDisplay(mContext, visibleCards,
+ hiddenCards);
}
-
- if (getNumberOfLargeCard(eligibleCards) == 1) {
- return eligibleCards;
- }
-
- eligibleCards.remove(eligibleCards.size() - 1);
-
- return eligibleCards;
}
@VisibleForTesting
@@ -169,8 +195,8 @@ public class ContextualCardLoader extends AsyncLoaderCompat
private int getNumberOfLargeCard(List cards) {
return (int) cards.stream()
- .filter(card -> card.getSliceUri().equals(CustomSliceRegistry.WIFI_SLICE_URI)
- || card.getSliceUri().equals(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI))
+ .filter(card -> card.getSliceUri().equals(WIFI_SLICE_URI)
+ || card.getSliceUri().equals(CONNECTED_DEVICE_SLICE_URI))
.count();
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 5f397d787eb..28ad0d30e8e 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -16,8 +16,7 @@
package com.android.settings.homepage.contextualcards;
-import static com.android.settings.homepage.contextualcards.ContextualCardLoader
- .CARD_CONTENT_LOADER_ID;
+import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
import static java.util.stream.Collectors.groupingBy;
@@ -33,6 +32,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -72,6 +72,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
private final List mLifecycleObservers;
private ContextualCardUpdateListener mListener;
+ private long mStartTime;
public ContextualCardManager(Context context, Lifecycle lifecycle) {
mContext = context;
@@ -86,6 +87,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
}
void loadContextualCards(ContextualCardsFragment fragment) {
+ mStartTime = System.currentTimeMillis();
final CardContentLoaderCallbacks cardContentLoaderCallbacks =
new CardContentLoaderCallbacks(mContext);
cardContentLoaderCallbacks.setListener(this);
@@ -168,6 +170,10 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
@Override
public void onFinishCardLoading(List cards) {
onContextualCardUpdated(cards.stream().collect(groupingBy(ContextualCard::getCardType)));
+ final long elapsedTime = System.currentTimeMillis() - mStartTime;
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
+ contextualCardFeatureProvider.logHomepageDisplay(mContext, elapsedTime);
}
public ControllerRendererPool getControllerRendererPool() {
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
index 08631f7bdfc..b3f94114776 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -16,13 +16,20 @@
package com.android.settings.homepage.contextualcards;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
+import android.os.UserHandle;
+import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -31,6 +38,9 @@ import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class ContextualCardFeatureProviderImplTest {
@@ -48,7 +58,7 @@ public class ContextualCardFeatureProviderImplTest {
final Intent intent = new Intent();
mImpl.sendBroadcast(mContext, intent);
- verify(mContext, never()).sendBroadcast(intent);
+ verify(mContext, never()).sendBroadcastAsUser(intent, UserHandle.ALL);
}
@Test
@@ -57,6 +67,37 @@ public class ContextualCardFeatureProviderImplTest {
final Intent intent = new Intent();
mImpl.sendBroadcast(mContext, intent);
- verify(mContext).sendBroadcast(intent);
+ verify(mContext).sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void logContextualCardDisplay_hasAction_sendBroadcast() {
+ mImpl.logContextualCardDisplay(mContext, new ArrayList<>(), new ArrayList<>());
+
+ verify(mContext).sendBroadcastAsUser(any(Intent.class), any());
+ }
+
+ @Test
+ public void serialize_hasSizeTwo_returnSizeTwo() {
+ final List cards = new ArrayList<>();
+ cards.add(new ContextualCard.Builder()
+ .setName("name1")
+ .setSliceUri(Uri.parse("uri1"))
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("name2")
+ .setSliceUri(Uri.parse("uri2"))
+ .build());
+
+
+ final byte[] data = mImpl.serialize(cards);
+
+ try {
+ assertThat(ContextualCardList
+ .parseFrom(data).getCardCount()).isEqualTo(cards.size());
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
}
}
\ No newline at end of file
From 8727a408939176d4a60d0bd4380b04c51b55e097 Mon Sep 17 00:00:00 2001
From: Doris Ling
Date: Thu, 6 Dec 2018 17:12:05 -0800
Subject: [PATCH 19/26] Don't plot usage data beyond current date.
- the new data usage api returns buckets for future date with 0 usage.
When we plot the data usage chart, need to check the bucket date to make
sure we only plot points up to the current date.
Change-Id: I50e161ca9cdbb30c8fda8f6cdd24c993b546ad0d
Fixes: 120490567
Test: make RunSettingsRoboTests
---
.../datausage/ChartDataUsagePreference.java | 4 ++
.../ChartDataUsagePreferenceTest.java | 68 +++++++++++++++++--
2 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index 1c8eb528694..17f23c4ec8f 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -95,9 +95,13 @@ public class ChartDataUsagePreference extends Preference {
final SparseIntArray points = new SparseIntArray();
points.put(0, 0);
+ final long now = System.currentTimeMillis();
long totalData = 0;
for (NetworkCycleData data : usageSummary) {
final long startTime = data.getStartTime();
+ if (startTime > now) {
+ break;
+ }
final long endTime = data.getEndTime();
// increment by current bucket total
diff --git a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
index af56029ddc0..0f9aed118e7 100644
--- a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
@@ -37,11 +37,14 @@ import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@RunWith(SettingsRobolectricTestRunner.class)
public class ChartDataUsagePreferenceTest {
+ // Test cycle start date, 20 Mar 2018 22:00: GMT
private static final long TIMESTAMP_START = 1521583200000L;
+ // Test bucket end date, 22 Mar 2018 00:00:00
private static final long TIMESTAMP_END = 1521676800000L;
private List mNetworkCycleData;
@@ -55,8 +58,6 @@ public class ChartDataUsagePreferenceTest {
mContext = RuntimeEnvironment.application;
mPreference = new ChartDataUsagePreference(mContext, null);
- createTestNetworkData();
- mPreference.setNetworkCycleData(mNetworkCycleChartData);
}
@Test
@@ -64,11 +65,13 @@ public class ChartDataUsagePreferenceTest {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
+ createTestNetworkData();
+ mPreference.setNetworkCycleData(mNetworkCycleChartData);
mPreference.calcPoints(usageView, mNetworkCycleData.subList(0, 5));
verify(usageView).addPath(pointsCaptor.capture());
- SparseIntArray points = pointsCaptor.getValue();
+ final SparseIntArray points = pointsCaptor.getValue();
// the point should be normal usage data
assertThat(points.valueAt(1)).isNotEqualTo(-1);
}
@@ -78,16 +81,73 @@ public class ChartDataUsagePreferenceTest {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
+ createTestNetworkData();
+ mPreference.setNetworkCycleData(mNetworkCycleChartData);
mPreference.calcPoints(usageView, mNetworkCycleData.subList(2, 7));
verify(usageView).addPath(pointsCaptor.capture());
- SparseIntArray points = pointsCaptor.getValue();
+ final SparseIntArray points = pointsCaptor.getValue();
// indicator that no data is available
assertThat(points.keyAt(1)).isEqualTo(points.keyAt(2) - 1);
assertThat(points.valueAt(1)).isEqualTo(-1);
}
+ @Test
+ public void calcPoints_shouldNotDrawPointForFutureDate() {
+ final UsageView usageView = mock(UsageView.class);
+ final ArgumentCaptor pointsCaptor =
+ ArgumentCaptor.forClass(SparseIntArray.class);
+ final long tonight = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(12);
+ mNetworkCycleData = new ArrayList<>();
+ // add test usage data for last 5 days
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight - TimeUnit.DAYS.toMillis(5), tonight - TimeUnit.DAYS.toMillis(4), 743823454L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight - TimeUnit.DAYS.toMillis(4), tonight - TimeUnit.DAYS.toMillis(3), 64396L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight - TimeUnit.DAYS.toMillis(3), tonight - TimeUnit.DAYS.toMillis(2), 2832L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight - TimeUnit.DAYS.toMillis(2), tonight - TimeUnit.DAYS.toMillis(1), 83849690L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight - TimeUnit.DAYS.toMillis(1), tonight, 1883657L));
+ // add dummy usage data for next 5 days
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight, tonight + TimeUnit.DAYS.toMillis(1), 0L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight + TimeUnit.DAYS.toMillis(1), tonight + TimeUnit.DAYS.toMillis(2), 0L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight + TimeUnit.DAYS.toMillis(2), tonight + TimeUnit.DAYS.toMillis(3), 0L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight + TimeUnit.DAYS.toMillis(3), tonight + TimeUnit.DAYS.toMillis(4), 0L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight + TimeUnit.DAYS.toMillis(4), tonight + TimeUnit.DAYS.toMillis(5), 0L));
+ mNetworkCycleData.add(createNetworkCycleData(
+ tonight + TimeUnit.DAYS.toMillis(5), tonight + TimeUnit.DAYS.toMillis(6), 0L));
+
+ final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
+ builder.setUsageBuckets(mNetworkCycleData)
+ .setStartTime(tonight - TimeUnit.DAYS.toMillis(5))
+ .setEndTime(tonight + TimeUnit.DAYS.toMillis(6));
+ mNetworkCycleChartData = builder.build();
+ mPreference.setNetworkCycleData(mNetworkCycleChartData);
+
+ mPreference.calcPoints(usageView, mNetworkCycleData);
+
+ verify(usageView).addPath(pointsCaptor.capture());
+ final SparseIntArray points = pointsCaptor.getValue();
+ // should only have 7 points: 1 dummy point indicating the start of data, starting point 0,
+ // and 5 actual data point for each day
+ assertThat(points.size()).isEqualTo(7);
+ assertThat(points.keyAt(0)).isEqualTo(-1);
+ assertThat(points.keyAt(1)).isEqualTo(0);
+ assertThat(points.keyAt(2)).isEqualTo(TimeUnit.DAYS.toMinutes(1));
+ assertThat(points.keyAt(3)).isEqualTo(TimeUnit.DAYS.toMinutes(2));
+ assertThat(points.keyAt(4)).isEqualTo(TimeUnit.DAYS.toMinutes(3));
+ assertThat(points.keyAt(5)).isEqualTo(TimeUnit.DAYS.toMinutes(4));
+ assertThat(points.keyAt(6)).isEqualTo(TimeUnit.DAYS.toMinutes(5));
+ }
+
private void createTestNetworkData() {
mNetworkCycleData = new ArrayList<>();
// create 10 arbitrary network data
From ddfc085f2ba050089213608dbffdae8059718c33 Mon Sep 17 00:00:00 2001
From: Yi-Ling Chuang
Date: Thu, 6 Dec 2018 22:13:35 +0800
Subject: [PATCH 20/26] Reload data if slice binding returns null at rendering
time.
We are not able to guarantee the binding results in the pre-check and
real binding would always be the same sinc slice may decide what it
would be based on some conditions. Hence, we should reload data and
refresh UI when it comes to null to prevent from blank suggestion.
Bug: 120221527
Test: visual
Change-Id: I79790edfe7fc3af7b9c3b3a7df6a7ffa7d405d50
---
.../slices/SliceContextualCardRenderer.java | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 267fe4dce25..be03c281e9a 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -41,6 +41,7 @@ import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;
import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.CardContentProvider;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
@@ -94,6 +95,8 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
final SliceViewHolder cardHolder = (SliceViewHolder) holder;
final Uri uri = card.getSliceUri();
+ //TODO(b/120629936): Take this out once blank card issue is fixed.
+ Log.d(TAG, "bindView - uri = " + uri);
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Log.w(TAG, "Invalid uri, skipping slice: " + uri);
@@ -116,6 +119,11 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
sliceLiveData.observe(mLifecycleOwner, slice -> {
if (slice == null) {
Log.w(TAG, "Slice is null");
+ mContext.getContentResolver().notifyChange(CardContentProvider.URI, null);
+ return;
+ } else {
+ //TODO(b/120629936): Take this out once blank card issue is fixed.
+ Log.d(TAG, "Slice callback - uri = " + slice.getUri());
}
cardHolder.sliceView.setSlice(slice);
});
From 1312a2b13edd9918d3296fdb3d78ff97b291cf35 Mon Sep 17 00:00:00 2001
From: Mill Chen
Date: Fri, 7 Dec 2018 16:18:32 +0800
Subject: [PATCH 21/26] Update the strings of conditional card
Bug: 113451905
Test: visual
Change-Id: Ie863855eff5a6a23f28b899809e5216c129fb448
---
res/values/strings.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 85f133f2a22..63a7662b9ae 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8976,7 +8976,7 @@
Mobile data is off
- Internet is available only via Wi-Fi
+ Internet only available via Wi\u2011Fi
Data Saver
@@ -8988,7 +8988,7 @@
Work profile is off
- Apps, background sync, and other features related to your work profile are turned off.
+ For apps & notifications
Turn on sound
From 5eec4ef7a9f1851ba3148b18431e8de7c24fa151 Mon Sep 17 00:00:00 2001
From: Sunny Shao
Date: Fri, 7 Dec 2018 15:16:56 +0800
Subject: [PATCH 22/26] Modified the shadow of the search bar
Modified the SearchBarStyle and added cardElevation and
enforceMaterialTheme attributes.
Bug: 118886724
Test: manual
Change-Id: If9f39ee5dcc85d837036391ae92aeedd6aea4ab6
---
res/values/styles.xml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 141426e6862..19ce33377ca 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -461,8 +461,9 @@