From f4a785cec70c7ba1dc1cd9a3d0338d0bf92cb321 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Thu, 27 Sep 2018 23:57:21 +0800 Subject: [PATCH] Add device info slice in Contextual Settings Homepage - Add device info card that implements CustomSliceable in Contextual Settings Homepage. - Add test case for device info slice. Bug: 114790594, 115971399 Test: robotests, manual, SliceBrowser Change-Id: I627a5b442e6ee20b3fd2e0500b31921bfec7b1d3 --- .../settings/homepage/CardContentLoader.java | 5 +- .../homepage/deviceinfo/DeviceInfoSlice.java | 147 ++++++++++++++++++ .../settings/slices/CustomSliceManager.java | 2 + .../deviceinfo/DeviceInfoSliceTest.java | 93 +++++++++++ 4 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java create mode 100644 tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java diff --git a/src/com/android/settings/homepage/CardContentLoader.java b/src/com/android/settings/homepage/CardContentLoader.java index 5b81a2381f0..9980503b216 100644 --- a/src/com/android/settings/homepage/CardContentLoader.java +++ b/src/com/android/settings/homepage/CardContentLoader.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.settings.homepage.deviceinfo.DataUsageSlice; +import com.android.settings.homepage.deviceinfo.DeviceInfoSlice; import com.android.settingslib.utils.AsyncLoaderCompat; import java.util.ArrayList; @@ -103,8 +104,8 @@ public class CardContentLoader extends AsyncLoaderCompat> { .setIsHalfWidth(true) .build()); add(new ContextualCard.Builder() - .setSliceUri("content://com.android.settings.slices/intent/device_info_card") - .setName(packageName + "/" + "device_info_card") + .setSliceUri(DeviceInfoSlice.DEVICE_INFO_CARD_URI.toString()) + .setName(packageName + "/" + DeviceInfoSlice.PATH_DEVICE_INFO_CARD) .setPackageName(packageName) .setRankingScore(rankingScore) .setAppVersion(appVersionCode) diff --git a/src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java b/src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java new file mode 100644 index 00000000000..dc315c53515 --- /dev/null +++ b/src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java @@ -0,0 +1,147 @@ +/* + * 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.homepage.deviceinfo; + +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.BidiFormatter; +import android.text.TextDirectionHeuristics; +import android.text.TextUtils; + +import androidx.annotation.VisibleForTesting; +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.SubSettings; +import com.android.settings.Utils; +import com.android.settings.deviceinfo.DeviceModelPreferenceController; +import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; +import com.android.settings.slices.CustomSliceable; +import com.android.settings.slices.SettingsSliceProvider; +import com.android.settings.slices.SliceBuilderUtils; +import com.android.settingslib.DeviceInfoUtils; + +import java.util.List; + +public class DeviceInfoSlice implements CustomSliceable { + private static final String TAG = "DeviceInfoSlice"; + + /** + * The path denotes the unique name of device info slice + */ + public static final String PATH_DEVICE_INFO_CARD = "device_info_card"; + + /** + * Backing Uri for the Device info Slice. + */ + public static final Uri DEVICE_INFO_CARD_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(PATH_DEVICE_INFO_CARD) + .build(); + + private final Context mContext; + private final TelephonyManager mTelephonyManager; + private final SubscriptionManager mSubscriptionManager; + + public DeviceInfoSlice(Context context) { + mContext = context; + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + } + + /** + * Return a device info slice bound to {@Link #DEVICE_INFO_CARD_URI} + */ + @Override + public Slice getSlice() { + final IconCompat icon = IconCompat.createWithResource(mContext, + R.drawable.ic_info_outline_24dp); + final String title = mContext.getString(R.string.device_info_label); + final SliceAction primaryAction = new SliceAction(getPrimaryAction(), icon, title); + return new ListBuilder(mContext, DEVICE_INFO_CARD_URI, ListBuilder.INFINITY) + .setAccentColor((Utils.getColorAccentDefaultColor(mContext))) + .setHeader(new ListBuilder.HeaderBuilder().setTitle(title)) + .addRow(new ListBuilder.RowBuilder() + .setTitle(getPhoneNumber()) + .setSubtitle(getDeviceModel()) + .setPrimaryAction(primaryAction)) + .build(); + } + + @Override + public Uri getUri() { + return DEVICE_INFO_CARD_URI; + } + + @Override + public Intent getIntent() { + final String screenTitle = mContext.getText(R.string.device_info_label).toString(); + final Uri contentUri = new Uri.Builder().appendPath(PATH_DEVICE_INFO_CARD).build(); + return SliceBuilderUtils.buildSearchResultPageIntent(mContext, + MyDeviceInfoFragment.class.getName(), PATH_DEVICE_INFO_CARD, screenTitle, + MetricsProto.MetricsEvent.SLICE) + .setClassName(mContext.getPackageName(), SubSettings.class.getName()) + .setData(contentUri); + } + + private PendingIntent getPrimaryAction() { + final Intent intent = getIntent(); + return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */); + } + + @VisibleForTesting + CharSequence getPhoneNumber() { + final SubscriptionInfo subscriptionInfo = getFirstSubscriptionInfo(); + if (subscriptionInfo == null) { + return mContext.getString(R.string.device_info_default); + } + final String phoneNumber = DeviceInfoUtils.getFormattedPhoneNumber(mContext, + subscriptionInfo); + return TextUtils.isEmpty(phoneNumber) ? mContext.getString(R.string.device_info_default) + : BidiFormatter.getInstance().unicodeWrap(phoneNumber, TextDirectionHeuristics.LTR); + } + + private CharSequence getDeviceModel() { + return DeviceModelPreferenceController.getDeviceModel(); + } + + @VisibleForTesting + SubscriptionInfo getFirstSubscriptionInfo() { + final List subscriptionInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfoList == null) { + return null; + } + return subscriptionInfoList.get(0); + } + + @Override + public void onNotifyChange(Intent intent) { + + } +} diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java index 3d81392735d..3d708c722e8 100644 --- a/src/com/android/settings/slices/CustomSliceManager.java +++ b/src/com/android/settings/slices/CustomSliceManager.java @@ -21,6 +21,7 @@ import android.net.Uri; import android.util.ArrayMap; import com.android.settings.homepage.deviceinfo.DataUsageSlice; +import com.android.settings.homepage.deviceinfo.DeviceInfoSlice; import com.android.settings.wifi.WifiSlice; import java.util.Map; @@ -89,5 +90,6 @@ public class CustomSliceManager { private void addSlices() { mUriMap.put(WifiSlice.WIFI_URI, WifiSlice.class); mUriMap.put(DataUsageSlice.DATA_USAGE_CARD_URI, DataUsageSlice.class); + mUriMap.put(DeviceInfoSlice.DEVICE_INFO_CARD_URI, DeviceInfoSlice.class); } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java b/tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java new file mode 100644 index 00000000000..2480bafa0e4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java @@ -0,0 +1,93 @@ +/* + * 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.homepage.deviceinfo; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.telephony.SubscriptionInfo; + +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.core.SliceAction; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.SliceTester; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +public class DeviceInfoSliceTest { + + @Mock + private SubscriptionInfo mSubscriptionInfo; + + private Context mContext; + private DeviceInfoSlice mDeviceInfoSlice; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + + mDeviceInfoSlice = spy(new DeviceInfoSlice(mContext)); + } + + @Test + public void getSlice_hasSubscriptionInfo_shouldBeCorrectSliceContent() { + final String phoneNumber = "1111111111"; + doReturn(mSubscriptionInfo).when(mDeviceInfoSlice).getFirstSubscriptionInfo(); + doReturn(phoneNumber).when(mDeviceInfoSlice).getPhoneNumber(); + final Slice slice = mDeviceInfoSlice.getSlice(); + final SliceMetadata metadata = SliceMetadata.from(mContext, slice); + final SliceAction primaryAction = metadata.getPrimaryAction(); + final IconCompat expectedIcon = IconCompat.createWithResource(mContext, + R.drawable.ic_info_outline_24dp); + assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedIcon.toString()); + + final List sliceItems = slice.getItems(); + SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label)); + SliceTester.assertTitle(sliceItems, phoneNumber); + } + + @Test + public void getSlice_hasNoSubscriptionInfo_shouldShowUnknown() { + final Slice slice = mDeviceInfoSlice.getSlice(); + final List sliceItems = slice.getItems(); + + SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label)); + SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_default)); + } +}