Loading AndroidManifest.xml +3 −0 Original line number Diff line number Diff line Loading @@ -3959,6 +3959,9 @@ </intent-filter> </receiver> <service android:name=".sim.PrimarySubscriptionListChangedService" android:permission="android.permission.BIND_JOB_SERVICE" /> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.files" Loading res/values/integers.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <integer name="sim_notification_send">104</integer> <integer name="sim_slot_changed">105</integer> <integer name="power_monitor_receiver">106</integer> <integer name="primary_subscription_list_changed">107</integer> <!-- Controls the maximum number of faces enrollable during SUW --> <integer name="suw_max_faces_enrollable">1</integer> Loading src/com/android/settings/network/SatelliteRepository.kt +13 −4 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ class SatelliteRepository( * `false` otherwise. */ fun requestIsSessionStarted(executor: Executor): ListenableFuture<Boolean> { isSessionStarted?.let { return immediateFuture(it) } val satelliteManager: SatelliteManager? = context.getSystemService(SatelliteManager::class.java) if (satelliteManager == null) { Loading Loading @@ -166,10 +168,6 @@ class SatelliteRepository( } } companion object { private const val TAG: String = "SatelliteRepository" } /** * Check if the modem is in a satellite session. * Loading @@ -184,5 +182,16 @@ class SatelliteRepository( else -> true } } companion object { private const val TAG: String = "SatelliteRepository" private var isSessionStarted: Boolean? = null @VisibleForTesting fun setIsSessionStartedForTesting(isEnabled: Boolean) { this.isSessionStarted = isEnabled } } } src/com/android/settings/sim/PrimarySubscriptionListChangedService.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.content.Intent import android.util.Log import com.android.settings.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch /** A JobService work on primary subscription list changed. */ class PrimarySubscriptionListChangedService : JobService() { private var job: Job? = null override fun onStartJob(params: JobParameters): Boolean { job = CoroutineScope(Dispatchers.Default + SupervisorJob()).launch { try { val intent = Intent() intent.putExtras(params.transientExtras) SimSelectNotification.onPrimarySubscriptionListChanged( this@PrimarySubscriptionListChangedService, intent ) } catch (exception: Throwable) { Log.e(TAG, "Exception running job", exception) } jobFinished(params, false) } return true } override fun onStopJob(params: JobParameters): Boolean { job?.cancel() return false } companion object { private const val TAG = "PrimarySubscriptionListChangedService" /** * Schedules a service to work on primary subscription changed. * * @param context is the caller context. */ @JvmStatic fun scheduleJob(context: Context, intent: Intent) { val component = ComponentName(context, PrimarySubscriptionListChangedService::class.java) val jobScheduler = context.getSystemService(JobScheduler::class.java)!! val jobInfoBuilder = JobInfo.Builder(R.integer.primary_subscription_list_changed, component) intent.extras?.let { jobInfoBuilder.setTransientExtras(it) } jobScheduler.schedule(jobInfoBuilder.build()) } } } No newline at end of file src/com/android/settings/sim/SimSelectNotification.java +57 −13 Original line number Diff line number Diff line Loading @@ -49,13 +49,28 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.HelpTrampoline; import com.android.settings.R; import com.android.settings.network.SatelliteRepository; import com.android.settings.network.SubscriptionUtil; import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class SimSelectNotification extends BroadcastReceiver { private static final String TAG = "SimSelectNotification"; private static final int DEFAULT_TIMEOUT_MS = 1000; @VisibleForTesting public static final int SIM_SELECT_NOTIFICATION_ID = 1; @VisibleForTesting Loading Loading @@ -90,7 +105,7 @@ public class SimSelectNotification extends BroadcastReceiver { switch (action) { case TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED: onPrimarySubscriptionListChanged(context, intent); PrimarySubscriptionListChangedService.scheduleJob(context, intent); break; case Settings.ACTION_ENABLE_MMS_DATA_REQUEST: onEnableMmsDataRequest(context, intent); Loading Loading @@ -150,12 +165,41 @@ public class SimSelectNotification extends BroadcastReceiver { createEnableMmsNotification(context, notificationTitle, notificationSummary, subId); } private void onPrimarySubscriptionListChanged(Context context, Intent intent) { /** * Handles changes to the primary subscription list, performing actions only * if the device is not currently in a satellite session. This method is * intended to be executed on a worker thread. * * @param context The application context * @param intent The intent signaling a primary subscription change */ @WorkerThread public static void onPrimarySubscriptionListChanged(@NonNull Context context, @NonNull Intent intent) { Log.d(TAG, "Checking satellite enabled status"); Executor executor = Executors.newSingleThreadExecutor(); ListenableFuture<Boolean> isSatelliteSessionStartedFuture = new SatelliteRepository(context).requestIsSessionStarted(executor); boolean isSatelliteSessionStarted = false; try { isSatelliteSessionStarted = isSatelliteSessionStartedFuture.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { Log.w(TAG, "Can't get satellite session status", e); } finally { if (isSatelliteSessionStarted) { Log.i(TAG, "Device is in a satellite session.g Unable to handle primary" + " subscription list changes"); } else { Log.i(TAG, "Device is not in a satellite session. Handle primary" + " subscription list changes"); startSimSelectDialogIfNeeded(context, intent); sendSimCombinationWarningIfNeeded(context, intent); } } } private void startSimSelectDialogIfNeeded(Context context, Intent intent) { private static void startSimSelectDialogIfNeeded(Context context, Intent intent) { int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE); Loading Loading @@ -195,7 +239,7 @@ public class SimSelectNotification extends BroadcastReceiver { } } private void sendSimCombinationWarningIfNeeded(Context context, Intent intent) { private static void sendSimCombinationWarningIfNeeded(Context context, Intent intent) { final int warningType = intent.getIntExtra(EXTRA_SIM_COMBINATION_WARNING_TYPE, EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE); Loading @@ -208,7 +252,7 @@ public class SimSelectNotification extends BroadcastReceiver { } } private void createSimSelectNotification(Context context){ private static void createSimSelectNotification(Context context) { final Resources resources = context.getResources(); NotificationChannel notificationChannel = new NotificationChannel( Loading Loading @@ -280,7 +324,7 @@ public class SimSelectNotification extends BroadcastReceiver { notificationManager.cancel(ENABLE_MMS_NOTIFICATION_ID); } private void createSimCombinationWarningNotification(Context context, Intent intent){ private static void createSimCombinationWarningNotification(Context context, Intent intent) { final Resources resources = context.getResources(); final String simNames = intent.getStringExtra(EXTRA_SIM_COMBINATION_NAMES); Loading Loading
AndroidManifest.xml +3 −0 Original line number Diff line number Diff line Loading @@ -3959,6 +3959,9 @@ </intent-filter> </receiver> <service android:name=".sim.PrimarySubscriptionListChangedService" android:permission="android.permission.BIND_JOB_SERVICE" /> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.files" Loading
res/values/integers.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <integer name="sim_notification_send">104</integer> <integer name="sim_slot_changed">105</integer> <integer name="power_monitor_receiver">106</integer> <integer name="primary_subscription_list_changed">107</integer> <!-- Controls the maximum number of faces enrollable during SUW --> <integer name="suw_max_faces_enrollable">1</integer> Loading
src/com/android/settings/network/SatelliteRepository.kt +13 −4 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ class SatelliteRepository( * `false` otherwise. */ fun requestIsSessionStarted(executor: Executor): ListenableFuture<Boolean> { isSessionStarted?.let { return immediateFuture(it) } val satelliteManager: SatelliteManager? = context.getSystemService(SatelliteManager::class.java) if (satelliteManager == null) { Loading Loading @@ -166,10 +168,6 @@ class SatelliteRepository( } } companion object { private const val TAG: String = "SatelliteRepository" } /** * Check if the modem is in a satellite session. * Loading @@ -184,5 +182,16 @@ class SatelliteRepository( else -> true } } companion object { private const val TAG: String = "SatelliteRepository" private var isSessionStarted: Boolean? = null @VisibleForTesting fun setIsSessionStartedForTesting(isEnabled: Boolean) { this.isSessionStarted = isEnabled } } }
src/com/android/settings/sim/PrimarySubscriptionListChangedService.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.content.Intent import android.util.Log import com.android.settings.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch /** A JobService work on primary subscription list changed. */ class PrimarySubscriptionListChangedService : JobService() { private var job: Job? = null override fun onStartJob(params: JobParameters): Boolean { job = CoroutineScope(Dispatchers.Default + SupervisorJob()).launch { try { val intent = Intent() intent.putExtras(params.transientExtras) SimSelectNotification.onPrimarySubscriptionListChanged( this@PrimarySubscriptionListChangedService, intent ) } catch (exception: Throwable) { Log.e(TAG, "Exception running job", exception) } jobFinished(params, false) } return true } override fun onStopJob(params: JobParameters): Boolean { job?.cancel() return false } companion object { private const val TAG = "PrimarySubscriptionListChangedService" /** * Schedules a service to work on primary subscription changed. * * @param context is the caller context. */ @JvmStatic fun scheduleJob(context: Context, intent: Intent) { val component = ComponentName(context, PrimarySubscriptionListChangedService::class.java) val jobScheduler = context.getSystemService(JobScheduler::class.java)!! val jobInfoBuilder = JobInfo.Builder(R.integer.primary_subscription_list_changed, component) intent.extras?.let { jobInfoBuilder.setTransientExtras(it) } jobScheduler.schedule(jobInfoBuilder.build()) } } } No newline at end of file
src/com/android/settings/sim/SimSelectNotification.java +57 −13 Original line number Diff line number Diff line Loading @@ -49,13 +49,28 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.HelpTrampoline; import com.android.settings.R; import com.android.settings.network.SatelliteRepository; import com.android.settings.network.SubscriptionUtil; import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class SimSelectNotification extends BroadcastReceiver { private static final String TAG = "SimSelectNotification"; private static final int DEFAULT_TIMEOUT_MS = 1000; @VisibleForTesting public static final int SIM_SELECT_NOTIFICATION_ID = 1; @VisibleForTesting Loading Loading @@ -90,7 +105,7 @@ public class SimSelectNotification extends BroadcastReceiver { switch (action) { case TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED: onPrimarySubscriptionListChanged(context, intent); PrimarySubscriptionListChangedService.scheduleJob(context, intent); break; case Settings.ACTION_ENABLE_MMS_DATA_REQUEST: onEnableMmsDataRequest(context, intent); Loading Loading @@ -150,12 +165,41 @@ public class SimSelectNotification extends BroadcastReceiver { createEnableMmsNotification(context, notificationTitle, notificationSummary, subId); } private void onPrimarySubscriptionListChanged(Context context, Intent intent) { /** * Handles changes to the primary subscription list, performing actions only * if the device is not currently in a satellite session. This method is * intended to be executed on a worker thread. * * @param context The application context * @param intent The intent signaling a primary subscription change */ @WorkerThread public static void onPrimarySubscriptionListChanged(@NonNull Context context, @NonNull Intent intent) { Log.d(TAG, "Checking satellite enabled status"); Executor executor = Executors.newSingleThreadExecutor(); ListenableFuture<Boolean> isSatelliteSessionStartedFuture = new SatelliteRepository(context).requestIsSessionStarted(executor); boolean isSatelliteSessionStarted = false; try { isSatelliteSessionStarted = isSatelliteSessionStartedFuture.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { Log.w(TAG, "Can't get satellite session status", e); } finally { if (isSatelliteSessionStarted) { Log.i(TAG, "Device is in a satellite session.g Unable to handle primary" + " subscription list changes"); } else { Log.i(TAG, "Device is not in a satellite session. Handle primary" + " subscription list changes"); startSimSelectDialogIfNeeded(context, intent); sendSimCombinationWarningIfNeeded(context, intent); } } } private void startSimSelectDialogIfNeeded(Context context, Intent intent) { private static void startSimSelectDialogIfNeeded(Context context, Intent intent) { int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE); Loading Loading @@ -195,7 +239,7 @@ public class SimSelectNotification extends BroadcastReceiver { } } private void sendSimCombinationWarningIfNeeded(Context context, Intent intent) { private static void sendSimCombinationWarningIfNeeded(Context context, Intent intent) { final int warningType = intent.getIntExtra(EXTRA_SIM_COMBINATION_WARNING_TYPE, EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE); Loading @@ -208,7 +252,7 @@ public class SimSelectNotification extends BroadcastReceiver { } } private void createSimSelectNotification(Context context){ private static void createSimSelectNotification(Context context) { final Resources resources = context.getResources(); NotificationChannel notificationChannel = new NotificationChannel( Loading Loading @@ -280,7 +324,7 @@ public class SimSelectNotification extends BroadcastReceiver { notificationManager.cancel(ENABLE_MMS_NOTIFICATION_ID); } private void createSimCombinationWarningNotification(Context context, Intent intent){ private static void createSimCombinationWarningNotification(Context context, Intent intent) { final Resources resources = context.getResources(); final String simNames = intent.getStringExtra(EXTRA_SIM_COMBINATION_NAMES); Loading