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 java.util.Set;
32import java.util.HashMap;
33import java.util.List;
34import java.util.ArrayList;
35import android.content.Context;
36import android.content.Intent;
37import android.app.PendingIntent;
38import android.content.IntentFilter;
39import android.os.RemoteException;
40import android.app.AlarmManager;
41import android.os.SystemClock;
42
43import com.android.ims.internal.uce.presence.PresCmdStatus;
44
45import com.android.ims.RcsManager.ResultCode;
46import com.android.ims.RcsPresenceInfo;
47import com.android.ims.IRcsPresenceListener;
48
49import com.android.ims.internal.Logger;
50import com.android.service.ims.TaskManager;
51
52/**
53 * PresenceCapabilityTask
54 */
55public class PresenceCapabilityTask extends PresenceTask{
56    /*
57     * The logger
58     */
59    private Logger logger = Logger.getLogger(this.getClass().getName());
60
61    public static final String ACTION_TASK_TIMEOUT_ALARM =
62            "com.android.service.ims.presence.task.timeout";
63
64    private Context mContext = null;
65
66    // The result code will be used for retry.
67    public int mResultCode;
68
69    // The alarm manager.
70    static AlarmManager sAlarmManager = null;
71    PendingIntent mAlarmIntent = null;
72    boolean mTimerStarted = false;
73
74    // it will be set to true after got sip response.
75    public boolean mWaitingForNotify;
76
77    // The time when created the task.
78    private long mCreatedTimeStamp;
79
80    private long mTimeout;
81
82    public PresenceCapabilityTask(Context context, int taskId, int cmdId,
83            IRcsPresenceListener listener, String[] contacts,
84            long timeout){
85        super(taskId, cmdId, listener, contacts);
86        mContext = context;
87        mWaitingForNotify = false;
88
89        mCreatedTimeStamp = System.currentTimeMillis();
90        mTimeout = timeout;
91
92        if(mTimeout <=0){
93            // The terminal notification may be received shortly after the time limit of
94            // the subscription due to network delays or retransmissions.
95            // Device shall wait for 3sec after the end of the subscription period in order to
96            // accept such notifications without returning spurious errors (e.g. SIP 481).
97            mTimeout = 36000;
98        }
99
100        if(listener != null){
101            startTimer();
102        } //else it will be removed after got sip response.
103    }
104
105    public String toString(){
106        return super.toString() +
107                " mCreatedTimeStamp=" + mCreatedTimeStamp +
108                " mTimeout=" + mTimeout;
109    }
110
111    private void startTimer(){
112        if(mContext == null){
113            logger.error("startTimer mContext is null");
114            return;
115        }
116
117        Intent intent = new Intent(ACTION_TASK_TIMEOUT_ALARM);
118        intent.setClass(mContext, AlarmBroadcastReceiver.class);
119        intent.putExtra("taskId", mTaskId);
120        PendingIntent mAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
121                PendingIntent.FLAG_ONE_SHOT);
122
123        if(sAlarmManager == null){
124            sAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
125        }
126
127        long triggerAt = SystemClock.elapsedRealtime() + mTimeout;
128        logger.debug("startTimer taskId=" + mTaskId + " mTimeout=" + mTimeout +
129                " triggerAt=" + triggerAt + " mAlarmIntent=" + mAlarmIntent);
130        sAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt, mAlarmIntent);
131        mTimerStarted = true;
132    }
133
134    public void cancelTimer(){
135        if(mTimerStarted){
136            logger.debug("cancelTimer, taskId=" + mTaskId);
137            if(mAlarmIntent != null && sAlarmManager != null) {
138                sAlarmManager.cancel(mAlarmIntent);
139            }
140            mTimerStarted = false;
141        }
142    }
143
144    public void onTimeout(){
145        logger.debug("onTimeout, taskId=" + mTaskId);
146        try{
147            if(mListener != null){
148                mListener.onTimeout(mTaskId);
149            }
150        }catch (RemoteException e){
151            logger.error("RemoteException", e);
152        }
153
154        TaskManager.getDefault().removeTask(mTaskId);
155    }
156
157    public void setWaitingForNotify(boolean waitingForNotify){
158        mWaitingForNotify = waitingForNotify;
159    }
160
161    public boolean isWaitingForNotify(){
162        return mWaitingForNotify;
163    }
164
165    public void onTerminated(String reason){
166        if(!mWaitingForNotify){
167            logger.debug("onTerminated mWaitingForNotify is false. task=" + this);
168            return;
169        }
170
171        cancelTimer();
172        try{
173            if(mListener != null){
174                mListener.onFinish(mTaskId);
175            }
176        }catch (RemoteException e){
177            logger.error("RemoteException", e);
178        }
179
180        TaskManager.getDefault().removeTask(mTaskId);
181    }
182};
183
184