1 /* 2 * Copyright (c) 2015, Motorola Mobility LLC 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * - Neither the name of Motorola Mobility nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 * DAMAGE. 27 */ 28 29 package com.android.service.ims.presence; 30 31 import android.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.database.Cursor; 39 import android.os.Handler; 40 import android.os.HandlerThread; 41 import android.os.Message; 42 import android.os.Process; 43 import android.os.SystemClock; 44 import android.telephony.PhoneNumberUtils; 45 import android.telephony.SubscriptionManager; 46 import android.telephony.TelephonyManager; 47 import android.telephony.ims.ImsException; 48 import android.telephony.ims.ImsManager; 49 import android.telephony.ims.ProvisioningManager; 50 import android.telephony.ims.RcsUceAdapter; 51 import android.text.format.TimeMigrationUtils; 52 import android.text.TextUtils; 53 54 import com.android.ims.RcsException; 55 import com.android.ims.RcsManager; 56 import com.android.ims.RcsPresence; 57 import com.android.ims.RcsPresence.PublishState; 58 import com.android.ims.internal.ContactNumberUtils; 59 import com.android.ims.internal.Logger; 60 61 import java.util.ArrayList; 62 import java.util.List; 63 64 public class CapabilityPolling { 65 private Logger logger = Logger.getLogger(this.getClass().getName()); 66 private final Context mContext; 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 public static final String ACTION_PERIODICAL_DISCOVERY_ALARM = 73 "com.android.service.ims.presence.periodical_capability_discovery"; 74 private PendingIntent mDiscoveryAlarmIntent = null; 75 76 public static final int ACTION_POLLING_NORMAL = 0; 77 public static final int ACTION_POLLING_NEW_CONTACTS = 1; 78 79 public static final int DELAY_REGISTER_CALLBACK_MS = 5000; 80 81 private long mCapabilityPollInterval = 604800000L; 82 private long mMinCapabilityPollInterval = 60480000L; 83 private long mCapabilityCacheExpiration = 7776000000L; 84 private long mNextPollingTimeStamp = 0L; 85 86 private boolean mInitialized = false; 87 private AlarmManager mAlarmManager = null; 88 private EABContactManager mEABContactManager = null; 89 private boolean mStackAvailable = false; 90 private int mPublished = -1; 91 private int mProvisioned = -1; 92 private int mDefaultSubId; 93 private boolean isInitializing = false; 94 95 private HandlerThread mDiscoveryThread; 96 private Handler mDiscoveryHandler; 97 98 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 99 @Override 100 public void onReceive(Context context, Intent intent) { 101 logger.info("onReceive(), intent: " + intent + 102 ", context: " + context); 103 104 String action = intent.getAction(); 105 if (RcsManager.ACTION_RCS_SERVICE_AVAILABLE.equals(action)) { 106 enqueueServiceStatusChanged(true); 107 } else if (RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE.equals(action)) { 108 enqueueServiceStatusChanged(false); 109 } else if (RcsManager.ACTION_RCS_SERVICE_DIED.equals(action)) { 110 logger.warn("No handler for this intent: " + action); 111 } else if (RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(action)) { 112 int state = intent.getIntExtra( 113 RcsPresence.EXTRA_PUBLISH_STATE, 114 RcsPresence.PublishState.PUBLISH_STATE_NOT_PUBLISHED); 115 enqueuePublishStateChanged(state); 116 } else { 117 logger.debug("No interest in this intent: " + action); 118 } 119 } 120 }; 121 122 private ProvisioningManager.Callback mProvisioningManagerCallback = 123 new ProvisioningManager.Callback() { 124 @Override 125 public void onProvisioningIntChanged(int item, int value) { 126 if ((ProvisioningManager.KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC == item) || 127 (ProvisioningManager.KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC == item)) { 128 enqueueSettingsChanged(); 129 } else if ((ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS == item) || 130 (ProvisioningManager.KEY_VT_PROVISIONING_STATUS == item) || 131 (ProvisioningManager.KEY_EAB_PROVISIONING_STATUS == item)) { 132 enqueueProvisionStateChanged(); 133 } 134 } 135 }; 136 137 private RcsUceAdapter.OnPublishStateChangedListener mPublishStateCallback = 138 new RcsUceAdapter.OnPublishStateChangedListener() { 139 @Override 140 public void onPublishStateChange(int publishState) { 141 logger.info("publish state changed: " + publishState); 142 Intent intent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED); 143 intent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState); 144 mContext.sendStickyBroadcast(intent); 145 launchPersistService(intent); 146 } 147 }; 148 launchPersistService(Intent intent)149 private void launchPersistService(Intent intent) { 150 ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE, 151 PERSIST_SERVICE_NAME); 152 intent.setComponent(component); 153 mContext.startService(intent); 154 } 155 156 private Runnable mRegisterCallbackRunnable = this::tryProvisioningManagerRegistration; 157 158 private static CapabilityPolling sInstance = null; getInstance(Context context)159 public static synchronized CapabilityPolling getInstance(Context context) { 160 if ((sInstance == null) && (context != null)) { 161 sInstance = new CapabilityPolling(context); 162 } 163 164 return sInstance; 165 } 166 CapabilityPolling(Context context)167 private CapabilityPolling(Context context) { 168 mContext = context; 169 170 ContactNumberUtils.getDefault().setContext(mContext); 171 PresencePreferences.getInstance().setContext(mContext); 172 173 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 174 mEABContactManager = new EABContactManager(mContext.getContentResolver(), 175 mContext.getPackageName()); 176 177 setRcsTestMode(PresencePreferences.getInstance().getRcsTestMode()); 178 logger.debug("CapabilityPolling is created."); 179 } 180 setRcsTestMode(boolean test)181 public void setRcsTestMode(boolean test) { 182 logger.setRcsTestMode(test); 183 184 PresencePreferences pref = PresencePreferences.getInstance(); 185 if (pref != null) { 186 if (pref.getRcsTestMode() != test) { 187 pref.setRcsTestMode(test); 188 } 189 } 190 } 191 initialise()192 private void initialise() { 193 if (mInitialized) { 194 return; 195 } 196 long capabilityPollInterval = PresenceSetting.getCapabilityPollInterval(mDefaultSubId); 197 logger.print("getCapabilityPollInterval: " + capabilityPollInterval); 198 if (capabilityPollInterval == -1) { 199 capabilityPollInterval = mContext.getResources().getInteger( 200 R.integer.capability_poll_interval); 201 } 202 if (capabilityPollInterval < 10) { 203 capabilityPollInterval = 10; 204 } 205 206 long capabilityCacheExpiration = 207 PresenceSetting.getCapabilityCacheExpiration(mDefaultSubId); 208 logger.print("getCapabilityCacheExpiration: " + capabilityCacheExpiration); 209 if (capabilityCacheExpiration == -1) { 210 capabilityCacheExpiration = mContext.getResources().getInteger( 211 R.integer.capability_cache_expiration); 212 } 213 if (capabilityCacheExpiration < 10) { 214 capabilityCacheExpiration = 10; 215 } 216 217 int publishTimer = PresenceSetting.getPublishTimer(mDefaultSubId); 218 logger.print("getPublishTimer: " + publishTimer); 219 int publishTimerExtended = PresenceSetting.getPublishTimerExtended(mDefaultSubId); 220 logger.print("getPublishTimerExtended: " + publishTimerExtended); 221 int maxEntriesInRequest = 222 PresenceSetting.getMaxNumberOfEntriesInRequestContainedList(mDefaultSubId); 223 logger.print("getMaxNumberOfEntriesInRequestContainedList: " + maxEntriesInRequest); 224 if ((capabilityPollInterval <= 30 * 60) || // default: 7 days 225 (capabilityCacheExpiration <= 60 * 60) || // default: 90 days 226 (maxEntriesInRequest <= 20) || // default: 100 227 (publishTimer <= 10 * 60) || // default: 20 minutes 228 (publishTimerExtended <= 20 * 60)) { // default: 1 day 229 setRcsTestMode(true); 230 } 231 232 if (capabilityCacheExpiration < capabilityPollInterval) { 233 capabilityPollInterval = capabilityCacheExpiration; 234 } 235 236 mCapabilityPollInterval = capabilityPollInterval * 1000; 237 mMinCapabilityPollInterval = mCapabilityPollInterval / 10; 238 logger.info("mCapabilityPollInterval: " + mCapabilityPollInterval + 239 ", mMinCapabilityPollInterval: " + mMinCapabilityPollInterval); 240 241 mCapabilityCacheExpiration = capabilityCacheExpiration * 1000; 242 logger.info("mCapabilityCacheExpiration: " + mCapabilityCacheExpiration); 243 244 mInitialized = true; 245 } 246 start()247 public void start() { 248 mDiscoveryThread = new HandlerThread("Presence-DiscoveryThread"); 249 mDiscoveryThread.start(); 250 mDiscoveryHandler = new Handler(mDiscoveryThread.getLooper(), mDiscoveryCallback); 251 mDefaultSubId = PresenceSetting.getDefaultSubscriptionId(); 252 253 registerForBroadcasts(); 254 255 if (isPollingReady()) { 256 schedulePolling(5 * 1000, ACTION_POLLING_NORMAL); 257 } 258 } 259 stop()260 public void stop() { 261 cancelDiscoveryAlarm(); 262 clearPollingTasks(); 263 mContext.unregisterReceiver(mReceiver); 264 unregisterPublishStateChangedCallback(); 265 mDiscoveryThread.quit(); 266 267 if (SubscriptionManager.isValidSubscriptionId(mDefaultSubId)) { 268 ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(mDefaultSubId); 269 pm.unregisterProvisioningChangedCallback(mProvisioningManagerCallback); 270 } 271 mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 272 } 273 registerForBroadcasts()274 private void registerForBroadcasts() { 275 IntentFilter intentFilter = new IntentFilter(); 276 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_AVAILABLE); 277 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE); 278 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_DIED); 279 intentFilter.addAction(RcsPresence.ACTION_PUBLISH_STATE_CHANGED); 280 intentFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); 281 mContext.registerReceiver(mReceiver, intentFilter); 282 } 283 registerPublishStateChangedCallback()284 private void registerPublishStateChangedCallback() { 285 try { 286 ImsManager imsManager = 287 (ImsManager) mContext.getSystemService(Context.TELEPHONY_IMS_SERVICE); 288 RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(mDefaultSubId).getUceAdapter(); 289 uceAdapter.addOnPublishStateChangedListener(mContext.getMainExecutor(), 290 mPublishStateCallback); 291 } catch (Exception ex) { 292 logger.warn("register publish state callback failed, exception: " + ex); 293 } 294 } 295 unregisterPublishStateChangedCallback()296 private void unregisterPublishStateChangedCallback() { 297 try { 298 ImsManager imsManager = 299 (ImsManager) mContext.getSystemService(Context.TELEPHONY_IMS_SERVICE); 300 RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(mDefaultSubId).getUceAdapter(); 301 uceAdapter.removeOnPublishStateChangedListener(mPublishStateCallback); 302 } catch (Exception ex) { 303 logger.warn("unregister publish state callback failed, exception: " + ex); 304 } 305 } 306 isPollingReady()307 private boolean isPollingReady() { 308 RcsManager rcsManager = RcsManager.getInstance(mContext, 0); 309 if (rcsManager != null) { 310 mStackAvailable = rcsManager.isRcsServiceAvailable(); 311 logger.print("isPollingReady, mStackAvailable: " + mStackAvailable); 312 try { 313 RcsPresence rcsPresence = rcsManager.getRcsPresenceInterface(); 314 if (rcsPresence != null) { 315 int state = rcsPresence.getPublishState(); 316 mPublished = (PublishState.PUBLISH_STATE_200_OK == state) ? 1 : 0; 317 logger.print("isPollingReady, mPublished: " + mPublished); 318 } 319 } catch (RcsException ex) { 320 logger.warn("RcsPresence.getPublishState failed, exception: " + ex); 321 mPublished = -1; 322 } 323 } 324 325 try { 326 mProvisioned = PresenceSetting.getEabProvisioningConfig(mDefaultSubId); 327 } catch (Exception e) { 328 logger.warn("isPollingReady, couldn't get ProvisioningManager, exception=" 329 + e.getMessage()); 330 mProvisioned = -1; 331 } 332 333 logger.print("isPollingReady, mProvisioned: " + mProvisioned + 334 ", mStackAvailable: " + mStackAvailable + ", mPublished: " + mPublished); 335 return mStackAvailable && (mPublished == 1) && (mProvisioned == 1); 336 } 337 serviceStatusChanged(boolean enabled)338 private void serviceStatusChanged(boolean enabled) { 339 logger.print("Enter serviceStatusChanged: " + enabled); 340 mStackAvailable = enabled; 341 342 if (isPollingReady()) { 343 schedulePolling(0, ACTION_POLLING_NORMAL); 344 } else { 345 cancelDiscoveryAlarm(); 346 clearPollingTasks(); 347 } 348 } 349 publishStateChanged(int state)350 private void publishStateChanged(int state) { 351 logger.print("Enter publishStateChanged: " + state); 352 mPublished = (PublishState.PUBLISH_STATE_200_OK == state) ? 1 : 0; 353 if (mPublished == 1) { 354 PresencePreferences pref = PresencePreferences.getInstance(); 355 if (pref != null) { 356 String mdn_old = pref.getLine1Number(); 357 String subscriberId_old = pref.getSubscriberId(); 358 if (TextUtils.isEmpty(mdn_old) && TextUtils.isEmpty(subscriberId_old)) { 359 String mdn = getLine1Number(); 360 pref.setLine1Number(mdn); 361 String subscriberId = getSubscriberId(); 362 pref.setSubscriberId(subscriberId); 363 } 364 } 365 } 366 367 if (isPollingReady()) { 368 schedulePolling(0, ACTION_POLLING_NORMAL); 369 } else { 370 cancelDiscoveryAlarm(); 371 clearPollingTasks(); 372 } 373 } 374 provisionStateChanged()375 private void provisionStateChanged() { 376 boolean volteProvisioned = PresenceSetting.getVoLteProvisioningConfig(mDefaultSubId) == 377 ProvisioningManager.PROVISIONING_VALUE_ENABLED; 378 boolean vtProvisioned = PresenceSetting.getVtProvisioningConfig(mDefaultSubId) == 379 ProvisioningManager.PROVISIONING_VALUE_ENABLED; 380 boolean eabProvisioned = PresenceSetting.getEabProvisioningConfig(mDefaultSubId) == 381 ProvisioningManager.PROVISIONING_VALUE_ENABLED; 382 logger.print("Provision state changed, VolteProvision: " 383 + volteProvisioned + ", vtProvision: " + vtProvisioned 384 + ", eabProvision: " + eabProvisioned); 385 if ((mProvisioned == 1) && !eabProvisioned) { 386 logger.print("EAB Provision is disabled, clear all capabilities!"); 387 if (mEABContactManager != null) { 388 mEABContactManager.updateAllCapabilityToUnknown(); 389 } 390 } 391 mProvisioned = eabProvisioned ? 1 : 0; 392 393 if (isPollingReady()) { 394 schedulePolling(0, ACTION_POLLING_NORMAL); 395 } else { 396 cancelDiscoveryAlarm(); 397 clearPollingTasks(); 398 } 399 } 400 settingsChanged()401 private void settingsChanged() { 402 logger.print("Enter settingsChanged."); 403 cancelDiscoveryAlarm(); 404 clearPollingTasks(); 405 mInitialized = false; 406 407 if (isPollingReady()) { 408 schedulePolling(0, ACTION_POLLING_NORMAL); 409 } 410 } 411 newContactAdded(String number)412 private void newContactAdded(String number) { 413 if (TextUtils.isEmpty(number)) { 414 return; 415 } 416 417 EABContactManager.Request request = new EABContactManager.Request(number) 418 .setLastUpdatedTimeStamp(0); 419 int result = mEABContactManager.update(request); 420 if (result <= 0) { 421 return; 422 } 423 424 if (isPollingReady()) { 425 schedulePolling(5 * 1000, ACTION_POLLING_NEW_CONTACTS); 426 } 427 } 428 verifyPollingResult(int counts)429 private void verifyPollingResult(int counts) { 430 if (isPollingReady()) { 431 PresencePreferences pref = PresencePreferences.getInstance(); 432 if ((pref != null) && pref.getRcsTestMode()) { 433 counts = 1; 434 } 435 long lm = (long)(1 << (counts - 1)); 436 schedulePolling(30 * 1000 * lm, ACTION_POLLING_NORMAL); 437 } 438 } 439 schedulePolling(long msec, int type)440 public synchronized void schedulePolling(long msec, int type) { 441 logger.print("schedulePolling msec=" + msec + " type=" + type); 442 if (!isPollingReady()) { 443 logger.debug("Cancel the polling since the network is not ready"); 444 return; 445 } 446 447 if (type == ACTION_POLLING_NEW_CONTACTS) { 448 cancelDiscoveryAlarm(); 449 } 450 451 if (mNextPollingTimeStamp != 0L) { 452 long scheduled = mNextPollingTimeStamp - System.currentTimeMillis(); 453 if ((scheduled > 0) && (scheduled < msec)) { 454 logger.print("There has been a discovery scheduled at " 455 + getTimeString(mNextPollingTimeStamp)); 456 return; 457 } 458 } 459 460 long nextTime = System.currentTimeMillis() + msec; 461 logger.print("A new discovery needs to be started in " + 462 (msec / 1000) + " seconds at " 463 + getTimeString(nextTime)); 464 465 cancelDiscoveryAlarm(); 466 467 if (msec <= 0) { 468 enqueueDiscovery(type); 469 return; 470 } 471 472 Intent intent = new Intent(ACTION_PERIODICAL_DISCOVERY_ALARM); 473 intent.setClass(mContext, AlarmBroadcastReceiver.class); 474 intent.putExtra("pollingType", type); 475 476 mDiscoveryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 477 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); 478 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 479 SystemClock.elapsedRealtime() + msec, mDiscoveryAlarmIntent); 480 481 mNextPollingTimeStamp = nextTime; 482 } 483 doCapabilityDiscovery(int type)484 private synchronized void doCapabilityDiscovery(int type) { 485 logger.print("doCapabilityDiscovery type=" + type); 486 if (!isPollingReady()) { 487 logger.debug("doCapabilityDiscovery isPollingReady=false"); 488 return; 489 } 490 491 long delay = 0; 492 List<Contacts.Item> list = null; 493 494 initialise(); 495 496 mNextPollingTimeStamp = 0L; 497 Cursor cursor = null; 498 EABContactManager.Query baseQuery = new EABContactManager.Query() 499 .orderBy(EABContactManager.COLUMN_LAST_UPDATED_TIMESTAMP, 500 EABContactManager.Query.ORDER_ASCENDING); 501 try { 502 logger.debug("doCapabilityDiscovery.query:\n" + baseQuery); 503 cursor = mEABContactManager.query(baseQuery); 504 if (cursor == null) { 505 logger.print("Cursor is null, there is no database found."); 506 return; 507 } 508 int count = cursor.getCount(); 509 if (count == 0) { 510 logger.print("Cursor.getCount() is 0, there is no items found in db."); 511 return; 512 } 513 514 list = new ArrayList<Contacts.Item>(); 515 list.clear(); 516 517 long current = System.currentTimeMillis(); 518 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 519 long id = cursor.getLong(cursor.getColumnIndex(Contacts.Impl._ID)); 520 long last = cursor.getLong(cursor.getColumnIndex( 521 Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP)); 522 523 Contacts.Item item = new Contacts.Item(id); 524 item.setLastUpdateTime(last); 525 item.setNumber(cursor.getString( 526 cursor.getColumnIndex(Contacts.Impl.CONTACT_NUMBER))); 527 item.setName(cursor.getString( 528 cursor.getColumnIndex(Contacts.Impl.CONTACT_NAME))); 529 item.setVolteTimestamp(cursor.getLong( 530 cursor.getColumnIndex(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP))); 531 item.setVideoTimestamp(cursor.getLong( 532 cursor.getColumnIndex(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP))); 533 534 if ((current - last < 0) || 535 (current - last >= mCapabilityPollInterval - mMinCapabilityPollInterval)) { 536 logger.print("This item will be updated:\n" 537 + item); 538 if (item.isValid()) { 539 list.add(item); 540 } 541 } else { 542 logger.print("The first item which will be updated next time:\n" + item); 543 delay = randomCapabilityPollInterval() - (current - last); 544 if (delay > 0) { 545 break; 546 } 547 } 548 } 549 } catch (Exception ex) { 550 logger.warn("Exception in doCapabilityDiscovery: " + ex); 551 if (delay <= 0) { 552 delay = 5 * 60 * 1000; 553 } 554 } finally { 555 if (cursor != null) { 556 cursor.close(); 557 } 558 } 559 560 if (delay <= 0) { 561 delay = randomCapabilityPollInterval(); 562 } 563 logger.print("Polling delay: " + delay); 564 schedulePolling(delay, ACTION_POLLING_NORMAL); 565 566 updateObsoleteItems(); 567 568 if ((list != null) && (list.size() > 0)) { 569 PollingsQueue queue = PollingsQueue.getInstance(mContext); 570 if (queue != null) { 571 queue.setCapabilityPolling(this); 572 queue.add(type, list, mDefaultSubId); 573 } 574 } 575 } 576 randomCapabilityPollInterval()577 private long randomCapabilityPollInterval() { 578 double random = Math.random() * 0.2 + 0.9; 579 logger.print("The random for this time polling is: " + random); 580 random = random * mCapabilityPollInterval; 581 return (long)random; 582 } 583 updateObsoleteItems()584 private void updateObsoleteItems() { 585 long current = System.currentTimeMillis(); 586 long last = current - mCapabilityCacheExpiration; 587 long last3year = current - 3 * 365 * 24 * 3600000L; 588 StringBuilder sb = new StringBuilder(); 589 sb.append("(("); 590 sb.append(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP + "<='" + last + "'"); 591 sb.append(" OR "); 592 sb.append(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP + "<='" + last + "'"); 593 sb.append(") AND "); 594 sb.append(Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP + ">='" + last3year + "'"); 595 sb.append(")"); 596 EABContactManager.Query baseQuery = new EABContactManager.Query() 597 .setFilterByTime(sb.toString()) 598 .orderBy(EABContactManager.COLUMN_ID, 599 EABContactManager.Query.ORDER_ASCENDING); 600 601 Cursor cursor = null; 602 List<Contacts.Item> list = null; 603 try { 604 logger.debug("updateObsoleteItems.query:\n" + baseQuery); 605 cursor = mEABContactManager.query(baseQuery); 606 if (cursor == null) { 607 logger.print("Cursor is null, there is no database found."); 608 return; 609 } 610 int count = cursor.getCount(); 611 if (count == 0) { 612 logger.print("Cursor.getCount() is 0, there is no obsolete items found."); 613 return; 614 } 615 616 list = new ArrayList<Contacts.Item>(); 617 list.clear(); 618 619 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 620 long id = cursor.getLong(cursor.getColumnIndex(Contacts.Impl._ID)); 621 622 Contacts.Item item = new Contacts.Item(id); 623 item.setLastUpdateTime(cursor.getLong( 624 cursor.getColumnIndex(Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP))); 625 item.setNumber(cursor.getString( 626 cursor.getColumnIndex(Contacts.Impl.CONTACT_NUMBER))); 627 item.setName(cursor.getString( 628 cursor.getColumnIndex(Contacts.Impl.CONTACT_NAME))); 629 item.setVolteTimestamp(cursor.getLong( 630 cursor.getColumnIndex(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP))); 631 item.setVideoTimestamp(cursor.getLong( 632 cursor.getColumnIndex(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP))); 633 logger.print("updateObsoleteItems, the obsolete item:\n" + item); 634 635 if ((item.lastUpdateTime() > 0) && item.isValid()) { 636 list.add(item); 637 } 638 } 639 } catch (Exception ex) { 640 logger.warn("Exception in updateObsoleteItems: " + ex); 641 } finally { 642 if (cursor != null) { 643 cursor.close(); 644 } 645 } 646 647 if ((list == null) || (list.size() <= 0)) { 648 return; 649 } 650 651 for (Contacts.Item item : list) { 652 EABContactManager.Request request = new EABContactManager.Request(item.id()); 653 if (item.volteTimestamp() <= last) { 654 request.setVolteCallCapability(false); 655 request.setVolteCallCapabilityTimeStamp(current); 656 } 657 if (item.videoTimestamp() <= last) { 658 request.setVideoCallCapability(false); 659 request.setVideoCallCapabilityTimeStamp(current); 660 } 661 int result = mEABContactManager.update(request); 662 if (result <= 0) { 663 logger.print("Failed to update this request: " + request); 664 } 665 } 666 } 667 cancelDiscoveryAlarm()668 private void cancelDiscoveryAlarm() { 669 if (mDiscoveryAlarmIntent != null) { 670 mAlarmManager.cancel(mDiscoveryAlarmIntent); 671 mDiscoveryAlarmIntent = null; 672 mNextPollingTimeStamp = 0L; 673 } 674 } 675 clearPollingTasks()676 private void clearPollingTasks() { 677 PollingsQueue queue = PollingsQueue.getInstance(null); 678 if (queue != null) { 679 queue.clear(); 680 } 681 } 682 getTimeString(long time)683 private String getTimeString(long time) { 684 if (time <= 0) { 685 time = System.currentTimeMillis(); 686 } 687 688 String timeString = TimeMigrationUtils.formatMillisWithFixedFormat(time); 689 return String.format("%s.%s", timeString, time % 1000); 690 } 691 692 private static final int MSG_CHECK_DISCOVERY = 1; 693 private static final int MSG_NEW_CONTACT_ADDED = 2; 694 private static final int MSG_SERVICE_STATUS_CHANGED = 3; 695 private static final int MSG_SETTINGS_CHANGED = 4; 696 private static final int MSG_PUBLISH_STATE_CHANGED = 5; 697 private static final int MSG_PROVISION_STATE_CHANGED = 6; 698 private static final int MSG_VERIFY_POLLING_RESULT = 7; 699 enqueueDiscovery(int type)700 public void enqueueDiscovery(int type) { 701 mDiscoveryHandler.removeMessages(MSG_CHECK_DISCOVERY); 702 mDiscoveryHandler.obtainMessage(MSG_CHECK_DISCOVERY, type, -1).sendToTarget(); 703 } 704 enqueueNewContact(String number)705 public void enqueueNewContact(String number) { 706 mDiscoveryHandler.obtainMessage(MSG_NEW_CONTACT_ADDED, number).sendToTarget(); 707 } 708 enqueueServiceStatusChanged(boolean enabled)709 private void enqueueServiceStatusChanged(boolean enabled) { 710 mDiscoveryHandler.removeMessages(MSG_SERVICE_STATUS_CHANGED); 711 mDiscoveryHandler.obtainMessage(MSG_SERVICE_STATUS_CHANGED, 712 enabled ? 1 : 0, -1).sendToTarget(); 713 } 714 enqueuePublishStateChanged(int state)715 private void enqueuePublishStateChanged(int state) { 716 mDiscoveryHandler.removeMessages(MSG_PUBLISH_STATE_CHANGED); 717 mDiscoveryHandler.obtainMessage(MSG_PUBLISH_STATE_CHANGED, 718 state, -1).sendToTarget(); 719 } 720 enqueueSettingsChanged()721 public void enqueueSettingsChanged() { 722 mDiscoveryHandler.removeMessages(MSG_SETTINGS_CHANGED); 723 mDiscoveryHandler.obtainMessage(MSG_SETTINGS_CHANGED).sendToTarget(); 724 } 725 enqueueProvisionStateChanged()726 private void enqueueProvisionStateChanged() { 727 mDiscoveryHandler.removeMessages(MSG_PROVISION_STATE_CHANGED); 728 mDiscoveryHandler.obtainMessage(MSG_PROVISION_STATE_CHANGED).sendToTarget(); 729 } 730 enqueueVerifyPollingResult(int counts)731 public void enqueueVerifyPollingResult(int counts) { 732 mDiscoveryHandler.removeMessages(MSG_VERIFY_POLLING_RESULT); 733 mDiscoveryHandler.obtainMessage(MSG_VERIFY_POLLING_RESULT, counts, -1).sendToTarget(); 734 } 735 enqueueTryRegisterConfigCallback()736 private void enqueueTryRegisterConfigCallback() { 737 mContext.getMainThreadHandler().removeCallbacks(mRegisterCallbackRunnable); 738 mContext.getMainThreadHandler().postDelayed(mRegisterCallbackRunnable, 739 DELAY_REGISTER_CALLBACK_MS); 740 } 741 742 private Handler.Callback mDiscoveryCallback = new Handler.Callback() { 743 @Override 744 public boolean handleMessage(Message msg) { 745 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 746 747 if (msg.what == MSG_CHECK_DISCOVERY) { 748 doCapabilityDiscovery(msg.arg1); 749 } else if (msg.what == MSG_NEW_CONTACT_ADDED) { 750 newContactAdded((String)msg.obj); 751 } else if (msg.what == MSG_SERVICE_STATUS_CHANGED) { 752 serviceStatusChanged(msg.arg1 == 1); 753 } else if (msg.what == MSG_PUBLISH_STATE_CHANGED) { 754 publishStateChanged(msg.arg1); 755 } else if (msg.what == MSG_SETTINGS_CHANGED) { 756 settingsChanged(); 757 } else if(msg.what == MSG_PROVISION_STATE_CHANGED) { 758 provisionStateChanged(); 759 } else if(msg.what == MSG_VERIFY_POLLING_RESULT) { 760 verifyPollingResult(msg.arg1); 761 } else { 762 } 763 764 return true; 765 } 766 }; 767 setDefaultSubscriberIds()768 private void setDefaultSubscriberIds() { 769 PresencePreferences pref = PresencePreferences.getInstance(); 770 if (pref == null) { 771 return; 772 } 773 774 String mdn_old = pref.getLine1Number(); 775 if (TextUtils.isEmpty(mdn_old)) { 776 return; 777 } 778 String subscriberId_old = pref.getSubscriberId(); 779 if (TextUtils.isEmpty(subscriberId_old)) { 780 return; 781 } 782 783 String mdn = getLine1Number(); 784 String subscriberId = getSubscriberId(); 785 if (TextUtils.isEmpty(mdn) && TextUtils.isEmpty(subscriberId)) { 786 return; 787 } 788 789 boolean mdnMatched = false; 790 if (TextUtils.isEmpty(mdn) || PhoneNumberUtils.compare(mdn_old, mdn)) { 791 mdnMatched = true; 792 } 793 boolean subscriberIdMatched = false; 794 if (TextUtils.isEmpty(subscriberId) || subscriberId.equals(subscriberId_old)) { 795 subscriberIdMatched = true; 796 } 797 if (mdnMatched && subscriberIdMatched) { 798 return; 799 } 800 801 logger.print("Remove presence cache for Sim card changed!"); 802 pref.setLine1Number(""); 803 pref.setSubscriberId(""); 804 } 805 806 // Track the default subscription (the closest we can get to MSIM). 807 // call from main thread only. handleDefaultSubscriptionChanged(int newDefaultSubId)808 public void handleDefaultSubscriptionChanged(int newDefaultSubId) { 809 logger.print("handleDefaultSubscriptionChanged: new default= " 810 + newDefaultSubId); 811 812 if (!SubscriptionManager.isValidSubscriptionId(newDefaultSubId)) { 813 return; 814 } 815 if (isInitializing && (mDefaultSubId == newDefaultSubId)) { 816 return; 817 } else { 818 isInitializing = true; 819 } 820 // unregister old default first 821 if (SubscriptionManager.isValidSubscriptionId(mDefaultSubId)) { 822 ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(mDefaultSubId); 823 pm.unregisterProvisioningChangedCallback(mProvisioningManagerCallback); 824 825 unregisterPublishStateChangedCallback(); 826 } 827 // register new default and clear old cached values in EAB only if we are changing the 828 // default sub ID. 829 if (SubscriptionManager.isValidSubscriptionId(newDefaultSubId) 830 && mEABContactManager != null) { 831 mEABContactManager.updateAllCapabilityToUnknown(); 832 } 833 mDefaultSubId = newDefaultSubId; 834 SharedPrefUtil.saveLastUsedSubscriptionId(mContext, mDefaultSubId); 835 tryProvisioningManagerRegistration(); 836 // Clear defaults and recalculate. 837 setDefaultSubscriberIds(); 838 mProvisioned = -1; 839 enqueueSettingsChanged(); 840 // load settings for new default. 841 enqueueProvisionStateChanged(); 842 registerPublishStateChangedCallback(); 843 } 844 tryProvisioningManagerRegistration()845 public void tryProvisioningManagerRegistration() { 846 ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(mDefaultSubId); 847 try { 848 pm.registerProvisioningChangedCallback(mContext.getMainExecutor(), 849 mProvisioningManagerCallback); 850 } catch (ImsException e) { 851 if (e.getCode() == ImsException.CODE_ERROR_SERVICE_UNAVAILABLE) { 852 enqueueTryRegisterConfigCallback(); 853 } 854 } 855 } 856 getLine1Number()857 private String getLine1Number() { 858 if (mContext == null) { 859 return null; 860 } 861 862 TelephonyManager telephony = (TelephonyManager) 863 mContext.getSystemService(Context.TELEPHONY_SERVICE); 864 if (telephony == null) { 865 return null; 866 } 867 868 int subId = PresenceSetting.getDefaultSubscriptionId(); 869 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 870 // no valid subscriptions available. 871 return null; 872 } 873 telephony = telephony.createForSubscriptionId(subId); 874 String mdn = telephony.getLine1Number(); 875 876 if ((mdn == null) || (mdn.length() == 0) || mdn.startsWith("00000")) { 877 return null; 878 } 879 880 logger.print("getLine1Number: " + mdn); 881 return mdn; 882 } 883 getSubscriberId()884 private String getSubscriberId() { 885 if (mContext == null) { 886 return null; 887 } 888 889 TelephonyManager telephony = (TelephonyManager) 890 mContext.getSystemService(Context.TELEPHONY_SERVICE); 891 if (telephony == null) { 892 return null; 893 } 894 895 int subId = PresenceSetting.getDefaultSubscriptionId(); 896 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 897 return null; 898 } 899 telephony.createForSubscriptionId(subId); 900 String subscriberId = telephony.getSubscriberId(); 901 902 logger.print("getSubscriberId: " + subscriberId); 903 return subscriberId; 904 } 905 } 906