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.Service; 32 import android.content.BroadcastReceiver; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.database.ContentObserver; 38 import android.net.ConnectivityManager; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.RemoteException; 43 import android.os.ServiceManager; 44 import android.provider.Settings; 45 import android.provider.Telephony; 46 import android.telecom.TelecomManager; 47 import android.telephony.AccessNetworkConstants; 48 import android.telephony.SubscriptionManager; 49 import android.telephony.ims.ImsException; 50 import android.telephony.ims.ImsMmTelManager; 51 import android.telephony.ims.ImsReasonInfo; 52 import android.telephony.ims.ProvisioningManager; 53 import android.telephony.ims.RcsContactUceCapability; 54 import android.telephony.ims.RegistrationManager; 55 import android.telephony.ims.feature.MmTelFeature; 56 57 import com.android.ims.IRcsPresenceListener; 58 import com.android.ims.RcsPresenceInfo; 59 import com.android.ims.ResultCode; 60 import com.android.ims.RcsPresence; 61 import com.android.ims.internal.IRcsPresence; 62 import com.android.ims.internal.IRcsService; 63 import com.android.ims.internal.Logger; 64 import com.android.service.ims.R; 65 import com.android.service.ims.presence.ContactCapabilityResponse; 66 import com.android.service.ims.presence.PresenceBase; 67 import com.android.service.ims.presence.PresencePublication; 68 import com.android.service.ims.presence.PresenceSubscriber; 69 70 import java.util.ArrayList; 71 import java.util.List; 72 import java.util.stream.Collectors; 73 74 public class RcsService extends Service { 75 76 private static final int IMS_SERVICE_RETRY_TIMEOUT_MS = 5000; 77 78 private Logger logger = Logger.getLogger(this.getClass().getName()); 79 80 private RcsStackAdaptor mRcsStackAdaptor = null; 81 private PresencePublication mPublication = null; 82 private PresenceSubscriber mSubscriber = null; 83 84 private Handler mRetryHandler; 85 private Runnable mRegisterCallbacks = this::registerImsCallbacksAndSetAssociatedSubscription; 86 private int mNetworkRegistrationType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 87 88 private int mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 89 90 private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener 91 = new SubscriptionManager.OnSubscriptionsChangedListener() { 92 @Override 93 public void onSubscriptionsChanged() { 94 registerImsCallbacksAndSetAssociatedSubscription(); 95 } 96 }; 97 98 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 99 @Override 100 public void onReceive(Context context, Intent intent) { 101 switch (intent.getAction()) { 102 case TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED: { 103 int newPreferredTtyMode = intent.getIntExtra( 104 TelecomManager.EXTRA_TTY_PREFERRED_MODE, 105 TelecomManager.TTY_MODE_OFF); 106 if (mPublication != null) { 107 mPublication.onTtyPreferredModeChanged(newPreferredTtyMode); 108 } 109 break; 110 } 111 case Intent.ACTION_AIRPLANE_MODE_CHANGED: { 112 boolean airplaneMode = intent.getBooleanExtra("state", false); 113 if (mPublication != null) { 114 mPublication.onAirplaneModeChanged(airplaneMode); 115 } 116 break; 117 } 118 case SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED: { 119 mRetryHandler.removeCallbacks(mRegisterCallbacks); 120 mRetryHandler.post(mRegisterCallbacks); 121 } 122 } 123 } 124 }; 125 126 private class CapabilityResultListener implements ContactCapabilityResponse { 127 128 private final IRcsPresenceListener mListener; 129 CapabilityResultListener(IRcsPresenceListener listener)130 public CapabilityResultListener(IRcsPresenceListener listener) { 131 mListener = listener; 132 } 133 134 @Override onSuccess(int reqId)135 public void onSuccess(int reqId) { 136 try { 137 mListener.onSuccess(reqId); 138 } catch (RemoteException e) { 139 logger.warn("CapabilityResultListener: onSuccess exception = " + e.getMessage()); 140 } 141 } 142 143 @Override onError(int reqId, int resultCode)144 public void onError(int reqId, int resultCode) { 145 try { 146 mListener.onError(reqId, resultCode); 147 } catch (RemoteException e) { 148 logger.warn("CapabilityResultListener: onError exception = " + e.getMessage()); 149 } 150 } 151 152 @Override onFinish(int reqId)153 public void onFinish(int reqId) { 154 try { 155 mListener.onFinish(reqId); 156 } catch (RemoteException e) { 157 logger.warn("CapabilityResultListener: onFinish exception = " + e.getMessage()); 158 } 159 } 160 161 @Override onTimeout(int reqId)162 public void onTimeout(int reqId) { 163 try { 164 mListener.onTimeout(reqId); 165 } catch (RemoteException e) { 166 logger.warn("CapabilityResultListener: onTimeout exception = " + e.getMessage()); 167 } 168 } 169 170 @Override onCapabilitiesUpdated(int reqId, List<RcsContactUceCapability> contactCapabilities, boolean updateLastTimestamp)171 public void onCapabilitiesUpdated(int reqId, 172 List<RcsContactUceCapability> contactCapabilities, boolean updateLastTimestamp) { 173 ArrayList<RcsPresenceInfo> presenceInfoList = contactCapabilities.stream().map( 174 PresenceInfoParser::getRcsPresenceInfo).collect( 175 Collectors.toCollection(ArrayList::new)); 176 177 logger.debug("capabilities updated:"); 178 for (RcsPresenceInfo info : presenceInfoList) { 179 logger.debug("capabilities updated: info -" + info); 180 } 181 // For some reason it uses an intent to send this info back instead of just using the 182 // active binder... 183 Intent intent = new Intent(RcsPresence.ACTION_PRESENCE_CHANGED); 184 intent.putParcelableArrayListExtra(RcsPresence.EXTRA_PRESENCE_INFO_LIST, 185 presenceInfoList); 186 intent.putExtra("updateLastTimestamp", updateLastTimestamp); 187 launchPersistService(intent); 188 } 189 } 190 launchPersistService(Intent intent)191 private void launchPersistService(Intent intent) { 192 ComponentName component = new ComponentName("com.android.service.ims.presence", 193 "com.android.service.ims.presence.PersistService"); 194 intent.setComponent(component); 195 startService(intent); 196 } 197 198 @Override onCreate()199 public void onCreate() { 200 super.onCreate(); 201 202 logger.debug("RcsService onCreate"); 203 204 mRcsStackAdaptor = RcsStackAdaptor.getInstance(this); 205 206 mPublication = new PresencePublication(mRcsStackAdaptor, this, 207 getResources().getStringArray( 208 R.array.config_volte_provision_error_on_publish_response), 209 getResources().getStringArray( 210 R.array.config_rcs_provision_error_on_publish_response)); 211 mRcsStackAdaptor.getListener().setPresencePublication(mPublication); 212 213 mSubscriber = new PresenceSubscriber(mRcsStackAdaptor, this, 214 getResources().getStringArray( 215 R.array.config_volte_provision_error_on_subscribe_response), 216 getResources().getStringArray( 217 R.array.config_rcs_provision_error_on_subscribe_response)); 218 mRcsStackAdaptor.getListener().setPresenceSubscriber(mSubscriber); 219 mPublication.setSubscriber(mSubscriber); 220 221 final ConnectivityManager cm = getSystemService(ConnectivityManager.class); 222 if (cm != null) { 223 boolean enabled = Settings.Global.getInt(getContentResolver(), 224 Settings.Global.MOBILE_DATA, 1) == 1; 225 logger.debug("Mobile data enabled status: " + (enabled ? "ON" : "OFF")); 226 227 onMobileDataEnabled(enabled); 228 } 229 230 // TODO: support MSIM 231 ServiceManager.addService("rcs", mBinder); 232 233 mObserver = new MobileDataContentObserver(); 234 getContentResolver().registerContentObserver( 235 Settings.Global.getUriFor(Settings.Global.MOBILE_DATA), 236 false, mObserver); 237 238 mSiminfoSettingObserver = new SimInfoContentObserver(); 239 getContentResolver().registerContentObserver(Telephony.SimInfo.CONTENT_URI, false, 240 mSiminfoSettingObserver); 241 242 mRetryHandler = new Handler(Looper.getMainLooper()); 243 registerBroadcastReceiver(); 244 registerSubscriptionChangedListener(); 245 } 246 registerBroadcastReceiver()247 private void registerBroadcastReceiver() { 248 IntentFilter filter = new IntentFilter(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); 249 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 250 filter.addAction(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); 251 registerReceiver(mReceiver, filter); 252 } 253 unregisterBroadcastReceiver()254 private void unregisterBroadcastReceiver() { 255 unregisterReceiver(mReceiver); 256 } 257 registerSubscriptionChangedListener()258 private void registerSubscriptionChangedListener() { 259 SubscriptionManager subscriptionManager = getSystemService(SubscriptionManager.class); 260 if (subscriptionManager != null) { 261 // This will call back after the listener is added automatically. 262 subscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 263 } else { 264 logger.error("SubscriptionManager not available! Retrying..."); 265 // Retry this again after some time. 266 mRetryHandler.postDelayed(this::registerSubscriptionChangedListener, 267 IMS_SERVICE_RETRY_TIMEOUT_MS); 268 } 269 } 270 registerImsCallbacksAndSetAssociatedSubscription()271 private void registerImsCallbacksAndSetAssociatedSubscription() { 272 SubscriptionManager sm = getSystemService(SubscriptionManager.class); 273 if (sm == null) { 274 logger.warn("handleSubscriptionsChanged: SubscriptionManager is null!"); 275 return; 276 } 277 int defaultSub = RcsSettingUtils.getDefaultSubscriptionId(this); 278 // If the presence SIP PUBLISH procedure is not supported, treat it as if there is no valid 279 // associated sub 280 if (!RcsSettingUtils.isPublishEnabled(this, defaultSub)) { 281 defaultSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 282 } 283 284 try { 285 if (defaultSub == mAssociatedSubscription) { 286 // Don't register duplicate callbacks for the same subscription. 287 return; 288 } 289 if (mAssociatedSubscription != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 290 // Get rid of any existing registrations. 291 ImsMmTelManager oldImsManager = ImsMmTelManager.createForSubscriptionId( 292 mAssociatedSubscription); 293 ProvisioningManager oldProvisioningManager = 294 ProvisioningManager.createForSubscriptionId(mAssociatedSubscription); 295 oldImsManager.unregisterImsRegistrationCallback(mImsRegistrationCallback); 296 oldImsManager.unregisterMmTelCapabilityCallback(mCapabilityCallback); 297 oldProvisioningManager.unregisterProvisioningChangedCallback( 298 mProvisioningChangedCallback); 299 logger.print("callbacks unregistered for sub " + mAssociatedSubscription); 300 } 301 if (SubscriptionManager.isValidSubscriptionId(defaultSub)) { 302 ImsMmTelManager imsManager = ImsMmTelManager.createForSubscriptionId(defaultSub); 303 ProvisioningManager provisioningManager = 304 ProvisioningManager.createForSubscriptionId(defaultSub); 305 // move over registrations if the new sub id is valid. 306 imsManager.registerImsRegistrationCallback(getMainExecutor(), 307 mImsRegistrationCallback); 308 imsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback); 309 provisioningManager.registerProvisioningChangedCallback(getMainExecutor(), 310 mProvisioningChangedCallback); 311 mAssociatedSubscription = defaultSub; 312 logger.print("callbacks registered for sub " + mAssociatedSubscription); 313 } else { 314 mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 315 } 316 logger.print("registerImsCallbacksAndSetAssociatedSubscription: new default=" 317 + mAssociatedSubscription); 318 handleAssociatedSubscriptionChanged(mAssociatedSubscription); 319 } catch (ImsException e) { 320 logger.info("Couldn't register callbacks for " + defaultSub + ": " 321 + e.getMessage()); 322 if (e.getCode() == ImsException.CODE_ERROR_SERVICE_UNAVAILABLE) { 323 handleAssociatedSubscriptionChanged(SubscriptionManager.INVALID_SUBSCRIPTION_ID); 324 // IMS temporarily unavailable. Retry after a few seconds. 325 mRetryHandler.removeCallbacks(mRegisterCallbacks); 326 mRetryHandler.postDelayed(mRegisterCallbacks, IMS_SERVICE_RETRY_TIMEOUT_MS); 327 } 328 } 329 } 330 handleAssociatedSubscriptionChanged(int newSubId)331 private void handleAssociatedSubscriptionChanged(int newSubId) { 332 if (mSubscriber != null) { 333 mSubscriber.handleAssociatedSubscriptionChanged(newSubId); 334 } 335 if (mPublication != null) { 336 mPublication.handleAssociatedSubscriptionChanged(newSubId); 337 } 338 if (mRcsStackAdaptor != null) { 339 mRcsStackAdaptor.handleAssociatedSubscriptionChanged(newSubId); 340 } 341 } 342 343 @Override onStartCommand(Intent intent, int flags, int startId)344 public int onStartCommand(Intent intent, int flags, int startId) { 345 logger.debug("RcsService onStartCommand"); 346 347 return super.onStartCommand(intent, flags, startId); 348 } 349 350 /** 351 * Cleans up when the service is destroyed 352 */ 353 @Override onDestroy()354 public void onDestroy() { 355 unregisterBroadcastReceiver(); 356 getContentResolver().unregisterContentObserver(mObserver); 357 getContentResolver().unregisterContentObserver(mSiminfoSettingObserver); 358 getSystemService(SubscriptionManager.class) 359 .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 360 361 mRcsStackAdaptor.finish(); 362 mPublication = null; 363 mSubscriber = null; 364 365 logger.debug("RcsService onDestroy"); 366 super.onDestroy(); 367 } 368 getPublication()369 public PresencePublication getPublication() { 370 return mPublication; 371 } 372 373 IRcsPresence.Stub mIRcsPresenceImpl = new IRcsPresence.Stub() { 374 /** 375 * Asyncrhonously request the latest capability for a given contact list. 376 * The result will be saved to DB directly if the contactNumber can be found in DB. 377 * And then send intent com.android.ims.presence.CAPABILITY_STATE_CHANGED to notify it. 378 * @param contactsNumber the contact list which will request capability. 379 * Currently only support phone number. 380 * @param listener the listener to get the response. 381 * @return the resultCode which is defined by ResultCode. 382 * @note framework uses only. 383 * @hide 384 */ 385 public int requestCapability(List<String> contactsNumber, 386 IRcsPresenceListener listener){ 387 logger.debug("calling requestCapability"); 388 if(mSubscriber == null){ 389 logger.debug("requestCapability, mPresenceSubscriber == null"); 390 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 391 } 392 393 return mSubscriber.requestCapability(contactsNumber, 394 new CapabilityResultListener(listener)); 395 } 396 397 /** 398 * Asyncrhonously request the latest presence for a given contact. 399 * The result will be saved to DB directly if it can be found in DB. And then send intent 400 * com.android.ims.presence.AVAILABILITY_STATE_CHANGED to notify it. 401 * @param contactNumber the contact which will request available. 402 * Currently only support phone number. 403 * @param listener the listener to get the response. 404 * @return the resultCode which is defined by ResultCode. 405 * @note framework uses only. 406 * @hide 407 */ 408 public int requestAvailability(String contactNumber, IRcsPresenceListener listener){ 409 if(mSubscriber == null){ 410 logger.error("requestAvailability, mPresenceSubscriber is null"); 411 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 412 } 413 414 // check availability cache (in RAM). 415 return mSubscriber.requestAvailability(contactNumber, 416 new CapabilityResultListener(listener), false); 417 } 418 419 /** 420 * Same as requestAvailability. but requestAvailability will consider throttle to avoid too 421 * fast call. Which means it will not send the request to network in next 60s for the same 422 * request. 423 * The error code SUBSCRIBE_TOO_FREQUENTLY will be returned under the case. 424 * But for this funcation it will always send the request to network. 425 * 426 * @see IRcsPresenceListener 427 * @see RcsManager.ResultCode 428 * @see ResultCode.SUBSCRIBE_TOO_FREQUENTLY 429 */ 430 public int requestAvailabilityNoThrottle(String contactNumber, 431 IRcsPresenceListener listener) { 432 if(mSubscriber == null){ 433 logger.error("requestAvailabilityNoThrottle, mPresenceSubscriber is null"); 434 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE; 435 } 436 437 // check availability cache (in RAM). 438 return mSubscriber.requestAvailability(contactNumber, 439 new CapabilityResultListener(listener), true); 440 } 441 442 public int getPublishState() throws RemoteException { 443 return publisherPublishStateToPublishState(mPublication.getPublishState()); 444 } 445 }; 446 447 @Override onBind(Intent arg0)448 public IBinder onBind(Intent arg0) { 449 return mBinder; 450 } 451 452 /** 453 * Receives notifications when Mobile data is enabled or disabled. 454 */ 455 private class MobileDataContentObserver extends ContentObserver { MobileDataContentObserver()456 public MobileDataContentObserver() { 457 super(new Handler()); 458 } 459 460 @Override onChange(final boolean selfChange)461 public void onChange(final boolean selfChange) { 462 boolean enabled = Settings.Global.getInt(getContentResolver(), 463 Settings.Global.MOBILE_DATA, 1) == 1; 464 logger.debug("Mobile data enabled status: " + (enabled ? "ON" : "OFF")); 465 onMobileDataEnabled(enabled); 466 } 467 } 468 469 /** Observer to get notified when Mobile data enabled status changes */ 470 private MobileDataContentObserver mObserver; 471 onMobileDataEnabled(final boolean enabled)472 private void onMobileDataEnabled(final boolean enabled) { 473 logger.debug("Enter onMobileDataEnabled: " + enabled); 474 Thread thread = new Thread(new Runnable() { 475 @Override 476 public void run() { 477 try{ 478 if(mPublication != null){ 479 mPublication.onMobileDataChanged(enabled); 480 return; 481 } 482 }catch(Exception e){ 483 logger.error("Exception onMobileDataEnabled:", e); 484 } 485 } 486 }, "onMobileDataEnabled thread"); 487 488 thread.start(); 489 } 490 491 492 private SimInfoContentObserver mSiminfoSettingObserver; 493 494 /** 495 * Receives notifications when the TelephonyProvider is changed. 496 */ 497 private class SimInfoContentObserver extends ContentObserver { SimInfoContentObserver()498 public SimInfoContentObserver() { 499 super(new Handler()); 500 } 501 502 @Override onChange(final boolean selfChange)503 public void onChange(final boolean selfChange) { 504 if (mAssociatedSubscription == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 505 return; 506 } 507 ImsMmTelManager ims = ImsMmTelManager.createForSubscriptionId(mAssociatedSubscription); 508 try { 509 boolean enabled = ims.isVtSettingEnabled(); 510 logger.debug("vt enabled status: " + (enabled ? "ON" : "OFF")); 511 onVtEnabled(enabled); 512 } catch (Exception e) { 513 logger.info("Exception getting VT status for sub:" + mAssociatedSubscription 514 + ", Exception = " + e.getMessage()); 515 } 516 } 517 } 518 onVtEnabled(boolean enabled)519 private void onVtEnabled(boolean enabled) { 520 if(mPublication != null){ 521 mPublication.onVtEnabled(enabled); 522 } 523 } 524 525 private final IRcsService.Stub mBinder = new IRcsService.Stub() { 526 /** 527 * return true if the rcs service is ready for use. 528 */ 529 public boolean isRcsServiceAvailable(){ 530 logger.debug("calling isRcsServiceAvailable"); 531 if(mRcsStackAdaptor == null){ 532 return false; 533 } 534 535 return mRcsStackAdaptor.isImsEnableState(); 536 } 537 538 /** 539 * Gets the presence interface. 540 * 541 * @see IRcsPresence 542 */ 543 public IRcsPresence getRcsPresenceInterface(){ 544 return mIRcsPresenceImpl; 545 } 546 }; 547 548 private RegistrationManager.RegistrationCallback mImsRegistrationCallback = 549 new RegistrationManager.RegistrationCallback() { 550 551 @Override 552 public void onRegistered(int imsTransportType) { 553 logger.debug("onImsConnected imsTransportType=" + imsTransportType); 554 mNetworkRegistrationType = imsTransportType; 555 if(mPublication != null) { 556 mPublication.onImsConnected(); 557 } 558 } 559 560 @Override 561 public void onUnregistered(ImsReasonInfo info) { 562 logger.debug("onImsDisconnected"); 563 mNetworkRegistrationType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 564 if(mPublication != null) { 565 mPublication.onImsDisconnected(); 566 } 567 } 568 }; 569 570 private ImsMmTelManager.CapabilityCallback mCapabilityCallback = 571 new ImsMmTelManager.CapabilityCallback() { 572 573 @Override 574 public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) { 575 mPublication.onFeatureCapabilityChanged(mNetworkRegistrationType, capabilities); 576 } 577 }; 578 579 private ProvisioningManager.Callback mProvisioningChangedCallback = 580 new ProvisioningManager.Callback() { 581 582 @Override 583 public void onProvisioningIntChanged(int item, int value) { 584 switch (item) { 585 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS: 586 // intentional fallthrough 587 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS: 588 // intentional fallthrough 589 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS: 590 if (mPublication != null) { 591 mPublication.handleProvisioningChanged(); 592 } 593 } 594 } 595 }; 596 publisherPublishStateToPublishState(int publisherPublishState)597 private static int publisherPublishStateToPublishState(int publisherPublishState) { 598 switch(publisherPublishState) { 599 case PresenceBase.PUBLISH_STATE_200_OK: 600 return RcsPresence.PublishState.PUBLISH_STATE_200_OK; 601 case PresenceBase.PUBLISH_STATE_NOT_PUBLISHED: 602 return RcsPresence.PublishState.PUBLISH_STATE_NOT_PUBLISHED; 603 case PresenceBase.PUBLISH_STATE_VOLTE_PROVISION_ERROR: 604 return RcsPresence.PublishState.PUBLISH_STATE_VOLTE_PROVISION_ERROR; 605 case PresenceBase.PUBLISH_STATE_RCS_PROVISION_ERROR: 606 return RcsPresence.PublishState.PUBLISH_STATE_RCS_PROVISION_ERROR; 607 case PresenceBase.PUBLISH_STATE_REQUEST_TIMEOUT: 608 return RcsPresence.PublishState.PUBLISH_STATE_REQUEST_TIMEOUT; 609 case PresenceBase.PUBLISH_STATE_OTHER_ERROR: 610 return RcsPresence.PublishState.PUBLISH_STATE_OTHER_ERROR; 611 612 } 613 return PresenceBase.PUBLISH_STATE_OTHER_ERROR; 614 } 615 } 616 617