| /* |
| * Copyright (c) 2015, Motorola Mobility LLC |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * - Neither the name of Motorola Mobility nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| */ |
| |
| package com.android.service.ims; |
| |
| import java.util.List; |
| import java.util.concurrent.Semaphore; |
| import java.util.concurrent.TimeUnit; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.content.pm.ServiceInfo; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.app.PendingIntent; |
| import android.content.IntentFilter; |
| import android.content.ServiceConnection; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.telephony.TelephonyManager; |
| import android.app.AlarmManager; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import com.android.ims.ImsConfig; |
| import com.android.ims.ImsManager; |
| import com.android.ims.ImsException; |
| import android.telephony.SubscriptionManager; |
| |
| import com.android.ims.IRcsPresenceListener; |
| import com.android.ims.RcsPresence; |
| import com.android.ims.RcsManager.ResultCode; |
| import com.android.ims.RcsPresence.PublishState; |
| |
| import com.android.ims.internal.Logger; |
| import com.android.ims.internal.ContactNumberUtils; |
| import com.android.service.ims.presence.PresencePublication; |
| |
| import com.android.ims.internal.uce.presence.IPresenceService; |
| import com.android.ims.internal.uce.presence.PresCapInfo; |
| import com.android.ims.internal.uce.common.CapInfo; |
| import com.android.ims.internal.uce.uceservice.IUceService; |
| import com.android.ims.internal.uce.uceservice.ImsUceManager; |
| import com.android.ims.internal.uce.common.UceLong; |
| import com.android.ims.internal.uce.common.StatusCode; |
| |
| import com.android.ims.IRcsPresenceListener; |
| import com.android.ims.RcsPresenceInfo; |
| |
| import com.android.service.ims.presence.StackListener; |
| import com.android.service.ims.presence.PresenceInfoParser; |
| import com.android.service.ims.presence.AlarmBroadcastReceiver; |
| |
| public class RcsStackAdaptor{ |
| private static final boolean DEBUG = true; |
| |
| private static final String PERSIST_SERVICE_NAME = |
| "com.android.service.ims.presence.PersistService"; |
| private static final String PERSIST_SERVICE_PACKAGE = "com.android.service.ims.presence"; |
| |
| // The logger |
| private Logger logger = Logger.getLogger(this.getClass().getName()); |
| |
| private static final int PRESENCE_INIT_IMS_UCE_SERVICE = 1; |
| |
| private Context mContext = null; |
| |
| // true when the stack presence service got available. (Called IQPresListener_ServiceAvailable) |
| private volatile boolean mImsEnableState = false; |
| |
| // provision status can be set by both subscribe and pubilish |
| // for unprovisioned for 403 or 404 |
| private volatile int mPublishingState = PublishState.PUBLISH_STATE_NOT_PUBLISHED; |
| |
| // It is initializing the stack presence service. |
| private volatile boolean mIsIniting = false; |
| |
| // The time which the stack presence service got initialized. |
| private volatile long mLastInitSubService = -1; //last time which inited the sub service |
| |
| // Used for synchronizing |
| private final Object mSyncObj = new Object(); |
| |
| // We need wait RCS stack become unavailable before close RCS service. |
| static private boolean sInPowerDown = false; |
| |
| // This could happen when the stack first launch or modem panic. |
| private static final int PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE =1; |
| |
| // The initialization was triggered by retry. |
| private static final int PRESENCE_INIT_TYPE_RETRY = 2; |
| |
| // The initialization was triggered by retry. |
| private static final int PRESENCE_INIT_TYPE_IMS_REGISTERED = 3; |
| |
| // The maximum retry count for initializing the stack service. |
| private static final int MAX_RETRY_COUNT = 6;//Maximum time is 64s |
| |
| public boolean isImsEnableState() { |
| synchronized (mSyncObj) { |
| return mImsEnableState; |
| } |
| } |
| |
| public void setImsEnableState(boolean imsEnableState) { |
| synchronized (mSyncObj) { |
| logger.debug("imsEnableState=" + imsEnableState); |
| mImsEnableState = imsEnableState; |
| } |
| } |
| |
| // The UCE manager for RCS stack. |
| private ImsUceManager mImsUceManager = null; |
| |
| // The stack RCS Service instance. |
| private IUceService mStackService = null; |
| |
| // The stack presence service |
| private IPresenceService mStackPresService = null; |
| |
| // The stack Presence Service handle. |
| private int mStackPresenceServiceHandle; |
| |
| // The listener which listen to the response for presence service. |
| private StackListener mListenerHandler = null; |
| |
| // The handler of the listener. |
| private UceLong mListenerHandle = new UceLong(); |
| |
| // The singleton. |
| private static RcsStackAdaptor sInstance = null; |
| |
| // Constructor |
| private RcsStackAdaptor(Context context) { |
| mContext = context; |
| |
| init(); |
| } |
| |
| public static synchronized RcsStackAdaptor getInstance(Context context) { |
| if ((sInstance == null) && (context != null)) { |
| sInstance = new RcsStackAdaptor(context); |
| } |
| |
| return sInstance; |
| } |
| |
| private Handler mMsgHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| super.handleMessage(msg); |
| |
| logger.debug( "Thread=" + Thread.currentThread().getName() + " received " |
| + msg); |
| if(msg == null){ |
| logger.error("msg=null"); |
| return; |
| } |
| |
| switch (msg.what) { |
| case PRESENCE_INIT_IMS_UCE_SERVICE: |
| logger.debug("handleMessage msg=PRESENCE_INIT_IMS_UCE_SERVICE" ); |
| doInitImsUceService(); |
| break; |
| |
| default: |
| logger.debug("handleMessage unknown msg=" + msg.what); |
| } |
| } |
| }; |
| |
| public StackListener getListener(){ |
| return mListenerHandler; |
| } |
| |
| public int checkStackAndPublish(){ |
| if (!RcsSettingUtils.getCapabilityDiscoveryEnabled(mContext)) { |
| logger.error("getCapabilityDiscoveryEnabled = false"); |
| return ResultCode.ERROR_SERVICE_NOT_ENABLED; |
| } |
| |
| int ret = checkStackStatus(); |
| if (ret != ResultCode.SUCCESS) { |
| logger.error("checkStackAndPublish ret=" + ret); |
| return ret; |
| } |
| |
| if (!isPublished()) { |
| logger.error( |
| "checkStackAndPublish ERROR_SERVICE_NOT_PUBLISHED"); |
| return ResultCode.ERROR_SERVICE_NOT_PUBLISHED; |
| } |
| |
| return ResultCode.SUCCESS; |
| } |
| |
| private boolean isPublished(){ |
| if(getPublishState() != PublishState.PUBLISH_STATE_200_OK){ |
| logger.error("Didnt' publish properly"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| public void setPublishState(int publishState) { |
| synchronized (mSyncObj) { |
| logger.print("mPublishingState=" + mPublishingState + " publishState=" + publishState); |
| if (mPublishingState != publishState) { |
| // save it for recovery when PresenceService crash. |
| SystemProperties.set("rcs.publish.status", |
| String.valueOf(publishState)); |
| |
| Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED); |
| publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState); |
| // Start PersistService and broadcast to other receivers that are listening |
| // dynamically. |
| mContext.sendStickyBroadcast(publishIntent); |
| launchPersistService(publishIntent); |
| } |
| |
| mPublishingState = publishState; |
| } |
| } |
| |
| public int getPublishState(){ |
| synchronized (mSyncObj) { |
| return mPublishingState; |
| } |
| } |
| |
| public int checkStackStatus(){ |
| synchronized (mSyncObj) { |
| if (!RcsSettingUtils.isEabProvisioned(mContext)) { |
| logger.error("Didn't get EAB provisioned by DM"); |
| return ResultCode.ERROR_SERVICE_NOT_ENABLED; |
| } |
| |
| // Don't send request to RCS stack when it is under powering off. |
| // RCS stack is sending UNPUBLISH. It could get race PUBLISH trigger under the case. |
| if (sInPowerDown) { |
| logger.error("checkStackStatus: under powering off"); |
| return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| if (mStackService == null) { |
| logger.error("checkStackStatus: mStackService == null"); |
| return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| if (mStackPresService == null) { |
| logger.error("Didn't init sub rcs service."); |
| return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| if (!mImsEnableState) { |
| logger.error("mImsEnableState = false"); |
| return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| } |
| |
| return ResultCode.SUCCESS; |
| } |
| |
| public int requestCapability(String[] formatedContacts, int taskId){ |
| logger.print("requestCapability formatedContacts=" + formatedContacts); |
| |
| int ret = ResultCode.SUCCESS; |
| try { |
| synchronized (mSyncObj) { |
| StatusCode retCode; |
| if (formatedContacts.length == 1) { |
| retCode = mStackPresService.getContactCap( |
| mStackPresenceServiceHandle, formatedContacts[0], taskId); |
| } else { |
| retCode = mStackPresService.getContactListCap( |
| mStackPresenceServiceHandle, formatedContacts, taskId); |
| } |
| |
| logger.print("GetContactListCap retCode=" + retCode); |
| |
| ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode()); |
| } |
| |
| logger.debug("requestCapability ret=" + ret); |
| }catch(Exception e){ |
| logger.error("requestCapability exception", e); |
| ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| return ret; |
| } |
| |
| public int requestAvailability(String formatedContact, int taskId){ |
| logger.debug("requestAvailability ..."); |
| |
| int ret = ResultCode.SUCCESS; |
| try{ |
| synchronized (mSyncObj) { |
| StatusCode retCode = mStackPresService.getContactCap( |
| mStackPresenceServiceHandle, formatedContact, taskId); |
| logger.print("getContactCap retCode=" + retCode); |
| |
| ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode()); |
| } |
| logger.debug("requestAvailability ret=" + ret); |
| }catch(Exception e){ |
| logger.error("requestAvailability exception", e); |
| ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| return ret; |
| } |
| |
| public int requestPublication(RcsPresenceInfo presenceInfo, IRcsPresenceListener listener) { |
| logger.debug("requestPublication ..."); |
| |
| // Don't use checkStackAndPublish() |
| // since it will check publish status which in dead loop. |
| int ret = checkStackStatus(); |
| if(ret != ResultCode.SUCCESS){ |
| logger.error("requestPublication ret=" + ret); |
| return ret; |
| } |
| |
| TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService( |
| Context.TELEPHONY_SERVICE); |
| if(teleMgr == null){ |
| logger.error("teleMgr = null"); |
| return PresencePublication.PUBLISH_GENIRIC_FAILURE; |
| } |
| |
| String myNumUri = null; |
| String myDomain = teleMgr.getIsimDomain(); |
| logger.debug("myDomain=" + myDomain); |
| if(myDomain != null && myDomain.length() !=0){ |
| String[] impu = teleMgr.getIsimImpu(); |
| |
| if(impu !=null){ |
| for(int i=0; i<impu.length; i++){ |
| logger.debug("impu[" + i + "]=" + impu[i]); |
| if(impu[i] != null && impu[i].startsWith("sip:") && |
| impu[i].endsWith(myDomain)){ |
| myNumUri = impu[i]; |
| break; |
| } |
| } |
| } |
| } |
| |
| String myNumber = PresenceInfoParser.getPhoneFromUri(myNumUri); |
| |
| if(myNumber == null){ |
| myNumber = ContactNumberUtils.getDefault().format(teleMgr.getLine1Number()); |
| if(myDomain != null && myDomain.length() !=0){ |
| myNumUri = "sip:" + myNumber + "@" + myDomain; |
| }else{ |
| myNumUri = "tel:" + myNumber; |
| } |
| } |
| |
| logger.print("myNumUri=" + myNumUri + " myNumber=" + myNumber); |
| if(myNumUri == null || myNumber == null){ |
| logger.error("Didn't find number or impu."); |
| return PresencePublication.PUBLISH_GENIRIC_FAILURE; |
| } |
| |
| int taskId = TaskManager.getDefault().addPublishTask(myNumber, listener); |
| try{ |
| PresCapInfo pMyCapInfo = new PresCapInfo(); |
| // Fill cap info |
| pMyCapInfo.setContactUri(myNumUri); |
| |
| CapInfo capInfo = new CapInfo(); |
| capInfo.setIpVoiceSupported(presenceInfo.getServiceState( |
| RcsPresenceInfo.ServiceType.VOLTE_CALL) |
| == RcsPresenceInfo.ServiceState.ONLINE); |
| capInfo.setIpVideoSupported(presenceInfo.getServiceState( |
| RcsPresenceInfo.ServiceType.VT_CALL) |
| == RcsPresenceInfo.ServiceState.ONLINE); |
| capInfo.setCdViaPresenceSupported(true); |
| |
| capInfo.setFtSupported(false); // TODO: support FT |
| capInfo.setImSupported(false);//TODO: support chat |
| capInfo.setFullSnFGroupChatSupported(false); //TODO: support chat |
| |
| pMyCapInfo.setCapInfo(capInfo); |
| |
| logger.print( "myNumUri = " + myNumUri |
| + " audioSupported = " + capInfo.isIpVoiceSupported() |
| + " videoSupported= " + capInfo.isIpVideoSupported() |
| ); |
| |
| |
| synchronized (mSyncObj) { |
| StatusCode status = mStackPresService.publishMyCap( |
| mStackPresenceServiceHandle, pMyCapInfo, taskId); |
| logger.print("PublishMyCap status=" + status.getStatusCode()); |
| ret = RcsUtils.statusCodeToResultCode(status.getStatusCode()); |
| } |
| |
| logger.debug("requestPublication ret=" + ret); |
| if(ret != ResultCode.SUCCESS){ |
| logger.error("requestPublication remove taskId=" + taskId); |
| TaskManager.getDefault().removeTask(taskId); |
| return ret; |
| } |
| }catch(RemoteException e){ |
| e.printStackTrace(); |
| logger.error("Exception when call mStackPresService.getContactCap"); |
| logger.error("requestPublication remove taskId=" + taskId); |
| TaskManager.getDefault().removeTask(taskId); |
| |
| return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; |
| } |
| |
| return ResultCode.SUCCESS; |
| } |
| |
| private void launchPersistService(Intent intent) { |
| ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE, |
| PERSIST_SERVICE_NAME); |
| intent.setComponent(component); |
| mContext.startService(intent); |
| } |
| |
| private void createListeningThread() { |
| HandlerThread listenerThread = new HandlerThread("Listener", |
| android.os.Process.THREAD_PRIORITY_BACKGROUND); |
| |
| listenerThread.start(); |
| Looper listenerLooper = listenerThread.getLooper(); |
| mListenerHandler = new StackListener(mContext, listenerLooper); |
| } |
| |
| private void initImsUceService(){ |
| // Send message to avoid ANR |
| Message reinitMessage = mMsgHandler.obtainMessage( |
| PRESENCE_INIT_IMS_UCE_SERVICE, null); |
| mMsgHandler.sendMessage(reinitMessage); |
| } |
| |
| private void doInitImsUceService(){ |
| synchronized (mSyncObj) { |
| logger.debug("doInitImsUceService"); |
| |
| if (mStackService != null) { |
| logger.debug("doInitImsUceService mStackService != null"); |
| return; |
| } |
| |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_UP); |
| filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_DOWN); |
| |
| mRcsServiceReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| // do something based on the intent's action |
| logger.print("onReceive intent " + intent); |
| String action = intent.getAction(); |
| if (ImsUceManager.ACTION_UCE_SERVICE_UP.equals(action)) { |
| startInitPresenceTimer(0, PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE); |
| } else if (ImsUceManager.ACTION_UCE_SERVICE_DOWN.equals(action)) { |
| clearImsUceService(); |
| } else { |
| logger.debug("unknown intent " + intent); |
| } |
| } |
| }; |
| |
| mContext.registerReceiver(mRcsServiceReceiver, filter); |
| |
| if (mImsUceManager == null) { |
| mImsUceManager = ImsUceManager.getInstance(mContext, |
| SubscriptionManager.from(mContext).getDefaultDataPhoneId()); |
| if (mImsUceManager == null) { |
| logger.error("Can't init mImsUceManager"); |
| return; |
| } |
| } |
| |
| mImsUceManager.createUceService(false); |
| mStackService = mImsUceManager.getUceServiceInstance(); |
| logger.debug("doInitImsUceService mStackService=" + mStackService); |
| |
| // Do not connect to vendor UCE stack until ACTION_UCE_SERVICE_UP is called. |
| // The intent is sticky, so if we crash, we will get the UCE_SERVICE_UP intent again. |
| } |
| } |
| |
| private PendingIntent mRetryAlarmIntent = null; |
| private AlarmManager mAlarmManager = null; |
| private BroadcastReceiver mRcsServiceReceiver = null; |
| |
| /* |
| * Init All Sub service of RCS |
| */ |
| int initAllSubRcsServices(IUceService uceService, int currentRetry) { |
| int ret = -1; |
| synchronized (mSyncObj) { |
| // we could receive useless retry since we could fail to cancel the retry timer. |
| // We need to ignore such retry if the sub service had been initialized already. |
| if(mStackPresService != null && currentRetry>0){ |
| logger.debug("mStackPresService != null and currentRetry=" + currentRetry + |
| " ignore it"); |
| return 0; |
| } |
| |
| logger.debug("Init All Services Under RCS uceService=" + uceService); |
| if(uceService == null){ |
| logger.error("initAllServices : uceService is NULL "); |
| mIsIniting = false; |
| mLastInitSubService = -1; |
| return ret; |
| } |
| |
| try { |
| if(mStackPresService != null){ |
| logger.print("RemoveListener and QRCSDestroyPresService"); |
| mStackPresService.removeListener(mStackPresenceServiceHandle, |
| mListenerHandle); |
| uceService.destroyPresenceService(mStackPresenceServiceHandle); |
| |
| mStackPresService = null; |
| } |
| |
| boolean serviceStatus = false; |
| serviceStatus = uceService.getServiceStatus(); |
| //init only once and ensure connection to UCE service is available. |
| if (true == serviceStatus && mStackPresService == null && mStackService != null) { |
| logger.print("initAllService : serviceStatus = true "); |
| logger.debug("Create PresService"); |
| mStackPresenceServiceHandle = mStackService.createPresenceService( |
| mListenerHandler.mPresenceListener, mListenerHandle); |
| // If the service handle is -1, then creating the service failed somehow. |
| // schedule a retry. |
| if (mStackPresenceServiceHandle < 0) { |
| logger.error("initAllService : service handle < 0, retrying..."); |
| mIsIniting = false; |
| mLastInitSubService = -1; |
| return ret; |
| } |
| mStackPresService = mStackService.getPresenceService(); |
| ret = 0; |
| } else { |
| logger.error("initAllService : serviceStatus = false - serviceStatus: " |
| + serviceStatus + ", mStackPresService: " + mStackPresService |
| + ", mStackService: " + mStackService); |
| } |
| } catch (RemoteException e) { |
| logger.error("initAllServices : DeadObjectException dialog "); |
| e.printStackTrace(); |
| } |
| mIsIniting = false; |
| } |
| return ret; |
| } |
| |
| public void startInitThread(int times){ |
| final int currentRetry = times; |
| Thread thread = new Thread(() -> { |
| synchronized (mSyncObj) { |
| if (currentRetry >= 0 && currentRetry <= MAX_RETRY_COUNT) { |
| refreshUceService(); |
| |
| if (initAllSubRcsServices(mStackService, currentRetry) >= 0) { |
| logger.debug("init sub rcs service successfully."); |
| if (mRetryAlarmIntent != null) { |
| mAlarmManager.cancel(mRetryAlarmIntent); |
| } |
| } else { |
| startInitPresenceTimer(currentRetry + 1, PRESENCE_INIT_TYPE_RETRY); |
| } |
| } else { |
| logger.debug("Retry times=" + currentRetry); |
| if (mRetryAlarmIntent != null) { |
| mAlarmManager.cancel(mRetryAlarmIntent); |
| } |
| } |
| } |
| }, "initAllSubRcsServices thread"); |
| |
| thread.start(); |
| } |
| |
| private void init() { |
| createListeningThread(); |
| logger.debug("after createListeningThread"); |
| |
| if(mAlarmManager == null){ |
| mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); |
| } |
| |
| initImsUceService(); |
| |
| setInPowerDown(false); |
| logger.debug("init finished"); |
| } |
| |
| private void startInitPresenceTimer(int times, int initType){ |
| synchronized (mSyncObj) { |
| logger.print("set the retry alarm, times=" + times + " initType=" + initType + |
| " mIsIniting=" + mIsIniting); |
| if(mIsIniting){ |
| //initing is on going in 5 seconds, discard this one. |
| if(mLastInitSubService != -1 && |
| System.currentTimeMillis() - mLastInitSubService < 5000){ |
| logger.print("already in initing. ignore it"); |
| return; |
| }//else suppose the init has problem. so continue |
| } |
| |
| mIsIniting = true; |
| |
| Intent intent = new Intent(AlarmBroadcastReceiver.ACTION_RETRY_ALARM); |
| intent.putExtra("times", times); |
| intent.setClass(mContext, AlarmBroadcastReceiver.class); |
| mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, |
| PendingIntent.FLAG_UPDATE_CURRENT); |
| |
| // Wait for 1s to ignore duplicate init request as possible as we can. |
| long timeSkip = 1000; |
| if(times < 0 || times >= MAX_RETRY_COUNT){ |
| times = MAX_RETRY_COUNT; |
| } |
| |
| //Could failed to cancel a timer in 1s. So use exponential retry to make sure it |
| //will be stopped for non-VoLte SIM. |
| timeSkip = (timeSkip << times); |
| logger.debug("timeSkip = " + timeSkip); |
| |
| mLastInitSubService = System.currentTimeMillis(); |
| |
| //the timer intent could have a longer delay. call directly at first time |
| if(times == 0) { |
| startInitThread(0); |
| } else { |
| mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, |
| SystemClock.elapsedRealtime() + timeSkip, mRetryAlarmIntent); |
| } |
| } |
| } |
| |
| private void refreshUceService() { |
| synchronized (mSyncObj) { |
| logger.debug("refreshUceService mImsUceManager=" + mImsUceManager + |
| " mStackService=" + mStackService); |
| |
| if (mImsUceManager == null) { |
| mImsUceManager = ImsUceManager.getInstance(mContext, |
| SubscriptionManager.from(mContext).getDefaultDataPhoneId()); |
| if (mImsUceManager == null) { |
| logger.error("Can't init mImsUceManager"); |
| return; |
| } |
| } |
| |
| if (mStackService == null) { |
| mImsUceManager.createUceService(false); |
| mStackService = mImsUceManager.getUceServiceInstance(); |
| } |
| |
| logger.debug("refreshUceService mStackService=" + mStackService); |
| } |
| } |
| |
| private void clearImsUceService() { |
| synchronized (mSyncObj) { |
| try { |
| logger.info("clearImsUceService: removing listener and presence service."); |
| if (mStackPresService != null) { |
| mStackPresService.removeListener(mStackPresenceServiceHandle, |
| mListenerHandle); |
| } |
| if (mStackService != null) { |
| mStackService.destroyPresenceService(mStackPresenceServiceHandle); |
| } |
| } catch (RemoteException e) { |
| logger.warn("clearImsUceService: Couldn't clean up stack service"); |
| } |
| mImsUceManager = null; |
| mStackService = null; |
| mStackPresService = null; |
| } |
| } |
| |
| public void finish() { |
| if(mRetryAlarmIntent != null){ |
| mAlarmManager.cancel(mRetryAlarmIntent); |
| mRetryAlarmIntent = null; |
| } |
| |
| if (mRcsServiceReceiver != null) { |
| mContext.unregisterReceiver(mRcsServiceReceiver); |
| mRcsServiceReceiver = null; |
| } |
| |
| clearImsUceService(); |
| } |
| |
| protected void finalize() throws Throwable { |
| super.finalize(); |
| finish(); |
| } |
| |
| static public boolean isInPowerDown() { |
| return sInPowerDown; |
| } |
| |
| static void setInPowerDown(boolean inPowerDown) { |
| sInPowerDown = inPowerDown; |
| } |
| } |
| |