/* * Copyright (c) 2015, Motorola Mobility LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of Motorola Mobility nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package com.android.service.ims.presence; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.SystemClock; import android.text.format.TimeMigrationUtils; import com.android.ims.internal.Logger; import java.util.ArrayList; import java.util.List; public class PollingTask { private Logger logger = Logger.getLogger(this.getClass().getName()); private Context mContext = null; private static long sMaxId = 0; public static final String ACTION_POLLING_RETRY_ALARM = "com.android.service.ims.presence.capability_polling_retry"; private PendingIntent mRetryAlarmIntent = null; public long mId; public int mType; public List mContacts = new ArrayList(); public int mSubId; private long mTimeUnit; private int mTotalRetry; private int mCurrentRetry; private long mLastUpdateTime; private boolean mCancelled = false; private boolean mCompleted = false; public PollingTask(int type, List list, int subId) { mId = sMaxId++; mType = type; mSubId = subId; mContacts.clear(); for(int i = 0; i < list.size(); i++) { Contacts.Item item = list.get(i); mContacts.add(item); } mCurrentRetry = 0; mTotalRetry = 5; mTimeUnit = 1800; // 1800s = 30 minutes if (CapabilityPolling.ACTION_POLLING_NEW_CONTACTS == mType) { mTotalRetry = 4; mTimeUnit = 60; // 60s = 1 minute } mLastUpdateTime = 0; } public void execute() { PollingsQueue queue = PollingsQueue.getInstance(null); if (queue == null) { return; } PollingAction action = new PollingAction(queue.getContext(), this); action.execute(); } public void finish(boolean fullUpdated) { cancelRetryAlarm(); PollingsQueue queue = PollingsQueue.getInstance(null); if (queue == null) { return; } mCompleted = fullUpdated ? true : false; queue.remove(this); } public void retry() { mCurrentRetry += 1; logger.print("retry mCurrentRetry=" + mCurrentRetry); if (mCurrentRetry > mTotalRetry) { logger.print("Retry finished for task: " + this); updateTimeStampToCurrent(); finish(false); return; } if (mCancelled) { logger.print("Task is cancelled: " + this); finish(false); return; } long delay = mTimeUnit; for (int i = 0; i < mCurrentRetry - 1; i++) { delay *= 2; } logger.print("retry delay=" + delay); scheduleRetry(delay * 1000); } public void cancel() { mCancelled = true; logger.print("Cancel this task: " + this); if (mRetryAlarmIntent != null) { cancelRetryAlarm(); finish(false); } } public void onPreExecute() { logger.print("onPreExecute(), id = " + mId); cancelRetryAlarm(); } public void onPostExecute(int result) { logger.print("onPostExecute(), result = " + result); mLastUpdateTime = System.currentTimeMillis(); } private void updateTimeStampToCurrent() { if (mContext == null) { return; } EABContactManager contactManager = new EABContactManager( mContext.getContentResolver(), mContext.getPackageName()); for (int i = 0; i < mContacts.size(); i++) { Contacts.Item item = mContacts.get(i); String number = item.number(); long current = System.currentTimeMillis(); EABContactManager.Request request = new EABContactManager.Request(number) .setLastUpdatedTimeStamp(current); int result = contactManager.update(request); if (result <= 0) { logger.debug("failed to update timestamp for contact: "); } } } private void cancelRetryAlarm() { if (mRetryAlarmIntent != null) { if (mContext != null) { AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(mRetryAlarmIntent); } mRetryAlarmIntent = null; } } private void scheduleRetry(long msec) { logger.print("scheduleRetry msec=" + msec); cancelRetryAlarm(); if (mContext == null) { PollingsQueue queue = PollingsQueue.getInstance(null); if (queue != null) { mContext = queue.getContext(); } } if (mContext != null) { Intent intent = new Intent(ACTION_POLLING_RETRY_ALARM); intent.setClass(mContext, AlarmBroadcastReceiver.class); intent.putExtra("pollingTaskId", mId); mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + msec, mRetryAlarmIntent); } } private String getTimeString(long time) { if (time <= 0) { time = System.currentTimeMillis(); } String timeString = TimeMigrationUtils.formatMillisWithFixedFormat(time); return String.format("%s.%s", timeString, time % 1000); } public boolean isCompleted() { return mCompleted; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PollingTask)) return false; PollingTask that = (PollingTask)o; return (this.mId == that.mId) && (this.mType == that.mType); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("PollingTask { "); sb.append("\nId: " + mId); sb.append("\nType: " + mType); sb.append("\nCurrentRetry: " + mCurrentRetry); sb.append("\nTotalRetry: " + mTotalRetry); sb.append("\nTimeUnit: " + mTimeUnit); sb.append("\nLast update time: " + mLastUpdateTime + "(" + getTimeString(mLastUpdateTime) + ")"); sb.append("\nContacts: " + mContacts.size()); for (int i = 0; i < mContacts.size(); i++) { sb.append("\n"); Contacts.Item item = mContacts.get(i); sb.append("Number " + i + ": " + Logger.hidePhoneNumberPii(item.number())); } sb.append("\nCompleted: " + mCompleted); sb.append(" }"); return sb.toString(); } }