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 29package com.android.service.ims.presence; 30 31import android.app.AlarmManager; 32import android.app.PendingIntent; 33import android.content.Context; 34import android.content.Intent; 35import android.os.SystemClock; 36import android.text.format.Time; 37 38import com.android.ims.internal.Logger; 39 40import java.util.ArrayList; 41import java.util.List; 42 43public class PollingTask { 44 private Logger logger = Logger.getLogger(this.getClass().getName()); 45 private Context mContext = null; 46 47 private static long sMaxId = 0; 48 public static final String ACTION_POLLING_RETRY_ALARM = 49 "com.android.service.ims.presence.capability_polling_retry"; 50 private PendingIntent mRetryAlarmIntent = null; 51 52 public long mId; 53 public int mType; 54 public List<Contacts.Item> mContacts = new ArrayList<Contacts.Item>(); 55 56 private long mTimeUnit; 57 private int mTotalRetry; 58 private int mCurrentRetry; 59 private long mLastUpdateTime; 60 61 private boolean mCancelled = false; 62 private boolean mCompleted = false; 63 64 public PollingTask(int type, List<Contacts.Item> list) { 65 mId = sMaxId++; 66 mType = type; 67 68 mContacts.clear(); 69 for(int i = 0; i < list.size(); i++) { 70 Contacts.Item item = list.get(i); 71 mContacts.add(item); 72 } 73 74 mCurrentRetry = 0; 75 mTotalRetry = 5; 76 mTimeUnit = 1800; // 1800s = 30 minutes 77 if (CapabilityPolling.ACTION_POLLING_NEW_CONTACTS == mType) { 78 mTotalRetry = 4; 79 mTimeUnit = 60; // 60s = 1 minute 80 } 81 mLastUpdateTime = 0; 82 } 83 84 public void execute() { 85 PollingsQueue queue = PollingsQueue.getInstance(null); 86 if (queue == null) { 87 return; 88 } 89 90 PollingAction action = new PollingAction(queue.getContext(), this); 91 action.execute(); 92 } 93 94 public void finish(boolean fullUpdated) { 95 cancelRetryAlarm(); 96 97 PollingsQueue queue = PollingsQueue.getInstance(null); 98 if (queue == null) { 99 return; 100 } 101 102 mCompleted = fullUpdated ? true : false; 103 queue.remove(this); 104 } 105 106 public void retry() { 107 mCurrentRetry += 1; 108 logger.print("retry mCurrentRetry=" + mCurrentRetry); 109 if (mCurrentRetry > mTotalRetry) { 110 logger.print("Retry finished for task: " + this); 111 updateTimeStampToCurrent(); 112 finish(false); 113 return; 114 } 115 116 if (mCancelled) { 117 logger.print("Task is cancelled: " + this); 118 finish(false); 119 return; 120 } 121 122 long delay = mTimeUnit; 123 for (int i = 0; i < mCurrentRetry - 1; i++) { 124 delay *= 2; 125 } 126 127 logger.print("retry delay=" + delay); 128 129 scheduleRetry(delay * 1000); 130 } 131 132 public void cancel() { 133 mCancelled = true; 134 logger.print("Cancel this task: " + this); 135 136 if (mRetryAlarmIntent != null) { 137 cancelRetryAlarm(); 138 finish(false); 139 } 140 } 141 142 public void onPreExecute() { 143 logger.print("onPreExecute(), id = " + mId); 144 cancelRetryAlarm(); 145 } 146 147 public void onPostExecute(int result) { 148 logger.print("onPostExecute(), result = " + result); 149 mLastUpdateTime = System.currentTimeMillis(); 150 } 151 152 private void updateTimeStampToCurrent() { 153 if (mContext == null) { 154 return; 155 } 156 157 EABContactManager contactManager = new EABContactManager( 158 mContext.getContentResolver(), mContext.getPackageName()); 159 for (int i = 0; i < mContacts.size(); i++) { 160 Contacts.Item item = mContacts.get(i); 161 162 String number = item.number(); 163 long current = System.currentTimeMillis(); 164 EABContactManager.Request request = new EABContactManager.Request(number) 165 .setLastUpdatedTimeStamp(current); 166 int result = contactManager.update(request); 167 if (result <= 0) { 168 logger.debug("failed to update timestamp for contact: "); 169 } 170 } 171 } 172 173 private void cancelRetryAlarm() { 174 if (mRetryAlarmIntent != null) { 175 if (mContext != null) { 176 AlarmManager alarmManager = (AlarmManager) 177 mContext.getSystemService(Context.ALARM_SERVICE); 178 alarmManager.cancel(mRetryAlarmIntent); 179 } 180 mRetryAlarmIntent = null; 181 } 182 } 183 184 private void scheduleRetry(long msec) { 185 logger.print("scheduleRetry msec=" + msec); 186 187 cancelRetryAlarm(); 188 189 if (mContext == null) { 190 PollingsQueue queue = PollingsQueue.getInstance(null); 191 if (queue != null) { 192 mContext = queue.getContext(); 193 } 194 } 195 196 if (mContext != null) { 197 Intent intent = new Intent(ACTION_POLLING_RETRY_ALARM); 198 intent.setClass(mContext, AlarmBroadcastReceiver.class); 199 intent.putExtra("pollingTaskId", mId); 200 201 mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 202 PendingIntent.FLAG_UPDATE_CURRENT); 203 204 AlarmManager alarmManager = (AlarmManager) 205 mContext.getSystemService(Context.ALARM_SERVICE); 206 alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 207 SystemClock.elapsedRealtime() + msec, mRetryAlarmIntent); 208 } 209 } 210 211 private String getTimeString(long time) { 212 if (time <= 0) { 213 time = System.currentTimeMillis(); 214 } 215 216 Time tobj = new Time(); 217 tobj.set(time); 218 return String.format("%s.%s", tobj.format("%m-%d %H:%M:%S"), time % 1000); 219 } 220 221 public boolean isCompleted() { 222 return mCompleted; 223 } 224 225 @Override 226 public boolean equals(Object o) { 227 if (this == o) return true; 228 if (!(o instanceof PollingTask)) return false; 229 230 PollingTask that = (PollingTask)o; 231 return (this.mId == that.mId) && (this.mType == that.mType); 232 } 233 234 @Override 235 public String toString() { 236 StringBuilder sb = new StringBuilder(); 237 sb.append("PollingTask { "); 238 sb.append("\nId: " + mId); 239 sb.append("\nType: " + mType); 240 sb.append("\nCurrentRetry: " + mCurrentRetry); 241 sb.append("\nTotalRetry: " + mTotalRetry); 242 sb.append("\nTimeUnit: " + mTimeUnit); 243 sb.append("\nLast update time: " + mLastUpdateTime + "(" + 244 getTimeString(mLastUpdateTime) + ")"); 245 sb.append("\nContacts: " + mContacts.size()); 246 for (int i = 0; i < mContacts.size(); i++) { 247 sb.append("\n"); 248 Contacts.Item item = mContacts.get(i); 249 sb.append("Number " + i + ": " + Logger.hidePhoneNumberPii(item.number())); 250 } 251 sb.append("\nCompleted: " + mCompleted); 252 sb.append(" }"); 253 return sb.toString(); 254 } 255} 256 257