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