• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.wifi.calling;
18 
19 import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
20 
21 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
22 import static com.android.settings.slices.CustomSliceRegistry.WIFI_CALLING_PREFERENCE_URI;
23 import static com.android.settings.slices.CustomSliceRegistry.WIFI_CALLING_URI;
24 
25 import android.app.PendingIntent;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.res.Resources;
30 import android.net.Uri;
31 import android.os.PersistableBundle;
32 import android.provider.Settings;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.SubscriptionManager;
35 import android.telephony.ims.ImsMmTelManager;
36 import android.text.TextUtils;
37 import android.util.Log;
38 
39 import androidx.annotation.VisibleForTesting;
40 import androidx.core.graphics.drawable.IconCompat;
41 import androidx.slice.Slice;
42 import androidx.slice.builders.ListBuilder;
43 import androidx.slice.builders.ListBuilder.RowBuilder;
44 import androidx.slice.builders.SliceAction;
45 
46 import com.android.settings.R;
47 import com.android.settings.Utils;
48 import com.android.settings.network.ims.WifiCallingQueryImsState;
49 import com.android.settings.slices.SliceBroadcastReceiver;
50 
51 import java.util.concurrent.Callable;
52 import java.util.concurrent.ExecutionException;
53 import java.util.concurrent.ExecutorService;
54 import java.util.concurrent.Executors;
55 import java.util.concurrent.FutureTask;
56 import java.util.concurrent.TimeUnit;
57 import java.util.concurrent.TimeoutException;
58 
59 /**
60  * Helper class to control slices for wifi calling settings.
61  */
62 public class WifiCallingSliceHelper {
63 
64     private static final String TAG = "WifiCallingSliceHelper";
65 
66     /**
67      * Settings slice path to wifi calling setting.
68      */
69     public static final String PATH_WIFI_CALLING = "wifi_calling";
70 
71     /**
72      * Settings slice path to wifi calling preference setting.
73      */
74     public static final String PATH_WIFI_CALLING_PREFERENCE =
75             "wifi_calling_preference";
76 
77     /**
78      * Action passed for changes to wifi calling slice (toggle).
79      */
80     public static final String ACTION_WIFI_CALLING_CHANGED =
81             "com.android.settings.wifi.calling.action.WIFI_CALLING_CHANGED";
82 
83     /**
84      * Action passed when user selects wifi only preference.
85      */
86     public static final String ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY =
87             "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_WIFI_ONLY";
88     /**
89      * Action passed when user selects wifi preferred preference.
90      */
91     public static final String ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED =
92             "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_WIFI_PREFERRED";
93     /**
94      * Action passed when user selects cellular preferred preference.
95      */
96     public static final String ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED =
97             "com.android.settings.slice.action.WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED";
98 
99     /**
100      * Action for Wifi calling Settings activity which
101      * allows setting configuration for Wifi calling
102      * related settings
103      */
104     public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY =
105             "android.settings.WIFI_CALLING_SETTINGS";
106 
107     /**
108      * Timeout for querying wifi calling setting from ims manager.
109      */
110     private static final int TIMEOUT_MILLIS = 2000;
111 
112     private final Context mContext;
113 
114     @VisibleForTesting
WifiCallingSliceHelper(Context context)115     public WifiCallingSliceHelper(Context context) {
116         mContext = context;
117     }
118 
119     /**
120      * Returns Slice object for wifi calling settings.
121      *
122      * If wifi calling is being turned on and if wifi calling activation is needed for the current
123      * carrier, this method will return Slice with instructions to go to Settings App.
124      *
125      * If wifi calling is not supported for the current carrier, this method will return slice with
126      * not supported message.
127      *
128      * If wifi calling setting can be changed, this method will return the slice to toggle wifi
129      * calling option with ACTION_WIFI_CALLING_CHANGED as endItem.
130      */
createWifiCallingSlice(Uri sliceUri)131     public Slice createWifiCallingSlice(Uri sliceUri) {
132         final int subId = getDefaultVoiceSubId();
133 
134         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
135             Log.d(TAG, "Invalid subscription Id");
136             return null;
137         }
138 
139         if (!queryImsState(subId).isWifiCallingProvisioned()) {
140             Log.d(TAG, "Wifi calling is either not provisioned or not enabled by Platform");
141             return null;
142         }
143 
144         final boolean isWifiCallingEnabled = isWifiCallingEnabled();
145         final Intent activationAppIntent =
146                 getWifiCallingCarrierActivityIntent(subId);
147 
148         // Send this actionable wifi calling slice to toggle the setting
149         // only when there is no need for wifi calling activation with the server
150         if (activationAppIntent != null && !isWifiCallingEnabled) {
151             Log.d(TAG, "Needs Activation");
152             // Activation needed for the next action of the user
153             // Give instructions to go to settings app
154             final Resources res = getResourcesForSubId(subId);
155             return getNonActionableWifiCallingSlice(
156                     res.getText(R.string.wifi_calling_settings_title),
157                     res.getText(R.string.wifi_calling_settings_activation_instructions),
158                     sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
159         }
160         return getWifiCallingSlice(sliceUri, isWifiCallingEnabled, subId);
161     }
162 
isWifiCallingEnabled()163     private boolean isWifiCallingEnabled() {
164         final WifiCallingQueryImsState queryState = queryImsState(getDefaultVoiceSubId());
165         return queryState.isEnabledByUser() && queryState.isAllowUserControl();
166     }
167 
168     /**
169      * Builds a toggle slice where the intent takes you to the wifi calling page and the toggle
170      * enables/disables wifi calling.
171      */
getWifiCallingSlice(Uri sliceUri, boolean isWifiCallingEnabled, int subId)172     private Slice getWifiCallingSlice(Uri sliceUri, boolean isWifiCallingEnabled, int subId) {
173         final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
174         final Resources res = getResourcesForSubId(subId);
175 
176         return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
177                 .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
178                 .addRow(new RowBuilder()
179                         .setTitle(res.getText(R.string.wifi_calling_settings_title))
180                         .addEndItem(
181                                 SliceAction.createToggle(
182                                         getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED),
183                                         null /* actionTitle */, isWifiCallingEnabled))
184                         .setPrimaryAction(SliceAction.createDeeplink(
185                                 getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
186                                 icon,
187                                 ListBuilder.ICON_IMAGE,
188                                 res.getText(R.string.wifi_calling_settings_title))))
189                 .build();
190     }
191 
192     /**
193      * Returns Slice object for wifi calling preference.
194      *
195      * If wifi calling is not turned on, this method will return a slice to turn on wifi calling.
196      *
197      * If wifi calling preference is not user editable, this method will return a slice to display
198      * appropriate message.
199      *
200      * If wifi calling preference can be changed, this method will return a slice with 3 or 4 rows:
201      * Header Row: current preference settings
202      * Row 1: wifi only option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY, if wifi only option
203      * is editable
204      * Row 2: wifi preferred option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED
205      * Row 3: cellular preferred option with ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED
206      */
createWifiCallingPreferenceSlice(Uri sliceUri)207     public Slice createWifiCallingPreferenceSlice(Uri sliceUri) {
208         final int subId = getDefaultVoiceSubId();
209 
210         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
211             Log.d(TAG, "Invalid Subscription Id");
212             return null;
213         }
214 
215         final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled(
216                 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false);
217         final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled(
218                 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true);
219 
220         if (!isWifiCallingPrefEditable) {
221             Log.d(TAG, "Wifi calling preference is not editable");
222             return null;
223         }
224 
225         if (!queryImsState(subId).isWifiCallingProvisioned()) {
226             Log.d(TAG, "Wifi calling is either not provisioned or not enabled by platform");
227             return null;
228         }
229 
230         boolean isWifiCallingEnabled = false;
231         int wfcMode = -1;
232         try {
233             final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
234             isWifiCallingEnabled = isWifiCallingEnabled();
235             wfcMode = getWfcMode(imsMmTelManager);
236         } catch (InterruptedException | ExecutionException | TimeoutException e) {
237             Log.e(TAG, "Unable to get wifi calling preferred mode", e);
238             return null;
239         }
240         if (!isWifiCallingEnabled) {
241             // wifi calling is not enabled. Ask user to enable wifi calling
242             final Resources res = getResourcesForSubId(subId);
243             return getNonActionableWifiCallingSlice(
244                     res.getText(R.string.wifi_calling_mode_title),
245                     res.getText(R.string.wifi_calling_turn_on),
246                     sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
247         }
248         // Return the slice to change wifi calling preference
249         return getWifiCallingPreferenceSlice(
250                 isWifiOnlySupported, wfcMode, sliceUri, subId);
251     }
252 
253     /**
254      * Returns actionable wifi calling preference slice.
255      *
256      * @param isWifiOnlySupported adds row for wifi only if this is true
257      * @param currentWfcPref      current Preference {@link ImsConfig}
258      * @param sliceUri            sliceUri
259      * @param subId               subscription id
260      * @return Slice for actionable wifi calling preference settings
261      */
getWifiCallingPreferenceSlice(boolean isWifiOnlySupported, int currentWfcPref, Uri sliceUri, int subId)262     private Slice getWifiCallingPreferenceSlice(boolean isWifiOnlySupported,
263             int currentWfcPref,
264             Uri sliceUri,
265             int subId) {
266         final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
267         final Resources res = getResourcesForSubId(subId);
268         // Top row shows information on current preference state
269         final ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
270                 .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
271         final ListBuilder.HeaderBuilder headerBuilder = new ListBuilder.HeaderBuilder()
272                 .setTitle(res.getText(R.string.wifi_calling_mode_title))
273                 .setPrimaryAction(SliceAction.createDeeplink(
274                         getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
275                         icon,
276                         ListBuilder.ICON_IMAGE,
277                         res.getText(R.string.wifi_calling_mode_title)));
278         if (!Utils.isSettingsIntelligence(mContext)) {
279             headerBuilder.setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref, subId));
280         }
281         listBuilder.setHeader(headerBuilder);
282 
283         if (isWifiOnlySupported) {
284             listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
285                     com.android.internal.R.string.wfc_mode_wifi_only_summary,
286                     ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY,
287                     currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_ONLY, subId));
288         }
289 
290         listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
291                 com.android.internal.R.string.wfc_mode_wifi_preferred_summary,
292                 ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED,
293                 currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED, subId));
294 
295         listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder,
296                 com.android.internal.R.string.wfc_mode_cellular_preferred_summary,
297                 ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED,
298                 currentWfcPref == ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED, subId));
299 
300         return listBuilder.build();
301     }
302 
303     /**
304      * Returns RowBuilder for a new row containing specific wifi calling preference.
305      *
306      * @param listBuilder          ListBuilder that will be the parent for this RowBuilder
307      * @param preferenceTitleResId resource Id for the preference row title
308      * @param action               action to be added for the row
309      * @param subId                subscription id
310      * @return RowBuilder for the row
311      */
wifiPreferenceRowBuilder(ListBuilder listBuilder, int preferenceTitleResId, String action, boolean checked, int subId)312     private RowBuilder wifiPreferenceRowBuilder(ListBuilder listBuilder,
313             int preferenceTitleResId, String action, boolean checked, int subId) {
314         final IconCompat icon =
315                 IconCompat.createWithResource(mContext, R.drawable.radio_button_check);
316         final Resources res = getResourcesForSubId(subId);
317         return new RowBuilder()
318                 .setTitle(res.getText(preferenceTitleResId))
319                 .setTitleItem(SliceAction.createToggle(getBroadcastIntent(action),
320                         icon, res.getText(preferenceTitleResId), checked));
321     }
322 
323 
324     /**
325      * Returns the String describing wifi calling preference mentioned in wfcMode
326      *
327      * @param wfcMode ImsConfig constant for the preference {@link ImsConfig}
328      * @return summary/name of the wifi calling preference
329      */
getWifiCallingPreferenceSummary(int wfcMode, int subId)330     private CharSequence getWifiCallingPreferenceSummary(int wfcMode, int subId) {
331         final Resources res = getResourcesForSubId(subId);
332         switch (wfcMode) {
333             case ImsMmTelManager.WIFI_MODE_WIFI_ONLY:
334                 return res.getText(
335                         com.android.internal.R.string.wfc_mode_wifi_only_summary);
336             case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
337                 return res.getText(
338                         com.android.internal.R.string.wfc_mode_wifi_preferred_summary);
339             case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED:
340                 return res.getText(
341                         com.android.internal.R.string.wfc_mode_cellular_preferred_summary);
342             default:
343                 return null;
344         }
345     }
346 
getImsMmTelManager(int subId)347     protected ImsMmTelManager getImsMmTelManager(int subId) {
348         return ImsMmTelManager.createForSubscriptionId(subId);
349     }
350 
getWfcMode(ImsMmTelManager imsMmTelManager)351     private int getWfcMode(ImsMmTelManager imsMmTelManager)
352             throws InterruptedException, ExecutionException, TimeoutException {
353         final FutureTask<Integer> wfcModeTask = new FutureTask<>(new Callable<Integer>() {
354             @Override
355             public Integer call() {
356                 return imsMmTelManager.getVoWiFiModeSetting();
357             }
358         });
359         final ExecutorService executor = Executors.newSingleThreadExecutor();
360         executor.execute(wfcModeTask);
361         return wfcModeTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
362     }
363 
364     /**
365      * Handles wifi calling setting change from wifi calling slice and posts notification. Should be
366      * called when intent action is ACTION_WIFI_CALLING_CHANGED. Executed in @WorkerThread
367      *
368      * @param intent action performed
369      */
handleWifiCallingChanged(Intent intent)370     public void handleWifiCallingChanged(Intent intent) {
371         final int subId = getDefaultVoiceSubId();
372 
373         if (SubscriptionManager.isValidSubscriptionId(subId)) {
374             final WifiCallingQueryImsState queryState = queryImsState(subId);
375             if (queryState.isWifiCallingProvisioned()) {
376                 final boolean currentValue = queryState.isEnabledByUser()
377                         && queryState.isAllowUserControl();
378                 final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
379                         currentValue);
380                 final Intent activationAppIntent =
381                         getWifiCallingCarrierActivityIntent(subId);
382                 if (!newValue || activationAppIntent == null) {
383                     // If either the action is to turn off wifi calling setting
384                     // or there is no activation involved - Update the setting
385                     if (newValue != currentValue) {
386                         final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
387                         imsMmTelManager.setVoWiFiSettingEnabled(newValue);
388                     }
389                 }
390             }
391         }
392         // notify change in slice in any case to get re-queried. This would result in displaying
393         // appropriate message with the updated setting.
394         mContext.getContentResolver().notifyChange(WIFI_CALLING_URI, null);
395     }
396 
397     /**
398      * Handles wifi calling preference Setting change from wifi calling preference Slice and posts
399      * notification for the change. Should be called when intent action is one of the below
400      * ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY
401      * ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED
402      * ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED
403      *
404      * @param intent intent
405      */
handleWifiCallingPreferenceChanged(Intent intent)406     public void handleWifiCallingPreferenceChanged(Intent intent) {
407         final int subId = getDefaultVoiceSubId();
408         final int errorValue = -1;
409 
410         if (SubscriptionManager.isValidSubscriptionId(subId)) {
411             final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled(
412                     CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false);
413             final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled(
414                     CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true);
415 
416             final WifiCallingQueryImsState queryState = queryImsState(subId);
417             if (isWifiCallingPrefEditable
418                     && queryState.isWifiCallingProvisioned()
419                     && queryState.isEnabledByUser()
420                     && queryState.isAllowUserControl()) {
421                 // Change the preference only when wifi calling is enabled
422                 // And when wifi calling preference is editable for the current carrier
423                 final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId);
424                 final int currentValue = imsMmTelManager.getVoWiFiModeSetting();
425                 int newValue = errorValue;
426                 switch (intent.getAction()) {
427                     case ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY:
428                         if (isWifiOnlySupported) {
429                             // change to wifi_only when wifi_only is enabled.
430                             newValue = ImsMmTelManager.WIFI_MODE_WIFI_ONLY;
431                         }
432                         break;
433                     case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED:
434                         newValue = ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED;
435                         break;
436                     case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED:
437                         newValue = ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED;
438                         break;
439                 }
440                 if (newValue != errorValue && newValue != currentValue) {
441                     // Update the setting only when there is a valid update
442                     imsMmTelManager.setVoWiFiModeSetting(newValue);
443                 }
444             }
445         }
446 
447         // notify change in slice in any case to get re-queried. This would result in displaying
448         // appropriate message.
449         mContext.getContentResolver().notifyChange(WIFI_CALLING_PREFERENCE_URI, null);
450     }
451 
452     /**
453      * Returns Slice with the title and subtitle provided as arguments with wifi signal Icon.
454      *
455      * @param title    Title of the slice
456      * @param subtitle Subtitle of the slice
457      * @param sliceUri slice uri
458      * @return Slice with title and subtitle
459      */
getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle, Uri sliceUri, PendingIntent primaryActionIntent)460     private Slice getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle,
461             Uri sliceUri, PendingIntent primaryActionIntent) {
462         final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
463         final RowBuilder rowBuilder = new RowBuilder()
464                 .setTitle(title)
465                 .setPrimaryAction(SliceAction.createDeeplink(
466                         primaryActionIntent, icon, ListBuilder.SMALL_IMAGE,
467                         title));
468         if (!Utils.isSettingsIntelligence(mContext)) {
469             rowBuilder.setSubtitle(subtitle);
470         }
471         return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
472                 .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
473                 .addRow(rowBuilder)
474                 .build();
475     }
476 
477     /**
478      * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
479      */
isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue)480     protected boolean isCarrierConfigManagerKeyEnabled(String key, int subId,
481             boolean defaultValue) {
482         final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
483         boolean ret = false;
484         if (configManager != null) {
485             final PersistableBundle bundle = configManager.getConfigForSubId(subId);
486             if (bundle != null) {
487                 ret = bundle.getBoolean(key, defaultValue);
488             }
489         }
490         return ret;
491     }
492 
getCarrierConfigManager(Context mContext)493     protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
494         return mContext.getSystemService(CarrierConfigManager.class);
495     }
496 
497     /**
498      * Returns the current default voice subId obtained from SubscriptionManager
499      */
getDefaultVoiceSubId()500     protected int getDefaultVoiceSubId() {
501         return SubscriptionManager.getDefaultVoiceSubscriptionId();
502     }
503 
504     /**
505      * Returns Intent of the activation app required to activate wifi calling or null if there is no
506      * need for activation.
507      */
getWifiCallingCarrierActivityIntent(int subId)508     protected Intent getWifiCallingCarrierActivityIntent(int subId) {
509         final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
510         if (configManager == null) {
511             return null;
512         }
513 
514         final PersistableBundle bundle = configManager.getConfigForSubId(subId);
515         if (bundle == null) {
516             return null;
517         }
518 
519         final String carrierApp = bundle.getString(
520                 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
521         if (TextUtils.isEmpty(carrierApp)) {
522             return null;
523         }
524 
525         final ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
526         if (componentName == null) {
527             return null;
528         }
529 
530         final Intent intent = new Intent();
531         intent.setComponent(componentName);
532         return intent;
533     }
534 
535     /**
536      * @return {@link PendingIntent} to the Settings home page.
537      */
getSettingsIntent(Context context)538     public static PendingIntent getSettingsIntent(Context context) {
539         final Intent intent = new Intent(Settings.ACTION_SETTINGS);
540         return PendingIntent.getActivity(context, 0 /* requestCode */, intent,
541                 PendingIntent.FLAG_IMMUTABLE);
542     }
543 
getBroadcastIntent(String action)544     private PendingIntent getBroadcastIntent(String action) {
545         final Intent intent = new Intent(action);
546         intent.setClass(mContext, SliceBroadcastReceiver.class);
547         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
548         return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
549                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
550     }
551 
552     /**
553      * Returns PendingIntent to start activity specified by action
554      */
getActivityIntent(String action)555     private PendingIntent getActivityIntent(String action) {
556         final Intent intent = new Intent(action);
557         intent.setPackage(SETTINGS_PACKAGE_NAME);
558         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
559         return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
560                 PendingIntent.FLAG_IMMUTABLE);
561     }
562 
getResourcesForSubId(int subId)563     private Resources getResourcesForSubId(int subId) {
564         return SubscriptionManager.getResourcesForSubId(mContext, subId);
565     }
566 
567     @VisibleForTesting
queryImsState(int subId)568     WifiCallingQueryImsState queryImsState(int subId) {
569         return new WifiCallingQueryImsState(mContext, subId);
570     }
571 }
572