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