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.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.database.Cursor; 38 import android.net.Uri; 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.text.format.Time; 48 import android.text.TextUtils; 49 import android.content.ComponentName; 50 51 import com.android.ims.ImsConfig; 52 import com.android.ims.ImsException; 53 import com.android.ims.ImsManager; 54 import com.android.internal.telephony.IccCardConstants; 55 import com.android.internal.telephony.TelephonyIntents; 56 57 import com.android.ims.RcsException; 58 import com.android.ims.RcsManager; 59 import com.android.ims.RcsManager.ResultCode; 60 import com.android.ims.RcsPresence; 61 import com.android.ims.RcsPresence.PublishState; 62 import com.android.ims.RcsPresenceInfo; 63 import com.android.ims.internal.ContactNumberUtils; 64 import com.android.ims.internal.Logger; 65 66 import java.util.ArrayList; 67 import java.util.List; 68 69 public class CapabilityPolling { 70 private Logger logger = Logger.getLogger(this.getClass().getName()); 71 private final Context mContext; 72 73 public static final String ACTION_PERIODICAL_DISCOVERY_ALARM = 74 "com.android.service.ims.presence.periodical_capability_discovery"; 75 private PendingIntent mDiscoveryAlarmIntent = null; 76 77 public static final int ACTION_POLLING_NORMAL = 0; 78 public static final int ACTION_POLLING_NEW_CONTACTS = 1; 79 80 private long mCapabilityPollInterval = 604800000L; 81 private long mMinCapabilityPollInterval = 60480000L; 82 private long mCapabilityCacheExpiration = 7776000000L; 83 private long mNextPollingTimeStamp = 0L; 84 private final Object mScheduleSyncObj = new Object(); 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 93 private HandlerThread mDiscoveryThread; 94 private Handler mDiscoveryHandler; 95 96 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 97 @Override 98 public void onReceive(Context context, Intent intent) { 99 logger.info("onReceive(), intent: " + intent + 100 ", context: " + context); 101 102 String action = intent.getAction(); 103 if (RcsManager.ACTION_RCS_SERVICE_AVAILABLE.equals(action)) { 104 enqueueServiceStatusChanged(true); 105 } else if (RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE.equals(action)) { 106 enqueueServiceStatusChanged(false); 107 } else if (RcsManager.ACTION_RCS_SERVICE_DIED.equals(action)) { 108 logger.warn("No handler for this intent: " + action); 109 } else if (RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(action)) { 110 int state = intent.getIntExtra( 111 RcsPresence.EXTRA_PUBLISH_STATE, 112 RcsPresence.PublishState.PUBLISH_STATE_NOT_PUBLISHED); 113 enqueuePublishStateChanged(state); 114 } else if (ImsConfig.ACTION_IMS_CONFIG_CHANGED.equals(action)) { 115 int item = intent.getIntExtra(ImsConfig.EXTRA_CHANGED_ITEM, -1); 116 if ((ImsConfig.ConfigConstants.CAPABILITIES_POLL_INTERVAL == item) || 117 (ImsConfig.ConfigConstants.CAPABILITIES_CACHE_EXPIRATION == item)) { 118 enqueueSettingsChanged(); 119 } else if ((ImsConfig.ConfigConstants.VLT_SETTING_ENABLED == item) || 120 (ImsConfig.ConfigConstants.LVC_SETTING_ENABLED == item) || 121 (ImsConfig.ConfigConstants.EAB_SETTING_ENABLED == item)) { 122 enqueueProvisionStateChanged(); 123 } 124 } else if(TelephonyIntents.ACTION_SIM_STATE_CHANGED.equalsIgnoreCase(action)) { 125 String stateExtra = intent.getStringExtra( 126 IccCardConstants.INTENT_KEY_ICC_STATE); 127 logger.print("SIM_STATE_CHANGED: " + stateExtra); 128 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equalsIgnoreCase(stateExtra)) { 129 enqueueSimLoaded(); 130 } 131 } else { 132 logger.debug("No interest in this intent: " + action); 133 } 134 } 135 }; 136 137 private static CapabilityPolling sInstance = null; getInstance(Context context)138 public static synchronized CapabilityPolling getInstance(Context context) { 139 if ((sInstance == null) && (context != null)) { 140 sInstance = new CapabilityPolling(context); 141 } 142 143 return sInstance; 144 } 145 CapabilityPolling(Context context)146 private CapabilityPolling(Context context) { 147 mContext = context; 148 149 ContactNumberUtils.getDefault().setContext(mContext); 150 PresencePreferences.getInstance().setContext(mContext); 151 152 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 153 mEABContactManager = new EABContactManager(mContext.getContentResolver(), 154 mContext.getPackageName()); 155 156 setRcsTestMode(PresencePreferences.getInstance().getRcsTestMode()); 157 logger.debug("CapabilityPolling is created."); 158 } 159 setRcsTestMode(boolean test)160 public void setRcsTestMode(boolean test) { 161 logger.setRcsTestMode(test); 162 163 PresencePreferences pref = PresencePreferences.getInstance(); 164 if (pref != null) { 165 if (pref.getRcsTestMode() != test) { 166 pref.setRcsTestMode(test); 167 } 168 } 169 } 170 initialise()171 private void initialise() { 172 if (mInitialized) { 173 return; 174 } 175 176 PresenceSetting.init(mContext); 177 long capabilityPollInterval = PresenceSetting.getCapabilityPollInterval(); 178 logger.print("getCapabilityPollInterval: " + capabilityPollInterval); 179 if (capabilityPollInterval == -1) { 180 capabilityPollInterval = mContext.getResources().getInteger( 181 R.integer.capability_poll_interval); 182 } 183 if (capabilityPollInterval < 10) { 184 capabilityPollInterval = 10; 185 } 186 187 long capabilityCacheExpiration = PresenceSetting.getCapabilityCacheExpiration(); 188 logger.print("getCapabilityCacheExpiration: " + capabilityCacheExpiration); 189 if (capabilityCacheExpiration == -1) { 190 capabilityCacheExpiration = mContext.getResources().getInteger( 191 R.integer.capability_cache_expiration); 192 } 193 if (capabilityCacheExpiration < 10) { 194 capabilityCacheExpiration = 10; 195 } 196 197 int publishTimer = PresenceSetting.getPublishTimer(); 198 logger.print("getPublishTimer: " + publishTimer); 199 int publishTimerExtended = PresenceSetting.getPublishTimerExtended(); 200 logger.print("getPublishTimerExtended: " + publishTimerExtended); 201 int maxEntriesInRequest = PresenceSetting.getMaxNumberOfEntriesInRequestContainedList(); 202 logger.print("getMaxNumberOfEntriesInRequestContainedList: " + maxEntriesInRequest); 203 if ((capabilityPollInterval <= 30 * 60) || // default: 7 days 204 (capabilityCacheExpiration <= 60 * 60) || // default: 90 days 205 (maxEntriesInRequest <= 20) || // default: 100 206 (publishTimer <= 10 * 60) || // default: 20 minutes 207 (publishTimerExtended <= 20 * 60)) { // default: 1 day 208 setRcsTestMode(true); 209 } 210 211 if (capabilityCacheExpiration < capabilityPollInterval) { 212 capabilityPollInterval = capabilityCacheExpiration; 213 } 214 215 mCapabilityPollInterval = capabilityPollInterval * 1000; 216 mMinCapabilityPollInterval = mCapabilityPollInterval / 10; 217 logger.info("mCapabilityPollInterval: " + mCapabilityPollInterval + 218 ", mMinCapabilityPollInterval: " + mMinCapabilityPollInterval); 219 220 mCapabilityCacheExpiration = capabilityCacheExpiration * 1000; 221 logger.info("mCapabilityCacheExpiration: " + mCapabilityCacheExpiration); 222 223 mInitialized = true; 224 } 225 start()226 public void start() { 227 mDiscoveryThread = new HandlerThread("Presence-DiscoveryThread"); 228 mDiscoveryThread.start(); 229 mDiscoveryHandler = new Handler(mDiscoveryThread.getLooper(), mDiscoveryCallback); 230 231 registerForBroadcasts(); 232 233 if (isPollingReady()) { 234 schedulePolling(5 * 1000, ACTION_POLLING_NORMAL); 235 } 236 } 237 stop()238 public void stop() { 239 cancelDiscoveryAlarm(); 240 clearPollingTasks(); 241 mContext.unregisterReceiver(mReceiver); 242 mDiscoveryThread.quit(); 243 } 244 registerForBroadcasts()245 private void registerForBroadcasts() { 246 IntentFilter intentFilter = new IntentFilter(); 247 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_AVAILABLE); 248 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE); 249 intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_DIED); 250 intentFilter.addAction(RcsPresence.ACTION_PUBLISH_STATE_CHANGED); 251 intentFilter.addAction(ImsConfig.ACTION_IMS_CONFIG_CHANGED); 252 intentFilter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 253 mContext.registerReceiver(mReceiver, intentFilter); 254 } 255 isPollingReady()256 private boolean isPollingReady() { 257 if (mPublished == -1) { 258 RcsManager rcsManager = RcsManager.getInstance(mContext, 0); 259 if (rcsManager != null) { 260 mStackAvailable = rcsManager.isRcsServiceAvailable(); 261 logger.print("isPollingReady, mStackAvailable: " + mStackAvailable); 262 try { 263 RcsPresence rcsPresence = rcsManager.getRcsPresenceInterface(); 264 if (rcsPresence != null) { 265 int state = rcsPresence.getPublishState(); 266 mPublished = (PublishState.PUBLISH_STATE_200_OK == state) ? 1 : 0; 267 logger.print("isPollingReady, mPublished: " + mPublished); 268 } 269 } catch (RcsException ex) { 270 logger.warn("RcsPresence.getPublishState failed, exception: " + ex); 271 mPublished = -1; 272 } 273 } 274 } 275 276 if (mProvisioned == -1) { 277 ImsManager imsManager = ImsManager.getInstance(mContext, 278 SubscriptionManager.getDefaultVoicePhoneId()); 279 if (imsManager != null) { 280 try { 281 ImsConfig imsConfig = imsManager.getConfigInterface(); 282 if (imsConfig != null) { 283 mProvisioned = imsConfig.getProvisionedValue( 284 ImsConfig.ConfigConstants.EAB_SETTING_ENABLED); 285 logger.print("isPollingReady, mProvisioned: " + mProvisioned); 286 } 287 } catch (ImsException ex) { 288 logger.warn("ImsConfig.getEabProvisioned failed, exception: " + ex); 289 mProvisioned = -1; 290 } 291 } 292 } 293 logger.print("isPollingReady, mProvisioned: " + mProvisioned + 294 ", mStackAvailable: " + mStackAvailable + ", mPublished: " + mPublished); 295 return mStackAvailable && (mPublished == 1) && (mProvisioned == 1); 296 } 297 serviceStatusChanged(boolean enabled)298 private void serviceStatusChanged(boolean enabled) { 299 logger.print("Enter serviceStatusChanged: " + enabled); 300 mStackAvailable = enabled; 301 302 if (isPollingReady()) { 303 schedulePolling(0, ACTION_POLLING_NORMAL); 304 } else { 305 cancelDiscoveryAlarm(); 306 clearPollingTasks(); 307 } 308 } 309 publishStateChanged(int state)310 private void publishStateChanged(int state) { 311 logger.print("Enter publishStateChanged: " + state); 312 mPublished = (PublishState.PUBLISH_STATE_200_OK == state) ? 1 : 0; 313 if (mPublished == 1) { 314 PresencePreferences pref = PresencePreferences.getInstance(); 315 if (pref != null) { 316 String mdn_old = pref.getLine1Number(); 317 String subscriberId_old = pref.getSubscriberId(); 318 if (TextUtils.isEmpty(mdn_old) && TextUtils.isEmpty(subscriberId_old)) { 319 String mdn = getLine1Number(); 320 pref.setLine1Number(mdn); 321 String subscriberId = getSubscriberId(); 322 pref.setSubscriberId(subscriberId); 323 } 324 } 325 } 326 327 if (isPollingReady()) { 328 schedulePolling(0, ACTION_POLLING_NORMAL); 329 } else { 330 cancelDiscoveryAlarm(); 331 clearPollingTasks(); 332 } 333 } 334 provisionStateChanged()335 private void provisionStateChanged() { 336 ImsManager imsManager = ImsManager.getInstance(mContext, 337 SubscriptionManager.getDefaultVoicePhoneId()); 338 if (imsManager == null) { 339 return; 340 } 341 342 try { 343 ImsConfig imsConfig = imsManager.getConfigInterface(); 344 if (imsConfig == null) { 345 return; 346 } 347 boolean volteProvision = imsConfig.getProvisionedValue( 348 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED) 349 == ImsConfig.FeatureValueConstants.ON; 350 boolean vtProvision = imsConfig.getProvisionedValue( 351 ImsConfig.ConfigConstants.LVC_SETTING_ENABLED) 352 == ImsConfig.FeatureValueConstants.ON; 353 boolean eabProvision = imsConfig.getProvisionedValue( 354 ImsConfig.ConfigConstants.EAB_SETTING_ENABLED) 355 == ImsConfig.FeatureValueConstants.ON; 356 logger.print("Provision state changed, VolteProvision: " 357 + volteProvision + ", vtProvision: " + vtProvision 358 + ", eabProvision: " + eabProvision); 359 360 if ((mProvisioned == 1) && !eabProvision) { 361 logger.print("EAB Provision is disabled, clear all capabilities!"); 362 if (mEABContactManager != null) { 363 mEABContactManager.updateAllCapabilityToUnknown(); 364 } 365 } 366 mProvisioned = eabProvision ? 1 : 0; 367 } catch (ImsException ex) { 368 logger.warn("ImsConfig.getEabProvisioned failed, exception: " + ex); 369 mProvisioned = -1; 370 return; 371 } 372 373 if (isPollingReady()) { 374 schedulePolling(0, ACTION_POLLING_NORMAL); 375 } else { 376 cancelDiscoveryAlarm(); 377 clearPollingTasks(); 378 } 379 } 380 settingsChanged()381 private void settingsChanged() { 382 logger.print("Enter settingsChanged."); 383 cancelDiscoveryAlarm(); 384 clearPollingTasks(); 385 mInitialized = false; 386 387 if (isPollingReady()) { 388 schedulePolling(0, ACTION_POLLING_NORMAL); 389 } 390 } 391 newContactAdded(String number)392 private void newContactAdded(String number) { 393 if (TextUtils.isEmpty(number)) { 394 return; 395 } 396 397 EABContactManager.Request request = new EABContactManager.Request(number) 398 .setLastUpdatedTimeStamp(0); 399 int result = mEABContactManager.update(request); 400 if (result <= 0) { 401 return; 402 } 403 404 if (isPollingReady()) { 405 schedulePolling(5 * 1000, ACTION_POLLING_NEW_CONTACTS); 406 } 407 } 408 verifyPollingResult(int counts)409 private void verifyPollingResult(int counts) { 410 if (isPollingReady()) { 411 PresencePreferences pref = PresencePreferences.getInstance(); 412 if ((pref != null) && pref.getRcsTestMode()) { 413 counts = 1; 414 } 415 long lm = (long)(1 << (counts - 1)); 416 schedulePolling(30 * 1000 * lm, ACTION_POLLING_NORMAL); 417 } 418 } 419 schedulePolling(long msec, int type)420 public synchronized void schedulePolling(long msec, int type) { 421 logger.print("schedulePolling msec=" + msec + " type=" + type); 422 if (!isPollingReady()) { 423 logger.debug("Cancel the polling since the network is not ready"); 424 return; 425 } 426 427 if (type == ACTION_POLLING_NEW_CONTACTS) { 428 cancelDiscoveryAlarm(); 429 } 430 431 if (mNextPollingTimeStamp != 0L) { 432 long scheduled = mNextPollingTimeStamp - System.currentTimeMillis(); 433 if ((scheduled > 0) && (scheduled < msec)) { 434 logger.print("There has been a discovery scheduled at " 435 + getTimeString(mNextPollingTimeStamp)); 436 return; 437 } 438 } 439 440 long nextTime = System.currentTimeMillis() + msec; 441 logger.print("A new discovery needs to be started in " + 442 (msec / 1000) + " seconds at " 443 + getTimeString(nextTime)); 444 445 cancelDiscoveryAlarm(); 446 447 if (msec <= 0) { 448 enqueueDiscovery(type); 449 return; 450 } 451 452 Intent intent = new Intent(ACTION_PERIODICAL_DISCOVERY_ALARM); 453 intent.setClass(mContext, AlarmBroadcastReceiver.class); 454 intent.putExtra("pollingType", type); 455 456 mDiscoveryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 457 PendingIntent.FLAG_UPDATE_CURRENT); 458 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 459 SystemClock.elapsedRealtime() + msec, mDiscoveryAlarmIntent); 460 461 mNextPollingTimeStamp = nextTime; 462 } 463 doCapabilityDiscovery(int type)464 private synchronized void doCapabilityDiscovery(int type) { 465 logger.print("doCapabilityDiscovery type=" + type); 466 if (!isPollingReady()) { 467 logger.debug("doCapabilityDiscovery isPollingReady=false"); 468 return; 469 } 470 471 long delay = 0; 472 List<Contacts.Item> list = null; 473 474 initialise(); 475 476 mNextPollingTimeStamp = 0L; 477 Cursor cursor = null; 478 EABContactManager.Query baseQuery = new EABContactManager.Query() 479 .orderBy(EABContactManager.COLUMN_LAST_UPDATED_TIMESTAMP, 480 EABContactManager.Query.ORDER_ASCENDING); 481 try { 482 logger.debug("doCapabilityDiscovery.query:\n" + baseQuery); 483 cursor = mEABContactManager.query(baseQuery); 484 if (cursor == null) { 485 logger.print("Cursor is null, there is no database found."); 486 return; 487 } 488 int count = cursor.getCount(); 489 if (count == 0) { 490 logger.print("Cursor.getCount() is 0, there is no items found in db."); 491 return; 492 } 493 494 list = new ArrayList<Contacts.Item>(); 495 list.clear(); 496 497 long current = System.currentTimeMillis(); 498 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 499 long id = cursor.getLong(cursor.getColumnIndex(Contacts.Impl._ID)); 500 long last = cursor.getLong(cursor.getColumnIndex( 501 Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP)); 502 503 Contacts.Item item = new Contacts.Item(id); 504 item.setLastUpdateTime(last); 505 item.setNumber(cursor.getString( 506 cursor.getColumnIndex(Contacts.Impl.CONTACT_NUMBER))); 507 item.setName(cursor.getString( 508 cursor.getColumnIndex(Contacts.Impl.CONTACT_NAME))); 509 item.setVolteTimestamp(cursor.getLong( 510 cursor.getColumnIndex(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP))); 511 item.setVideoTimestamp(cursor.getLong( 512 cursor.getColumnIndex(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP))); 513 514 if ((current - last < 0) || 515 (current - last >= mCapabilityPollInterval - mMinCapabilityPollInterval)) { 516 logger.print("This item will be updated:\n" 517 + item); 518 if (item.isValid()) { 519 list.add(item); 520 } 521 } else { 522 logger.print("The first item which will be updated next time:\n" + item); 523 delay = randomCapabilityPollInterval() - (current - last); 524 if (delay > 0) { 525 break; 526 } 527 } 528 } 529 } catch (Exception ex) { 530 logger.warn("Exception in doCapabilityDiscovery: " + ex); 531 if (delay <= 0) { 532 delay = 5 * 60 * 1000; 533 } 534 } finally { 535 if (cursor != null) { 536 cursor.close(); 537 } 538 } 539 540 if (delay <= 0) { 541 delay = randomCapabilityPollInterval(); 542 } 543 logger.print("Polling delay: " + delay); 544 schedulePolling(delay, ACTION_POLLING_NORMAL); 545 546 updateObsoleteItems(); 547 548 if ((list != null) && (list.size() > 0)) { 549 PollingsQueue queue = PollingsQueue.getInstance(mContext); 550 if (queue != null) { 551 queue.setCapabilityPolling(this); 552 queue.add(type, list); 553 } 554 } 555 } 556 randomCapabilityPollInterval()557 private long randomCapabilityPollInterval() { 558 double random = Math.random() * 0.2 + 0.9; 559 logger.print("The random for this time polling is: " + random); 560 random = random * mCapabilityPollInterval; 561 return (long)random; 562 } 563 updateObsoleteItems()564 private void updateObsoleteItems() { 565 long current = System.currentTimeMillis(); 566 long last = current - mCapabilityCacheExpiration; 567 long last3year = current - 3 * 365 * 24 * 3600000L; 568 StringBuilder sb = new StringBuilder(); 569 sb.append("(("); 570 sb.append(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP + "<='" + last + "'"); 571 sb.append(" OR "); 572 sb.append(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP + "<='" + last + "'"); 573 sb.append(") AND "); 574 sb.append(Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP + ">='" + last3year + "'"); 575 sb.append(")"); 576 EABContactManager.Query baseQuery = new EABContactManager.Query() 577 .setFilterByTime(sb.toString()) 578 .orderBy(EABContactManager.COLUMN_ID, 579 EABContactManager.Query.ORDER_ASCENDING); 580 581 Cursor cursor = null; 582 List<Contacts.Item> list = null; 583 try { 584 logger.debug("updateObsoleteItems.query:\n" + baseQuery); 585 cursor = mEABContactManager.query(baseQuery); 586 if (cursor == null) { 587 logger.print("Cursor is null, there is no database found."); 588 return; 589 } 590 int count = cursor.getCount(); 591 if (count == 0) { 592 logger.print("Cursor.getCount() is 0, there is no obsolete items found."); 593 return; 594 } 595 596 list = new ArrayList<Contacts.Item>(); 597 list.clear(); 598 599 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 600 long id = cursor.getLong(cursor.getColumnIndex(Contacts.Impl._ID)); 601 602 Contacts.Item item = new Contacts.Item(id); 603 item.setLastUpdateTime(cursor.getLong( 604 cursor.getColumnIndex(Contacts.Impl.CONTACT_LAST_UPDATED_TIMESTAMP))); 605 item.setNumber(cursor.getString( 606 cursor.getColumnIndex(Contacts.Impl.CONTACT_NUMBER))); 607 item.setName(cursor.getString( 608 cursor.getColumnIndex(Contacts.Impl.CONTACT_NAME))); 609 item.setVolteTimestamp(cursor.getLong( 610 cursor.getColumnIndex(Contacts.Impl.VOLTE_CALL_CAPABILITY_TIMESTAMP))); 611 item.setVideoTimestamp(cursor.getLong( 612 cursor.getColumnIndex(Contacts.Impl.VIDEO_CALL_CAPABILITY_TIMESTAMP))); 613 logger.print("updateObsoleteItems, the obsolete item:\n" + item); 614 615 if ((item.lastUpdateTime() > 0) && item.isValid()) { 616 list.add(item); 617 } 618 } 619 } catch (Exception ex) { 620 logger.warn("Exception in updateObsoleteItems: " + ex); 621 } finally { 622 if (cursor != null) { 623 cursor.close(); 624 } 625 } 626 627 if ((list == null) || (list.size() <= 0)) { 628 return; 629 } 630 631 for (Contacts.Item item : list) { 632 EABContactManager.Request request = new EABContactManager.Request(item.id()); 633 if (item.volteTimestamp() <= last) { 634 request.setVolteCallCapability(false); 635 request.setVolteCallCapabilityTimeStamp(current); 636 } 637 if (item.videoTimestamp() <= last) { 638 request.setVideoCallCapability(false); 639 request.setVideoCallCapabilityTimeStamp(current); 640 } 641 int result = mEABContactManager.update(request); 642 if (result <= 0) { 643 logger.print("Failed to update this request: " + request); 644 } 645 } 646 } 647 cancelDiscoveryAlarm()648 private void cancelDiscoveryAlarm() { 649 if (mDiscoveryAlarmIntent != null) { 650 mAlarmManager.cancel(mDiscoveryAlarmIntent); 651 mDiscoveryAlarmIntent = null; 652 mNextPollingTimeStamp = 0L; 653 } 654 } 655 clearPollingTasks()656 private void clearPollingTasks() { 657 PollingsQueue queue = PollingsQueue.getInstance(null); 658 if (queue != null) { 659 queue.clear(); 660 } 661 } 662 getTimeString(long time)663 private String getTimeString(long time) { 664 if (time <= 0) { 665 time = System.currentTimeMillis(); 666 } 667 668 Time tobj = new Time(); 669 tobj.set(time); 670 return String.format("%s.%s", tobj.format("%m-%d %H:%M:%S"), time % 1000); 671 } 672 673 private static final int MSG_CHECK_DISCOVERY = 1; 674 private static final int MSG_NEW_CONTACT_ADDED = 2; 675 private static final int MSG_SERVICE_STATUS_CHANGED = 3; 676 private static final int MSG_SETTINGS_CHANGED = 4; 677 private static final int MSG_PUBLISH_STATE_CHANGED = 5; 678 private static final int MSG_SIM_LOADED = 6; 679 private static final int MSG_PROVISION_STATE_CHANGED = 7; 680 private static final int MSG_VERIFY_POLLING_RESULT = 8; 681 enqueueDiscovery(int type)682 public void enqueueDiscovery(int type) { 683 mDiscoveryHandler.removeMessages(MSG_CHECK_DISCOVERY); 684 mDiscoveryHandler.obtainMessage(MSG_CHECK_DISCOVERY, type, -1).sendToTarget(); 685 } 686 enqueueNewContact(String number)687 public void enqueueNewContact(String number) { 688 mDiscoveryHandler.obtainMessage(MSG_NEW_CONTACT_ADDED, number).sendToTarget(); 689 } 690 enqueueServiceStatusChanged(boolean enabled)691 private void enqueueServiceStatusChanged(boolean enabled) { 692 mDiscoveryHandler.removeMessages(MSG_SERVICE_STATUS_CHANGED); 693 mDiscoveryHandler.obtainMessage(MSG_SERVICE_STATUS_CHANGED, 694 enabled ? 1 : 0, -1).sendToTarget(); 695 } 696 enqueuePublishStateChanged(int state)697 private void enqueuePublishStateChanged(int state) { 698 mDiscoveryHandler.removeMessages(MSG_PUBLISH_STATE_CHANGED); 699 mDiscoveryHandler.obtainMessage(MSG_PUBLISH_STATE_CHANGED, 700 state, -1).sendToTarget(); 701 } 702 enqueueSettingsChanged()703 public void enqueueSettingsChanged() { 704 mDiscoveryHandler.removeMessages(MSG_SETTINGS_CHANGED); 705 mDiscoveryHandler.obtainMessage(MSG_SETTINGS_CHANGED).sendToTarget(); 706 } 707 enqueueSimLoaded()708 private void enqueueSimLoaded() { 709 mDiscoveryHandler.removeMessages(MSG_SIM_LOADED); 710 mDiscoveryHandler.obtainMessage(MSG_SIM_LOADED).sendToTarget(); 711 } 712 enqueueProvisionStateChanged()713 private void enqueueProvisionStateChanged() { 714 mDiscoveryHandler.removeMessages(MSG_PROVISION_STATE_CHANGED); 715 mDiscoveryHandler.obtainMessage(MSG_PROVISION_STATE_CHANGED).sendToTarget(); 716 } 717 enqueueVerifyPollingResult(int counts)718 public void enqueueVerifyPollingResult(int counts) { 719 mDiscoveryHandler.removeMessages(MSG_VERIFY_POLLING_RESULT); 720 mDiscoveryHandler.obtainMessage(MSG_VERIFY_POLLING_RESULT, counts, -1).sendToTarget(); 721 } 722 723 private Handler.Callback mDiscoveryCallback = new Handler.Callback() { 724 @Override 725 public boolean handleMessage(Message msg) { 726 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 727 728 if (msg.what == MSG_CHECK_DISCOVERY) { 729 doCapabilityDiscovery(msg.arg1); 730 } else if (msg.what == MSG_NEW_CONTACT_ADDED) { 731 newContactAdded((String)msg.obj); 732 } else if (msg.what == MSG_SERVICE_STATUS_CHANGED) { 733 serviceStatusChanged(msg.arg1 == 1); 734 } else if (msg.what == MSG_PUBLISH_STATE_CHANGED) { 735 publishStateChanged(msg.arg1); 736 } else if (msg.what == MSG_SETTINGS_CHANGED) { 737 settingsChanged(); 738 } else if(msg.what == MSG_SIM_LOADED) { 739 onSimLoaded(); 740 } else if(msg.what == MSG_PROVISION_STATE_CHANGED) { 741 provisionStateChanged(); 742 } else if(msg.what == MSG_VERIFY_POLLING_RESULT) { 743 verifyPollingResult(msg.arg1); 744 } else { 745 } 746 747 return true; 748 } 749 }; 750 onSimLoaded()751 private void onSimLoaded() { 752 PresencePreferences pref = PresencePreferences.getInstance(); 753 if (pref == null) { 754 return; 755 } 756 757 String mdn_old = pref.getLine1Number(); 758 if (TextUtils.isEmpty(mdn_old)) { 759 return; 760 } 761 String subscriberId_old = pref.getSubscriberId(); 762 if (TextUtils.isEmpty(subscriberId_old)) { 763 return; 764 } 765 766 String mdn = getLine1Number(); 767 String subscriberId = getSubscriberId(); 768 if (TextUtils.isEmpty(mdn) && TextUtils.isEmpty(subscriberId)) { 769 return; 770 } 771 772 boolean mdnMatched = false; 773 if (TextUtils.isEmpty(mdn) || PhoneNumberUtils.compare(mdn_old, mdn)) { 774 mdnMatched = true; 775 } 776 boolean subscriberIdMatched = false; 777 if (TextUtils.isEmpty(subscriberId) || subscriberId.equals(subscriberId_old)) { 778 subscriberIdMatched = true; 779 } 780 if (mdnMatched && subscriberIdMatched) { 781 return; 782 } 783 784 logger.print("Remove presence cache for Sim card changed!"); 785 pref.setLine1Number(""); 786 pref.setSubscriberId(""); 787 788 if (mEABContactManager != null) { 789 mEABContactManager.updateAllCapabilityToUnknown(); 790 } 791 } 792 793 private static final int DEFAULT_SUBSCRIPTION = 1; getLine1Number()794 private String getLine1Number() { 795 if (mContext == null) { 796 return null; 797 } 798 799 TelephonyManager telephony = (TelephonyManager) 800 mContext.getSystemService(Context.TELEPHONY_SERVICE); 801 if (telephony == null) { 802 return null; 803 } 804 805 String mdn = null; 806 if (TelephonyManager.getDefault().isMultiSimEnabled()) { 807 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 808 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 809 subId = DEFAULT_SUBSCRIPTION; 810 } 811 mdn = telephony.getLine1Number(subId); 812 } else { 813 mdn = telephony.getLine1Number(); 814 } 815 816 if ((mdn == null) || (mdn.length() == 0) || mdn.startsWith("00000")) { 817 return null; 818 } 819 820 logger.print("getLine1Number: " + mdn); 821 return mdn; 822 } 823 getSubscriberId()824 private String getSubscriberId() { 825 if (mContext == null) { 826 return null; 827 } 828 829 TelephonyManager telephony = (TelephonyManager) 830 mContext.getSystemService(Context.TELEPHONY_SERVICE); 831 if (telephony == null) { 832 return null; 833 } 834 835 String subscriberId = null; 836 if (TelephonyManager.getDefault().isMultiSimEnabled()) { 837 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 838 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 839 subId = DEFAULT_SUBSCRIPTION; 840 } 841 subscriberId = telephony.getSubscriberId(subId); 842 } else { 843 subscriberId = telephony.getSubscriberId(); 844 } 845 846 logger.print("getSubscriberId: " + subscriberId); 847 return subscriberId; 848 } 849 } 850