1ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville/*
2ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * Copyright (C) 2013 The Android Open Source Project
3ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville *
4ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * you may not use this file except in compliance with the License.
6ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * You may obtain a copy of the License at
7ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville *
8ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville *
10ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * Unless required by applicable law or agreed to in writing, software
11ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * See the License for the specific language governing permissions and
14ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * limitations under the License.
15ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville */
16ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savillepackage com.android.internal.telephony.dataconnection;
17ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
18ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.app.AlarmManager;
19ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.app.PendingIntent;
20ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.content.BroadcastReceiver;
21ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.content.Context;
22ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.content.Intent;
23ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.content.IntentFilter;
24ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.os.AsyncResult;
25ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.os.SystemClock;
26ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.telephony.Rlog;
27ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport android.text.TextUtils;
28ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
29ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport com.android.internal.telephony.PhoneBase;
30ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savilleimport com.android.internal.telephony.RILConstants;
31ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
32ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville/**
33ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville * The Data Connection Retry Alarm Controller.
34ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville */
35ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Savillepublic class DcRetryAlarmController {
36ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private String mLogTag = "DcRac";
37ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private static final boolean DBG = true;
38ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
39ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private PhoneBase mPhone;
40ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private DataConnection mDc;
41ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private AlarmManager mAlarmManager;
42ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
43ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    // The Intent action for retrying and its two extra's
44ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private String mActionRetry;
45ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private static final String INTENT_RETRY_ALARM_WHAT = "what";
46ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private static final String INTENT_RETRY_ALARM_TAG = "tag";
47ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
48ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
49ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            @Override
50ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        public void onReceive(Context context, Intent intent) {
51ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            String action = intent.getAction();
52ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (TextUtils.isEmpty(action)) {
53ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                // Our mActionXxxx's could be null when disposed this could match an empty action.
54ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                log("onReceive: ignore empty action='" + action + "'");
55ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                return;
56ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            }
57ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (TextUtils.equals(action, mActionRetry)) {
58ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                if (!intent.hasExtra(INTENT_RETRY_ALARM_WHAT)) {
59ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                    throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_WHAT");
60ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                }
61ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                if (!intent.hasExtra(INTENT_RETRY_ALARM_TAG)) {
62ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                    throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_TAG");
63ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                }
64ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                int what = intent.getIntExtra(INTENT_RETRY_ALARM_WHAT, Integer.MAX_VALUE);
65ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                int tag = intent.getIntExtra(INTENT_RETRY_ALARM_TAG, Integer.MAX_VALUE);
66ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                if (DBG) {
67ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                    log("onReceive: action=" + action
68ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                            + " sendMessage(what:" + mDc.getWhatToString(what)
69ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                            + ", tag:" + tag + ")");
70ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                }
71ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                mDc.sendMessage(mDc.obtainMessage(what, tag, 0));
72ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            } else {
73ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                if (DBG) log("onReceive: unknown action=" + action);
74ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            }
75ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        }
76ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    };
77ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
78ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    DcRetryAlarmController(PhoneBase phone, DataConnection dc) {
79ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mLogTag = dc.getName();
80ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mPhone = phone;
81ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mDc = dc;
82ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mAlarmManager = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
83ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mActionRetry = mDc.getClass().getCanonicalName() + "." + mDc.getName() + ".action_retry";
84ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
85ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        IntentFilter filter = new IntentFilter();
86ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        filter.addAction(mActionRetry);
87ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        log("DcRetryAlarmController: register for intent action=" + mActionRetry);
88ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
89ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mDc.getHandler());
90ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
91ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
92ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    /**
93ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * Dispose of resources when shutting down
94ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     */
95ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    void dispose() {
96ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        if (DBG) log("dispose");
97ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mPhone.getContext().unregisterReceiver(mIntentReceiver);
98ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mPhone = null;
99ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mDc = null;
100ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mAlarmManager = null;
101ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mActionRetry = null;
102ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
103ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
104ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    /**
105ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * Using dc.mRetryManager and the result of the SETUP_DATA_CALL determine
106ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * the retry delay.
107ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     *
108ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * @param dc is the DataConnection
109ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * @param ar is the result from SETUP_DATA_CALL
110ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     * @return < 0 if no retry is needed otherwise the delay to the next SETUP_DATA_CALL
111ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville     */
112ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    int getSuggestedRetryTime(DataConnection dc, AsyncResult ar) {
113ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        int retryDelay;
114ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
115ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        DataCallResponse response = (DataCallResponse) ar.result;
116ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        retryDelay = response.suggestedRetryTime;
117ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        if (retryDelay == RILConstants.MAX_INT) {
118ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is MAX_INT, retry NOT needed");
119ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            retryDelay = -1;
120ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        } else if (retryDelay >= 0) {
121ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is >= 0 use it");
122ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        } else if (dc.mRetryManager.isRetryNeeded()) {
123ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            retryDelay = dc.mRetryManager.getRetryTimer();
124ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (retryDelay < 0) {
125ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                retryDelay = 0;
126ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            }
127ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (DBG) log("getSuggestedRetryTime: retry is needed");
128ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        } else {
129ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            if (DBG) log("getSuggestedRetryTime: retry is NOT needed");
130ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            retryDelay = -1;
131ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        }
132ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
133ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        if (DBG) {
134ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            log("getSuggestedRetryTime: " + retryDelay + " response=" + response + " dc=" + dc);
135ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        }
136ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        return retryDelay;
137ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
138ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
139ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    public void startRetryAlarm(int what, int tag, int delay) {
140ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        Intent intent = new Intent(mActionRetry);
141ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        intent.putExtra(INTENT_RETRY_ALARM_WHAT, what);
142ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        intent.putExtra(INTENT_RETRY_ALARM_TAG, tag);
143ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
144ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        if (DBG) {
145ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville            log("startRetryAlarm: next attempt in " + (delay / 1000) + "s" +
146ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                    " what=" + what + " tag=" + tag);
147ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        }
148ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
149ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        PendingIntent retryIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
150ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                                        intent, PendingIntent.FLAG_UPDATE_CURRENT);
151ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
152ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville                SystemClock.elapsedRealtime() + delay, retryIntent);
153ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
154ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
155ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    @Override
156ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    public String toString() {
157ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        StringBuilder sb = new StringBuilder();
158ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        sb.append(mLogTag).append(" [dcRac] ");
159ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        sb.append(" mPhone=").append(mPhone);
160ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        sb.append(" mDc=").append(mDc);
161ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        sb.append(" mAlaramManager=").append(mAlarmManager);
162ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        sb.append(" mActionRetry=").append(mActionRetry);
163ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        return sb.toString();
164ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
165ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville
166ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    private void log(String s) {
167ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville        Rlog.d(mLogTag, "[dcRac] " + s);
168ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville    }
169ff4e317d24f0d23bdc0f306d53ddc51f2f1ecf6aWink Saville}
170