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