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; 30 31 import android.app.AlarmManager; 32 import android.app.PendingIntent; 33 import android.content.BroadcastReceiver; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.os.Handler; 39 import android.os.HandlerThread; 40 import android.os.Looper; 41 import android.os.Message; 42 import android.os.RemoteException; 43 import android.os.SystemClock; 44 import android.telephony.SubscriptionInfo; 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 51 import com.android.ims.ResultCode; 52 import com.android.ims.RcsPresence; 53 import com.android.ims.internal.Logger; 54 import com.android.ims.internal.uce.common.CapInfo; 55 import com.android.ims.internal.uce.common.StatusCode; 56 import com.android.ims.internal.uce.common.UceLong; 57 import com.android.ims.internal.uce.presence.IPresenceService; 58 import com.android.ims.internal.uce.presence.PresCapInfo; 59 import com.android.ims.internal.uce.uceservice.IUceService; 60 import com.android.ims.internal.uce.uceservice.ImsUceManager; 61 import com.android.service.ims.presence.PresenceBase; 62 import com.android.service.ims.presence.PresencePublisher; 63 import com.android.service.ims.presence.SubscribePublisher; 64 65 public class RcsStackAdaptor implements PresencePublisher, SubscribePublisher { 66 private static final boolean DEBUG = true; 67 68 private static final String PERSIST_SERVICE_NAME = 69 "com.android.service.ims.presence.PersistService"; 70 private static final String PERSIST_SERVICE_PACKAGE = "com.android.service.ims.presence"; 71 72 /** 73 * PendingIntent action used to retry getting the UCE service. Need an associated 74 * BroadcastReceiver. 75 */ 76 public static final String ACTION_RETRY_ALARM = "com.android.service.ims.presence.retry"; 77 78 // The logger 79 private Logger logger = Logger.getLogger(this.getClass().getName()); 80 81 private static final int PRESENCE_INIT_IMS_UCE_SERVICE = 1; 82 83 private Context mContext = null; 84 85 // true when the stack presence service got available. (Called IQPresListener_ServiceAvailable) 86 private volatile boolean mImsEnableState = false; 87 88 // provision status can be set by both subscribe and pubilish 89 // for unprovisioned for 403 or 404 90 private volatile int mPublishingState = PresenceBase.PUBLISH_STATE_NOT_PUBLISHED; 91 92 // It is initializing the stack presence service. 93 private volatile boolean mIsIniting = false; 94 95 // The time which the stack presence service got initialized. 96 private volatile long mLastInitSubService = -1; //last time which inited the sub service 97 98 // Used for synchronizing 99 private final Object mSyncObj = new Object(); 100 101 // We need wait RCS stack become unavailable before close RCS service. 102 static private boolean sInPowerDown = false; 103 104 // This could happen when the stack first launch or modem panic. 105 private static final int PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE =1; 106 107 // The initialization was triggered by retry. 108 private static final int PRESENCE_INIT_TYPE_RETRY = 2; 109 110 // The initialization was triggered by retry. 111 private static final int PRESENCE_INIT_TYPE_SUB_CHANGED = 3; 112 113 // The maximum retry count for initializing the stack service. 114 private static final int MAX_RETRY_COUNT = 6;//Maximum time is 64s 115 isImsEnableState()116 public boolean isImsEnableState() { 117 synchronized (mSyncObj) { 118 return mImsEnableState; 119 } 120 } 121 setImsEnableState(boolean imsEnableState)122 public void setImsEnableState(boolean imsEnableState) { 123 synchronized (mSyncObj) { 124 logger.debug("imsEnableState=" + imsEnableState); 125 mImsEnableState = imsEnableState; 126 } 127 } 128 129 // The UCE manager for RCS stack. 130 private ImsUceManager mImsUceManager = null; 131 132 // The stack RCS Service instance. 133 private IUceService mStackService = null; 134 135 // The stack presence service 136 private IPresenceService mStackPresService = null; 137 138 // The stack Presence Service handle. 139 private int mStackPresenceServiceHandle; 140 141 // The listener which listen to the response for presence service. 142 private StackListener mListenerHandler = null; 143 144 // The handler of the listener. 145 private UceLong mListenerHandle = new UceLong(); 146 147 // The singleton. 148 private static RcsStackAdaptor sInstance = null; 149 150 // the subscription on MSIM devices that is used for presence, since there is no MSIM support. 151 private int mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 152 153 // Only start connecting to the stack after we have received ACTION_UCE_SERVICE_UP. 154 private boolean mStackAvailable = false; 155 156 // Constructor RcsStackAdaptor(Context context)157 private RcsStackAdaptor(Context context) { 158 mContext = context; 159 160 init(); 161 } 162 getInstance(Context context)163 public static synchronized RcsStackAdaptor getInstance(Context context) { 164 if ((sInstance == null) && (context != null)) { 165 sInstance = new RcsStackAdaptor(context); 166 } 167 168 return sInstance; 169 } 170 171 private Handler mMsgHandler = new Handler(Looper.getMainLooper()) { 172 @Override 173 public void handleMessage(Message msg) { 174 super.handleMessage(msg); 175 176 logger.debug( "Thread=" + Thread.currentThread().getName() + " received " 177 + msg); 178 if(msg == null){ 179 logger.error("msg=null"); 180 return; 181 } 182 183 switch (msg.what) { 184 case PRESENCE_INIT_IMS_UCE_SERVICE: 185 logger.debug("handleMessage msg=PRESENCE_INIT_IMS_UCE_SERVICE" ); 186 registerBroadcastReceiver(); 187 doInitImsUceService(); 188 break; 189 190 default: 191 logger.debug("handleMessage unknown msg=" + msg.what); 192 } 193 } 194 }; 195 getListener()196 public StackListener getListener(){ 197 return mListenerHandler; 198 } 199 handleAssociatedSubscriptionChanged(int newSubId)200 public void handleAssociatedSubscriptionChanged(int newSubId) { 201 synchronized (mSyncObj) { 202 if (mAssociatedSubscription == newSubId) { 203 return; 204 } 205 mAssociatedSubscription = newSubId; 206 207 if (!SubscriptionManager.isValidSubscriptionId(mAssociatedSubscription)) { 208 destroyStackConnection(); 209 return; 210 } 211 212 SubscriptionManager subscriptionManager = mContext.getSystemService( 213 SubscriptionManager.class); 214 if (subscriptionManager == null) { 215 logger.error("handleAssociatedSubscriptionChanged: error getting sub manager"); 216 return; 217 } 218 if (mStackAvailable) { 219 startInitPresenceTimer(0, PRESENCE_INIT_TYPE_SUB_CHANGED); 220 } 221 } 222 } 223 224 @Override getStackStatusForCapabilityRequest()225 public int getStackStatusForCapabilityRequest() { 226 if (!RcsSettingUtils.getCapabilityDiscoveryEnabled(mAssociatedSubscription)) { 227 logger.error("getCapabilityDiscoveryEnabled = false"); 228 return ResultCode.ERROR_SERVICE_NOT_ENABLED; 229 } 230 231 int ret = checkStackStatus(); 232 if (ret != ResultCode.SUCCESS) { 233 logger.error("checkStackAndPublish ret=" + ret); 234 return ret; 235 } 236 237 if (!isPublished()) { 238 logger.error("checkStackAndPublish ERROR_SERVICE_NOT_PUBLISHED"); 239 return ResultCode.ERROR_SERVICE_NOT_PUBLISHED; 240 } 241 242 return ResultCode.SUCCESS; 243 } 244 isPublished()245 private boolean isPublished() { 246 if (getPublisherState() != PresenceBase.PUBLISH_STATE_200_OK) { 247 logger.error("Didnt' publish properly"); 248 return false; 249 } 250 251 return true; 252 } 253 254 @Override updatePublisherState(@resenceBase.PresencePublishState int publishState)255 public void updatePublisherState(@PresenceBase.PresencePublishState int publishState) { 256 synchronized (mSyncObj) { 257 logger.print("mPublishingState=" + mPublishingState + " publishState=" + publishState); 258 if (mPublishingState != publishState ) { 259 Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED); 260 publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState); 261 // Start PersistService and broadcast to other receivers that are listening 262 // dynamically. 263 mContext.sendStickyBroadcast(publishIntent); 264 launchPersistService(publishIntent); 265 } 266 mPublishingState = publishState; 267 } 268 } 269 270 @Override getPublisherState()271 public @PresenceBase.PresencePublishState int getPublisherState() { 272 synchronized (mSyncObj) { 273 return mPublishingState; 274 } 275 } 276 checkStackStatus()277 private int checkStackStatus() { 278 synchronized (mSyncObj) { 279 if (!RcsSettingUtils.isEabProvisioned(mContext, mAssociatedSubscription)) { 280 logger.error("Didn't get EAB provisioned by DM"); 281 return ResultCode.ERROR_SERVICE_NOT_ENABLED; 282 } 283 284 // Don't send request to RCS stack when it is under powering off. 285 // RCS stack is sending UNPUBLISH. It could get race PUBLISH trigger under the case. 286 if (sInPowerDown) { 287 logger.error("checkStackStatus: under powering off"); 288 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 289 } 290 291 if (mStackService == null) { 292 logger.error("checkStackStatus: mStackService == null"); 293 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 294 } 295 296 if (mStackPresService == null) { 297 logger.error("Didn't init sub rcs service."); 298 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 299 } 300 301 if (!mImsEnableState) { 302 logger.error("mImsEnableState = false"); 303 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 304 } 305 } 306 307 return ResultCode.SUCCESS; 308 } 309 310 @Override requestCapability(String[] formattedContacts, int taskId)311 public int requestCapability(String[] formattedContacts, int taskId) { 312 logger.print("requestCapability formattedContacts=" + formattedContacts); 313 314 int ret = ResultCode.SUCCESS; 315 try { 316 synchronized (mSyncObj) { 317 StatusCode retCode; 318 if (formattedContacts.length == 1) { 319 retCode = mStackPresService.getContactCap( 320 mStackPresenceServiceHandle, formattedContacts[0], taskId); 321 } else { 322 retCode = mStackPresService.getContactListCap( 323 mStackPresenceServiceHandle, formattedContacts, taskId); 324 } 325 326 logger.print("GetContactListCap retCode=" + retCode); 327 328 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode()); 329 } 330 331 logger.debug("requestCapability ret=" + ret); 332 }catch(Exception e){ 333 logger.error("requestCapability exception", e); 334 ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 335 } 336 337 return ret; 338 } 339 340 @Override requestAvailability(String formattedContact, int taskId)341 public int requestAvailability(String formattedContact, int taskId) { 342 logger.debug("requestAvailability ..."); 343 344 int ret = ResultCode.SUCCESS; 345 try{ 346 synchronized (mSyncObj) { 347 StatusCode retCode = mStackPresService.getContactCap( 348 mStackPresenceServiceHandle, formattedContact, taskId); 349 logger.print("getContactCap retCode=" + retCode); 350 351 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode()); 352 } 353 logger.debug("requestAvailability ret=" + ret); 354 }catch(Exception e){ 355 logger.error("requestAvailability exception", e); 356 ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 357 } 358 359 return ret; 360 } 361 362 @Override requestPublication(RcsContactUceCapability capabilities, String myUri, int taskId)363 public int requestPublication(RcsContactUceCapability capabilities, String myUri, int taskId) { 364 logger.debug("requestPublication ..."); 365 366 // Don't use checkStackAndPublish() 367 // since it will check publish status which in dead loop. 368 int ret = checkStackStatus(); 369 if(ret != ResultCode.SUCCESS){ 370 logger.error("requestPublication ret=" + ret); 371 return ret; 372 } 373 if (myUri == null) { 374 logger.error("Didn't find number or impu."); 375 return ResultCode.PUBLISH_GENERIC_FAILURE; 376 } 377 try { 378 PresCapInfo pMyCapInfo = new PresCapInfo(); 379 // Fill cap info 380 pMyCapInfo.setContactUri(myUri); 381 382 CapInfo capInfo = new CapInfo(); 383 capInfo.setIpVoiceSupported(isVolteSupported(capabilities)); 384 capInfo.setIpVideoSupported(isVtSupported(capabilities)); 385 capInfo.setCdViaPresenceSupported(true); 386 387 capInfo.setFtSupported(false); // TODO: support FT 388 capInfo.setImSupported(false);//TODO: support chat 389 capInfo.setFullSnFGroupChatSupported(false); //TODO: support chat 390 391 pMyCapInfo.setCapInfo(capInfo); 392 393 logger.print( "myNumUri = " + myUri 394 + " audioSupported = " + capInfo.isIpVoiceSupported() 395 + " videoSupported= " + capInfo.isIpVideoSupported() 396 ); 397 398 399 synchronized (mSyncObj) { 400 StatusCode status = mStackPresService.publishMyCap( 401 mStackPresenceServiceHandle, pMyCapInfo, taskId); 402 logger.print("PublishMyCap status=" + status.getStatusCode()); 403 ret = RcsUtils.statusCodeToResultCode(status.getStatusCode()); 404 } 405 406 logger.debug("requestPublication ret=" + ret); 407 if (ret != ResultCode.SUCCESS) { 408 logger.error("requestPublication remove taskId=" + taskId); 409 return ret; 410 } 411 } catch (RemoteException e) { 412 e.printStackTrace(); 413 logger.error("Exception when call mStackPresService.getContactCap"); 414 logger.error("requestPublication remove taskId=" + taskId); 415 416 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 417 } 418 419 return ResultCode.SUCCESS; 420 } 421 isVolteSupported(RcsContactUceCapability capabilities)422 private boolean isVolteSupported(RcsContactUceCapability capabilities) { 423 RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple( 424 RcsContactPresenceTuple.SERVICE_ID_MMTEL); 425 if (presenceTuple != null) { 426 ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities(); 427 if (serviceCaps != null && serviceCaps.isAudioCapable()) { 428 return true; 429 } 430 } 431 return false; 432 } 433 isVtSupported(RcsContactUceCapability capabilities)434 private boolean isVtSupported(RcsContactUceCapability capabilities) { 435 RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple( 436 RcsContactPresenceTuple.SERVICE_ID_MMTEL); 437 if (presenceTuple != null) { 438 ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities(); 439 if (serviceCaps != null && serviceCaps.isVideoCapable()) { 440 return true; 441 } 442 } 443 return false; 444 } 445 launchPersistService(Intent intent)446 private void launchPersistService(Intent intent) { 447 ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE, 448 PERSIST_SERVICE_NAME); 449 intent.setComponent(component); 450 mContext.startService(intent); 451 } 452 createListeningThread()453 private void createListeningThread() { 454 HandlerThread listenerThread = new HandlerThread("Listener", 455 android.os.Process.THREAD_PRIORITY_BACKGROUND); 456 457 listenerThread.start(); 458 Looper listenerLooper = listenerThread.getLooper(); 459 mListenerHandler = new StackListener(mContext, listenerLooper); 460 } 461 initImsUceService()462 private void initImsUceService(){ 463 // Send message to avoid ANR 464 Message reinitMessage = mMsgHandler.obtainMessage( 465 PRESENCE_INIT_IMS_UCE_SERVICE, null); 466 mMsgHandler.sendMessage(reinitMessage); 467 } 468 registerBroadcastReceiver()469 private void registerBroadcastReceiver() { 470 synchronized (mSyncObj) { 471 logger.debug("registerBroadcastReceiver"); 472 473 IntentFilter filter = new IntentFilter(); 474 filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_UP); 475 filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_DOWN); 476 477 mRcsServiceReceiver = new BroadcastReceiver() { 478 @Override 479 public void onReceive(Context context, Intent intent) { 480 // do something based on the intent's action 481 logger.print("onReceive intent " + intent); 482 String action = intent.getAction(); 483 if (ImsUceManager.ACTION_UCE_SERVICE_UP.equals(action)) { 484 mStackAvailable = true; 485 startInitPresenceTimer(0, PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE); 486 } else if (ImsUceManager.ACTION_UCE_SERVICE_DOWN.equals(action)) { 487 mStackAvailable = false; 488 clearImsUceService(); 489 } else { 490 logger.debug("unknown intent " + intent); 491 } 492 } 493 }; 494 495 mContext.registerReceiver(mRcsServiceReceiver, filter); 496 } 497 } 498 doInitImsUceService()499 private void doInitImsUceService(){ 500 synchronized (mSyncObj) { 501 if (mStackService != null) { 502 logger.debug("registerBroadcastReceiver mStackService != null"); 503 return; 504 } 505 506 if (mImsUceManager == null) { 507 mImsUceManager = ImsUceManager.getInstance(mContext); 508 if (mImsUceManager == null) { 509 logger.error("Can't init mImsUceManager"); 510 return; 511 } 512 } 513 514 mImsUceManager.createUceService(false); 515 mStackService = mImsUceManager.getUceServiceInstance(); 516 logger.debug("doInitImsUceService mStackService=" + mStackService); 517 518 // Do not connect to vendor UCE stack until ACTION_UCE_SERVICE_UP is called. 519 // The intent is sticky, so if we crash, we will get the UCE_SERVICE_UP intent again. 520 } 521 } 522 523 private PendingIntent mRetryAlarmIntent = null; 524 private AlarmManager mAlarmManager = null; 525 private BroadcastReceiver mRcsServiceReceiver = null; 526 527 /* 528 * Init All Sub service of RCS 529 */ initAllSubRcsServices(IUceService uceService, int currentRetry)530 int initAllSubRcsServices(IUceService uceService, int currentRetry) { 531 int ret = -1; 532 synchronized (mSyncObj) { 533 logger.print("Create UCE service connection for sub " + mAssociatedSubscription); 534 if (uceService == null) { 535 logger.error("initAllSubRcsServices : uceService is NULL"); 536 mIsIniting = false; 537 mLastInitSubService = -1; 538 return ret; 539 } 540 541 try { 542 destroyStackConnection(); 543 544 if (!SubscriptionManager.isValidSubscriptionId(mAssociatedSubscription)) { 545 logger.print("initAllService : invalid sub id, stopping creation..."); 546 mIsIniting = false; 547 mLastInitSubService = -1; 548 // Do not create a new presence service for invalid sub id. 549 return 0; 550 } 551 552 boolean serviceAvailable; 553 serviceAvailable = uceService.getServiceStatus(); 554 //init only once and ensure connection to UCE service is available. 555 if (serviceAvailable && mStackPresService == null && mStackService != null) { 556 logger.print("initAllSubRcsServices : create "); 557 int handle = createStackConnection(); 558 logger.print("initAllSubRcsServices: handle=" + mStackPresenceServiceHandle + 559 ", service=" + mStackPresService); 560 // If the service handle is -1, then creating the service failed somehow. 561 // schedule a retry. 562 if (handle < 0) { 563 logger.error("initAllService : service handle < 0, retrying..."); 564 mIsIniting = false; 565 mLastInitSubService = -1; 566 return ret; 567 } 568 ret = 0; 569 } else { 570 logger.error("initAllService : serviceStatus = false - serviceStatus: " 571 + serviceAvailable + ", mStackPresService: " + mStackPresService 572 + ", mStackService: " + mStackService); 573 } 574 } catch (RemoteException e) { 575 logger.error("initAllServices : DeadObjectException dialog "); 576 e.printStackTrace(); 577 } 578 mIsIniting = false; 579 } 580 return ret; 581 } 582 destroyStackConnection()583 private void destroyStackConnection() { 584 synchronized (mSyncObj) { 585 try { 586 if (mStackPresService != null) { 587 logger.print("RemoveListener and presence service"); 588 mStackPresService.removeListener(mStackPresenceServiceHandle, 589 mListenerHandle); 590 } 591 if (mStackService != null) { 592 mStackService.destroyPresenceService(mStackPresenceServiceHandle); 593 } 594 mStackPresService = null; 595 } catch (RemoteException e) { 596 logger.error("destroyStackConnection : exception " + e.getMessage()); 597 e.printStackTrace(); 598 } 599 } 600 } 601 createStackConnection()602 private int createStackConnection() throws RemoteException { 603 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 604 SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); 605 if (tm == null) return -1; 606 if (sm == null) return -1; 607 SubscriptionInfo info = sm.getActiveSubscriptionInfo(mAssociatedSubscription); 608 if (info == null) { 609 logger.error("handleAssociatedSubscriptionChanged: sub id does not have valid info"); 610 return -1; 611 } 612 String associatedIccId = info.getIccId(); 613 boolean isMsim = tm.getSupportedModemCount() > 1; 614 synchronized (mSyncObj) { 615 if (isMsim) { 616 mStackPresenceServiceHandle = mStackService.createPresenceServiceForSubscription( 617 mListenerHandler.mPresenceListener, mListenerHandle, associatedIccId); 618 } else { 619 // createPresenceServiceForSubscription doesnt seem to work on older single sim 620 // devices. Use deprecated API for these devices. 621 mStackPresenceServiceHandle = mStackService.createPresenceService( 622 mListenerHandler.mPresenceListener, mListenerHandle); 623 } 624 // If the service handle is -1, then creating the service failed somehow. 625 if (mStackPresenceServiceHandle < 0) { 626 return mStackPresenceServiceHandle; 627 } 628 if (isMsim) { 629 mStackPresService = mStackService.getPresenceServiceForSubscription( 630 associatedIccId); 631 } else { 632 // getPresenceServiceForSubscription doesnt seem to work on older single SIM 633 // devices. Use deprecated API for these devices. 634 mStackPresService = mStackService.getPresenceService(); 635 } 636 return mStackPresenceServiceHandle; 637 } 638 } 639 startInitThread(int times)640 public void startInitThread(int times){ 641 final int currentRetry = times; 642 Thread thread = new Thread(() -> { 643 synchronized (mSyncObj) { 644 if (currentRetry >= 0 && currentRetry <= MAX_RETRY_COUNT) { 645 refreshUceService(); 646 647 if (initAllSubRcsServices(mStackService, currentRetry) >= 0) { 648 logger.debug("init sub rcs service successfully."); 649 if (mRetryAlarmIntent != null) { 650 mAlarmManager.cancel(mRetryAlarmIntent); 651 } 652 } else { 653 startInitPresenceTimer(currentRetry + 1, PRESENCE_INIT_TYPE_RETRY); 654 } 655 } else { 656 logger.debug("Retry times=" + currentRetry); 657 if (mRetryAlarmIntent != null) { 658 mAlarmManager.cancel(mRetryAlarmIntent); 659 } 660 } 661 } 662 }, "initAllSubRcsServices thread"); 663 664 thread.start(); 665 } 666 init()667 private void init() { 668 createListeningThread(); 669 logger.debug("after createListeningThread"); 670 671 if(mAlarmManager == null){ 672 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 673 } 674 675 initImsUceService(); 676 677 setInPowerDown(false); 678 logger.debug("init finished"); 679 } 680 startInitPresenceTimer(int times, int initType)681 private void startInitPresenceTimer(int times, int initType){ 682 synchronized (mSyncObj) { 683 logger.print("set the retry alarm, times=" + times + " initType=" + initType + 684 " mIsIniting=" + mIsIniting); 685 if(mIsIniting){ 686 //initing is on going in 5 seconds, discard this one. 687 if(mLastInitSubService != -1 && 688 System.currentTimeMillis() - mLastInitSubService < 5000){ 689 logger.print("already in initing. ignore it"); 690 return; 691 }//else suppose the init has problem. so continue 692 } 693 694 mIsIniting = true; 695 696 Intent intent = new Intent(ACTION_RETRY_ALARM); 697 intent.putExtra("times", times); 698 intent.setPackage(mContext.getPackageName()); 699 mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 700 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 701 702 // Wait for 1s to ignore duplicate init request as possible as we can. 703 long timeSkip = 1000; 704 if(times < 0 || times >= MAX_RETRY_COUNT){ 705 times = MAX_RETRY_COUNT; 706 } 707 708 //Could failed to cancel a timer in 1s. So use exponential retry to make sure it 709 //will be stopped for non-VoLte SIM. 710 timeSkip = (timeSkip << times); 711 logger.debug("timeSkip = " + timeSkip); 712 713 mLastInitSubService = System.currentTimeMillis(); 714 715 //the timer intent could have a longer delay. call directly at first time 716 if(times == 0) { 717 startInitThread(0); 718 } else { 719 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 720 SystemClock.elapsedRealtime() + timeSkip, mRetryAlarmIntent); 721 } 722 } 723 } 724 refreshUceService()725 private void refreshUceService() { 726 synchronized (mSyncObj) { 727 logger.debug("refreshUceService mImsUceManager=" + mImsUceManager + 728 " mStackService=" + mStackService); 729 730 if (mImsUceManager == null) { 731 mImsUceManager = ImsUceManager.getInstance(mContext); 732 if (mImsUceManager == null) { 733 logger.error("Can't init mImsUceManager"); 734 return; 735 } 736 } 737 738 if (mStackService == null) { 739 mImsUceManager.createUceService(false); 740 mStackService = mImsUceManager.getUceServiceInstance(); 741 } 742 743 logger.debug("refreshUceService mStackService=" + mStackService); 744 } 745 } 746 clearImsUceService()747 private void clearImsUceService() { 748 destroyStackConnection(); 749 mImsUceManager = null; 750 mStackService = null; 751 mStackPresService = null; 752 } 753 finish()754 public void finish() { 755 if(mRetryAlarmIntent != null){ 756 mAlarmManager.cancel(mRetryAlarmIntent); 757 mRetryAlarmIntent = null; 758 } 759 760 if (mRcsServiceReceiver != null) { 761 mContext.unregisterReceiver(mRcsServiceReceiver); 762 mRcsServiceReceiver = null; 763 } 764 765 clearImsUceService(); 766 } 767 finalize()768 protected void finalize() throws Throwable { 769 super.finalize(); 770 finish(); 771 } 772 isInPowerDown()773 static public boolean isInPowerDown() { 774 return sInPowerDown; 775 } 776 setInPowerDown(boolean inPowerDown)777 static void setInPowerDown(boolean inPowerDown) { 778 sInPowerDown = inPowerDown; 779 } 780 } 781 782