1 /* 2 * Copyright (c) 2015, Motorola Mobility LLC 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * - Neither the name of Motorola Mobility nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 * DAMAGE. 27 */ 28 29 package com.android.service.ims.presence; 30 31 import android.annotation.IntDef; 32 import android.app.AlarmManager; 33 import android.app.PendingIntent; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.net.Uri; 37 import android.os.Handler; 38 import android.os.Looper; 39 import android.os.Message; 40 import android.os.SystemClock; 41 import android.provider.Settings; 42 import android.telecom.PhoneAccount; 43 import android.telecom.TelecomManager; 44 import android.telephony.AccessNetworkConstants; 45 import android.telephony.SubscriptionManager; 46 import android.telephony.TelephonyManager; 47 import android.telephony.ims.RcsContactPresenceTuple; 48 import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities; 49 import android.telephony.ims.RcsContactUceCapability; 50 import android.telephony.ims.RcsContactUceCapability.PresenceBuilder; 51 import android.telephony.ims.feature.MmTelFeature; 52 import android.text.TextUtils; 53 54 import com.android.ims.ResultCode; 55 import com.android.ims.internal.ContactNumberUtils; 56 import com.android.ims.internal.Logger; 57 import com.android.service.ims.RcsSettingUtils; 58 import com.android.service.ims.Task; 59 import com.android.service.ims.TaskManager; 60 61 import java.lang.annotation.Retention; 62 import java.lang.annotation.RetentionPolicy; 63 64 public class PresencePublication extends PresenceBase { 65 private Logger logger = Logger.getLogger(this.getClass().getName()); 66 67 private final Object mSyncObj = new Object(); 68 69 private static final int TIMEOUT_CHECK_SUBSCRIPTION_READY_MS = 5000; 70 71 private static final String SIP_SCHEME = "sip"; 72 private static final String TEL_SCHEME = "tel"; 73 private static final String DOMAIN_SEPARATOR = "@"; 74 75 boolean mMovedToIWLAN = false; 76 boolean mMovedToLTE = false; 77 boolean mVoPSEnabled = false; 78 79 boolean mIsVolteAvailable = false; 80 boolean mIsVtAvailable = false; 81 boolean mIsVoWifiAvailable = false; 82 boolean mIsViWifiAvailable = false; 83 84 // Queue for the pending PUBLISH request. Just need cache the last one. 85 volatile PublishRequest mPendingRequest = null; 86 volatile PublishRequest mPublishingRequest = null; 87 volatile PublishRequest mPublishedRequest = null; 88 89 /* 90 * Message sent to mMsgHandler when there is a new request to Publish capabilities. 91 */ 92 private static final int MESSAGE_RCS_PUBLISH_REQUEST = 1; 93 /* 94 * Message sent when the default subscription has changed or become active for the first time. 95 */ 96 private static final int MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED = 2; 97 98 private Handler mMsgHandler = new Handler(Looper.getMainLooper()) { 99 @Override 100 public void handleMessage(Message msg) { 101 super.handleMessage(msg); 102 103 logger.debug( "Thread=" + Thread.currentThread().getName() + " received " 104 + msg); 105 if(msg == null){ 106 logger.error("msg=null"); 107 return; 108 } 109 110 switch (msg.what) { 111 case MESSAGE_RCS_PUBLISH_REQUEST: { 112 logger.debug("handleMessage msg=RCS_PUBLISH_REQUEST:"); 113 114 PublishRequest publishRequest = (PublishRequest) msg.obj; 115 synchronized (mSyncObj) { 116 mPendingRequest = null; 117 } 118 doPublish(publishRequest); 119 break; 120 } 121 case MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED: { 122 requestPublishIfSubscriptionReady(); 123 break; 124 } 125 default: 126 logger.debug("handleMessage unknown msg=" + msg.what); 127 } 128 } 129 }; 130 131 private PresencePublisher mPresencePublisher; 132 private PresenceSubscriber mSubscriber = null; 133 static private PresencePublication sPresencePublication = null; 134 135 private boolean mHasCachedTrigger = false; 136 private boolean mGotTriggerFromStack = false; 137 private boolean mDonotRetryUntilPowerCycle = false; 138 private boolean mSimLoaded = false; 139 private int mPreferredTtyMode = TelecomManager.TTY_MODE_OFF; 140 141 private boolean mImsRegistered = false; 142 private boolean mVtEnabled = false; 143 private boolean mDataEnabled = false; 144 private final String[] mConfigVolteProvisionErrorOnPublishResponse; 145 private final String[] mConfigRcsProvisionErrorOnPublishResponse; 146 private int mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 147 148 /** ETag expired. */ 149 public static final int UCE_PRES_PUBLISH_TRIGGER_ETAG_EXPIRED = 0; 150 /** Move to LTE with VoPS disabled. */ 151 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; 152 /** Move to LTE with VoPS enabled. */ 153 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; 154 /** Move to eHRPD. */ 155 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_EHRPD = 3; 156 /** Move to HSPA+. */ 157 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_HSPAPLUS = 4; 158 /** Move to 3G. */ 159 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_3G = 5; 160 /** Move to 2G. */ 161 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_2G = 6; 162 /** Move to WLAN */ 163 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_WLAN = 7; 164 /** Move to IWLAN */ 165 public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN = 8; 166 /** Trigger is unknown. */ 167 public static final int UCE_PRES_PUBLISH_TRIGGER_UNKNOWN = 9; 168 169 @IntDef(value = { 170 UCE_PRES_PUBLISH_TRIGGER_ETAG_EXPIRED, 171 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED, 172 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED, 173 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_EHRPD, 174 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_HSPAPLUS, 175 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_3G, 176 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_2G, 177 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_WLAN, 178 UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN, 179 UCE_PRES_PUBLISH_TRIGGER_UNKNOWN 180 }, prefix="UCE_PRES_PUBLISH_TRIGGER_") 181 @Retention(RetentionPolicy.SOURCE) 182 public @interface StackPublishTriggerType {} 183 184 public class PublishType { 185 public static final int PRES_PUBLISH_TRIGGER_DATA_CHANGED = 0; 186 // the lower layer should send trigger when enable volte 187 // the lower layer should unpublish when disable volte 188 // so only handle VT here. 189 public static final int PRES_PUBLISH_TRIGGER_VTCALL_CHANGED = 1; 190 public static final int PRES_PUBLISH_TRIGGER_CACHED_TRIGGER = 2; 191 public static final int PRES_PUBLISH_TRIGGER_TTY_ENABLE_STATUS = 3; 192 public static final int PRES_PUBLISH_TRIGGER_RETRY = 4; 193 public static final int PRES_PUBLISH_TRIGGER_FEATURE_AVAILABILITY_CHANGED = 5; 194 public static final int PRES_PUBLISH_TRIGGER_DEFAULT_SUB_CHANGED = 6; 195 }; 196 PresencePublication(PresencePublisher presencePublisher, Context context, String[] configVolteProvisionErrorOnPublishResponse, String[] configRcsProvisionErrorOnPublishResponse)197 public PresencePublication(PresencePublisher presencePublisher, Context context, 198 String[] configVolteProvisionErrorOnPublishResponse, 199 String[] configRcsProvisionErrorOnPublishResponse) { 200 super(context); 201 logger.debug("PresencePublication constrcuct"); 202 synchronized(mSyncObj) { 203 this.mPresencePublisher = presencePublisher; 204 } 205 mConfigVolteProvisionErrorOnPublishResponse = configVolteProvisionErrorOnPublishResponse; 206 mConfigRcsProvisionErrorOnPublishResponse = configRcsProvisionErrorOnPublishResponse; 207 208 mVtEnabled = RcsSettingUtils.isVtEnabledByUser(mAssociatedSubscription); 209 210 mDataEnabled = Settings.Global.getInt(mContext.getContentResolver(), 211 Settings.Global.MOBILE_DATA, 1) == 1; 212 logger.debug("The current mobile data is: " + (mDataEnabled ? "enabled" : "disabled")); 213 214 TelecomManager tm = mContext.getSystemService(TelecomManager.class); 215 mPreferredTtyMode = tm.getCurrentTtyMode(); 216 logger.debug("The current TTY mode is: " + mPreferredTtyMode); 217 218 sPresencePublication = this; 219 } 220 updatePresencePublisher(PresencePublisher presencePublisher)221 public void updatePresencePublisher(PresencePublisher presencePublisher) { 222 synchronized(mSyncObj) { 223 logger.debug("Update PresencePublisher"); 224 this.mPresencePublisher = presencePublisher; 225 } 226 } 227 removePresencePublisher()228 public void removePresencePublisher() { 229 synchronized(mSyncObj) { 230 logger.debug("Remove PresencePublisher"); 231 this.mPresencePublisher = null; 232 } 233 } 234 requestPublishIfSubscriptionReady()235 private void requestPublishIfSubscriptionReady() { 236 if (!SubscriptionManager.isValidSubscriptionId(mAssociatedSubscription)) { 237 // pulled out the SIM, set it as the same as power on status: 238 logger.print("subscription changed to invalid, setting to not published"); 239 240 // only reset when the SIM gets absent. 241 reset(); 242 mSimLoaded = false; 243 setPublishState(PUBLISH_STATE_NOT_PUBLISHED); 244 return; 245 } 246 if (isSimLoaded()) { 247 logger.print("subscription ready, requesting publish"); 248 mSimLoaded = true; 249 // treat hot SIM hot swap as power on. 250 mDonotRetryUntilPowerCycle = false; 251 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_DEFAULT_SUB_CHANGED); 252 } else { 253 mMsgHandler.removeMessages(MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED); 254 mMsgHandler.sendMessageDelayed( 255 mMsgHandler.obtainMessage(MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED), 256 TIMEOUT_CHECK_SUBSCRIPTION_READY_MS); 257 } 258 } 259 isSimLoaded()260 private boolean isSimLoaded() { 261 TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( 262 Context.TELEPHONY_SERVICE); 263 if (teleMgr == null) return false; 264 teleMgr = teleMgr.createForSubscriptionId(mAssociatedSubscription); 265 String[] myImpu = teleMgr.getIsimImpu(); 266 String myDomain = teleMgr.getIsimDomain(); 267 String line1Number = teleMgr.getLine1Number(); 268 return !TextUtils.isEmpty(line1Number) || (!TextUtils.isEmpty(myDomain) && myImpu != null 269 && myImpu.length != 0); 270 } 271 isIPVoiceSupported(boolean volteAvailable, boolean voWifiAvailable)272 private boolean isIPVoiceSupported(boolean volteAvailable, boolean voWifiAvailable) { 273 // volte and vowifi can be enabled separately 274 if(!RcsSettingUtils.isVoLteSupported(mAssociatedSubscription) && 275 !RcsSettingUtils.isVoWiFiSupported(mAssociatedSubscription)) { 276 logger.print("Disabled by platform, voiceSupported=false"); 277 return false; 278 } 279 280 if(!RcsSettingUtils.isVoLteProvisioned(mAssociatedSubscription) && 281 !RcsSettingUtils.isVowifiProvisioned(mAssociatedSubscription)) { 282 logger.print("Wasn't provisioned, voiceSupported=false"); 283 return false; 284 } 285 286 if(!RcsSettingUtils.isAdvancedCallingEnabledByUser(mAssociatedSubscription) && 287 !RcsSettingUtils.isWfcEnabledByUser(mAssociatedSubscription)){ 288 logger.print("User didn't enable volte or wfc, voiceSupported=false"); 289 return false; 290 } 291 292 // for IWLAN. All WFC settings and provision should be fine if voWifiAvailable is true. 293 if(isOnIWLAN()) { 294 boolean voiceSupported=volteAvailable || voWifiAvailable; 295 logger.print("on IWLAN, voiceSupported=" + voiceSupported); 296 return voiceSupported; 297 } 298 299 // for none-IWLAN 300 if(!isOnLTE()) { 301 logger.print("isOnLTE=false, voiceSupported=false"); 302 return false; 303 } 304 305 if(!mVoPSEnabled) { 306 logger.print("mVoPSEnabled=false, voiceSupported=false"); 307 return false; 308 } 309 310 logger.print("voiceSupported=true"); 311 return true; 312 } 313 isIPVideoSupported(boolean vtAvailable, boolean viWifiAvailable)314 private boolean isIPVideoSupported(boolean vtAvailable, boolean viWifiAvailable) { 315 // if volte or vt was disabled then the viwifi will be disabled as well. 316 if(!RcsSettingUtils.isVoLteSupported(mAssociatedSubscription) || 317 !RcsSettingUtils.isVtSupported(mAssociatedSubscription)) { 318 logger.print("Disabled by platform, videoSupported=false"); 319 return false; 320 } 321 322 if(!RcsSettingUtils.isVoLteProvisioned(mAssociatedSubscription) || 323 !RcsSettingUtils.isLvcProvisioned(mAssociatedSubscription)) { 324 logger.print("Not provisioned. videoSupported=false"); 325 return false; 326 } 327 328 if(!RcsSettingUtils.isAdvancedCallingEnabledByUser(mAssociatedSubscription) || !mVtEnabled){ 329 logger.print("User disabled volte or vt, videoSupported=false"); 330 return false; 331 } 332 333 if(isTtyOn()){ 334 logger.print("isTtyOn=true, videoSupported=false"); 335 return false; 336 } 337 338 // for IWLAN, all WFC settings and provision should be fine if viWifiAvailable is true. 339 if(isOnIWLAN()) { 340 boolean videoSupported = vtAvailable || viWifiAvailable; 341 logger.print("on IWLAN, videoSupported=" + videoSupported); 342 return videoSupported; 343 } 344 345 if(!isDataEnabled()) { 346 logger.print("isDataEnabled()=false, videoSupported=false"); 347 return false; 348 } 349 350 if(!isOnLTE()) { 351 logger.print("isOnLTE=false, videoSupported=false"); 352 return false; 353 } 354 355 if(!mVoPSEnabled) { 356 logger.print("mVoPSEnabled=false, videoSupported=false"); 357 return false; 358 } 359 360 return true; 361 } 362 onTtyPreferredModeChanged(int newTtyPreferredMode)363 public void onTtyPreferredModeChanged(int newTtyPreferredMode) { 364 logger.debug("Tty mode changed from " + mPreferredTtyMode 365 + " to " + newTtyPreferredMode); 366 367 boolean mIsTtyEnabled = isTtyEnabled(mPreferredTtyMode); 368 boolean isTtyEnabled = isTtyEnabled(newTtyPreferredMode); 369 mPreferredTtyMode = newTtyPreferredMode; 370 if (mIsTtyEnabled != isTtyEnabled) { 371 logger.print("ttyEnabled status changed from " + mIsTtyEnabled 372 + " to " + isTtyEnabled); 373 requestLocalPublish(PresencePublication.PublishType. 374 PRES_PUBLISH_TRIGGER_TTY_ENABLE_STATUS ); 375 } 376 } 377 onAirplaneModeChanged(boolean isAirplaneModeEnabled)378 public void onAirplaneModeChanged(boolean isAirplaneModeEnabled) { 379 if(isAirplaneModeEnabled){ 380 logger.print("Airplane mode, set to PUBLISH_STATE_NOT_PUBLISHED"); 381 reset(); 382 setPublishState(PUBLISH_STATE_NOT_PUBLISHED); 383 } 384 } 385 isTtyOn()386 public boolean isTtyOn() { 387 logger.debug("isTtyOn settingsTtyMode=" + mPreferredTtyMode); 388 return isTtyEnabled(mPreferredTtyMode); 389 } 390 onImsConnected()391 public void onImsConnected() { 392 mImsRegistered = true; 393 } 394 onImsDisconnected()395 public void onImsDisconnected() { 396 logger.debug("reset PUBLISH status for IMS had been disconnected"); 397 mImsRegistered = false; 398 reset(); 399 } 400 reset()401 private void reset() { 402 mIsVolteAvailable = false; 403 mIsVtAvailable = false; 404 mIsVoWifiAvailable = false; 405 mIsViWifiAvailable = false; 406 407 synchronized(mSyncObj) { 408 mPendingRequest = null; //ignore the previous request 409 mPublishingRequest = null; 410 mPublishedRequest = null; 411 } 412 } 413 handleAssociatedSubscriptionChanged(int newSubId)414 public void handleAssociatedSubscriptionChanged(int newSubId) { 415 if (mAssociatedSubscription == newSubId) { 416 return; 417 } 418 reset(); 419 mAssociatedSubscription = newSubId; 420 mMsgHandler.removeMessages(MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED); 421 mMsgHandler.sendMessage(mMsgHandler.obtainMessage(MESSAGE_DEFAULT_SUBSCRIPTION_CHANGED)); 422 } 423 handleProvisioningChanged()424 public void handleProvisioningChanged() { 425 if(RcsSettingUtils.isEabProvisioned(mContext, mAssociatedSubscription)) { 426 logger.debug("provisioned, set mDonotRetryUntilPowerCycle to false"); 427 mDonotRetryUntilPowerCycle = false; 428 if(mHasCachedTrigger) { 429 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_CACHED_TRIGGER); 430 } 431 } 432 } 433 getPresencePublication()434 static public PresencePublication getPresencePublication() { 435 return sPresencePublication; 436 } 437 setSubscriber(PresenceSubscriber subscriber)438 public void setSubscriber(PresenceSubscriber subscriber) { 439 mSubscriber = subscriber; 440 } 441 isDataEnabled()442 public boolean isDataEnabled() { 443 return Settings.Global.getInt(mContext.getContentResolver(), 444 Settings.Global.MOBILE_DATA, 1) == 1; 445 } 446 onMobileDataChanged(boolean value)447 public void onMobileDataChanged(boolean value){ 448 logger.print("onMobileDataChanged, mDataEnabled=" + mDataEnabled + " value=" + value); 449 if(mDataEnabled != value) { 450 mDataEnabled = value; 451 452 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_DATA_CHANGED); 453 } 454 } 455 onVtEnabled(boolean enabled)456 public void onVtEnabled(boolean enabled) { 457 logger.debug("onVtEnabled mVtEnabled=" + mVtEnabled + " enabled=" + enabled); 458 459 if(mVtEnabled != enabled) { 460 mVtEnabled = enabled; 461 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_VTCALL_CHANGED); 462 } 463 } 464 465 @Override onCommandStatusUpdated(int taskId, int requestId, int resultCode)466 public void onCommandStatusUpdated(int taskId, int requestId, int resultCode) { 467 logger.info("onCommandStatusUpdated: resultCode= " + resultCode); 468 super.onCommandStatusUpdated(taskId, requestId, resultCode); 469 } 470 471 /** 472 * @return return true if it had been PUBLISHED. 473 */ isPublishedOrPublishing()474 private boolean isPublishedOrPublishing() { 475 long publishThreshold = RcsSettingUtils.getPublishThrottle(mAssociatedSubscription); 476 477 boolean publishing = false; 478 publishing = (mPublishingRequest != null) && 479 (System.currentTimeMillis() - mPublishingRequest.getTimestamp() 480 <= publishThreshold); 481 482 return (getPublishState() == PUBLISH_STATE_200_OK || publishing); 483 } 484 485 /** 486 * @return The result of the last Publish request. 487 */ getPublishState()488 public @PresenceBase.PresencePublishState int getPublishState() { 489 PresencePublisher presencePublisher = null; 490 synchronized(mSyncObj) { 491 presencePublisher = mPresencePublisher; 492 } 493 494 if (presencePublisher != null) { 495 return presencePublisher.getPublisherState(); 496 } 497 return PUBLISH_STATE_NOT_PUBLISHED; 498 } 499 500 /** 501 * @param publishState The result of the last publish request. 502 */ setPublishState(int publishState)503 public void setPublishState(int publishState) { 504 PresencePublisher presencePublisher = null; 505 synchronized(mSyncObj) { 506 presencePublisher = mPresencePublisher; 507 } 508 509 if (presencePublisher != null) { 510 presencePublisher.updatePublisherState(publishState); 511 } 512 } 513 514 // Trigger a local publish based off of state changes in the framework. requestLocalPublish(int trigger)515 private void requestLocalPublish(int trigger) { 516 517 // if the value is true then it will call stack to send the PUBLISH 518 // though the previous publish had the same capability 519 // for example: for retry PUBLISH. 520 boolean bForceToNetwork = true; 521 switch(trigger) 522 { 523 case PublishType.PRES_PUBLISH_TRIGGER_DATA_CHANGED: 524 { 525 logger.print("PRES_PUBLISH_TRIGGER_DATA_CHANGED"); 526 bForceToNetwork = false; 527 break; 528 } 529 case PublishType.PRES_PUBLISH_TRIGGER_VTCALL_CHANGED: 530 { 531 logger.print("PRES_PUBLISH_TRIGGER_VTCALL_CHANGED"); 532 // Didn't get featureCapabilityChanged sometimes. 533 bForceToNetwork = true; 534 break; 535 } 536 case PublishType.PRES_PUBLISH_TRIGGER_CACHED_TRIGGER: 537 { 538 logger.print("PRES_PUBLISH_TRIGGER_CACHED_TRIGGER"); 539 break; 540 } 541 case PublishType.PRES_PUBLISH_TRIGGER_TTY_ENABLE_STATUS: 542 { 543 logger.print("PRES_PUBLISH_TRIGGER_TTY_ENABLE_STATUS"); 544 bForceToNetwork = true; 545 546 break; 547 } 548 case PublishType.PRES_PUBLISH_TRIGGER_FEATURE_AVAILABILITY_CHANGED: 549 { 550 bForceToNetwork = false; 551 logger.print("PRES_PUBLISH_TRIGGER_FEATURE_AVAILABILITY_CHANGED"); 552 break; 553 } 554 case PublishType.PRES_PUBLISH_TRIGGER_RETRY: 555 { 556 logger.print("PRES_PUBLISH_TRIGGER_RETRY"); 557 break; 558 } 559 case PublishType.PRES_PUBLISH_TRIGGER_DEFAULT_SUB_CHANGED: 560 { 561 logger.print("PRES_PUBLISH_TRIGGER_DEFAULT_SUB_CHANGED"); 562 bForceToNetwork = true; 563 break; 564 } 565 default: 566 { 567 logger.print("Unknown publish trigger from AP"); 568 } 569 } 570 571 if(mGotTriggerFromStack == false){ 572 // Waiting for RCS stack get ready. 573 logger.print("Didn't get trigger from stack yet, discard framework trigger."); 574 return; 575 } 576 577 if (mDonotRetryUntilPowerCycle) { 578 logger.print("Don't publish until next power cycle"); 579 return; 580 } 581 582 if(!mSimLoaded){ 583 //need to read some information from SIM to publish 584 logger.print("invokePublish cache the trigger since the SIM is not ready"); 585 mHasCachedTrigger = true; 586 return; 587 } 588 589 //the provision status didn't be read from modem yet 590 if(!RcsSettingUtils.isEabProvisioned(mContext, mAssociatedSubscription)) { 591 logger.print("invokePublish cache the trigger, not provision yet"); 592 mHasCachedTrigger = true; 593 return; 594 } 595 596 PublishRequest publishRequest = new PublishRequest( 597 bForceToNetwork, System.currentTimeMillis()); 598 599 requestPublication(publishRequest); 600 601 return; 602 } 603 onStackPublishRequested(@tackPublishTriggerType int publishTriggerType)604 public void onStackPublishRequested(@StackPublishTriggerType int publishTriggerType) { 605 mGotTriggerFromStack = true; 606 607 switch (publishTriggerType) 608 { 609 case UCE_PRES_PUBLISH_TRIGGER_ETAG_EXPIRED: 610 { 611 logger.print("PUBLISH_TRIGGER_ETAG_EXPIRED"); 612 break; 613 } 614 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED: 615 { 616 logger.print("PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED"); 617 mMovedToLTE = true; 618 mVoPSEnabled = false; 619 mMovedToIWLAN = false; 620 621 // onImsConnected could came later than this trigger. 622 mImsRegistered = true; 623 break; 624 } 625 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED: 626 { 627 logger.print("PUBLISH_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED"); 628 mMovedToLTE = true; 629 mVoPSEnabled = true; 630 mMovedToIWLAN = false; 631 632 // onImsConnected could came later than this trigger. 633 mImsRegistered = true; 634 break; 635 } 636 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN: 637 { 638 logger.print("QRCS_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN"); 639 mMovedToLTE = false; 640 mVoPSEnabled = false; 641 mMovedToIWLAN = true; 642 643 // onImsConnected could came later than this trigger. 644 mImsRegistered = true; 645 break; 646 } 647 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_EHRPD: 648 { 649 logger.print("PUBLISH_TRIGGER_MOVE_TO_EHRPD"); 650 mMovedToLTE = false; 651 mVoPSEnabled = false; 652 mMovedToIWLAN = false; 653 654 // onImsConnected could came later than this trigger. 655 mImsRegistered = true; 656 break; 657 } 658 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_HSPAPLUS: 659 { 660 logger.print("PUBLISH_TRIGGER_MOVE_TO_HSPAPLUS"); 661 mMovedToLTE = false; 662 mVoPSEnabled = false; 663 mMovedToIWLAN = false; 664 break; 665 } 666 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_2G: 667 { 668 logger.print("PUBLISH_TRIGGER_MOVE_TO_2G"); 669 mMovedToLTE = false; 670 mVoPSEnabled = false; 671 mMovedToIWLAN = false; 672 break; 673 } 674 case UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_3G: 675 { 676 logger.print("PUBLISH_TRIGGER_MOVE_TO_3G"); 677 mMovedToLTE = false; 678 mVoPSEnabled = false; 679 mMovedToIWLAN = false; 680 break; 681 } 682 default: 683 logger.print("Unknow Publish Trigger Type"); 684 } 685 686 if (mDonotRetryUntilPowerCycle) { 687 logger.print("Don't publish until next power cycle"); 688 return; 689 } 690 691 if(!mSimLoaded){ 692 //need to read some information from SIM to publish 693 logger.print("invokePublish cache the trigger since the SIM is not ready"); 694 mHasCachedTrigger = true; 695 return; 696 } 697 698 //the provision status didn't be read from modem yet 699 if(!RcsSettingUtils.isEabProvisioned(mContext, mAssociatedSubscription)) { 700 logger.print("invokePublish cache the trigger, not provision yet"); 701 mHasCachedTrigger = true; 702 return; 703 } 704 705 // Always send the PUBLISH when we got the trigger from stack. 706 // This can avoid any issue when switch the phone between IWLAN and LTE. 707 PublishRequest publishRequest = new PublishRequest( 708 true /*forceToNetwork*/, System.currentTimeMillis()); 709 710 requestPublication(publishRequest); 711 } 712 713 /** 714 * Trigger a publish when the stack becomes available and we have a cached trigger waiting. 715 */ onStackAvailable()716 public void onStackAvailable() { 717 if (mHasCachedTrigger) { 718 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_CACHED_TRIGGER); 719 } 720 } 721 722 public class PublishRequest { 723 private boolean mForceToNetwork; 724 private long mCurrentTime; 725 private boolean mVolteCapable = false; 726 private boolean mVtCapable = false; 727 PublishRequest(boolean bForceToNetwork, long currentTime)728 PublishRequest(boolean bForceToNetwork, long currentTime) { 729 refreshPublishContent(); 730 mForceToNetwork = bForceToNetwork; 731 mCurrentTime = currentTime; 732 } 733 refreshPublishContent()734 public void refreshPublishContent() { 735 setVolteCapable(isIPVoiceSupported(mIsVolteAvailable, mIsVoWifiAvailable)); 736 setVtCapable(isIPVideoSupported(mIsVtAvailable, mIsViWifiAvailable)); 737 } 738 getForceToNetwork()739 public boolean getForceToNetwork() { 740 return mForceToNetwork; 741 } 742 setForceToNetwork(boolean bForceToNetwork)743 public void setForceToNetwork(boolean bForceToNetwork) { 744 mForceToNetwork = bForceToNetwork; 745 } 746 getTimestamp()747 public long getTimestamp() { 748 return mCurrentTime; 749 } 750 setTimestamp(long currentTime)751 public void setTimestamp(long currentTime) { 752 mCurrentTime = currentTime; 753 } 754 setVolteCapable(boolean capable)755 public void setVolteCapable(boolean capable) { 756 mVolteCapable = capable; 757 } 758 setVtCapable(boolean capable)759 public void setVtCapable(boolean capable) { 760 mVtCapable = capable; 761 } 762 getVolteCapable()763 public boolean getVolteCapable() { 764 return mVolteCapable; 765 } 766 getVtCapable()767 public boolean getVtCapable() { 768 return mVtCapable; 769 } 770 hasSamePublishContent(PublishRequest request)771 public boolean hasSamePublishContent(PublishRequest request) { 772 if(request == null) { 773 logger.error("request == null"); 774 return false; 775 } 776 777 return (mVolteCapable == request.getVolteCapable() && 778 mVtCapable == request.getVtCapable()); 779 } 780 toString()781 public String toString(){ 782 return "mForceToNetwork=" + mForceToNetwork + 783 " mCurrentTime=" + mCurrentTime + 784 " mVolteCapable=" + mVolteCapable + 785 " mVtCapable=" + mVtCapable; 786 } 787 } 788 requestPublication(PublishRequest publishRequest)789 private void requestPublication(PublishRequest publishRequest) { 790 // this is used to avoid the temp false feature change when switched between network. 791 if(publishRequest == null) { 792 logger.error("Invalid parameter publishRequest == null"); 793 return; 794 } 795 796 long requestThrottle = 2000; 797 long currentTime = System.currentTimeMillis(); 798 synchronized(mSyncObj){ 799 // There is a PUBLISH will be done soon. Discard it 800 if((mPendingRequest != null) && currentTime - mPendingRequest.getTimestamp() 801 <= requestThrottle) { 802 logger.print("A publish is pending, update the pending request and discard this one"); 803 if(publishRequest.getForceToNetwork() && !mPendingRequest.getForceToNetwork()) { 804 mPendingRequest.setForceToNetwork(true); 805 } 806 mPendingRequest.setTimestamp(publishRequest.getTimestamp()); 807 return; 808 } 809 810 mPendingRequest = publishRequest; 811 } 812 813 Message publishMessage = mMsgHandler.obtainMessage( 814 MESSAGE_RCS_PUBLISH_REQUEST, mPendingRequest); 815 mMsgHandler.sendMessageDelayed(publishMessage, requestThrottle); 816 } 817 doPublish(PublishRequest publishRequest)818 private void doPublish(PublishRequest publishRequest) { 819 820 if(publishRequest == null) { 821 logger.error("publishRequest == null"); 822 return; 823 } 824 825 PresencePublisher presencePublisher = null; 826 synchronized(mSyncObj) { 827 presencePublisher = mPresencePublisher; 828 } 829 830 if (presencePublisher == null) { 831 logger.error("mPresencePublisher == null"); 832 return; 833 } 834 835 if(!mImsRegistered) { 836 logger.error("IMS wasn't registered"); 837 return; 838 } 839 840 // Since we are doing a publish, don't need the retry any more. 841 if(mPendingRetry) { 842 mPendingRetry = false; 843 mAlarmManager.cancel(mRetryAlarmIntent); 844 } 845 846 // always publish the latest status. 847 synchronized(mSyncObj) { 848 publishRequest.refreshPublishContent(); 849 } 850 851 logger.print("publishRequest=" + publishRequest); 852 if(!publishRequest.getForceToNetwork() && isPublishedOrPublishing() && 853 (publishRequest.hasSamePublishContent(mPublishingRequest) || 854 (mPublishingRequest == null) && 855 publishRequest.hasSamePublishContent(mPublishedRequest)) && 856 (getPublishState() != PUBLISH_STATE_NOT_PUBLISHED)) { 857 logger.print("Don't need publish since the capability didn't change publishRequest " 858 + publishRequest + " getPublishState()=" + getPublishState()); 859 return; 860 } 861 862 // Don't publish too frequently. Checking the throttle timer. 863 if(isPublishedOrPublishing()) { 864 if(mPendingRetry) { 865 logger.print("Pending a retry"); 866 return; 867 } 868 869 long publishThreshold = RcsSettingUtils.getPublishThrottle(mAssociatedSubscription); 870 long passed = publishThreshold; 871 if(mPublishingRequest != null) { 872 passed = System.currentTimeMillis() - mPublishingRequest.getTimestamp(); 873 } else if(mPublishedRequest != null) { 874 passed = System.currentTimeMillis() - mPublishedRequest.getTimestamp(); 875 } 876 passed = passed>=0?passed:publishThreshold; 877 878 long left = publishThreshold - passed; 879 left = left>120000?120000:left; // Don't throttle more then 2 mintues. 880 if(left > 0) { 881 // A publish is ongoing or published in 1 minute. 882 // Since the new publish has new status. So schedule 883 // the publish after the throttle timer. 884 scheduleRetryPublish(left); 885 return; 886 } 887 } 888 889 // we need send PUBLISH once even the volte is off when power on the phone. 890 // That will tell other phone that it has no volte/vt capability. 891 if(!RcsSettingUtils.isAdvancedCallingEnabledByUser(mAssociatedSubscription) && 892 getPublishState() != PUBLISH_STATE_NOT_PUBLISHED) { 893 // volte was not enabled. 894 // or it is turnning off volte. lower layer should unpublish 895 reset(); 896 return; 897 } 898 899 TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( 900 Context.TELEPHONY_SERVICE); 901 teleMgr = teleMgr.createForSubscriptionId(mAssociatedSubscription); 902 if (teleMgr == null) { 903 logger.error("TelephonyManager not available."); 904 return; 905 } 906 Uri myUri = getUriForPublication(); 907 if (myUri == null) { 908 logger.error("doPublish, myUri is null"); 909 return; 910 } 911 912 boolean isVolteCapble = publishRequest.getVolteCapable(); 913 boolean isVtCapable = publishRequest.getVtCapable(); 914 RcsContactUceCapability presenceInfo = 915 getRcsContactUceCapability(myUri, isVolteCapble, isVtCapable); 916 917 synchronized(mSyncObj) { 918 mPublishingRequest = publishRequest; 919 mPublishingRequest.setTimestamp(System.currentTimeMillis()); 920 } 921 922 String myNumber = getNumberFromUri(myUri); 923 int taskId = TaskManager.getDefault().addPublishTask(myNumber); 924 logger.print("doPublish, uri=" + myUri + ", myNumber=" + myNumber + ", taskId=" + taskId); 925 int ret = presencePublisher.requestPublication(presenceInfo, myUri.toString(), taskId); 926 if (ret != ResultCode.SUCCESS) { 927 logger.print("doPublish, task=" + taskId + " failed with code=" + ret); 928 TaskManager.getDefault().removeTask(taskId); 929 } 930 // cache the latest publication request if temporarily not available. 931 mHasCachedTrigger = (ret == ResultCode.ERROR_SERVICE_NOT_AVAILABLE); 932 } 933 getRcsContactUceCapability(Uri contact, boolean isVolteCapable, boolean isVtCapable)934 private RcsContactUceCapability getRcsContactUceCapability(Uri contact, boolean isVolteCapable, 935 boolean isVtCapable) { 936 937 ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder( 938 isVolteCapable, isVtCapable); 939 servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL); 940 941 RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder( 942 RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, 943 RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0"); 944 tupleBuilder.setContactUri(contact) 945 .setServiceCapabilities(servCapsBuilder.build()); 946 947 PresenceBuilder presenceBuilder = new PresenceBuilder(contact, 948 RcsContactUceCapability.SOURCE_TYPE_CACHED, 949 RcsContactUceCapability.REQUEST_RESULT_FOUND); 950 presenceBuilder.addCapabilityTuple(tupleBuilder.build()); 951 952 return presenceBuilder.build(); 953 } 954 getNumberFromUri(Uri uri)955 private String getNumberFromUri(Uri uri) { 956 if (uri == null) return null; 957 String number = uri.getSchemeSpecificPart(); 958 String[] numberParts = number.split("[@;:]"); 959 960 if (numberParts.length == 0) { 961 logger.error("getNumberFromUri: invalid uri=" + uri); 962 return null; 963 } 964 return numberParts[0]; 965 } 966 getUriForPublication()967 private Uri getUriForPublication() { 968 TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( 969 Context.TELEPHONY_SERVICE); 970 if (teleMgr == null) { 971 logger.error("getUriForPublication, teleMgr = null"); 972 return null; 973 } 974 teleMgr = teleMgr.createForSubscriptionId(mAssociatedSubscription); 975 976 Uri myNumUri = null; 977 String myDomain = teleMgr.getIsimDomain(); 978 logger.debug("myDomain=" + myDomain); 979 if (!TextUtils.isEmpty(myDomain)) { 980 String[] impu = teleMgr.getIsimImpu(); 981 if (impu != null) { 982 for (int i = 0; i < impu.length; i++) { 983 logger.debug("impu[" + i + "]=" + impu[i]); 984 if (!TextUtils.isEmpty(impu[i])) { 985 Uri impuUri = Uri.parse(impu[i]); 986 if (SIP_SCHEME.equals(impuUri.getScheme()) && 987 impuUri.getSchemeSpecificPart().endsWith(myDomain)) { 988 myNumUri = impuUri; 989 logger.debug("impu[" + i + "] -> uri:" + myNumUri); 990 } 991 break; 992 } 993 } 994 } 995 } 996 997 // Try to parse URI, if it works, we are good! 998 String myNumber = myNumUri == null ? null : myNumUri.getSchemeSpecificPart(); 999 if (!TextUtils.isEmpty(myNumber)) { 1000 return myNumUri; 1001 } 1002 1003 // Fall back to trying to use the line 1 number to construct URI 1004 myNumber = ContactNumberUtils.getDefault().format(teleMgr.getLine1Number()); 1005 if (myNumber == null) return null; 1006 if (!TextUtils.isEmpty(myDomain)) { 1007 return Uri.fromParts(SIP_SCHEME, myNumber + DOMAIN_SEPARATOR + myDomain, null); 1008 } else { 1009 return Uri.fromParts(TEL_SCHEME, myNumber, null); 1010 } 1011 } 1012 1013 private PendingIntent mRetryAlarmIntent = null; 1014 public static final String ACTION_RETRY_PUBLISH_ALARM = 1015 "com.android.service.ims.presence.retry.publish"; 1016 private AlarmManager mAlarmManager = null; 1017 boolean mCancelRetry = true; 1018 boolean mPendingRetry = false; 1019 scheduleRetryPublish(long timeSpan)1020 private void scheduleRetryPublish(long timeSpan) { 1021 logger.print("timeSpan=" + timeSpan + 1022 " mPendingRetry=" + mPendingRetry + 1023 " mCancelRetry=" + mCancelRetry); 1024 1025 // avoid duplicated retry. 1026 if(mPendingRetry) { 1027 logger.debug("There was a retry already"); 1028 return; 1029 } 1030 mPendingRetry = true; 1031 mCancelRetry = false; 1032 1033 Intent intent = new Intent(ACTION_RETRY_PUBLISH_ALARM); 1034 intent.setPackage(mContext.getPackageName()); 1035 mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 1036 PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE); 1037 1038 if(mAlarmManager == null) { 1039 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 1040 } 1041 1042 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1043 SystemClock.elapsedRealtime() + timeSpan, mRetryAlarmIntent); 1044 } 1045 retryPublish()1046 public void retryPublish() { 1047 logger.print("mCancelRetry=" + mCancelRetry); 1048 mPendingRetry = false; 1049 1050 // Need some time to cancel it (1 minute for longest) 1051 // Don't do it if it was canceled already. 1052 if(mCancelRetry) { 1053 return; 1054 } 1055 1056 requestLocalPublish(PublishType.PRES_PUBLISH_TRIGGER_RETRY); 1057 } 1058 onSipResponse(int requestId, int responseCode, String reasonPhrase)1059 public void onSipResponse(int requestId, int responseCode, String reasonPhrase) { 1060 logger.print( "Publish response code = " + responseCode 1061 +"Publish response reason phrase = " + reasonPhrase); 1062 1063 synchronized(mSyncObj) { 1064 mPublishedRequest = mPublishingRequest; 1065 mPublishingRequest = null; 1066 } 1067 1068 if (isInConfigList(responseCode, reasonPhrase, 1069 mConfigVolteProvisionErrorOnPublishResponse)) { 1070 logger.print("volte provision error. sipCode=" + responseCode + " phrase=" + 1071 reasonPhrase); 1072 setPublishState(PUBLISH_STATE_VOLTE_PROVISION_ERROR); 1073 mDonotRetryUntilPowerCycle = true; 1074 1075 notifyDm(); 1076 1077 return; 1078 } 1079 1080 if (isInConfigList(responseCode, reasonPhrase, mConfigRcsProvisionErrorOnPublishResponse)) { 1081 logger.print("rcs provision error.sipCode=" + responseCode + " phrase=" + reasonPhrase); 1082 setPublishState(PUBLISH_STATE_RCS_PROVISION_ERROR); 1083 mDonotRetryUntilPowerCycle = true; 1084 1085 return; 1086 } 1087 1088 switch (responseCode) { 1089 case 999: 1090 logger.debug("Publish ignored - No capability change"); 1091 break; 1092 case 200: 1093 setPublishState(PUBLISH_STATE_200_OK); 1094 if(mSubscriber != null) { 1095 mSubscriber.retryToGetAvailability(); 1096 } 1097 break; 1098 1099 case 408: 1100 setPublishState(PUBLISH_STATE_REQUEST_TIMEOUT); 1101 break; 1102 1103 default: // Generic Failure 1104 if ((responseCode < 100) || (responseCode > 699)) { 1105 logger.debug("Ignore internal response code, sipCode=" + responseCode); 1106 // internal error 1107 // 0- PERMANENT ERROR: UI should not retry immediately 1108 // 888- TEMP ERROR: UI Can retry immediately 1109 // 999- NO CHANGE: No Publish needs to be sent 1110 if(responseCode == 888) { 1111 // retry per 2 minutes 1112 scheduleRetryPublish(120000); 1113 } else { 1114 logger.debug("Ignore internal response code, sipCode=" + responseCode); 1115 } 1116 } else { 1117 logger.debug( "Generic Failure"); 1118 setPublishState(PUBLISH_STATE_OTHER_ERROR); 1119 1120 if ((responseCode>=400) && (responseCode <= 699)) { 1121 // 4xx/5xx/6xx, No retry, no impact on subsequent publish 1122 logger.debug( "No Retry in OEM"); 1123 } 1124 } 1125 break; 1126 } 1127 1128 // Suppose the request ID had been set when IQPresListener_CMDStatus 1129 Task task = TaskManager.getDefault().getTaskByRequestId(requestId); 1130 if(task != null){ 1131 task.mSipResponseCode = responseCode; 1132 task.mSipReasonPhrase = reasonPhrase; 1133 } 1134 1135 handleCallback(task, getPublishState(), false); 1136 } 1137 isTtyEnabled(int mode)1138 private static boolean isTtyEnabled(int mode) { 1139 return TelecomManager.TTY_MODE_OFF != mode; 1140 } 1141 onFeatureCapabilityChanged(int networkType, MmTelFeature.MmTelCapabilities capabilities)1142 public void onFeatureCapabilityChanged(int networkType, 1143 MmTelFeature.MmTelCapabilities capabilities) { 1144 logger.debug("onFeatureCapabilityChanged networkType=" + networkType 1145 +", capabilities=" + capabilities); 1146 1147 Thread thread = new Thread(() -> onFeatureCapabilityChangedInternal(networkType, 1148 capabilities), "onFeatureCapabilityChangedInternal thread"); 1149 1150 thread.start(); 1151 } 1152 onFeatureCapabilityChangedInternal(int networkType, MmTelFeature.MmTelCapabilities capabilities)1153 synchronized private void onFeatureCapabilityChangedInternal(int networkType, 1154 MmTelFeature.MmTelCapabilities capabilities) { 1155 boolean oldIsVolteAvailable = mIsVolteAvailable; 1156 boolean oldIsVtAvailable = mIsVtAvailable; 1157 boolean oldIsVoWifiAvailable = mIsVoWifiAvailable; 1158 boolean oldIsViWifiAvailable = mIsViWifiAvailable; 1159 1160 mIsVolteAvailable = (networkType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) && 1161 capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 1162 1163 mIsVoWifiAvailable = (networkType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) && 1164 capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 1165 1166 mIsVtAvailable = (networkType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) && 1167 capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO); 1168 1169 mIsViWifiAvailable = (networkType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) && 1170 capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO); 1171 1172 logger.print("mIsVolteAvailable=" + mIsVolteAvailable + 1173 " mIsVoWifiAvailable=" + mIsVoWifiAvailable + 1174 " mIsVtAvailable=" + mIsVtAvailable + 1175 " mIsViWifiAvailable=" + mIsViWifiAvailable + 1176 " oldIsVolteAvailable=" + oldIsVolteAvailable + 1177 " oldIsVoWifiAvailable=" + oldIsVoWifiAvailable + 1178 " oldIsVtAvailable=" + oldIsVtAvailable + 1179 " oldIsViWifiAvailable=" + oldIsViWifiAvailable); 1180 1181 if(oldIsVolteAvailable != mIsVolteAvailable || 1182 oldIsVtAvailable != mIsVtAvailable || 1183 oldIsVoWifiAvailable != mIsVoWifiAvailable || 1184 oldIsViWifiAvailable != mIsViWifiAvailable) { 1185 if(mGotTriggerFromStack) { 1186 if((Settings.Global.getInt(mContext.getContentResolver(), 1187 Settings.Global.AIRPLANE_MODE_ON, 0) != 0) && !mIsVoWifiAvailable && 1188 !mIsViWifiAvailable) { 1189 logger.print("Airplane mode was on and no vowifi and viwifi." + 1190 " Don't need publish. Stack will unpublish"); 1191 return; 1192 } 1193 1194 if(isOnIWLAN()) { 1195 // will check duplicated PUBLISH in requestPublication by invokePublish 1196 requestLocalPublish(PublishType. 1197 PRES_PUBLISH_TRIGGER_FEATURE_AVAILABILITY_CHANGED); 1198 } 1199 } else { 1200 mHasCachedTrigger = true; 1201 } 1202 } 1203 } 1204 isOnLTE()1205 private boolean isOnLTE() { 1206 TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( 1207 Context.TELEPHONY_SERVICE); 1208 int networkType = teleMgr.getDataNetworkType(); 1209 logger.debug("mMovedToLTE=" + mMovedToLTE + " networkType=" + networkType); 1210 1211 // Had reported LTE by trigger and still have DATA. 1212 return mMovedToLTE && (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN); 1213 } 1214 isOnIWLAN()1215 private boolean isOnIWLAN() { 1216 TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( 1217 Context.TELEPHONY_SERVICE); 1218 int networkType = teleMgr.getDataNetworkType(); 1219 logger.debug("mMovedToIWLAN=" + mMovedToIWLAN + " networkType=" + networkType); 1220 1221 // Had reported IWLAN by trigger and still have DATA. 1222 return mMovedToIWLAN && (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN); 1223 } 1224 } 1225