From 7dd82f966ccad9d94e405105e9f3df9daba29ffa Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Thu, 18 Apr 2019 19:45:04 -0700 Subject: [PATCH] Create enable MMS notification. Adding a notification in SimSelectNotification that will be triggered when receiving a enable MMS request. Tapping on the notificaiton will lead to the subscription setting page. Bug: 130222866 Test: manual -- have a test app that sends the intent when mobile data is turned off. And verify that the heads-up notificaiton is shown and that it will lead to subscription setting page. Change-Id: Ia80e8e5ab20adf78a31647a23cb2ba8dac690e41 --- AndroidManifest.xml | 2 + .../settings/sim/SimSelectNotification.java | 148 ++++++++++++++-- src/com/android/settings/sim/SimSettings.java | 2 +- .../sim/SimSelectNotificationTest.java | 166 ++++++++++++++++++ 4 files changed, 300 insertions(+), 18 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 764e1d2e4d7..5af6a99c563 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -136,6 +136,7 @@ + @@ -2623,6 +2624,7 @@ + diff --git a/src/com/android/settings/sim/SimSelectNotification.java b/src/com/android/settings/sim/SimSelectNotification.java index 3179e6a8028..911d0e84091 100644 --- a/src/com/android/settings/sim/SimSelectNotification.java +++ b/src/com/android/settings/sim/SimSelectNotification.java @@ -16,12 +16,18 @@ package com.android.settings.sim; +import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS; +import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS; +import static android.provider.Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON; +import static android.provider.Settings.EXTRA_SUB_ID; import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE; import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL; import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA; import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE; import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID; +import static android.telephony.data.ApnSetting.TYPE_MMS; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; @@ -32,28 +38,97 @@ import android.content.res.Resources; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settings.Settings.SimSettingsActivity; - -import androidx.core.app.NotificationCompat; +import com.android.settings.network.telephony.MobileNetworkActivity; public class SimSelectNotification extends BroadcastReceiver { private static final String TAG = "SimSelectNotification"; - private static final int NOTIFICATION_ID = 1; + @VisibleForTesting + public static final int SIM_SELECT_NOTIFICATION_ID = 1; + @VisibleForTesting + public static final int ENABLE_MMS_NOTIFICATION_ID = 2; - private static final String SIM_SELECT_NOTIFICATION_CHANNEL = + @VisibleForTesting + public static final String SIM_SELECT_NOTIFICATION_CHANNEL = "sim_select_notification_channel"; + @VisibleForTesting + public static final String ENABLE_MMS_NOTIFICATION_CHANNEL = + "enable_mms_notification_channel"; + @Override public void onReceive(Context context, Intent intent) { - if (!TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED.equals(intent.getAction())) { + String action = intent.getAction(); + + if (action == null) { + Log.w(TAG, "Received unexpected intent with null action."); return; } + + switch (action) { + case TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED: + onPrimarySubscriptionListChanged(context, intent); + break; + case Settings.ACTION_ENABLE_MMS_DATA_REQUEST: + onEnableMmsDataRequest(context, intent); + break; + default: + Log.w(TAG, "Received unexpected intent " + intent.getAction()); + } + } + + private void onEnableMmsDataRequest(Context context, Intent intent) { + // Getting subId from extra. + int subId = intent.getIntExtra(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + subId = SubscriptionManager.getDefaultSmsSubscriptionId(); + } + + SubscriptionManager subscriptionManager = ((SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE)); + if (!subscriptionManager.isActiveSubId(subId)) { + Log.w(TAG, "onEnableMmsDataRequest invalid sub ID " + subId); + return; + } + + // Getting request reason from extra, which will determine the notification title. + CharSequence notificationTitle = null; + int requestReason = intent.getIntExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON, -1); + if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS) { + notificationTitle = context.getResources().getText( + R.string.enable_receiving_mms_notification_title); + } else if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS) { + notificationTitle = context.getResources().getText( + R.string.enable_sending_mms_notification_title); + } else { + Log.w(TAG, "onEnableMmsDataRequest invalid request reason " + requestReason); + return; + } + + TelephonyManager tm = ((TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId); + + if (tm.isDataEnabledForApn(TYPE_MMS)) { + Log.w(TAG, "onEnableMmsDataRequest MMS data already enabled on sub ID " + subId); + return; + } + + CharSequence notificationSummary = context.getResources().getString( + R.string.enable_mms_notification_summary, tm.getSimOperatorName()); + + cancelEnableMmsNotification(context); + + createEnableMmsNotification(context, notificationTitle, notificationSummary, subId); + } + + private void onPrimarySubscriptionListChanged(Context context, Intent intent) { // Cancel any previous notifications - cancelNotification(context); + cancelSimSelectNotification(context); // Create a notification to tell the user that some defaults are missing - createNotification(context); + createSimSelectNotification(context); int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE); @@ -76,20 +151,20 @@ public class SimSelectNotification extends BroadcastReceiver { } } - private void createNotification(Context context){ + private void createSimSelectNotification(Context context){ final Resources resources = context.getResources(); NotificationChannel notificationChannel = new NotificationChannel( SIM_SELECT_NOTIFICATION_CHANNEL, - resources.getString(R.string.sim_selection_channel_title), + resources.getText(R.string.sim_selection_channel_title), NotificationManager.IMPORTANCE_LOW); - NotificationCompat.Builder builder = - new NotificationCompat.Builder(context, SIM_SELECT_NOTIFICATION_CHANNEL) + Notification.Builder builder = + new Notification.Builder(context, SIM_SELECT_NOTIFICATION_CHANNEL) .setSmallIcon(R.drawable.ic_sim_card_alert_white_48dp) .setColor(context.getColor(R.color.sim_noitification)) - .setContentTitle(resources.getString(R.string.sim_notification_title)) - .setContentText(resources.getString(R.string.sim_notification_summary)); + .setContentTitle(resources.getText(R.string.sim_notification_title)) + .setContentText(resources.getText(R.string.sim_notification_summary)); Intent resultIntent = new Intent(Settings.ACTION_WIRELESS_SETTINGS); resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, @@ -98,12 +173,51 @@ public class SimSelectNotification extends BroadcastReceiver { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(notificationChannel); - notificationManager.notify(NOTIFICATION_ID, builder.build()); + notificationManager.notify(SIM_SELECT_NOTIFICATION_ID, builder.build()); } - public static void cancelNotification(Context context) { + public static void cancelSimSelectNotification(Context context) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(NOTIFICATION_ID); + notificationManager.cancel(SIM_SELECT_NOTIFICATION_ID); + } + + private void createEnableMmsNotification(Context context, CharSequence titleString, + CharSequence notificationSummary, int subId) { + final Resources resources = context.getResources(); + + NotificationChannel notificationChannel = new NotificationChannel( + ENABLE_MMS_NOTIFICATION_CHANNEL, + resources.getText(R.string.enable_mms_notification_channel_title), + NotificationManager.IMPORTANCE_HIGH); + + Notification.Builder builder = + new Notification.Builder(context, ENABLE_MMS_NOTIFICATION_CHANNEL) + .setSmallIcon(R.drawable.ic_settings_24dp) + .setColor(context.getColor(R.color.sim_noitification)) + .setContentTitle(titleString) + .setContentText(notificationSummary) + .setStyle(new Notification.BigTextStyle().bigText(notificationSummary)); + + // Create the pending intent that will lead to the subscription setting page. + Intent resultIntent = new Intent(Settings.ACTION_MMS_MESSAGE_SETTING); + resultIntent.setClass(context, MobileNetworkActivity.class); + resultIntent.putExtra(Settings.EXTRA_SUB_ID, subId); + resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, + PendingIntent.FLAG_CANCEL_CURRENT); + builder.setContentIntent(resultPendingIntent); + + // Notify the notification. + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.createNotificationChannel(notificationChannel); + notificationManager.notify(ENABLE_MMS_NOTIFICATION_ID, builder.build()); + } + + private void cancelEnableMmsNotification(Context context) { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(ENABLE_MMS_NOTIFICATION_ID); } } diff --git a/src/com/android/settings/sim/SimSettings.java b/src/com/android/settings/sim/SimSettings.java index e43c6a5d83f..1222913d8c9 100644 --- a/src/com/android/settings/sim/SimSettings.java +++ b/src/com/android/settings/sim/SimSettings.java @@ -101,7 +101,7 @@ public class SimSettings extends RestrictedSettingsFragment implements Indexable mSimCards = (PreferenceScreen)findPreference(SIM_CARD_CATEGORY); mAvailableSubInfos = new ArrayList(mNumSlots); mSelectableSubInfos = new ArrayList(); - SimSelectNotification.cancelNotification(getActivity()); + SimSelectNotification.cancelSimSelectNotification(getActivity()); } private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener diff --git a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java new file mode 100644 index 00000000000..69c0919719f --- /dev/null +++ b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.settings.sim; + + +import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS; +import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS; +import static android.provider.Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON; +import static android.provider.Settings.EXTRA_SUB_ID; +import static android.telephony.data.ApnSetting.TYPE_MMS; + +import static com.android.settings.sim.SimSelectNotification.ENABLE_MMS_NOTIFICATION_CHANNEL; +import static com.android.settings.sim.SimSelectNotification.ENABLE_MMS_NOTIFICATION_ID; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.provider.Settings; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import com.android.settings.R; + +import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowAlertDialogCompat.class) +public class SimSelectNotificationTest { + @Mock + private Context mContext; + @Mock + private NotificationManager mNotificationManager; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; + @Mock + private PackageManager mPackageManager; + @Mock + private Resources mResources; + + private String mFakeOperatorName = "fake_operator_name"; + private CharSequence mFakeNotificationChannelTitle = "fake_notification_channel_title"; + private CharSequence mFakeNotificationTitle = "fake_notification_title"; + private String mFakeNotificationSummary = "fake_notification_Summary"; + + private int mSubId = 1; + + SimSelectNotification mSimSelectNotification = new SimSelectNotification(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)) + .thenReturn(mNotificationManager); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)) + .thenReturn(mTelephonyManager); + when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)) + .thenReturn(mSubscriptionManager); + when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.checkPermission(any(), any())) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); + when(mTelephonyManager.getSimOperatorName()).thenReturn(mFakeOperatorName); + when(mTelephonyManager.isDataEnabledForApn(TYPE_MMS)).thenReturn(false); + when(mSubscriptionManager.isActiveSubId(mSubId)).thenReturn(true); + when(mContext.getResources()).thenReturn(mResources); + + when(mResources.getText(R.string.enable_sending_mms_notification_title)) + .thenReturn(mFakeNotificationTitle); + when(mResources.getText(R.string.enable_mms_notification_channel_title)) + .thenReturn(mFakeNotificationChannelTitle); + when(mResources.getString(R.string.enable_mms_notification_summary, + mFakeOperatorName)).thenReturn(mFakeNotificationSummary); + } + + @Test + public void onReceiveEnableMms_notificationShouldSend() { + Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST); + intent.putExtra(EXTRA_SUB_ID, mSubId); + intent.putExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON, + ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS); + + mSimSelectNotification.onReceive(mContext, intent); + + // Capture the notification channel created and verify its fields. + ArgumentCaptor nc = ArgumentCaptor.forClass(NotificationChannel.class); + verify(mNotificationManager).createNotificationChannel(nc.capture()); + + assertThat(nc.getValue().getId()).isEqualTo(ENABLE_MMS_NOTIFICATION_CHANNEL); + assertThat(nc.getValue().getName()).isEqualTo(mFakeNotificationChannelTitle); + assertThat(nc.getValue().getImportance()).isEqualTo(IMPORTANCE_HIGH); + + // Capture the notification it notifies and verify its fields. + ArgumentCaptor notification = ArgumentCaptor.forClass(Notification.class); + verify(mNotificationManager).notify( + eq(ENABLE_MMS_NOTIFICATION_ID), notification.capture()); + assertThat(notification.getValue().extras.getCharSequence(Notification.EXTRA_TITLE)) + .isEqualTo(mFakeNotificationTitle); + assertThat(notification.getValue().extras.getCharSequence(Notification.EXTRA_BIG_TEXT)) + .isEqualTo(mFakeNotificationSummary); + assertThat(notification.getValue().contentIntent).isNotNull(); + } + + @Test + public void onReceiveEnableMms_NoExtra_notificationShouldNotSend() { + Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST); + + // EXTRA_SUB_ID and EXTRA_ENABLE_MMS_DATA_REQUEST_REASON are required. + mSimSelectNotification.onReceive(mContext, intent); + verify(mNotificationManager, never()).createNotificationChannel(any()); + } + + @Test + public void onReceiveEnableMms_MmsDataAlreadyEnabled_notificationShouldNotSend() { + when(mTelephonyManager.isDataEnabledForApn(TYPE_MMS)).thenReturn(true); + Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST); + intent.putExtra(EXTRA_SUB_ID, mSubId); + intent.putExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON, + ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS); + + // If MMS data is already enabled, there's no need to trigger the notification. + mSimSelectNotification.onReceive(mContext, intent); + verify(mNotificationManager, never()).createNotificationChannel(any()); + } +} +