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