1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import android.os.AsyncResult;
20import android.os.Handler;
21import android.os.Message;
22import android.os.SystemProperties;
23import android.text.TextUtils;
24import android.util.Log;
25
26import com.android.internal.telephony.CommandException;
27
28import java.io.FileDescriptor;
29import java.io.PrintWriter;
30
31
32/**
33 * {@hide}
34 */
35public abstract class CallTracker extends Handler {
36
37    private static final boolean DBG_POLL = false;
38
39    //***** Constants
40
41    static final int POLL_DELAY_MSEC = 250;
42
43    protected int pendingOperations;
44    protected boolean needsPoll;
45    protected Message lastRelevantPoll;
46
47    public CommandsInterface cm;
48
49
50    //***** Events
51
52    protected static final int EVENT_POLL_CALLS_RESULT             = 1;
53    protected static final int EVENT_CALL_STATE_CHANGE             = 2;
54    protected static final int EVENT_REPOLL_AFTER_DELAY            = 3;
55    protected static final int EVENT_OPERATION_COMPLETE            = 4;
56    protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE      = 5;
57
58    protected static final int EVENT_SWITCH_RESULT                 = 8;
59    protected static final int EVENT_RADIO_AVAILABLE               = 9;
60    protected static final int EVENT_RADIO_NOT_AVAILABLE           = 10;
61    protected static final int EVENT_CONFERENCE_RESULT             = 11;
62    protected static final int EVENT_SEPARATE_RESULT               = 12;
63    protected static final int EVENT_ECT_RESULT                    = 13;
64    protected static final int EVENT_EXIT_ECM_RESPONSE_CDMA        = 14;
65    protected static final int EVENT_CALL_WAITING_INFO_CDMA        = 15;
66    protected static final int EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA = 16;
67
68    protected void pollCallsWhenSafe() {
69        needsPoll = true;
70
71        if (checkNoOperationsPending()) {
72            lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
73            cm.getCurrentCalls(lastRelevantPoll);
74        }
75    }
76
77    protected void
78    pollCallsAfterDelay() {
79        Message msg = obtainMessage();
80
81        msg.what = EVENT_REPOLL_AFTER_DELAY;
82        sendMessageDelayed(msg, POLL_DELAY_MSEC);
83    }
84
85    protected boolean
86    isCommandExceptionRadioNotAvailable(Throwable e) {
87        return e != null && e instanceof CommandException
88                && ((CommandException)e).getCommandError()
89                        == CommandException.Error.RADIO_NOT_AVAILABLE;
90    }
91
92    protected abstract void handlePollCalls(AsyncResult ar);
93
94    protected void handleRadioAvailable() {
95        pollCallsWhenSafe();
96    }
97
98    /**
99     * Obtain a complete message that indicates that this operation
100     * does not require polling of getCurrentCalls(). However, if other
101     * operations that do need getCurrentCalls() are pending or are
102     * scheduled while this operation is pending, the invocation
103     * of getCurrentCalls() will be postponed until this
104     * operation is also complete.
105     */
106    protected Message
107    obtainNoPollCompleteMessage(int what) {
108        pendingOperations++;
109        lastRelevantPoll = null;
110        return obtainMessage(what);
111    }
112
113    /**
114     * @return true if we're idle or there's a call to getCurrentCalls() pending
115     * but nothing else
116     */
117    private boolean
118    checkNoOperationsPending() {
119        if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" +
120                pendingOperations);
121        return pendingOperations == 0;
122    }
123
124    /**
125     * Routine called from dial to check if the number is a test Emergency number
126     * and if so remap the number. This allows a short emergency number to be remapped
127     * to a regular number for testing how the frameworks handles emergency numbers
128     * without actually calling an emergency number.
129     *
130     * This is not a full test and is not a substitute for testing real emergency
131     * numbers but can be useful.
132     *
133     * To use this feature set a system property ril.test.emergencynumber to a pair of
134     * numbers separated by a colon. If the first number matches the number parameter
135     * this routine returns the second number. Example:
136     *
137     * ril.test.emergencynumber=112:1-123-123-45678
138     *
139     * To test Dial 112 take call then hang up on MO device to enter ECM
140     * see RIL#processSolicited RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
141     *
142     * @param number to test if it should be remapped
143     * @return the same number or the remapped number.
144     */
145    protected String checkForTestEmergencyNumber(String dialString) {
146        String testEn = SystemProperties.get("ril.test.emergencynumber");
147        if (DBG_POLL) {
148            log("checkForTestEmergencyNumber: dialString=" + dialString +
149                " testEn=" + testEn);
150        }
151        if (!TextUtils.isEmpty(testEn)) {
152            String values[] = testEn.split(":");
153            log("checkForTestEmergencyNumber: values.length=" + values.length);
154            if (values.length == 2) {
155                if (values[0].equals(
156                        android.telephony.PhoneNumberUtils.stripSeparators(dialString))) {
157                    cm.testingEmergencyCall();
158                    log("checkForTestEmergencyNumber: remap " +
159                            dialString + " to " + values[1]);
160                    dialString = values[1];
161                }
162            }
163        }
164        return dialString;
165    }
166
167    //***** Overridden from Handler
168    public abstract void handleMessage (Message msg);
169    public abstract void registerForVoiceCallStarted(Handler h, int what, Object obj);
170    public abstract void unregisterForVoiceCallStarted(Handler h);
171    public abstract void registerForVoiceCallEnded(Handler h, int what, Object obj);
172    public abstract void unregisterForVoiceCallEnded(Handler h);
173
174    protected abstract void log(String msg);
175
176    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
177        pw.println("CallTracker:");
178        pw.println(" pendingOperations=" + pendingOperations);
179        pw.println(" needsPoll=" + needsPoll);
180        pw.println(" lastRelevantPoll=" + lastRelevantPoll);
181    }
182}
183