Loading src/com/android/settings/homepage/CardContentLoader.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -103,8 +104,8 @@ public class CardContentLoader extends AsyncLoaderCompat<List<ContextualCard>> { .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) Loading src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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<SubscriptionInfo> subscriptionInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); if (subscriptionInfoList == null) { return null; } return subscriptionInfoList.get(0); } @Override public void onNotifyChange(Intent intent) { } } src/com/android/settings/slices/CustomSliceManager.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * 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<SliceItem> 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<SliceItem> sliceItems = slice.getItems(); SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label)); SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_default)); } } Loading
src/com/android/settings/homepage/CardContentLoader.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -103,8 +104,8 @@ public class CardContentLoader extends AsyncLoaderCompat<List<ContextualCard>> { .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) Loading
src/com/android/settings/homepage/deviceinfo/DeviceInfoSlice.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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<SubscriptionInfo> subscriptionInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); if (subscriptionInfoList == null) { return null; } return subscriptionInfoList.get(0); } @Override public void onNotifyChange(Intent intent) { } }
src/com/android/settings/slices/CustomSliceManager.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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
tests/robotests/src/com/android/settings/homepage/deviceinfo/DeviceInfoSliceTest.java 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * 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<SliceItem> 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<SliceItem> sliceItems = slice.getItems(); SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_label)); SliceTester.assertTitle(sliceItems, mContext.getString(R.string.device_info_default)); } }