diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3cf759470b8..9b8327c30f2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3652,6 +3652,17 @@
+
+
+
+
+
+
+
+
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 7a6e0aa6d31..3d73f64fabe 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -20,4 +20,5 @@
101
102
103
+ 104
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 041dbdd771b..ee5b87f5b80 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12083,6 +12083,17 @@
Try turning on the SIM again. If the problem continues, restart your device.
+
+
+ Network activation
+
+ %1$s is active
+
+ Tap to update SIM settings
+
+
+ SIM card
+
Erase this downloaded SIM?
diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
index 919415b53e0..1dc843a0c6e 100644
--- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
@@ -34,6 +34,7 @@ import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.SwitchToEuiccSubscriptionSidecar;
import com.android.settings.network.SwitchToRemovableSlotSidecar;
import com.android.settings.network.UiccSlotUtil;
+import com.android.settings.sim.SimActivationNotifier;
import com.google.common.collect.ImmutableList;
@@ -189,9 +190,8 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc
return;
}
Log.i(TAG, "User confirmed reboot to enable DSDS.");
+ SimActivationNotifier.setShowSimSettingsNotification(this, true);
mTelMgr.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS);
- // TODO(b/170507290): Store a bit in preferences for displaying the notification
- // after the reboot.
break;
case DIALOG_TAG_ENABLE_SIM_CONFIRMATION:
Log.i(TAG, "User confirmed to enable the subscription.");
diff --git a/src/com/android/settings/sim/SimActivationNotifier.java b/src/com/android/settings/sim/SimActivationNotifier.java
new file mode 100644
index 00000000000..85d3da2cd35
--- /dev/null
+++ b/src/com/android/settings/sim/SimActivationNotifier.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2020 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.content.Context.MODE_PRIVATE;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.core.app.TaskStackBuilder;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.network.SubscriptionUtil;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class manages the notification of SIM activation notification including creating and
+ * canceling the notifications.
+ */
+public class SimActivationNotifier {
+
+ private static final String TAG = "SimActivationNotifier";
+ private static final String SIM_SETUP_CHANNEL_ID = "sim_setup";
+ private static final String SIM_PREFS = "sim_prefs";
+ private static final String KEY_SHOW_SIM_SETTINGS_NOTIFICATION =
+ "show_sim_settings_notification";
+
+ public static final int SIM_ACTIVATION_NOTIFICATION_ID = 1;
+
+ /** Notification types */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ NotificationType.NETWORK_CONFIG,
+ })
+ public @interface NotificationType {
+ // The notification to remind users to config network Settings.
+ int NETWORK_CONFIG = 1;
+ }
+
+ private final Context mContext;
+ private final NotificationManager mNotificationManager;
+
+ public SimActivationNotifier(Context context) {
+ mContext = context;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+ mNotificationManager.createNotificationChannel(
+ new NotificationChannel(
+ SIM_SETUP_CHANNEL_ID,
+ mContext.getString(R.string.sim_setup_channel_id),
+ NotificationManager.IMPORTANCE_HIGH));
+ }
+
+ /**
+ * Sets whether Settings should send a push notification for the SIM activation.
+ *
+ * @param context
+ * @param showNotification whether Settings should send a push notification for the SIM
+ * activation.
+ */
+ public static void setShowSimSettingsNotification(Context context, boolean showNotification) {
+ final SharedPreferences prefs = context.getSharedPreferences(SIM_PREFS, MODE_PRIVATE);
+ prefs.edit().putBoolean(KEY_SHOW_SIM_SETTINGS_NOTIFICATION, showNotification).apply();
+ }
+
+ /**
+ * Gets whether Settings should send a push notification for the SIM activation.
+ *
+ * @param context
+ * @return true if Settings should send a push notification for SIM activation. Otherwise,
+ * return false.
+ */
+ public static boolean getShowSimSettingsNotification(Context context) {
+ final SharedPreferences prefs = context.getSharedPreferences(SIM_PREFS, MODE_PRIVATE);
+ return prefs.getBoolean(KEY_SHOW_SIM_SETTINGS_NOTIFICATION, false);
+ }
+
+ /** Sends a push notification for the SIM activation. It should be called after DSDS reboot. */
+ public void sendNetworkConfigNotification() {
+ SubscriptionManager subscriptionManager =
+ mContext.getSystemService(SubscriptionManager.class);
+ SubscriptionInfo activeRemovableSub =
+ SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream()
+ .filter(sub -> !sub.isEmbedded())
+ .findFirst()
+ .orElse(null);
+
+ if (activeRemovableSub == null) {
+ Log.e(TAG, "No removable subscriptions found. Do not show notification.");
+ return;
+ }
+
+ String carrierName =
+ TextUtils.isEmpty(activeRemovableSub.getDisplayName())
+ ? mContext.getString(R.string.sim_card_label)
+ : activeRemovableSub.getDisplayName().toString();
+ String title =
+ mContext.getString(
+ R.string.post_dsds_reboot_notification_title_with_carrier, carrierName);
+ String text = mContext.getString(R.string.post_dsds_reboot_notification_text);
+ Intent clickIntent = new Intent(mContext, Settings.MobileNetworkListActivity.class);
+ TaskStackBuilder stackBuilder =
+ TaskStackBuilder.create(mContext).addNextIntent(clickIntent);
+ PendingIntent contentIntent =
+ stackBuilder.getPendingIntent(
+ 0 /* requestCode */, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, SIM_SETUP_CHANNEL_ID)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(contentIntent)
+ .setSmallIcon(R.drawable.ic_sim_alert)
+ .setAutoCancel(true);
+ mNotificationManager.notify(SIM_ACTIVATION_NOTIFICATION_ID, builder.build());
+ }
+}
diff --git a/src/com/android/settings/sim/SimNotificationService.java b/src/com/android/settings/sim/SimNotificationService.java
new file mode 100644
index 00000000000..303c21d02c8
--- /dev/null
+++ b/src/com/android/settings/sim/SimNotificationService.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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 android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+import com.android.settings.R;
+
+/** A JobService sends SIM notifications. */
+public class SimNotificationService extends JobService {
+
+ private static final String TAG = "SimNotificationService";
+ private static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
+
+ /**
+ * Schedules a service to send SIM push notifications.
+ * @param context
+ * @param notificationType indicates which SIM notification to send.
+ */
+ public static void scheduleSimNotification(
+ Context context, @SimActivationNotifier.NotificationType int notificationType) {
+ final JobScheduler jobScheduler =
+ context.getApplicationContext().getSystemService(JobScheduler.class);
+ final ComponentName component =
+ new ComponentName(context.getApplicationContext(), SimNotificationService.class);
+ PersistableBundle extra = new PersistableBundle();
+ extra.putInt(EXTRA_NOTIFICATION_TYPE, notificationType);
+
+ jobScheduler.schedule(
+ new JobInfo.Builder(R.integer.sim_notification_send, component)
+ .setExtras(extra)
+ .build());
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ PersistableBundle extra = params.getExtras();
+ if (extra == null) {
+ Log.e(TAG, "Failed to get notification type.");
+ return false;
+ }
+ int notificationType = extra.getInt(EXTRA_NOTIFICATION_TYPE);
+ switch (notificationType) {
+ case SimActivationNotifier.NotificationType.NETWORK_CONFIG:
+ Log.i(TAG, "Sending SIM config notification.");
+ SimActivationNotifier.setShowSimSettingsNotification(this, false);
+ new SimActivationNotifier(this).sendNetworkConfigNotification();
+ break;
+ default:
+ Log.e(TAG, "Invalid notification type: " + notificationType);
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+}
diff --git a/src/com/android/settings/sim/receivers/SimCompleteBootReceiver.java b/src/com/android/settings/sim/receivers/SimCompleteBootReceiver.java
new file mode 100644
index 00000000000..e9acf94976e
--- /dev/null
+++ b/src/com/android/settings/sim/receivers/SimCompleteBootReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.receivers;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.settings.sim.SimActivationNotifier;
+import com.android.settings.sim.SimNotificationService;
+
+/** This class manage all SIM operations after device boot up. */
+public class SimCompleteBootReceiver extends BroadcastReceiver {
+ private static final String TAG = "SimCompleteBootReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ Log.e(TAG, "Invalid broadcast received.");
+ return;
+ }
+ if (SimActivationNotifier.getShowSimSettingsNotification(context)) {
+ SimNotificationService.scheduleSimNotification(
+ context, SimActivationNotifier.NotificationType.NETWORK_CONFIG);
+ }
+ }
+}