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 isWifiCallingEnabled), 184 null /* actionTitle */, isWifiCallingEnabled)) 185 .setPrimaryAction(SliceAction.createDeeplink( 186 getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), 187 icon, 188 ListBuilder.ICON_IMAGE, 189 res.getText(R.string.wifi_calling_settings_title)))) 190 .build(); 191 } 192 193 /** 194 * Returns Slice object for wifi calling preference. 195 * 196 * If wifi calling is not turned on, this method will return a slice to turn on wifi calling. 197 * 198 * If wifi calling preference is not user editable, this method will return a slice to display 199 * appropriate message. 200 * 201 * If wifi calling preference can be changed, this method will return a slice with 3 or 4 rows: 202 * Header Row: current preference settings 203 * Row 1: wifi only option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY, if wifi only option 204 * is editable 205 * Row 2: wifi preferred option with ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED 206 * Row 3: cellular preferred option with ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED 207 */ createWifiCallingPreferenceSlice(Uri sliceUri)208 public Slice createWifiCallingPreferenceSlice(Uri sliceUri) { 209 final int subId = getDefaultVoiceSubId(); 210 211 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 212 Log.d(TAG, "Invalid Subscription Id"); 213 return null; 214 } 215 216 final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled( 217 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false); 218 final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled( 219 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true); 220 221 if (!isWifiCallingPrefEditable) { 222 Log.d(TAG, "Wifi calling preference is not editable"); 223 return null; 224 } 225 226 if (!queryImsState(subId).isWifiCallingProvisioned()) { 227 Log.d(TAG, "Wifi calling is either not provisioned or not enabled by platform"); 228 return null; 229 } 230 231 boolean isWifiCallingEnabled = false; 232 int wfcMode = -1; 233 try { 234 final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId); 235 isWifiCallingEnabled = isWifiCallingEnabled(); 236 wfcMode = getWfcMode(imsMmTelManager); 237 } catch (InterruptedException | ExecutionException | TimeoutException e) { 238 Log.e(TAG, "Unable to get wifi calling preferred mode", e); 239 return null; 240 } 241 if (!isWifiCallingEnabled) { 242 // wifi calling is not enabled. Ask user to enable wifi calling 243 final Resources res = getResourcesForSubId(subId); 244 return getNonActionableWifiCallingSlice( 245 res.getText(R.string.wifi_calling_mode_title), 246 res.getText(R.string.wifi_calling_turn_on), 247 sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY)); 248 } 249 // Return the slice to change wifi calling preference 250 return getWifiCallingPreferenceSlice( 251 isWifiOnlySupported, wfcMode, sliceUri, subId); 252 } 253 254 /** 255 * Returns actionable wifi calling preference slice. 256 * 257 * @param isWifiOnlySupported adds row for wifi only if this is true 258 * @param currentWfcPref current Preference {@link ImsConfig} 259 * @param sliceUri sliceUri 260 * @param subId subscription id 261 * @return Slice for actionable wifi calling preference settings 262 */ getWifiCallingPreferenceSlice(boolean isWifiOnlySupported, int currentWfcPref, Uri sliceUri, int subId)263 private Slice getWifiCallingPreferenceSlice(boolean isWifiOnlySupported, 264 int currentWfcPref, 265 Uri sliceUri, 266 int subId) { 267 final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); 268 final Resources res = getResourcesForSubId(subId); 269 // Top row shows information on current preference state 270 final ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) 271 .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); 272 final ListBuilder.HeaderBuilder headerBuilder = new ListBuilder.HeaderBuilder() 273 .setTitle(res.getText(R.string.wifi_calling_mode_title)) 274 .setPrimaryAction(SliceAction.createDeeplink( 275 getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), 276 icon, 277 ListBuilder.ICON_IMAGE, 278 res.getText(R.string.wifi_calling_mode_title))); 279 if (!Utils.isSettingsIntelligence(mContext)) { 280 headerBuilder.setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref, subId)); 281 } 282 listBuilder.setHeader(headerBuilder); 283 284 if (isWifiOnlySupported) { 285 listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, 286 com.android.internal.R.string.wfc_mode_wifi_only_summary, 287 ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY, 288 currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_ONLY, subId)); 289 } 290 291 listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, 292 com.android.internal.R.string.wfc_mode_wifi_preferred_summary, 293 ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED, 294 currentWfcPref == ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED, subId)); 295 296 listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, 297 com.android.internal.R.string.wfc_mode_cellular_preferred_summary, 298 ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED, 299 currentWfcPref == ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED, subId)); 300 301 return listBuilder.build(); 302 } 303 304 /** 305 * Returns RowBuilder for a new row containing specific wifi calling preference. 306 * 307 * @param listBuilder ListBuilder that will be the parent for this RowBuilder 308 * @param preferenceTitleResId resource Id for the preference row title 309 * @param action action to be added for the row 310 * @param subId subscription id 311 * @return RowBuilder for the row 312 */ wifiPreferenceRowBuilder(ListBuilder listBuilder, int preferenceTitleResId, String action, boolean checked, int subId)313 private RowBuilder wifiPreferenceRowBuilder(ListBuilder listBuilder, 314 int preferenceTitleResId, String action, boolean checked, int subId) { 315 final IconCompat icon = 316 IconCompat.createWithResource(mContext, R.drawable.radio_button_check); 317 final Resources res = getResourcesForSubId(subId); 318 return new RowBuilder() 319 .setTitle(res.getText(preferenceTitleResId)) 320 .setTitleItem(SliceAction.createToggle(getBroadcastIntent(action, checked), 321 icon, res.getText(preferenceTitleResId), checked)); 322 } 323 324 325 /** 326 * Returns the String describing wifi calling preference mentioned in wfcMode 327 * 328 * @param wfcMode ImsConfig constant for the preference {@link ImsConfig} 329 * @return summary/name of the wifi calling preference 330 */ getWifiCallingPreferenceSummary(int wfcMode, int subId)331 private CharSequence getWifiCallingPreferenceSummary(int wfcMode, int subId) { 332 final Resources res = getResourcesForSubId(subId); 333 switch (wfcMode) { 334 case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: 335 return res.getText( 336 com.android.internal.R.string.wfc_mode_wifi_only_summary); 337 case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: 338 return res.getText( 339 com.android.internal.R.string.wfc_mode_wifi_preferred_summary); 340 case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: 341 return res.getText( 342 com.android.internal.R.string.wfc_mode_cellular_preferred_summary); 343 default: 344 return null; 345 } 346 } 347 getImsMmTelManager(int subId)348 protected ImsMmTelManager getImsMmTelManager(int subId) { 349 return ImsMmTelManager.createForSubscriptionId(subId); 350 } 351 getWfcMode(ImsMmTelManager imsMmTelManager)352 private int getWfcMode(ImsMmTelManager imsMmTelManager) 353 throws InterruptedException, ExecutionException, TimeoutException { 354 final FutureTask<Integer> wfcModeTask = new FutureTask<>(new Callable<Integer>() { 355 @Override 356 public Integer call() { 357 return imsMmTelManager.getVoWiFiModeSetting(); 358 } 359 }); 360 final ExecutorService executor = Executors.newSingleThreadExecutor(); 361 executor.execute(wfcModeTask); 362 return wfcModeTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 363 } 364 365 /** 366 * Handles wifi calling setting change from wifi calling slice and posts notification. Should be 367 * called when intent action is ACTION_WIFI_CALLING_CHANGED. Executed in @WorkerThread 368 * 369 * @param intent action performed 370 */ handleWifiCallingChanged(Intent intent)371 public void handleWifiCallingChanged(Intent intent) { 372 final int subId = getDefaultVoiceSubId(); 373 374 if (SubscriptionManager.isValidSubscriptionId(subId) 375 && intent.hasExtra(EXTRA_TOGGLE_STATE)) { 376 final WifiCallingQueryImsState queryState = queryImsState(subId); 377 if (queryState.isWifiCallingProvisioned()) { 378 final boolean currentValue = isWifiCallingEnabled(); 379 final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, 380 currentValue); 381 final Intent activationAppIntent = 382 getWifiCallingCarrierActivityIntent(subId); 383 if ((newValue == currentValue) && activationAppIntent == null) { 384 // If either the action is to turn off wifi calling setting 385 // or there is no activation involved - Update the setting 386 final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId); 387 imsMmTelManager.setVoWiFiSettingEnabled(!newValue); 388 } else { 389 Log.w(TAG, "action not taken: subId " + subId 390 + " from " + currentValue + " to " + newValue); 391 } 392 } else { 393 Log.w(TAG, "action not taken: subId " + subId + " needs provision"); 394 } 395 } else { 396 Log.w(TAG, "action not taken: subId " + subId); 397 } 398 399 // notify change in slice in any case to get re-queried. This would result in displaying 400 // appropriate message with the updated setting. 401 mContext.getContentResolver().notifyChange(WIFI_CALLING_URI, null); 402 } 403 404 /** 405 * Handles wifi calling preference Setting change from wifi calling preference Slice and posts 406 * notification for the change. Should be called when intent action is one of the below 407 * ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY 408 * ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED 409 * ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED 410 * 411 * @param intent intent 412 */ handleWifiCallingPreferenceChanged(Intent intent)413 public void handleWifiCallingPreferenceChanged(Intent intent) { 414 final int subId = getDefaultVoiceSubId(); 415 final int errorValue = -1; 416 417 if (SubscriptionManager.isValidSubscriptionId(subId)) { 418 final boolean isWifiCallingPrefEditable = isCarrierConfigManagerKeyEnabled( 419 CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, subId, false); 420 final boolean isWifiOnlySupported = isCarrierConfigManagerKeyEnabled( 421 CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, subId, true); 422 423 final WifiCallingQueryImsState queryState = queryImsState(subId); 424 if (isWifiCallingPrefEditable 425 && queryState.isWifiCallingProvisioned() 426 && queryState.isEnabledByUser() 427 && queryState.isAllowUserControl()) { 428 // Change the preference only when wifi calling is enabled 429 // And when wifi calling preference is editable for the current carrier 430 final ImsMmTelManager imsMmTelManager = getImsMmTelManager(subId); 431 final int currentValue = imsMmTelManager.getVoWiFiModeSetting(); 432 int newValue = errorValue; 433 switch (intent.getAction()) { 434 case ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY: 435 if (isWifiOnlySupported) { 436 // change to wifi_only when wifi_only is enabled. 437 newValue = ImsMmTelManager.WIFI_MODE_WIFI_ONLY; 438 } 439 break; 440 case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED: 441 newValue = ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED; 442 break; 443 case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED: 444 newValue = ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED; 445 break; 446 } 447 if (newValue != errorValue && newValue != currentValue) { 448 // Update the setting only when there is a valid update 449 imsMmTelManager.setVoWiFiModeSetting(newValue); 450 } 451 } 452 } 453 454 // notify change in slice in any case to get re-queried. This would result in displaying 455 // appropriate message. 456 mContext.getContentResolver().notifyChange(WIFI_CALLING_PREFERENCE_URI, null); 457 } 458 459 /** 460 * Returns Slice with the title and subtitle provided as arguments with wifi signal Icon. 461 * 462 * @param title Title of the slice 463 * @param subtitle Subtitle of the slice 464 * @param sliceUri slice uri 465 * @return Slice with title and subtitle 466 */ getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle, Uri sliceUri, PendingIntent primaryActionIntent)467 private Slice getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle, 468 Uri sliceUri, PendingIntent primaryActionIntent) { 469 final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); 470 final RowBuilder rowBuilder = new RowBuilder() 471 .setTitle(title) 472 .setPrimaryAction(SliceAction.createDeeplink( 473 primaryActionIntent, icon, ListBuilder.SMALL_IMAGE, 474 title)); 475 if (!Utils.isSettingsIntelligence(mContext)) { 476 rowBuilder.setSubtitle(subtitle); 477 } 478 return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) 479 .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) 480 .addRow(rowBuilder) 481 .build(); 482 } 483 484 /** 485 * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise. 486 */ isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue)487 protected boolean isCarrierConfigManagerKeyEnabled(String key, int subId, 488 boolean defaultValue) { 489 final CarrierConfigManager configManager = getCarrierConfigManager(mContext); 490 boolean ret = false; 491 if (configManager != null) { 492 final PersistableBundle bundle = configManager.getConfigForSubId(subId); 493 if (bundle != null) { 494 ret = bundle.getBoolean(key, defaultValue); 495 } 496 } 497 return ret; 498 } 499 getCarrierConfigManager(Context mContext)500 protected CarrierConfigManager getCarrierConfigManager(Context mContext) { 501 return mContext.getSystemService(CarrierConfigManager.class); 502 } 503 504 /** 505 * Returns the current default voice subId obtained from SubscriptionManager 506 */ getDefaultVoiceSubId()507 protected int getDefaultVoiceSubId() { 508 return SubscriptionManager.getDefaultVoiceSubscriptionId(); 509 } 510 511 /** 512 * Returns Intent of the activation app required to activate wifi calling or null if there is no 513 * need for activation. 514 */ getWifiCallingCarrierActivityIntent(int subId)515 protected Intent getWifiCallingCarrierActivityIntent(int subId) { 516 final CarrierConfigManager configManager = getCarrierConfigManager(mContext); 517 if (configManager == null) { 518 return null; 519 } 520 521 final PersistableBundle bundle = configManager.getConfigForSubId(subId); 522 if (bundle == null) { 523 return null; 524 } 525 526 final String carrierApp = bundle.getString( 527 CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING); 528 if (TextUtils.isEmpty(carrierApp)) { 529 return null; 530 } 531 532 final ComponentName componentName = ComponentName.unflattenFromString(carrierApp); 533 if (componentName == null) { 534 return null; 535 } 536 537 final Intent intent = new Intent(); 538 intent.setComponent(componentName); 539 return intent; 540 } 541 542 /** 543 * @return {@link PendingIntent} to the Settings home page. 544 */ getSettingsIntent(Context context)545 public static PendingIntent getSettingsIntent(Context context) { 546 final Intent intent = new Intent(Settings.ACTION_SETTINGS); 547 return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 548 PendingIntent.FLAG_IMMUTABLE); 549 } 550 551 /** 552 * Create PendingIntent for Slice. 553 * Note: SliceAction#createDeeplink() didn't support toggle status so far, 554 * therefore, embedding toggle status within PendingIntent. 555 * 556 * @param action Slice action 557 * @param isChecked Status when Slice created. 558 * @return PendingIntent 559 */ getBroadcastIntent(String action, boolean isChecked)560 private PendingIntent getBroadcastIntent(String action, boolean isChecked) { 561 final Intent intent = new Intent(action); 562 intent.setClass(mContext, SliceBroadcastReceiver.class); 563 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 564 intent.putExtra(EXTRA_TOGGLE_STATE, isChecked); 565 return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent, 566 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 567 } 568 569 /** 570 * Returns PendingIntent to start activity specified by action 571 */ getActivityIntent(String action)572 private PendingIntent getActivityIntent(String action) { 573 final Intent intent = new Intent(action); 574 intent.setPackage(SETTINGS_PACKAGE_NAME); 575 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 576 return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 577 PendingIntent.FLAG_IMMUTABLE); 578 } 579 getResourcesForSubId(int subId)580 private Resources getResourcesForSubId(int subId) { 581 return SubscriptionManager.getResourcesForSubId(mContext, subId); 582 } 583 584 @VisibleForTesting queryImsState(int subId)585 WifiCallingQueryImsState queryImsState(int subId) { 586 return new WifiCallingQueryImsState(mContext, subId); 587 } 588 } 589