PhoneUtils.java revision f8396c51f11b1044d236415f2ee88750b4e40e1f
1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/*
2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License.
6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at
7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and
14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License.
15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone;
18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
19b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.app.AlertDialog;
20b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.app.Dialog;
21b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.app.ProgressDialog;
22404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.content.ComponentName;
233d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Cataniaimport android.content.ContentResolver;
24b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.DialogInterface;
26b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
27404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.content.ServiceConnection;
282cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Cataniaimport android.content.pm.ApplicationInfo;
292cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Cataniaimport android.content.pm.PackageManager;
305e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Cataniaimport android.graphics.drawable.Drawable;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.AsyncResult;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler;
35404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.os.IBinder;
36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message;
37404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport android.os.RemoteException;
38aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brownimport android.os.SystemProperties;
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.TextUtils;
41b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.KeyEvent;
43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.LayoutInflater;
44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.View;
45b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.WindowManager;
46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.EditText;
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.Toast;
48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
49a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.Call;
50a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.CallStateException;
51a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.CallerInfo;
52a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.CallerInfoAsyncQuery;
53a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.Connection;
54404edc94de563aef5fd5ba48be9114a970cb93bbWink Savilleimport com.android.internal.telephony.IExtendedNetworkService;
55a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.MmiCode;
56a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Savilleimport com.android.internal.telephony.Phone;
57aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brownimport com.android.internal.telephony.TelephonyProperties;
583d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Cataniaimport com.android.internal.telephony.cdma.CdmaConnection;
598343169cc89621d46dce86449f5ee1ff5d3a4919John Wangimport com.android.internal.telephony.CallManager;
608343169cc89621d46dce86449f5ee1ff5d3a4919John Wangimport com.android.internal.telephony.sip.SipPhone;
618343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
62a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville
63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.Hashtable;
64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.Iterator;
65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.List;
66a50e10e2efadac960987eaadc0938c6f92d3ee90John Wangimport java.util.ArrayList;
67b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
68b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
69b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Misc utilities for the Phone app.
70b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
71b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class PhoneUtils {
72b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String LOG_TAG = "PhoneUtils";
73796c70c99bc39295bf685061056f06ab8949c742David Brown    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
74796c70c99bc39295bf685061056f06ab8949c742David Brown
75b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Control stack trace for Audio Mode settings */
76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final boolean DBG_SETAUDIOMODE_STACK = false;
77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Identifier for the "Add Call" intent extra. */
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final String ADD_CALL_MODE_KEY = "add_call_mode";
80b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Return codes from placeCall()
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int CALL_STATUS_DIALED = 0;  // The number was successfully dialed
83b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int CALL_STATUS_DIALED_MMI = 1;  // The specified number was an MMI code
84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int CALL_STATUS_FAILED = 2;  // The call failed
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
86b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // State of the Phone's audio modes
87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Each state can move to the other states, but within the state only certain
88b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    //  transitions for AudioManager.setMode() are allowed.
89b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int AUDIO_IDLE = 0;  /** audio behaviour at phone idle */
90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int AUDIO_RINGING = 1;  /** audio behaviour while ringing */
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static final int AUDIO_OFFHOOK = 2;  /** audio behaviour while in call. */
92b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
93b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Speaker state, persisting between wired headset connection events */
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static boolean sIsSpeakerEnabled = false;
95b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
96b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Hash table to store mute (Boolean) values based upon the connection.*/
97b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static Hashtable<Connection, Boolean> sConnectionMuteTable =
98b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        new Hashtable<Connection, Boolean>();
99b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Static handler for the connection/mute tracking */
101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static ConnectionHandler mConnectionHandler;
102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Phone state changed event*/
104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int PHONE_STATE_CHANGED = -1;
105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
10686c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu    /** Define for not a special CNAP string */
10786c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu    private static final int CNAP_SPECIAL_CASE_NO = -1;
10886c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu
1094ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    // Extended network service interface instance
1104ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    private static IExtendedNetworkService mNwService = null;
1114ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    // used to cancel MMI command after 15 seconds timeout for NWService requirement
1124ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    private static Message mMmiTimeoutCbMsg = null;
1134ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
114055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    /** Noise suppression status as selected by user */
115055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    private static boolean sIsNoiseSuppressionEnabled = true;
116055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Handler that tracks the connections and updates the value of the
119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Mute settings for each connection as needed.
120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static class ConnectionHandler extends Handler {
122153b94130a5e7a0e7bb17f17ce8f1ed294453d9eDmitri Plotnikov        @Override
123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public void handleMessage(Message msg) {
124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AsyncResult ar = (AsyncResult) msg.obj;
125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (msg.what) {
126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case PHONE_STATE_CHANGED:
127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("ConnectionHandler: updating mute state for each connection");
128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1298343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    CallManager cm = (CallManager) ar.userObj;
1308343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // update the foreground connections, if there are new connections.
132a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // Have to get all foreground calls instead of the active one
133a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // because there may two foreground calls co-exist in shore period
134a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // (a racing condition based on which phone changes firstly)
135a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // Otherwise the connection may get deleted.
136a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    List<Connection> fgConnections = new ArrayList<Connection>();
137a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    for (Call fgCall : cm.getForegroundCalls()) {
138a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        if (!fgCall.isIdle()) {
139a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                            fgConnections.addAll(fgCall.getConnections());
140a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        }
141a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    }
142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    for (Connection cn : fgConnections) {
143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (sConnectionMuteTable.get(cn) == null) {
144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            sConnectionMuteTable.put(cn, Boolean.FALSE);
145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
148a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // mute is connection based operation, we need loop over
149a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // all background calls instead of the first one to update
150a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    // the background connections, if there are new connections.
151a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    List<Connection> bgConnections = new ArrayList<Connection>();
152a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    for (Call bgCall : cm.getBackgroundCalls()) {
153a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        if (!bgCall.isIdle()) {
154a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                            bgConnections.addAll(bgCall.getConnections());
155a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        }
156a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    }
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    for (Connection cn : bgConnections) {
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (sConnectionMuteTable.get(cn) == null) {
159a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                          sConnectionMuteTable.put(cn, Boolean.FALSE);
160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Check to see if there are any lingering connections here
164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // (disconnected connections), use old-school iterators to avoid
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // concurrent modification exceptions.
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Connection cn;
167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    for (Iterator<Connection> cnlist = sConnectionMuteTable.keySet().iterator();
168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            cnlist.hasNext();) {
169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        cn = cnlist.next();
170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (!fgConnections.contains(cn) && !bgConnections.contains(cn)) {
171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            if (DBG) log("connection: " + cn + "not accounted for, removing.");
172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            cnlist.remove();
173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Restore the mute state of the foreground call if we're not IDLE,
177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // otherwise just clear the mute state. This is really saying that
178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // as long as there is one or more connections, we should update
179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // the mute state with the earliest connection on the foreground
180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // call, and that with no connections, we should be back to a
181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // non-mute state.
1828343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    if (cm.getState() != Phone.State.IDLE) {
183a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        restoreMuteState();
184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
185a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        setMuteInternal(cm.getFgPhone(), false);
186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
19219dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh
1934ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
1944ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    private static ServiceConnection ExtendedNetworkServiceConnection = new ServiceConnection() {
1954ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        public void onServiceConnected(ComponentName name, IBinder iBinder) {
1964ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            if (DBG) log("Extended NW onServiceConnected");
1974ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            mNwService = IExtendedNetworkService.Stub.asInterface(iBinder);
1984ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        }
1994ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
2004ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        public void onServiceDisconnected(ComponentName arg0) {
2014ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            if (DBG) log("Extended NW onServiceDisconnected");
2024ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            mNwService = null;
20319dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh        }
2044ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang    };
205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Register the ConnectionHandler with the phone, to receive connection events
208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
2098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    public static void initializeConnectionHandler(CallManager cm) {
210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mConnectionHandler == null) {
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mConnectionHandler = new ConnectionHandler();
212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2148343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        // pass over cm as user.obj
2158343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        cm.registerForPreciseCallStateChanged(mConnectionHandler, PHONE_STATE_CHANGED, cm);
2164ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        // Extended NW service
2174ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        Intent intent = new Intent("com.android.ussd.IExtendedNetworkService");
2188343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        cm.getDefaultPhone().getContext().bindService(intent,
2194ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                ExtendedNetworkServiceConnection, Context.BIND_AUTO_CREATE);
2204ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        if (DBG) log("Extended NW bindService IExtendedNetworkService");
2214ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** This class is never instantiated. */
225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private PhoneUtils() {
226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Answer the currently-ringing call.
230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we answered the call, or false if there wasn't
232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         actually a ringing incoming call, or some other error occurred.
233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @see answerAndEndHolding()
235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @see answerAndEndActive()
236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
2378343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean answerCall(Call ringing) {
238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("answerCall()...");
239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // If the ringer is currently ringing and/or vibrating, stop it
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // right now (before actually answering the call.)
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp.getInstance().getRinger().stopRing();
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean answered = false;
245ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu        PhoneApp app = PhoneApp.getInstance();
2468343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Phone phone = ringing.getPhone();
24779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        boolean phoneIsCdma = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA);
248ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu        BluetoothHandsfree bthf = null;
249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
25079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneIsCdma) {
25105fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu            // Stop any signalInfo tone being played when a Call waiting gets answered
2528343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (ringing.getState() == Call.State.WAITING) {
253329dc035267d5f65f96021e26601df3f7cc57659Peng Zhu                final CallNotifier notifier = app.notifier;
25405fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu                notifier.stopSignalInfoTone();
25505fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu            }
25605fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu        }
25705fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu
2588343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if (ringing != null && ringing.isRinging()) {
2598343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (DBG) log("answerCall: call state = " + ringing.getState());
260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            try {
26179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneIsCdma) {
2620fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    if (app.cdmaPhoneCallState.getCurrentCallState()
2630fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                            == CdmaPhoneCallState.PhoneCallState.IDLE) {
2640fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // This is the FIRST incoming call being answered.
2650fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // Set the Phone Call State to SINGLE_ACTIVE
2660fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        app.cdmaPhoneCallState.setCurrentCallState(
2670fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
2680fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    } else {
2690fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // This is the CALL WAITING call being answered.
2700fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        // Set the Phone Call State to CONF_CALL
2710fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        app.cdmaPhoneCallState.setCurrentCallState(
2720fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                                CdmaPhoneCallState.PhoneCallState.CONF_CALL);
27339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                        // Enable "Add Call" option after answering a Call Waiting as the user
27439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                        // should be allowed to add another call in case one of the parties
27539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                        // drops off
27639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                        app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
277c9d9ed30aa547b79b81adc13a4d148a003b6ee62w
278c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        // If a BluetoothHandsfree is valid we need to set the second call state
279c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        // so that the Bluetooth client can update the Call state correctly when
280c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        // a call waiting is answered from the Phone.
281ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                        bthf = app.getBluetoothHandsfree();
282c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        if (bthf != null) {
283c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                            bthf.cdmaSetSecondCallState(true);
284c9d9ed30aa547b79b81adc13a4d148a003b6ee62w                        }
2850fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    }
2860fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                }
28762b318a7a708e464b1fc13692feeef88860064cdPeng Zhu
28862b318a7a708e464b1fc13692feeef88860064cdPeng Zhu                //if (DBG) log("sPhone.acceptCall");
2898343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                PhoneApp.getInstance().mCM.acceptCall(ringing);
29062b318a7a708e464b1fc13692feeef88860064cdPeng Zhu                answered = true;
2918343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
2928343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                // Always reset to "unmuted" for a freshly-answered call
293a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                setMute(false);
2948343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
295a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan                setAudioMode();
2962eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu
2972eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                // Check is phone in any dock, and turn on speaker accordingly
2982eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                activateSpeakerIfDocked(phone);
299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } catch (CallStateException ex) {
300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Log.w(LOG_TAG, "answerCall: caught " + ex, ex);
301ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu
30279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneIsCdma) {
303ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                    // restore the cdmaPhoneCallState and bthf.cdmaSetSecondCallState:
304ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                    app.cdmaPhoneCallState.setCurrentCallState(
305ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                            app.cdmaPhoneCallState.getPreviousCallState());
306ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                    if (bthf != null) {
307ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                        bthf.cdmaSetSecondCallState(false);
308ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                    }
309ada76244191b2bb56fe8911d503c91f241083d80Peng Zhu                }
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return answered;
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Smart "hang up" helper method which hangs up exactly one connection,
317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * based on the current Phone state, as follows:
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <ul>
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <li>If there's a ringing call, hang that up.
320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <li>Else if there's a foreground call, hang that up.
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <li>Else if there's a background call, hang that up.
322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <li>Otherwise do nothing.
323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * </ul>
324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we successfully hung up, or false
325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *              if there were no active calls at all.
326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
3278343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean hangup(CallManager cm) {
328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean hungup = false;
3298343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call ringing = cm.getFirstActiveRingingCall();
3308343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call fg = cm.getActiveFgCall();
3318343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call bg = cm.getFirstActiveBgCall();
332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!ringing.isIdle()) {
334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("HANGUP ringing call");
3358343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            hungup = hangupRingingCall(ringing);
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (!fg.isIdle()) {
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("HANGUP foreground call");
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            hungup = hangup(fg);
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (!bg.isIdle()) {
340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("HANGUP background call");
341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            hungup = hangup(bg);
342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("hungup=" + hungup);
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return hungup;
347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3498343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean hangupRingingCall(Call ringing) {
350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("hangup ringing call");
3518343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        int phoneType = ringing.getPhone().getPhoneType();
3527fe7f7e57aaa38290c37ab48867d34a279d198f3w
35379b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
3547fe7f7e57aaa38290c37ab48867d34a279d198f3w            // CDMA: Ringing call and Call waiting hangup is handled differently.
3557fe7f7e57aaa38290c37ab48867d34a279d198f3w            // For Call waiting we DO NOT call the conventional hangup(call) function
3567fe7f7e57aaa38290c37ab48867d34a279d198f3w            // as in CDMA we just want to hungup the Call waiting connection.
357fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            Call.State state = ringing.getState();
358fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            if (state == Call.State.INCOMING) {
3597fe7f7e57aaa38290c37ab48867d34a279d198f3w                if (DBG) log("hangup ringing call");
3607fe7f7e57aaa38290c37ab48867d34a279d198f3w                return hangup(ringing);
361fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            } else if (state == Call.State.WAITING) {
3627fe7f7e57aaa38290c37ab48867d34a279d198f3w                if (DBG) log("hangup Call waiting call");
3637fe7f7e57aaa38290c37ab48867d34a279d198f3w                final CallNotifier notifier = PhoneApp.getInstance().notifier;
36477350aabae2f056ede7d0df806a9e5a3c22daf7aDavid Brown                notifier.sendCdmaCallWaitingReject();
3657fe7f7e57aaa38290c37ab48867d34a279d198f3w                return true;
366fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            } else {
367fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                // This should never happen cause hangupRingingCall should always be called
368fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                // if the call.isRinging() returns TRUE, which basically means that the call
369fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                // should either be in INCOMING or WAITING state
370fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                if (DBG) log("No Ringing call to hangup");
371fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai                return false;
3727fe7f7e57aaa38290c37ab48867d34a279d198f3w            }
373872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
374872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
3757fe7f7e57aaa38290c37ab48867d34a279d198f3w            // GSM:  Ringing Call and Call waiting, both are hungup by calling
3767fe7f7e57aaa38290c37ab48867d34a279d198f3w            // hangup(call) function.
3777fe7f7e57aaa38290c37ab48867d34a279d198f3w            if (DBG) log("hangup ringing call");
3787fe7f7e57aaa38290c37ab48867d34a279d198f3w            return hangup(ringing);
37979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
38079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            throw new IllegalStateException("Unexpected phone type: " + phoneType);
3817fe7f7e57aaa38290c37ab48867d34a279d198f3w        }
382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3848343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean hangupActiveCall(Call foreground) {
385b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("hangup active call");
3868343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return hangup(foreground);
387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3898343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean hangupHoldingCall(Call background) {
390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("hangup holding call");
3918343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return hangup(background);
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
394bab058c1c34d10f0707cf654e9ed917f631925d1David Brown    /**
395fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai     * Used in CDMA phones to end the complete Call session
396fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai     * @param phone the Phone object.
397fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai     * @return true if *any* call was successfully hung up
398fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai     */
399fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai    static boolean hangupRingingAndActive(Phone phone) {
400fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        boolean hungUpRingingCall = false;
401fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        boolean hungUpFgCall = false;
402fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        Call ringingCall = phone.getRingingCall();
403fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        Call fgCall = phone.getForegroundCall();
404fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai
405fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        // Hang up any Ringing Call
406fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        if (!ringingCall.isIdle()) {
407fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            if (DBG) log("endCallInternal: Hang up Ringing Call");
4088343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            hungUpRingingCall = hangupRingingCall(ringingCall);
409fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        }
410fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai
411fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        // Hang up any Active Call
412fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        if (!fgCall.isIdle()) {
413fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai            if (DBG) log("endCallInternal: Hang up Foreground Call");
4148343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            hungUpFgCall = hangupActiveCall(fgCall);
415fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        }
416fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai
417fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai        return hungUpRingingCall || hungUpFgCall;
418fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai    }
419fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai
420fe3abbbaea34fc41d6fa11f4abf5d69082e313d6Abhishek Pillai    /**
421bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * Trivial wrapper around Call.hangup(), except that we return a
422bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * boolean success code rather than throwing CallStateException on
423bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * failure.
424bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     *
425bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * @return true if the call was successfully hung up, or false
426bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     *         if the call wasn't actually active.
427bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     */
428b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static boolean hangup(Call call) {
429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        try {
430f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang            CallManager cm = PhoneApp.getInstance().mCM;
431f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang
432f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang            if (call.getState() == Call.State.ACTIVE && cm.hasActiveBgCall()) {
433f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang                // handle foreground call hangup while there is background call
434f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang                cm.hangupForegroundResumeBackground(cm.getFirstActiveBgCall());
435f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang            } else {
436f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang                call.hangup();
437f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang            }
438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return true;
439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } catch (CallStateException ex) {
440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.e(LOG_TAG, "Call hangup: caught " + ex, ex);
441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
446bab058c1c34d10f0707cf654e9ed917f631925d1David Brown    /**
447bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * Trivial wrapper around Connection.hangup(), except that we silently
448bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * do nothing (rather than throwing CallStateException) if the
449bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     * connection wasn't actually active.
450bab058c1c34d10f0707cf654e9ed917f631925d1David Brown     */
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static void hangup(Connection c) {
452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        try {
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (c != null) {
454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                c.hangup();
455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } catch (CallStateException ex) {
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.w(LOG_TAG, "Connection hangup: caught " + ex, ex);
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
4618343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean answerAndEndHolding(CallManager cm, Call ringing) {
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("end holding & answer waiting: 1");
4638343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if (!hangupHoldingCall(cm.getFirstActiveBgCall())) {
464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.e(LOG_TAG, "end holding failed!");
465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("end holding & answer waiting: 2");
4698343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return answerCall(ringing);
470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
4738343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static boolean answerAndEndActive(CallManager cm, Call ringing) {
474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("answerAndEndActive()...");
475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Unlike the answerCall() method, we *don't* need to stop the
477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // ringer or change audio modes here since the user is already
478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // in-call, which means that the audio mode is already set
479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // correctly, and that we wouldn't have started the ringer in the
480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // first place.
481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // hanging up the active call also accepts the waiting call
4838343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if ( !hangupActiveCall(cm.getActiveFgCall())) {
4848343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            Log.w(LOG_TAG, "end active call failed!");
4858343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            return false;
4868343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        }
4878343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
4888343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return answerCall(ringing);
489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
4923d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * For a CDMA phone, advance the call state upon making a new
4933d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * outgoing call.
4943d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     *
4953d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * <pre>
4963d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     *   IDLE -> SINGLE_ACTIVE
4973d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * or
4983d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     *   SINGLE_ACTIVE -> THRWAY_ACTIVE
4993d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * </pre>
5003d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * @param app The phone instance.
5013d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     */
5027f63f08c5c88d604abba447032ed42f4f972f3efDavid Brown    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneApp app) {
5033d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        if (app.cdmaPhoneCallState.getCurrentCallState() ==
5043d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            CdmaPhoneCallState.PhoneCallState.IDLE) {
5053d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            // This is the first outgoing call. Set the Phone Call State to ACTIVE
5063d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            app.cdmaPhoneCallState.setCurrentCallState(
5073d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
5083d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        } else {
5093d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            // This is the second outgoing call. Set the Phone Call State to 3WAY
5103d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            app.cdmaPhoneCallState.setCurrentCallState(
5113d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE);
5123d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
5133d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania    }
5143d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
5153d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania    /**
516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Dial the number using the phone passed in.
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param phone the Phone object.
5197a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param number to be dialed as requested by the user.
5207a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param contactRef that triggered the call. Either a 'tel:' or a
5217a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * 'content://contacts' uri depending on how the call was
5227a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * initiated (dialpad vs contact).
523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return either CALL_STATUS_DIALED, CALL_STATUS_DIALED_MMI, or CALL_STATUS_FAILED
524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static int placeCall(Phone phone, String number, Uri contactRef) {
526b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int status = CALL_STATUS_DIALED;
527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        try {
528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("placeCall: '" + number + "'...");
529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
5308343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            Connection cn = PhoneApp.getInstance().mCM.dial(phone, number);
531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("===> phone.dial() returned: " + cn);
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
53379b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            int phoneType = phone.getPhoneType();
53479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink
535fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal            // On GSM phones, null is returned for MMI codes
536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (cn == null) {
53779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneType == Phone.PHONE_TYPE_GSM) {
538fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                    if (DBG) log("dialed MMI code: " + number);
539fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                    status = CALL_STATUS_DIALED_MMI;
540fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                    // Set dialed MMI command to service
541fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                    if (mNwService != null) {
542fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                        try {
543fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                            mNwService.setMmiString(number);
544fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                            if (DBG) log("Extended NW bindService setUssdString (" + number + ")");
545fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                        } catch (RemoteException e) {
546fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                            mNwService = null;
547fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                        }
5484ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                    }
549fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                } else {
550fa3fbeedf018e40f8d6696a382bbf316219cf4aeReli Tal                    status = PhoneUtils.CALL_STATUS_FAILED;
5514ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                }
552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
5530fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                PhoneApp app = PhoneApp.getInstance();
5540fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
55579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                if (phoneType == Phone.PHONE_TYPE_CDMA) {
5563d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania                    updateCdmaCallStateOnNewOutgoingCall(app);
5570fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                }
5580fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // phone.dial() succeeded: we're now in a normal phone call.
560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // attach the URI to the CallerInfo Object if it is there,
561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // otherwise just attach the Uri Reference.
562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the uri does not have a "content" scheme, then we treat
563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // it as if it does NOT have a unique reference.
564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                String content = phone.getContext().getContentResolver().SCHEME_CONTENT;
565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if ((contactRef != null) && (contactRef.getScheme().equals(content))) {
566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    Object userDataObject = cn.getUserData();
567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (userDataObject == null) {
568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        cn.setUserData(contactRef);
569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } else {
5707a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania                        // TODO: This branch is dead code, we have
5717a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania                        // just created the connection 'cn' which has
5727a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania                        // no user data (null) by default.
573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (userDataObject instanceof CallerInfo) {
574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ((CallerInfo) userDataObject).contactRefUri = contactRef;
575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        } else {
576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            ((CallerInfoToken) userDataObject).currentInfo.contactRefUri =
577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                contactRef;
578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
581a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan                setAudioMode();
5822eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu
5832eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                // Check is phone in any dock, and turn on speaker accordingly
5842eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                activateSpeakerIfDocked(phone);
585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } catch (CallStateException ex) {
587d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania            Log.w(LOG_TAG, "Exception from phone.dial()", ex);
588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            status = CALL_STATUS_FAILED;
589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return status;
592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
5947a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    /**
5953d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * Dial the number using a 3rd party provider gateway.  Should
5963d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * *NOT* be called if the number is either:
5973d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * . An emergency one
5983d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * . A GSM MMI code
5993d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * . A CDMA feature code
6003d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * None of the above is  checked in this method, it's the caller's
6013d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * responsability to make sure the number is 'valid'.
6023d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     *
6033d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * If the connection is establised, this method issues a sync call
6043d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * that may block to query the caller info.
6053d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * TODO: Change the logic to use the async query.
6067a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     *
6077a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param phone the Phone object.
6083d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * @param context To perform the CallerInfo query.
6097a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param number to be dialed as requested by the user. This is
6107a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * NOT the phone number to connect to. It is used only to build the
6113d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * call card and to update the call log. See above for restrictions.
6127a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param contactRef that triggered the call. Typically a 'tel:'
6137a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * uri but can also be a 'content://contacts' one.
614d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     * @param gatewayUri Is the address used to setup the connection.
6153d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania     * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
6167a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     */
6173d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania    static int placeCallVia(Context context, Phone phone,
61869f61be83befb4effab14afd62951c9f01233d7bNicolas Catania                            String number, Uri contactRef, Uri gatewayUri) {
619d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        if (DBG) log("placeCallVia: '" + number + "' GW:'" + gatewayUri + "'");
620d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania
621d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // TODO: 'tel' should be a contant defined in framework base
622d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // somewhere (it is in webkit.)
62369f61be83befb4effab14afd62951c9f01233d7bNicolas Catania        if (null == gatewayUri || !"tel".equals(gatewayUri.getScheme())) {
62469f61be83befb4effab14afd62951c9f01233d7bNicolas Catania            Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
625d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania            return CALL_STATUS_FAILED;
626d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        }
6273d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
628d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // We can use getSchemeSpecificPart because we don't allow #
629d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // in the gateway numbers (treated a fragment delim.) However
630d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // if we allow more complex gateway numbers sequence (with
631d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // passwords or whatnot) that use #, this may break.
632d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        // TODO: Need to support MMI codes.
63369f61be83befb4effab14afd62951c9f01233d7bNicolas Catania        String gatewayNumber = gatewayUri.getSchemeSpecificPart();
6343d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        Connection connection;
6353d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        try {
6363d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            connection = phone.dial(gatewayNumber);
6373d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        } catch (CallStateException ex) {
638d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania            Log.e(LOG_TAG, "Exception dialing gateway", ex);
6393d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            connection = null;
6403d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6413d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6423d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        if (null == connection) {
643d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania            Log.e(LOG_TAG, "Got null connection.");
6443d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            return CALL_STATUS_FAILED;
6453d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6463d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6473d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        PhoneApp app = PhoneApp.getInstance();
64879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        boolean phoneIsCdma = (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA);
6493d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
65079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneIsCdma) {
6513d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            updateCdmaCallStateOnNewOutgoingCall(app);
6523d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6533d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6543d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // Clean up the number to be displayed.
65579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneIsCdma) {
6563d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            number = CdmaConnection.formatDialString(number);
6573d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6583d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        number = PhoneNumberUtils.extractNetworkPortion(number);
6593d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
6603d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        number = PhoneNumberUtils.formatNumber(number);
6613d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6623d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // Get the caller info synchronously because we need the final
6633d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // CallerInfo object to update the dialed number with the one
6643d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // requested by the user (and not the provider's gateway number).
6653d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        CallerInfo info = null;
6663d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6673d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        if (ContentResolver.SCHEME_CONTENT.equals(contactRef.getScheme())) {
6683d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            info = CallerInfo.getCallerInfo(context, contactRef);
6693d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6703d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania
6713d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // Fallback, lookup contact using the phone number if the
6723d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // contact's URI scheme was not content:// or if is was but
6733d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        // the lookup failed.
6743d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        if (null == info) {
6753d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania            info = CallerInfo.getCallerInfo(context, number);
6763d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        }
6773d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        info.phoneNumber = number;
6783d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        connection.setUserData(info);
6797a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania
680a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        setAudioMode();
6813d04d787659f87a21e7414b7e13c1d53be6b859fNicolas Catania        return CALL_STATUS_DIALED;
6827a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    }
6837a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania
684008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    /**
685008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * Wrapper function to control when to send an empty Flash command to the network.
686008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * Mainly needed for CDMA networks, such as scenarios when we need to send a blank flash
687008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * to the network prior to placing a 3-way call for it to be successful.
688008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     */
689008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    static void sendEmptyFlash(Phone phone) {
690008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
691008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            Call fgCall = phone.getForegroundCall();
692008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            if (fgCall.getState() == Call.State.ACTIVE) {
693008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                // Send the empty flash
694008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                if (DBG) Log.d(LOG_TAG, "onReceive: (CDMA) sending empty flash to network");
6958343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                switchHoldingAndActive(phone.getBackgroundCall());
696008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            }
697008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman        }
698008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    }
699008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
7008343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    /**
7018343169cc89621d46dce86449f5ee1ff5d3a4919John Wang     * @param heldCall is the background call want to be swapped
7028343169cc89621d46dce86449f5ee1ff5d3a4919John Wang     */
7038343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static void switchHoldingAndActive(Call heldCall) {
704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        try {
705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("switchHoldingAndActive");
7068343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            CallManager cm = PhoneApp.getInstance().mCM;
7078343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (heldCall.isIdle()) {
7088343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                // no heldCall, so it is to hold active call
7098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                cm.switchHoldingAndActive(cm.getFgPhone().getBackgroundCall());
7108343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            } else {
7118343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                // has particular heldCall, so to switch
7128343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                cm.switchHoldingAndActive(heldCall);
7138343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            }
714a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan            setAudioMode(cm);
715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } catch (CallStateException ex) {
716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.w(LOG_TAG, "switchHoldingAndActive: caught " + ex, ex);
717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Restore the mute setting from the earliest connection of the
722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * foreground call.
723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
724a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang    static Boolean restoreMuteState() {
725a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        Phone phone = PhoneApp.getInstance().mCM.getFgPhone();
726a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang
727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //get the earliest connection
728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Connection c = phone.getForegroundCall().getEarliestConnection();
729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // only do this if connection is not null.
731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (c != null) {
732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
73379b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            int phoneType = phone.getPhoneType();
73479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink
735b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // retrieve the mute value.
73602a199cd143518a01b2014c303908b95dfc58afbjsh            Boolean shouldMute = null;
7371f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu
7381f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu            // In CDMA, mute is not maintained per Connection. Single mute apply for
7391f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu            // a call where  call can have multiple connections such as
7401f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu            // Three way and Call Waiting.  Therefore retrieving Mute state for
7411f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu            // latest connection can apply for all connection in that call
7421f2526b75112595d0d7c4c43b98a52f89dfe09d9Peng Zhu            if (phoneType == Phone.PHONE_TYPE_CDMA) {
743c9eddc4caa45b1e39b964a60c4edab9ae6f689cfPaul Berman                shouldMute = sConnectionMuteTable.get(
744c9eddc4caa45b1e39b964a60c4edab9ae6f689cfPaul Berman                        phone.getForegroundCall().getLatestConnection());
745872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            } else if ((phoneType == Phone.PHONE_TYPE_GSM)
746872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                    || (phoneType == Phone.PHONE_TYPE_SIP)) {
747a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                shouldMute = sConnectionMuteTable.get(c);
748c9eddc4caa45b1e39b964a60c4edab9ae6f689cfPaul Berman            }
749b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (shouldMute == null) {
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("problem retrieving mute value for this connection.");
751b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                shouldMute = Boolean.FALSE;
752b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
753b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
754b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // set the mute value and return the result.
755a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang            setMute (shouldMute.booleanValue());
756b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return shouldMute;
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
758a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        return Boolean.valueOf(getMute());
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
761b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan    static void mergeCalls() {
762b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        mergeCalls(PhoneApp.getInstance().mCM);
763b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan    }
764b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan
765b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan    static void mergeCalls(CallManager cm) {
766b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        int phoneType = cm.getFgPhone().getPhoneType();
767b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        if (phoneType == Phone.PHONE_TYPE_CDMA) {
768c9d9ed30aa547b79b81adc13a4d148a003b6ee62w            if (DBG) log("mergeCalls");
7690fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            PhoneApp app = PhoneApp.getInstance();
7700fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            if (app.cdmaPhoneCallState.getCurrentCallState()
7710fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
7728ae7a57878143b10d0057cf63bfcc7466d4f2730Jaikumar Ganesh                // Set the Phone Call State to conference
7738ae7a57878143b10d0057cf63bfcc7466d4f2730Jaikumar Ganesh                app.cdmaPhoneCallState.setCurrentCallState(
7748ae7a57878143b10d0057cf63bfcc7466d4f2730Jaikumar Ganesh                        CdmaPhoneCallState.PhoneCallState.CONF_CALL);
7758ae7a57878143b10d0057cf63bfcc7466d4f2730Jaikumar Ganesh
7760fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // Send flash cmd
7779fd5e84fd6f5c2c5f488bf08d8dd9a2c0aab1370Wink Saville                // TODO: Need to change the call from switchHoldingAndActive to
7780fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // something meaningful as we are not actually trying to swap calls but
7790fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                // instead are merging two calls by sending a Flash command.
780b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                switchHoldingAndActive(cm.getFirstActiveBgCall());
7810fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            }
78279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
783b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan            try {
784b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                if (DBG) log("mergeCalls");
785b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                cm.conference(cm.getFirstActiveBgCall());
786b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan            } catch (CallStateException ex) {
787b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);
788b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan            }
789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static void separateCall(Connection c) {
793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        try {
794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("separateCall: " + c.getAddress());
795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            c.separate();
796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } catch (CallStateException ex) {
797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.w(LOG_TAG, "separateCall: caught " + ex, ex);
798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
802b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Handle the MMIInitiate message and put up an alert that lets
803b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * the user cancel the operation, if applicable.
804b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
805b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param context context to get strings.
806b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param mmiCode the MmiCode object being started.
807b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param buttonCallbackMessage message to post when button is clicked.
808b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param previousAlert a previous alert used in this activity.
809b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return the dialog handle
810b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
811b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static Dialog displayMMIInitiate(Context context,
812b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                          MmiCode mmiCode,
813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                          Message buttonCallbackMessage,
814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                          Dialog previousAlert) {
815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("displayMMIInitiate: " + mmiCode);
816b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (previousAlert != null) {
817b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            previousAlert.dismiss();
818b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // The UI paradigm we are using now requests that all dialogs have
821b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // user interaction, and that any other messages to the user should
822b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // be by way of Toasts.
823b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
824b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // In adhering to this request, all MMI initiating "OK" dialogs
825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // (non-cancelable MMIs) that end up being closed when the MMI
826b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // completes (thereby showing a completion dialog) are being
827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // replaced with Toasts.
828b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
829b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // As a side effect, moving to Toasts for the non-cancelable MMIs
830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // also means that buttonCallbackMessage (which was tied into "OK")
831b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // is no longer invokable for these dialogs.  This is not a problem
832b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // since the only callback messages we supported were for cancelable
833b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // MMIs anyway.
834b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
835b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // A cancelable MMI is really just a USSD request. The term
836b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // "cancelable" here means that we can cancel the request when the
837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // system prompts us for a response, NOT while the network is
838b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // processing the MMI request.  Any request to cancel a USSD while
839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the network is NOT ready for a response may be ignored.
840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // With this in mind, we replace the cancelable alert dialog with
842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // a progress dialog, displayed until we receive a request from
843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the the network.  For more information, please see the comments
844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // in the displayMMIComplete() method below.
845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Anything that is NOT a USSD request is a normal MMI request,
847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // which will bring up a toast (desribed above).
8484ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        // Optional code for Extended USSD running prompt
8494ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        if (mNwService != null) {
8504ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            if (DBG) log("running USSD code, displaying indeterminate progress.");
8514ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            // create the indeterminate progress dialog and display it.
8524ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            ProgressDialog pd = new ProgressDialog(context);
8534ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            CharSequence textmsg = "";
8544ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            try {
8554ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                textmsg = mNwService.getMmiRunningText();
85619dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh
8574ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            } catch (RemoteException e) {
8584ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mNwService = null;
85919dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh                textmsg = context.getText(R.string.ussdRunning);
8604ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            }
8614ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            if (DBG) log("Extended NW displayMMIInitiate (" + textmsg+ ")");
8624ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.setMessage(textmsg);
8634ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.setCancelable(false);
8644ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.setIndeterminate(true);
8654ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
8664ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
8674ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            pd.show();
8684ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            // trigger a 15 seconds timeout to clear this progress dialog
8694ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            mMmiTimeoutCbMsg = buttonCallbackMessage;
8704ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            try {
8714ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mMmiTimeoutCbMsg.getTarget().sendMessageDelayed(buttonCallbackMessage, 15000);
8724ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            } catch(NullPointerException e) {
8734ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mMmiTimeoutCbMsg = null;
8744ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            }
87519dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            return pd;
8764ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        }
8774ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean isCancelable = (mmiCode != null) && mmiCode.isCancelable();
879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (!isCancelable) {
881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("not a USSD code, displaying status toast.");
882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            CharSequence text = context.getText(R.string.mmiStarted);
883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Toast.makeText(context, text, Toast.LENGTH_SHORT)
884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                .show();
885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return null;
886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("running USSD code, displaying indeterminate progress.");
888b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
889b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // create the indeterminate progress dialog and display it.
890b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            ProgressDialog pd = new ProgressDialog(context);
891b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setMessage(context.getText(R.string.ussdRunning));
892b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setCancelable(false);
893b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setIndeterminate(true);
894b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
895b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
896b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.show();
897b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
898b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return pd;
899b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
900b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
901b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
902b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
903b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
904b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Handle the MMIComplete message and fire off an intent to display
905b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * the message.
906b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
907b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param context context to get strings.
908b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param mmiCode MMI result.
909b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param previousAlert a previous alert used in this activity.
910b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
911b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static void displayMMIComplete(final Phone phone, Context context, final MmiCode mmiCode,
912b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Message dismissCallbackMessage,
913b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            AlertDialog previousAlert) {
914b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        CharSequence text;
915b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int title = 0;  // title for the progress dialog, if needed.
916b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        MmiCode.State state = mmiCode.getState();
917b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
918b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("displayMMIComplete: state=" + state);
9194ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        // Clear timeout trigger message
9204ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        if(mMmiTimeoutCbMsg != null) {
9214ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            try{
9224ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mMmiTimeoutCbMsg.getTarget().removeMessages(mMmiTimeoutCbMsg.what);
9234ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                if (DBG) log("Extended NW displayMMIComplete removeMsg");
9244ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            } catch (NullPointerException e) {
9254ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            }
9264ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            mMmiTimeoutCbMsg = null;
9274ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        }
9284ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (state) {
931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case PENDING:
932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // USSD code asking for feedback from user.
933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                text = mmiCode.getMessage();
934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("- using text from PENDING MMI message: '" + text + "'");
935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case CANCELLED:
937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                text = context.getText(R.string.mmiCancelled);
938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
939b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case COMPLETE:
940b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (PhoneApp.getInstance().getPUKEntryActivity() != null) {
941b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // if an attempt to unPUK the device was made, we specify
942b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // the title and the message here.
943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    title = com.android.internal.R.string.PinMmi;
944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    text = context.getText(R.string.puk_unlocked);
945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // All other conditions for the COMPLETE mmi state will cause
948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // the case to fall through to message logic in common with
949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // the FAILED case.
950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case FAILED:
952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                text = mmiCode.getMessage();
953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("- using text from MMI message: '" + text + "'");
954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                break;
955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default:
956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                throw new IllegalStateException("Unexpected MmiCode state: " + state);
957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (previousAlert != null) {
960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            previousAlert.dismiss();
961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Check to see if a UI exists for the PUK activation.  If it does
964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // exist, then it indicates that we're trying to unblock the PUK.
965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp app = PhoneApp.getInstance();
96605fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu        if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.COMPLETE)) {
967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("displaying PUK unblocking progress dialog.");
968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // create the progress dialog, make sure the flags and type are
970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // set correctly.
971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            ProgressDialog pd = new ProgressDialog(app);
972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setTitle(title);
973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setMessage(text);
974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setCancelable(false);
975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.setIndeterminate(true);
976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // display the dialog
980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            pd.show();
981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // indicate to the Phone app that the progress dialog has
983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // been assigned for the PUK unlock / SIM READY process.
984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            app.setPukEntryProgressDialog(pd);
985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
986b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
987b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // In case of failure to unlock, we'll need to reset the
988b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // PUK unlock activity, so that the user may try again.
989b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (app.getPUKEntryActivity() != null) {
990b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                app.setPukEntryActivity(null);
991b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
992b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
993b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // A USSD in a pending state means that it is still
994b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // interacting with the user.
995b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (state != MmiCode.State.PENDING) {
996b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("MMI code has finished running.");
997b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
9984ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                // Replace response message with Extended Mmi wording
9994ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                if (mNwService != null) {
10004ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                    try {
10014ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                        text = mNwService.getUserMessage(text);
10024ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                    } catch (RemoteException e) {
10034ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                        mNwService = null;
10044ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                    }
10054ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                    if (DBG) log("Extended NW displayMMIInitiate (" + text + ")");
10061b8e24dac994b507540d25b02e2c56f52bff04abDaisuke Miyakawa                    if (text == null || text.length() == 0)
10074ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                        return;
10084ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                }
10094ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang
1010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // displaying system alert dialog on the screen instead of
1011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // using another activity to display the message.  This
1012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // places the message at the forefront of the UI.
1013b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                AlertDialog newDialog = new AlertDialog.Builder(context)
1014b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setMessage(text)
1015b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setPositiveButton(R.string.ok, null)
1016b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setCancelable(true)
1017b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .create();
1018b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1019b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.getWindow().setType(
1020b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
1021b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.getWindow().addFlags(
1022b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1023b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1024b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.show();
1025b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
1026b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("USSD code has requested user input. Constructing input dialog.");
1027b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1028b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // USSD MMI code that is interacting with the user.  The
1029b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // basic set of steps is this:
1030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   1. User enters a USSD request
1031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   2. We recognize the request and displayMMIInitiate
1032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      (above) creates a progress dialog.
1033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   3. Request returns and we get a PENDING or COMPLETE
1034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      message.
1035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   4. These MMI messages are caught in the PhoneApp
1036b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      (onMMIComplete) and the InCallScreen
1037b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      (mHandler.handleMessage) which bring up this dialog
1038b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      and closes the original progress dialog,
1039b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      respectively.
1040b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   5. If the message is anything other than PENDING,
1041b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      we are done, and the alert dialog (directly above)
1042b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      displays the outcome.
1043b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   6. If the network is requesting more information from
1044b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      the user, the MMI will be in a PENDING state, and
1045b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      we display this dialog with the message.
1046b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //   7. User input, or cancel requests result in a return
1047b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      to step 1.  Keep in mind that this is the only
1048b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                //      time that a USSD should be canceled.
1049b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1050b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // inflate the layout with the scrolling text area for the dialog.
1051b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                LayoutInflater inflater = (LayoutInflater) context.getSystemService(
1052b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        Context.LAYOUT_INFLATER_SERVICE);
1053b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                View dialogView = inflater.inflate(R.layout.dialog_ussd_response, null);
1054b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1055b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // get the input field.
1056b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                final EditText inputText = (EditText) dialogView.findViewById(R.id.input_field);
1057b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1058b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // specify the dialog's click listener, with SEND and CANCEL logic.
1059b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                final DialogInterface.OnClickListener mUSSDDialogListener =
1060b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    new DialogInterface.OnClickListener() {
1061b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        public void onClick(DialogInterface dialog, int whichButton) {
1062b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            switch (whichButton) {
1063edbbd998abc6d1d1d2c2f3b54c939779c91a2708Christian Mehlmauer                                case DialogInterface.BUTTON_POSITIVE:
1064b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    phone.sendUssdResponse(inputText.getText().toString());
1065b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    break;
1066edbbd998abc6d1d1d2c2f3b54c939779c91a2708Christian Mehlmauer                                case DialogInterface.BUTTON_NEGATIVE:
1067b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    if (mmiCode.isCancelable()) {
1068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                        mmiCode.cancel();
1069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    }
1070b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    break;
1071b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            }
1072b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1073b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    };
1074b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1075b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // build the dialog
1076b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                final AlertDialog newDialog = new AlertDialog.Builder(context)
1077b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setMessage(text)
1078b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setView(dialogView)
1079b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setPositiveButton(R.string.send_button, mUSSDDialogListener)
1080b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setNegativeButton(R.string.cancel, mUSSDDialogListener)
1081b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .setCancelable(false)
1082b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        .create();
1083b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1084b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // attach the key listener to the dialog's input field and make
1085b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // sure focus is set.
1086b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                final View.OnKeyListener mUSSDDialogInputListener =
1087b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    new View.OnKeyListener() {
1088b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        public boolean onKey(View v, int keyCode, KeyEvent event) {
1089b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            switch (keyCode) {
1090b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                case KeyEvent.KEYCODE_CALL:
1091b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                case KeyEvent.KEYCODE_ENTER:
1092b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    phone.sendUssdResponse(inputText.getText().toString());
1093b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    newDialog.dismiss();
1094b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                    return true;
1095b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            }
1096b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            return false;
1097b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1098b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    };
1099b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                inputText.setOnKeyListener(mUSSDDialogInputListener);
1100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                inputText.requestFocus();
1101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // set the window properties of the dialog
1103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.getWindow().setType(
1104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
1105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.getWindow().addFlags(
1106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // now show the dialog!
1109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                newDialog.show();
1110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1114b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1115b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Cancels the current pending MMI operation, if applicable.
1116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we canceled an MMI operation, or false
1117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         if the current pending MMI wasn't cancelable
1118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         or if there was no current pending MMI at all.
1119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @see displayMMIInitiate
1121b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static boolean cancelMmiCode(Phone phone) {
1123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        List<? extends MmiCode> pendingMmis = phone.getPendingMmiCodes();
1124b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int count = pendingMmis.size();
1125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("cancelMmiCode: num pending MMIs = " + count);
1126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean canceled = false;
1128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (count > 0) {
1129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // assume that we only have one pending MMI operation active at a time.
1130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // I don't think it's possible to enter multiple MMI codes concurrently
1131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // in the phone UI, because during the MMI operation, an Alert panel
1132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // is displayed, which prevents more MMI code from being entered.
1133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            MmiCode mmiCode = pendingMmis.get(0);
1134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mmiCode.isCancelable()) {
1135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mmiCode.cancel();
1136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                canceled = true;
1137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
11404ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        //clear timeout message and pre-set MMI command
11414ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        if (mNwService != null) {
11424ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            try {
11434ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mNwService.clearMmiString();
11444ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            } catch (RemoteException e) {
11454ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang                mNwService = null;
114619dd8f9c63ba7471c76fc31847a8063d18a83b6dJaikumar Ganesh            }
11474ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        }
11484ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        if (mMmiTimeoutCbMsg != null) {
11494ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang            mMmiTimeoutCbMsg = null;
11504ccb1b7d68d5b5bb7ed54251a1f214162013bc60John Wang        }
1151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return canceled;
1152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static class VoiceMailNumberMissingException extends Exception {
1155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        VoiceMailNumberMissingException() {
1156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            super();
1157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        VoiceMailNumberMissingException(String msg) {
1160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            super(msg);
1161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Gets the phone number to be called from an intent.  Requires a Context
1166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * to access the contacts database, and a Phone to access the voicemail
1167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * number.
1168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <p>If <code>phone</code> is <code>null</code>, the function will return
1170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <code>null</code> for <code>voicemail:</code> URIs;
1171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * if <code>context</code> is <code>null</code>, the function will return
1172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * <code>null</code> for person/phone URIs.</p>
1173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1174bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * <p>If the intent contains a <code>sip:</code> URI, the returned
1175bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * "number" is actually the SIP address.
1176bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     *
1177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param context a context to use (or
1178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param intent the intent
1179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @throws VoiceMailNumberMissingException if <code>intent</code> contains
1181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         a <code>voicemail:</code> URI, but <code>phone</code> does not
1182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         have a voicemail number set.
1183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1184bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * @return the phone number (or SIP address) that would be called by the intent,
1185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *         or <code>null</code> if the number cannot be found.
1186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
118761bde155c038489befc9c6cb9eb1765f44daaae0John Wang    static String getNumberFromIntent(Context context, Intent intent)
1188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            throws VoiceMailNumberMissingException {
1189bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        Uri uri = intent.getData();
1190bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        String scheme = uri.getScheme();
1191bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown
1192bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        // The sip: scheme is simple: just treat the rest of the URI as a
1193bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        // SIP address.
1194bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        if (scheme.equals("sip")) {
1195bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown            return uri.getSchemeSpecificPart();
1196bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        }
1197bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown
1198bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        // Otherwise, let PhoneNumberUtils.getNumberFromIntent() handle
1199bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        // the other cases (i.e. tel: and voicemail: and contact: URIs.)
1200bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown
1201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final String number = PhoneNumberUtils.getNumberFromIntent(intent, context);
1202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1203bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        // Check for a voicemail-dialing request.  If the voicemail number is
1204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // empty, throw a VoiceMailNumberMissingException.
1205bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown        if (scheme.equals("voicemail") &&
1206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                (number == null || TextUtils.isEmpty(number)))
1207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            throw new VoiceMailNumberMissingException();
1208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return number;
1210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns the caller-id info corresponding to the specified Connection.
1214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * (This is just a simple wrapper around CallerInfo.getCallerInfo(): we
1215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * extract a phone number from the specified Connection, and feed that
1216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * number into CallerInfo.getCallerInfo().)
1217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * The returned CallerInfo may be null in certain error cases, like if the
1219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * specified Connection was null, or if we weren't able to get a valid
1220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * phone number from the Connection.
1221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Finally, if the getCallerInfo() call did succeed, we save the resulting
1223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * CallerInfo object in the "userData" field of the Connection.
1224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * NOTE: This API should be avoided, with preference given to the
1226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * asynchronous startGetCallerInfo API.
1227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static CallerInfo getCallerInfo(Context context, Connection c) {
1229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        CallerInfo info = null;
1230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (c != null) {
1232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //See if there is a URI attached.  If there is, this means
1233b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //that there is no CallerInfo queried yet, so we'll need to
1234b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //replace the URI with a full CallerInfo object.
1235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Object userDataObject = c.getUserData();
1236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (userDataObject instanceof Uri) {
1237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                info = CallerInfo.getCallerInfo(context, (Uri) userDataObject);
1238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (info != null) {
1239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    c.setUserData(info);
1240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
1242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (userDataObject instanceof CallerInfoToken) {
1243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    //temporary result, while query is running
1244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    info = ((CallerInfoToken) userDataObject).currentInfo;
1245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
1246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    //final query result
1247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    info = (CallerInfo) userDataObject;
1248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (info == null) {
1250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // No URI, or Existing CallerInfo, so we'll have to make do with
1251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // querying a new CallerInfo using the connection's phone number.
1252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    String number = c.getAddress();
1253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("getCallerInfo: number = " + number);
1255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (!TextUtils.isEmpty(number)) {
1257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        info = CallerInfo.getCallerInfo(context, number);
1258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (info != null) {
1259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                            c.setUserData(info);
1260b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        }
1261b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
1262b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1263b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return info;
1266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Class returned by the startGetCallerInfo call to package a temporary
1270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * CallerInfo Object, to be superceded by the CallerInfo Object passed
1271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * into the listener when the query with token mAsyncQueryToken is complete.
1272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static class CallerInfoToken {
1274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**indicates that there will no longer be updates to this request.*/
1275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean isFinal;
1276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public CallerInfo currentInfo;
1278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public CallerInfoAsyncQuery asyncQuery;
1279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Start a CallerInfo Query based on the earliest connection in the call.
1283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static CallerInfoToken startGetCallerInfo(Context context, Call call,
1285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
12860fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        PhoneApp app = PhoneApp.getInstance();
12870fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        Connection conn = null;
1288872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        int phoneType = call.getPhone().getPhoneType();
128979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
12900fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            conn = call.getLatestConnection();
1291872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
1292872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
12930fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            conn = call.getEarliestConnection();
129479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
129579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            throw new IllegalStateException("Unexpected phone type: " + phoneType);
12960fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
12970fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
1298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return startGetCallerInfo(context, conn, listener, cookie);
1299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * place a temporary callerinfo object in the hands of the caller and notify
1303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * caller when the actual query is done.
1304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
1307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        CallerInfoToken cit;
1308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (c == null) {
1310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //TODO: perhaps throw an exception here.
1311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit = new CallerInfoToken();
1312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.asyncQuery = null;
1313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return cit;
1314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // There are now 3 states for the userdata.
1317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   1. Uri - query has not been executed yet
1318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   2. CallerInfoToken - query is executing, but has not completed.
1319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   3. CallerInfo - query has executed.
1320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // In each case we have slightly different behaviour:
1321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   1. If the query has not been executed yet (Uri or null), we start
1322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      query execution asynchronously, and note it by attaching a
1323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      CallerInfoToken as the userData.
1324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   2. If the query is executing (CallerInfoToken), we've essentially
1325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      reached a state where we've received multiple requests for the
1326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      same callerInfo.  That means that once the query is complete,
1327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      we'll need to execute the additional listener requested.
1328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   3. If the query has already been executed (CallerInfo), we just
1329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      return the CallerInfo object as expected.
1330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //   4. Regarding isFinal - there are cases where the CallerInfo object
1331b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      will not be attached, like when the number is empty (caller id
1332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      blocking).  This flag is used to indicate that the
1333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      CallerInfoToken object is going to be permanent since no
1334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      query results will be returned.  In the case where a query
1335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      has been completed, this flag is used to indicate to the caller
1336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      that the data will not be updated since it is valid.
1337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
1338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      Note: For the case where a number is NOT retrievable, we leave
1339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      the CallerInfo as null in the CallerInfoToken.  This is
1340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      something of a departure from the original code, since the old
1341b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      code manufactured a CallerInfo object regardless of the query
1342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      outcome.  From now on, we will append an empty CallerInfo
1343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      object, to mirror previous behaviour, and to avoid Null Pointer
1344b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //      Exceptions.
1345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Object userDataObject = c.getUserData();
1346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (userDataObject instanceof Uri) {
1347b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            //create a dummy callerinfo, populate with what we know from URI.
1348b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit = new CallerInfoToken();
1349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.currentInfo = new CallerInfo();
1350b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
1351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    (Uri) userDataObject, sCallerInfoQueryListener, c);
1352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
1353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.isFinal = false;
1354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            c.setUserData(cit);
1356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("startGetCallerInfo: query based on Uri: " + userDataObject);
1358b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1359b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (userDataObject == null) {
1360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // No URI, or Existing CallerInfo, so we'll have to make do with
1361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // querying a new CallerInfo using the connection's phone number.
1362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            String number = c.getAddress();
1363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit = new CallerInfoToken();
1365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.currentInfo = new CallerInfo();
1366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1367de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            // Store CNAP information retrieved from the Connection (we want to do this
1368de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            // here regardless of whether the number is empty or not).
1369de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            cit.currentInfo.cnapName =  c.getCnapName();
1370de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            cit.currentInfo.name = cit.currentInfo.cnapName; // This can still get overwritten
1371de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                                                             // by ContactInfo later
1372de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            cit.currentInfo.numberPresentation = c.getNumberPresentation();
1373de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            cit.currentInfo.namePresentation = c.getCnapNamePresentation();
1374de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman
1375a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania            if (DBG) {
1376a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                log("startGetCallerInfo: number = " + number);
1377a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                log("startGetCallerInfo: CNAP Info from FW(1): name="
1378de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    + cit.currentInfo.cnapName
1379de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
1380a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania            }
1381b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1382b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // handling case where number is null (caller id hidden) as well.
1383b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!TextUtils.isEmpty(number)) {
1384153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                // Check for special CNAP cases and modify the CallerInfo accordingly
1385153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                // to be sure we keep the right information to display/log later
1386153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                number = modifyForSpecialCnapCases(context, cit.currentInfo, number,
1387153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                        cit.currentInfo.numberPresentation);
138886c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu
138986c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                cit.currentInfo.phoneNumber = number;
13902f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                // For scenarios where we may receive a valid number from the network but a
13912f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                // restricted/unavailable presentation, we do not want to perform a contact query
13922f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                // (see note on isFinal above). So we set isFinal to true here as well.
13932f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                if (cit.currentInfo.numberPresentation != Connection.PRESENTATION_ALLOWED) {
13942f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    cit.isFinal = true;
13952f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                } else {
13962f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
13972f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                            number, sCallerInfoQueryListener, c);
13982f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
13992f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    cit.isFinal = false;
14002f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                }
1401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
1402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // This is the case where we are querying on a number that
1403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // is null or empty, like a caller whose caller id is
1404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // blocked or empty (CLIR).  The previous behaviour was to
1405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // throw a null CallerInfo object back to the user, but
1406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // this departure is somewhat cleaner.
1407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("startGetCallerInfo: No query to start, send trivial reply.");
1408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                cit.isFinal = true; // please see note on isFinal, above.
1409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1410b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1411b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            c.setUserData(cit);
1412b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1413b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("startGetCallerInfo: query based on number: " + number);
1414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (userDataObject instanceof CallerInfoToken) {
1416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // query is running, just tack on this listener to the queue.
1417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit = (CallerInfoToken) userDataObject;
1418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // handling case where number is null (caller id hidden) as well.
1420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (cit.asyncQuery != null) {
1421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
1422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("startGetCallerInfo: query already running, adding listener: " +
1424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        listener.getClass().toString());
1425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            } else {
142646532b66a467f247380054270c6151aa3dc7a761Wink Saville                // handling case where number/name gets updated later on by the network
142746532b66a467f247380054270c6151aa3dc7a761Wink Saville                String updatedNumber = c.getAddress();
1428de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                if (DBG) log("startGetCallerInfo: updatedNumber initially = " + updatedNumber);
142946532b66a467f247380054270c6151aa3dc7a761Wink Saville                if (!TextUtils.isEmpty(updatedNumber)) {
143046532b66a467f247380054270c6151aa3dc7a761Wink Saville                    // Store CNAP information retrieved from the Connection
143146532b66a467f247380054270c6151aa3dc7a761Wink Saville                    cit.currentInfo.cnapName =  c.getCnapName();
143246532b66a467f247380054270c6151aa3dc7a761Wink Saville                    // This can still get overwritten by ContactInfo
143346532b66a467f247380054270c6151aa3dc7a761Wink Saville                    cit.currentInfo.name = cit.currentInfo.cnapName;
143446532b66a467f247380054270c6151aa3dc7a761Wink Saville                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
143546532b66a467f247380054270c6151aa3dc7a761Wink Saville                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
143646532b66a467f247380054270c6151aa3dc7a761Wink Saville
1437de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    updatedNumber = modifyForSpecialCnapCases(context, cit.currentInfo,
1438de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                            updatedNumber, cit.currentInfo.numberPresentation);
1439de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman
1440de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    cit.currentInfo.phoneNumber = updatedNumber;
1441de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    if (DBG) log("startGetCallerInfo: updatedNumber=" + updatedNumber);
1442de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    if (DBG) log("startGetCallerInfo: CNAP Info from FW(2): name="
144346532b66a467f247380054270c6151aa3dc7a761Wink Saville                            + cit.currentInfo.cnapName
144446532b66a467f247380054270c6151aa3dc7a761Wink Saville                            + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
14452f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    // For scenarios where we may receive a valid number from the network but a
14462f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    // restricted/unavailable presentation, we do not want to perform a contact query
14472f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    // (see note on isFinal above). So we set isFinal to true here as well.
14482f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    if (cit.currentInfo.numberPresentation != Connection.PRESENTATION_ALLOWED) {
14492f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                        cit.isFinal = true;
14502f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    } else {
14512f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                        cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
14522f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                                updatedNumber, sCallerInfoQueryListener, c);
14532f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                        cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
14542f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                        cit.isFinal = false;
14552f5a2e9b6dc69123abe36fd6deb93b7fb46c1cadPaul Berman                    }
145646532b66a467f247380054270c6151aa3dc7a761Wink Saville                } else {
145746532b66a467f247380054270c6151aa3dc7a761Wink Saville                    if (DBG) log("startGetCallerInfo: No query to attach to, send trivial reply.");
145846532b66a467f247380054270c6151aa3dc7a761Wink Saville                    if (cit.currentInfo == null) {
145946532b66a467f247380054270c6151aa3dc7a761Wink Saville                        cit.currentInfo = new CallerInfo();
146046532b66a467f247380054270c6151aa3dc7a761Wink Saville                    }
1461de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    // Store CNAP information retrieved from the Connection
1462de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    cit.currentInfo.cnapName = c.getCnapName();  // This can still get
1463de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                                                                 // overwritten by ContactInfo
1464de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    cit.currentInfo.name = cit.currentInfo.cnapName;
1465de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
1466de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
1467de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman
1468de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                    if (DBG) log("startGetCallerInfo: CNAP Info from FW(3): name="
1469de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                            + cit.currentInfo.cnapName
1470de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                            + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
147146532b66a467f247380054270c6151aa3dc7a761Wink Saville                    cit.isFinal = true; // please see note on isFinal, above.
1472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
1473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit = new CallerInfoToken();
1476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.currentInfo = (CallerInfo) userDataObject;
1477b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.asyncQuery = null;
1478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            cit.isFinal = true;
1479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // since the query is already done, call the listener.
1480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("startGetCallerInfo: query already done, returning CallerInfo");
1481b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1482b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return cit;
1483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1486b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Implemented for CallerInfo.OnCallerInfoQueryCompleteListener interface.
1487b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Updates the connection's userData when called.
1488b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1489b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int QUERY_TOKEN = -1;
1490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static CallerInfoAsyncQuery.OnQueryCompleteListener sCallerInfoQueryListener =
1491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        new CallerInfoAsyncQuery.OnQueryCompleteListener () {
149205fb729f41a3f7e06891d0c73c04be4be933a89cPeng Zhu            public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
1493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("query complete, updating connection.userdata");
14943ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                Connection conn = (Connection) cookie;
1495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1496e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                // Added a check if CallerInfo is coming from ContactInfo or from Connection.
1497e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                // If no ContactInfo, then we want to use CNAP information coming from network
149864824003c89a7758240425f5c9f8d29cb00e4a65Nicolas Catania                if (DBG) log("- onQueryComplete: CallerInfo:" + ci);
149964824003c89a7758240425f5c9f8d29cb00e4a65Nicolas Catania                if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
15003ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // If the number presentation has not been set by
15013ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // the ContactInfo, use the one from the
15023ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // connection.
15033ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania
15043ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // TODO: Need a new util method to merge the info
15053ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // from the Connection in a CallerInfo object.
15063ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // Here 'ci' is a new CallerInfo instance read
15073ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // from the DB. It has lost all the connection
15083ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // info preset before the query (see PhoneUtils
15093ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // line 1334). We should have a method to merge
15103ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // back into this new instance the info from the
15113ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // connection object not set by the DB. If the
15123ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // Connection already has a CallerInfo instance in
15133ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // userData, then we could use this instance to
15143ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // fill 'ci' in. The same routine could be used in
15153ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    // PhoneUtils.
15163ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    if (0 == ci.numberPresentation) {
15173ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                        ci.numberPresentation = conn.getNumberPresentation();
15183ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    }
1519e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                } else {
15203ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                    CallerInfo newCi = getCallerInfo(null, conn);
1521e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                    if (newCi != null) {
1522e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                        newCi.phoneNumber = ci.phoneNumber; // To get formatted phone number
15233ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                        ci = newCi;
152464824003c89a7758240425f5c9f8d29cb00e4a65Nicolas Catania                    }
1525e2c9e16a099b6a120db0a589ad1959b8787b9f9bAbhishek Pillai                }
15263ba1cd466a39eb22addb6f6fe3c7b0f3e7916330Nicolas Catania                conn.setUserData(ci);
1527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
1529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns a single "name" for the specified given a CallerInfo object.
1533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * If the name is null, return defaultString as the default value, usually
1534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * context.getString(R.string.unknown).
1535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static String getCompactNameFromCallerInfo(CallerInfo ci, Context context) {
1537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("getCompactNameFromCallerInfo: info = " + ci);
1538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String compactName = null;
1540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (ci != null) {
1541a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania            if (TextUtils.isEmpty(ci.name)) {
1542a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                // Perform any modifications for special CNAP cases to
1543a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                // the phone number being displayed, if applicable.
1544a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                compactName = modifyForSpecialCnapCases(context, ci, ci.phoneNumber,
1545a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                                                        ci.numberPresentation);
1546a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania            } else {
1547a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                // Don't call modifyForSpecialCnapCases on regular name. See b/2160795.
1548a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                compactName = ci.name;
1549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1551de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman
15520fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        if ((compactName == null) || (TextUtils.isEmpty(compactName))) {
1553de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            // If we're still null/empty here, then check if we have a presentation
1554de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            // string that takes precedence that we could return, otherwise display
1555de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            // "unknown" string.
1556de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            if (ci != null && ci.numberPresentation == Connection.PRESENTATION_RESTRICTED) {
1557de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                compactName = context.getString(R.string.private_num);
1558de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            } else if (ci != null && ci.numberPresentation == Connection.PRESENTATION_PAYPHONE) {
1559de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                compactName = context.getString(R.string.payphone);
1560de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            } else {
1561de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                compactName = context.getString(R.string.unknown);
1562de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman            }
1563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1564de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        if (DBG) log("getCompactNameFromCallerInfo: compactName=" + compactName);
1565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return compactName;
1566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Returns true if the specified Call is a "conference call", meaning
1570b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * that it owns more than one Connection object.  This information is
1571b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * used to trigger certain UI changes that appear when a conference
1572b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * call is active (like displaying the label "Conference call", and
1573b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown     * enabling the "Manage conference" UI.)
1574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Watch out: This method simply checks the number of Connections,
1576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * *not* their states.  So if a Call has (for example) one ACTIVE
1577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * connection and one DISCONNECTED connection, this method will return
1578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * true (which is unintuitive, since the Call isn't *really* a
1579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * conference call any more.)
1580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if the specified call has more than one connection (in any state.)
1582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static boolean isConferenceCall(Call call) {
1584b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        // CDMA phones don't have the same concept of "conference call" as
1585b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        // GSM phones do; there's no special "conference call" state of
1586b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        // the UI or a "manage conference" function.  (Instead, when
1587b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        // you're in a 3-way call, all we can do is display the "generic"
1588b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        // state of the UI.)  So as far as the in-call UI is concerned,
15890fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        // Conference corresponds to generic display.
15900fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        PhoneApp app = PhoneApp.getInstance();
1591b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        int phoneType = call.getPhone().getPhoneType();
159279b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
159339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai            CdmaPhoneCallState.PhoneCallState state = app.cdmaPhoneCallState.getCurrentCallState();
159439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai            if ((state == CdmaPhoneCallState.PhoneCallState.CONF_CALL)
159539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    || ((state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
159639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing())) {
15970fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                return true;
15980fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            }
1599b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        } else {
16000fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            List<Connection> connections = call.getConnections();
16010fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            if (connections != null && connections.size() > 1) {
16020fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                return true;
16030fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            }
1604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
1606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // TODO: We may still want to change the semantics of this method
1608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // to say that a given call is only really a conference call if
1609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the number of ACTIVE connections, not the total number of
1610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // connections, is greater than one.  (See warning comment in the
1611b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // javadoc above.)
1612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Here's an implementation of that:
1613b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        if (connections == null) {
1614b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //            return false;
1615b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        }
1616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        int numActiveConnections = 0;
1617b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        for (Connection conn : connections) {
1618b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //            if (DBG) log("  - CONN: " + conn + ", state = " + conn.getState());
1619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //            if (conn.getState() == Call.State.ACTIVE) numActiveConnections++;
1620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //            if (numActiveConnections > 1) {
1621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //                return true;
1622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //            }
1623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        }
1624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //        return false;
1625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Launch the Dialer to start a new call.
1629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This is just a wrapper around the ACTION_DIAL intent.
1630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
16318343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static void startNewCall(final CallManager cm) {
1632b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Sanity-check that this is OK given the current state of the phone.
16338343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if (!okToAddCall(cm)) {
1634b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.w(LOG_TAG, "startNewCall: can't add a new call in the current state");
16358343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            dumpCallManager();
1636b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return;
1637b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1638b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1639b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if applicable, mute the call while we're showing the add call UI.
16408343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if (cm.hasActiveFgCall()) {
16418343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            setMuteInternal(cm.getActiveFgCall().getPhone(), true);
1642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Inform the phone app that this mute state was NOT done
1643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // voluntarily by the User.
1644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            PhoneApp.getInstance().setRestoreMuteOnInCallResume(true);
1645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = new Intent(Intent.ACTION_DIAL);
1648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // when we request the dialer come up, we also want to inform
1651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // it that we're going through the "add call" option from the
1652b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // InCallScreen / PhoneUtils.
1653b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        intent.putExtra(ADD_CALL_MODE_KEY, true);
1654b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1655b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp.getInstance().startActivity(intent);
1656b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1657b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1658425b8e3c9846d5e0e76466604b35cad8856d79deEric Laurent    static void turnOnSpeaker(Context context, boolean flag, boolean store) {
16596b0efb615a5b1a65984192384c88965fa7dd06a0David Brown        if (DBG) log("turnOnSpeaker(flag=" + flag + ", store=" + store + ")...");
1660b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1661b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        audioManager.setSpeakerphoneOn(flag);
1663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // record the speaker-enable value
1664425b8e3c9846d5e0e76466604b35cad8856d79deEric Laurent        if (store) {
1665425b8e3c9846d5e0e76466604b35cad8856d79deEric Laurent            sIsSpeakerEnabled = flag;
1666425b8e3c9846d5e0e76466604b35cad8856d79deEric Laurent        }
1667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (flag) {
1668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            NotificationMgr.getDefault().notifySpeakerphone();
1669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            NotificationMgr.getDefault().cancelSpeakerphone();
1671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // We also need to make a fresh call to PhoneApp.updateWakeState()
1674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // any time the speaker state changes, since the screen timeout is
1675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // sometimes different depending on whether or not the speaker is
1676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // in use.
1677b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp app = PhoneApp.getInstance();
1678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        app.updateWakeState();
1679d3744ff481f7d96669740b015a39d7441208152bAbhishek Pillai
1680d3744ff481f7d96669740b015a39d7441208152bAbhishek Pillai        // Update the Proximity sensor based on speaker state
1681d3744ff481f7d96669740b015a39d7441208152bAbhishek Pillai        app.updateProximitySensorMode(app.phone.getState());
1682b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1685b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Restore the speaker mode, called after a wired headset disconnect
1686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * event.
1687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static void restoreSpeakerMode(Context context) {
1689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("restoreSpeakerMode, restoring to: " + sIsSpeakerEnabled);
1690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // change the mode if needed.
1692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (isSpeakerOn(context) != sIsSpeakerEnabled) {
1693425b8e3c9846d5e0e76466604b35cad8856d79deEric Laurent            turnOnSpeaker(context, sIsSpeakerEnabled, false);
1694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static boolean isSpeakerOn(Context context) {
1698b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1699b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return audioManager.isSpeakerphoneOn();
1700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1702055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1703055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    static void turnOnNoiseSuppression(Context context, boolean flag, boolean store) {
1704055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (DBG) log("turnOnNoiseSuppression: " + flag);
1705055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1706055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1707055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
1708055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            return;
1709055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1710055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1711055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (flag) {
1712055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            audioManager.setParameters("noise_suppression=auto");
1713055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        } else {
1714055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            audioManager.setParameters("noise_suppression=off");
1715055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1716055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1717055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        // record the speaker-enable value
1718055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (store) {
1719055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            sIsNoiseSuppressionEnabled = flag;
1720055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1721055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1722055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        // TODO: implement and manage ICON
1723055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1724055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    }
1725055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1726055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    static void restoreNoiseSuppression(Context context) {
1727055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (DBG) log("restoreNoiseSuppression, restoring to: " + sIsNoiseSuppressionEnabled);
1728055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1729055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
1730055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            return;
1731055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1732055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1733055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        // change the mode if needed.
1734055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (isNoiseSuppressionOn(context) != sIsNoiseSuppressionEnabled) {
1735055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            turnOnNoiseSuppression(context, sIsNoiseSuppressionEnabled, false);
1736055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1737055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    }
1738055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1739055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    static boolean isNoiseSuppressionOn(Context context) {
1740055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1741055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
1742055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            return false;
1743055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1744055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1745055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1746055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        String noiseSuppression = audioManager.getParameters("noise_suppression");
1747055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (DBG) log("isNoiseSuppressionOn: " + noiseSuppression);
1748055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        if (noiseSuppression.contains("off")) {
1749055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            return false;
1750055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        } else {
1751055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent            return true;
1752055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent        }
1753055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent    }
1754055b927f7ee587bc1b1e595b12beaa232ab99ffcEric Laurent
1755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1756a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     *
1757a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * Mute / umute the foreground phone, which has the current foreground call
1758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * All muting / unmuting from the in-call UI should go through this
1760b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * wrapper.
1761a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     *
1762a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * Wrapper around Phone.setMute() and setMicrophoneMute().
1763a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * It also updates the connectionMuteTable and mute icon in the status bar.
1764a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     *
1765b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1766a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang    static void setMute(boolean muted) {
1767a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        CallManager cm = PhoneApp.getInstance().mCM;
1768a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang
1769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // make the call to mute the audio
1770a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        setMuteInternal(cm.getFgPhone(), muted);
1771a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang
1772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1773b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // update the foreground connections to match.  This includes
1774b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // all the connections on conference calls.
1775a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        for (Connection cn : cm.getActiveFgCall().getConnections()) {
1776b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (sConnectionMuteTable.get(cn) == null) {
1777b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("problem retrieving mute value for this connection.");
1778b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            sConnectionMuteTable.put(cn, Boolean.valueOf(muted));
1780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1784a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * Internally used muting function.
1785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1786a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang    private static void setMuteInternal(Phone phone, boolean muted) {
1787a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        if (DBG) log("setMuteInternal: " + muted);
1788c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        Context context = phone.getContext();
1789c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        boolean routeToAudioManager =
1790c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            context.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
1791c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        if (routeToAudioManager) {
1792c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            AudioManager audioManager =
1793c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi                (AudioManager) phone.getContext().getSystemService(Context.AUDIO_SERVICE);
1794a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang            if (DBG) log("setMicrophoneMute: " + muted);
1795c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            audioManager.setMicrophoneMute(muted);
1796c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        } else {
1797c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            phone.setMute(muted);
1798c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        }
1799a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        NotificationMgr.getDefault().updateMuteNotification();
1800b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1801b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1802a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang    /**
1803a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * Get the mute state of foreground phone, which has the current
1804a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     * foreground call
1805a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang     */
1806a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang    static boolean getMute() {
1807a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang        Phone phone = PhoneApp.getInstance().mCM.getFgPhone();
1808a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang
1809c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        Context context = phone.getContext();
1810c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        boolean routeToAudioManager =
1811c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            context.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
1812c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        if (routeToAudioManager) {
1813c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            AudioManager audioManager =
1814c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi                (AudioManager) phone.getContext().getSystemService(Context.AUDIO_SERVICE);
1815c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            return audioManager.isMicrophoneMute();
1816c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        } else {
1817c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi            return phone.getMute();
1818c8f4017c60f26ee760cd2f597de307e1845cf35aJean-Michel Trivi        }
1819b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1820b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1821a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan    /* package */ static void setAudioMode() {
1822a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        setAudioMode(PhoneApp.getInstance().mCM);
1823a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan    }
1824a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan
1825b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1826a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan     * Sets the audio mode per current phone state.
1827b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1828a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan    /* package */ static void setAudioMode(CallManager cm) {
1829a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        if (DBG) Log.d(LOG_TAG, "setAudioMode()..." + cm.getState());
1830b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1831a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        Context context = PhoneApp.getInstance();
1832a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        AudioManager audioManager = (AudioManager)
1833a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan                context.getSystemService(Context.AUDIO_SERVICE);
1834a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        int modeBefore = audioManager.getMode();
1835a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        cm.setAudioMode();
1836a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        int modeAfter = audioManager.getMode();
1837b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1838a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan        if (modeBefore != modeAfter) {
1839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Enable stack dump only when actively debugging ("new Throwable()" is expensive!)
1840b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG_SETAUDIOMODE_STACK) Log.d(LOG_TAG, "Stack:", new Throwable("stack dump"));
1841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
1842a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan            if (DBG) Log.d(LOG_TAG, "setAudioMode() no change: "
1843a4b443115c1442c9d65ba58fcb667b0e025993deHung-ying Tyan                    + audioModeToString(modeBefore));
1844b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1845b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1846b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static String audioModeToString(int mode) {
1847b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (mode) {
1848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case AudioManager.MODE_INVALID: return "MODE_INVALID";
1849b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case AudioManager.MODE_CURRENT: return "MODE_CURRENT";
1850b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case AudioManager.MODE_NORMAL: return "MODE_NORMAL";
1851b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case AudioManager.MODE_RINGTONE: return "MODE_RINGTONE";
1852b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case AudioManager.MODE_IN_CALL: return "MODE_IN_CALL";
1853b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            default: return String.valueOf(mode);
1854b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1855b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1856b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1857b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1858b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Handles the wired headset button while in-call.
1859b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1860b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This is called from the PhoneApp, not from the InCallScreen,
1861b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * since the HEADSETHOOK button means "mute or unmute the current
1862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * call" *any* time a call is active, even if the user isn't actually
1863b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * on the in-call screen.
1864b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1865b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we consumed the event.
1866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1867893d0233193b2095293d890a9ad1c73b1dc6a9a2mah    /* package */ static boolean handleHeadsetHook(Phone phone, KeyEvent event) {
1868893d0233193b2095293d890a9ad1c73b1dc6a9a2mah        if (DBG) log("handleHeadsetHook()..." + event.getAction() + " " + event.getRepeatCount());
1869b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1870b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // If the phone is totally idle, we ignore HEADSETHOOK events
1871b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // (and instead let them fall through to the media player.)
1872b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (phone.getState() == Phone.State.IDLE) {
1873b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
1874b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1876b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Ok, the phone is in use.
1877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // The headset button button means "Answer" if an incoming call is
1878b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // ringing.  If not, it toggles the mute / unmute state.
1879b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
1880b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // And in any case we *always* consume this event; this means
1881b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // that the usual mediaplayer-related behavior of the headset
1882b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // button will NEVER happen while the user is on a call.
1883b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1884b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
1885b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
1886b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
1887b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1888893d0233193b2095293d890a9ad1c73b1dc6a9a2mah        if (hasRingingCall &&
1889893d0233193b2095293d890a9ad1c73b1dc6a9a2mah            event.getRepeatCount() == 0 &&
1890893d0233193b2095293d890a9ad1c73b1dc6a9a2mah            event.getAction() == KeyEvent.ACTION_UP) {
18912312eba1a4821fd8f10535038555d12874e6fc67Wink Saville            // If an incoming call is ringing, answer it (just like with the
18922312eba1a4821fd8f10535038555d12874e6fc67Wink Saville            // CALL button):
189379b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            int phoneType = phone.getPhoneType();
189479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            if (phoneType == Phone.PHONE_TYPE_CDMA) {
18958343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                answerCall(phone.getRingingCall());
1896872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            } else if ((phoneType == Phone.PHONE_TYPE_GSM)
1897872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                    || (phoneType == Phone.PHONE_TYPE_SIP)) {
18980fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                if (hasActiveCall && hasHoldingCall) {
18990fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    if (DBG) log("handleHeadsetHook: ringing (both lines in use) ==> answer!");
19008343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    answerAndEndActive(PhoneApp.getInstance().mCM, phone.getRingingCall());
19010fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                } else {
19020fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    if (DBG) log("handleHeadsetHook: ringing ==> answer!");
19038343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    answerCall(phone.getRingingCall());  // Automatically holds the current active call,
19042312eba1a4821fd8f10535038555d12874e6fc67Wink Saville                                        // if there is one
19050fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                }
190679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            } else {
190779b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink                throw new IllegalStateException("Unexpected phone type: " + phoneType);
19082312eba1a4821fd8f10535038555d12874e6fc67Wink Saville            }
19092312eba1a4821fd8f10535038555d12874e6fc67Wink Saville        } else {
1910a52f06a12e64113097010cb126a722421c7c9cf3Peng Zhu            // No incoming ringing call.
1911893d0233193b2095293d890a9ad1c73b1dc6a9a2mah            if (event.isLongPress()) {
1912893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                if (DBG) log("handleHeadsetHook: longpress -> hangup");
19138343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                hangup(phone.getRingingCall());
1914893d0233193b2095293d890a9ad1c73b1dc6a9a2mah            }
1915893d0233193b2095293d890a9ad1c73b1dc6a9a2mah            else if (event.getAction() == KeyEvent.ACTION_UP &&
1916893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                     event.getRepeatCount() == 0) {
1917893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                Connection c = phone.getForegroundCall().getLatestConnection();
1918893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                // If it is NOT an emg #, toggle the mute state. Otherwise, ignore the hook.
1919893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                if (c != null && !PhoneNumberUtils.isEmergencyNumber(c.getAddress())) {
1920a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                    if (getMute()) {
1921893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                        if (DBG) log("handleHeadsetHook: UNmuting...");
1922a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        setMute(false);
1923893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                    } else {
1924893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                        if (DBG) log("handleHeadsetHook: muting...");
1925a50e10e2efadac960987eaadc0938c6f92d3ee90John Wang                        setMute(true);
1926893d0233193b2095293d890a9ad1c73b1dc6a9a2mah                    }
1927a52f06a12e64113097010cb126a722421c7c9cf3Peng Zhu                }
1928b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1929b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1930b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1931b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Even if the InCallScreen is the current activity, there's no
1932b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // need to force it to update, because (1) if we answered a
1933b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // ringing call, the InCallScreen will imminently get a phone
1934b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // state change event (causing an update), and (2) if we muted or
1935b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // unmuted, the setMute() call automagically updates the status
1936b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // bar, and there's no "mute" indication in the InCallScreen
1937b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // itself (other than the menu item, which only ever stays
1938b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // onscreen for a second anyway.)
1939b8df8173e1a0ea8ba89cea984176216201c4d5e7Paul Berman        // TODO: (2) isn't entirely true anymore. Once we return our result
1940b8df8173e1a0ea8ba89cea984176216201c4d5e7Paul Berman        // to the PhoneApp, we ask InCallScreen to update its control widgets
1941b8df8173e1a0ea8ba89cea984176216201c4d5e7Paul Berman        // in case we changed mute or speaker state and phones with touch-
1942b8df8173e1a0ea8ba89cea984176216201c4d5e7Paul Berman        // screen [toggle] buttons need to update themselves.
1943b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1944b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return true;
1945b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1946b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1947b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1948b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Look for ANY connections on the phone that qualify as being
1949b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * disconnected.
1950b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1951b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we find a connection that is disconnected over
1952b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * all the phone's call objects.
1953b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1954b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ static boolean hasDisconnectedConnections(Phone phone) {
1955b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return hasDisconnectedConnections(phone.getForegroundCall()) ||
1956b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                hasDisconnectedConnections(phone.getBackgroundCall()) ||
1957b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                hasDisconnectedConnections(phone.getRingingCall());
1958b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1959b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1960b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1961b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Iterate over all connections in a call to see if there are any
1962b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * that are not alive (disconnected or idle).
1963b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
1964b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we find a connection that is disconnected, and
1965b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * pending removal via
1966a69de9f9a2e99fe08f0009bb218b95ed7985c575Wink Saville     * {@link com.android.internal.telephony.gsm.GsmCall#clearDisconnected()}.
1967b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
1968b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final boolean hasDisconnectedConnections(Call call) {
1969b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // look through all connections for non-active ones.
1970b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (Connection c : call.getConnections()) {
1971b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!c.isAlive()) {
1972b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
1973b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
1974b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
1975b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
1976b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
1977b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1978b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    //
1979b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // Misc UI policy helper functions
1980b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    //
1981b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1982b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
1983b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we're allowed to swap calls, given the current
1984b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * state of the Phone.
1985b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
19868343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    /* package */ static boolean okToSwapCalls(CallManager cm) {
19878343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        int phoneType = cm.getDefaultPhone().getPhoneType();
198879b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
19890fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // CDMA: "Swap" is enabled only when the phone reaches a *generic*.
19900fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // state by either accepting a Call Waiting or by merging two calls
19910fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            PhoneApp app = PhoneApp.getInstance();
19920fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            return (app.cdmaPhoneCallState.getCurrentCallState()
19930fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
1994872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
1995872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
19960fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // GSM: "Swap" is available if both lines are in use and there's no
19970fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // incoming call.  (Actually we need to verify that the active
19980fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // call really is in the ACTIVE state and the holding call really
19990fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // is in the HOLDING state, since you *can't* actually swap calls
20000fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // when the foreground call is DIALING or ALERTING.)
20018343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            return !cm.hasActiveRingingCall()
20028343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    && (cm.getActiveFgCall().getState() == Call.State.ACTIVE)
20038343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    && (cm.getFirstActiveBgCall().getState() == Call.State.HOLDING);
200479b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
200579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            throw new IllegalStateException("Unexpected phone type: " + phoneType);
20060fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
2007b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2008b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2009b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
2010b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if we're allowed to merge calls, given the current
2011b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * state of the Phone.
2012b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
20138343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    /* package */ static boolean okToMergeCalls(CallManager cm) {
20148343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        int phoneType = cm.getFgPhone().getPhoneType();
201579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
20160fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // CDMA: "Merge" is enabled only when the user is in a 3Way call.
20170fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            PhoneApp app = PhoneApp.getInstance();
201839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai            return ((app.cdmaPhoneCallState.getCurrentCallState()
201939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
202039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
2021b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan        } else {
20220fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // GSM: "Merge" is available if both lines are in use and there's no
20230fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // incoming call, *and* the current conference isn't already
20240fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // "full".
20258343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // TODO: shall move all okToMerge logic to CallManager
2026b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan            return !cm.hasActiveRingingCall() && cm.hasActiveFgCall()
2027b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                    && cm.hasActiveBgCall()
2028b045b9344f339170d134cf814357361d96c349cfHung-ying Tyan                    && cm.canConference(cm.getFirstActiveBgCall());
20290fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
2030b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2031b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2032b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
2033b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @return true if the UI should let you add a new call, given the current
2034b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * state of the Phone.
2035b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
20368343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    /* package */ static boolean okToAddCall(CallManager cm) {
20378343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Phone phone = cm.getActiveFgCall().getPhone();
20388343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
203979b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        int phoneType = phone.getPhoneType();
20408343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        final Call.State fgCallState = cm.getActiveFgCall().getState();
204179b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phoneType == Phone.PHONE_TYPE_CDMA) {
20420fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville           // CDMA: "Add call" menu item is only enabled when the call is in
204339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai           // - ForegroundCall is in ACTIVE state
204439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai           // - After 30 seconds of user Ignoring/Missing a Call Waiting call.
20450fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            PhoneApp app = PhoneApp.getInstance();
204639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai            return ((fgCallState == Call.State.ACTIVE)
20470fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
2048872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        } else if ((phoneType == Phone.PHONE_TYPE_GSM)
2049872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                || (phoneType == Phone.PHONE_TYPE_SIP)) {
20500fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // GSM: "Add call" is available only if ALL of the following are true:
20510fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // - There's no incoming ringing call
20520fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // - There's < 2 lines in use
20530fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            // - The foreground call is ACTIVE or IDLE or DISCONNECTED.
20540fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            //   (We mainly need to make sure it *isn't* DIALING or ALERTING.)
20558343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            final boolean hasRingingCall = cm.hasActiveRingingCall();
20568343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            final boolean hasActiveCall = cm.hasActiveFgCall();
20578343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            final boolean hasHoldingCall = cm.hasActiveBgCall();
20580fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
20590fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville
20600fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville            return !hasRingingCall
20610fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    && !allLinesTaken
20620fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                    && ((fgCallState == Call.State.ACTIVE)
20630fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        || (fgCallState == Call.State.IDLE)
20640fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville                        || (fgCallState == Call.State.DISCONNECTED));
206579b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        } else {
206679b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink            throw new IllegalStateException("Unexpected phone type: " + phoneType);
20670fb2b4b8eff811fd3243aefdf536e7ba2b10f4e9Wink Saville        }
2068b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2069b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
207086c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu    /**
207186c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu     * Based on the input CNAP number string,
207286c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu     * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings.
207386c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu     * Otherwise, return CNAP_SPECIAL_CASE_NO.
207486c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu     */
207586c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu    private static int checkCnapSpecialCases(String n) {
207686c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu        if (n.equals("PRIVATE") ||
207786c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                n.equals("P") ||
207886c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                n.equals("RES")) {
207986c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            if (DBG) log("checkCnapSpecialCases, PRIVATE string: " + n);
208086c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            return Connection.PRESENTATION_RESTRICTED;
208186c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu        } else if (n.equals("UNAVAILABLE") ||
208286c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                n.equals("UNKNOWN") ||
208386c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                n.equals("UNA") ||
208486c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu                n.equals("U")) {
208586c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            if (DBG) log("checkCnapSpecialCases, UNKNOWN string: " + n);
208686c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            return Connection.PRESENTATION_UNKNOWN;
208786c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu        } else {
208886c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            if (DBG) log("checkCnapSpecialCases, normal str. number: " + n);
208986c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu            return CNAP_SPECIAL_CASE_NO;
209086c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu        }
209186c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu    }
209286c4a92aff88506bc81a7ad6d8a3853cd7fbe597Peng Zhu
2093153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman    /**
2094153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * Handles certain "corner cases" for CNAP. When we receive weird phone numbers
2095153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * from the network to indicate different number presentations, convert them to
2096153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * expected number and presentation values within the CallerInfo object.
2097153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * @param number number we use to verify if we are in a corner case
2098153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * @param presentation presentation value used to verify if we are in a corner case
2099153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     * @return the new String that should be used for the phone number
2100153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman     */
2101153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman    /* package */ static String modifyForSpecialCnapCases(Context context, CallerInfo ci,
2102153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            String number, int presentation) {
2103de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // Obviously we return number if ci == null, but still return number if
2104de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // number == null, because in these cases the correct string will still be
2105de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // displayed/logged after this function returns based on the presentation value.
21065607afe15a507715078025beff1bd743c883a5ccPaul Berman        if (ci == null || number == null) return number;
21075607afe15a507715078025beff1bd743c883a5ccPaul Berman
21085607afe15a507715078025beff1bd743c883a5ccPaul Berman        if (DBG) log("modifyForSpecialCnapCases: initially, number=" + number
2109a1449e3a5d5d9d5e0e8982c7098752ce11477680Nicolas Catania                + ", presentation=" + presentation + " ci " + ci);
2110153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman
2111153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        // "ABSENT NUMBER" is a possible value we could get from the network as the
2112153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        // phone number, so if this happens, change it to "Unknown" in the CallerInfo
2113153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        // and fix the presentation to be the same.
2114de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        if (number.equals(context.getString(R.string.absent_num))
2115de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                && presentation == Connection.PRESENTATION_ALLOWED) {
2116153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            number = context.getString(R.string.unknown);
2117153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            ci.numberPresentation = Connection.PRESENTATION_UNKNOWN;
2118153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        }
2119153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman
2120de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // Check for other special "corner cases" for CNAP and fix them similarly. Corner
2121de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // cases only apply if we received an allowed presentation from the network, so check
2122de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't
2123de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // match the presentation passed in for verification (meaning we changed it previously
2124de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman        // because it's a corner case and we're being called from a different entry point).
2125153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        if (ci.numberPresentation == Connection.PRESENTATION_ALLOWED
2126de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                || (ci.numberPresentation != presentation
2127de0d16c814b5e7f6c75d00025dc331f64703de1cPaul Berman                        && presentation == Connection.PRESENTATION_ALLOWED)) {
2128153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            int cnapSpecialCase = checkCnapSpecialCases(number);
2129153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) {
2130153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                // For all special strings, change number & numberPresentation.
2131153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                if (cnapSpecialCase == Connection.PRESENTATION_RESTRICTED) {
2132153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                    number = context.getString(R.string.private_num);
2133153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                } else if (cnapSpecialCase == Connection.PRESENTATION_UNKNOWN) {
2134153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                    number = context.getString(R.string.unknown);
2135153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                }
2136153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                if (DBG) log("SpecialCnap: number=" + number
2137153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                        + "; presentation now=" + cnapSpecialCase);
2138153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman                ci.numberPresentation = cnapSpecialCase;
2139153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman            }
2140153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        }
21415607afe15a507715078025beff1bd743c883a5ccPaul Berman        if (DBG) log("modifyForSpecialCnapCases: returning number string=" + number);
2142153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman        return number;
2143153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman    }
2144153e79d8d413b1ccd4abf55a8dbe4e266aa92799Paul Berman
2145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    //
21467a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    // Support for 3rd party phone service providers.
21477a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    //
21487a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania
21497a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    /**
2150d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     * Check if all the provider's info is present in the intent.
2151d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     * @param intent Expected to have the provider's extra.
2152d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     * @return true if the intent has all the extras to build the
2153d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     * in-call screen's provider info overlay.
2154d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania     */
2155d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania    /* package */ static boolean hasPhoneProviderExtras(Intent intent) {
21562cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        if (null == intent) {
21576fac3a6bdab79725a2ca2e3102eccb3f6e9c1ac4Nicolas Catania            return false;
21586fac3a6bdab79725a2ca2e3102eccb3f6e9c1ac4Nicolas Catania        }
21592cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        final String name = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
21602cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        final String gatewayUri = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI);
21612cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
21625e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        return !TextUtils.isEmpty(name) && !TextUtils.isEmpty(gatewayUri);
2163d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania    }
2164d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania
2165d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania    /**
21667a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * Copy all the expected extras set when a 3rd party provider is
21677a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * used from the source intent to the destination one.  Checks all
21687a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * the required extras are present, if any is missing, none will
21697a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * be copied.
21707a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param src Intent which may contain the provider's extras.
21717a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     * @param dst Intent where a copy of the extras will be added if applicable.
21727a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania     */
2173d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania    /* package */ static void checkAndCopyPhoneProviderExtras(Intent src, Intent dst) {
2174d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        if (!hasPhoneProviderExtras(src)) {
2175f24849566edae03c1123203b4362c688d8fa57a9Nicolas Catania            Log.d(LOG_TAG, "checkAndCopyPhoneProviderExtras: some or all extras are missing.");
2176d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania            return;
21777a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania        }
2178d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania
2179d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        dst.putExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE,
2180d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania                     src.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE));
2181d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        dst.putExtra(InCallScreen.EXTRA_GATEWAY_URI,
2182d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania                     src.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI));
21837a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    }
21847a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania
218562ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania    /**
21862cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * Get the provider's label from the intent.
21872cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @param context to lookup the provider's package name.
21882cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @param intent with an extra set to the provider's package name.
21895e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * @return The provider's application label. null if an error
21905e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * occurred during the lookup of the package name or the label.
21912cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     */
21922cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /* package */ static CharSequence getProviderLabel(Context context, Intent intent) {
21932cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        String packageName = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
21942cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        PackageManager pm = context.getPackageManager();
21952cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
21962cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        try {
21972cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
21982cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
21992cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            return pm.getApplicationLabel(info);
22002cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        } catch (PackageManager.NameNotFoundException e) {
22012cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            return null;
22022cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        }
22032cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    }
22042cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
22052cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /**
22065e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * Get the provider's icon.
22075e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * @param context to lookup the provider's icon.
22085e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * @param intent with an extra set to the provider's package name.
22095e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     * @return The provider's application icon. null if an error occured during the icon lookup.
22105e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania     */
22115e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania    /* package */ static Drawable getProviderIcon(Context context, Intent intent) {
22125e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        String packageName = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_PROVIDER_PACKAGE);
22135e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        PackageManager pm = context.getPackageManager();
22145e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania
22155e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        try {
22165e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania            return pm.getApplicationIcon(packageName);
22175e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        } catch (PackageManager.NameNotFoundException e) {
22185e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania            return null;
22195e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania        }
22205e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania    }
22215e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania
22225e16b62c17a9ad0457008953e2228d5ee8a406d3Nicolas Catania    /**
22232cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * Return the gateway uri from the intent.
22242cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @param intent With the gateway uri extra.
22252cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @return The gateway URI or null if not found.
22262cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     */
22272cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /* package */ static Uri getProviderGatewayUri(Intent intent) {
22282cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        String uri = intent.getStringExtra(InCallScreen.EXTRA_GATEWAY_URI);
22292cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
22302cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    }
22312cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
22322cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /**
22332cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * Return a formatted version of the uri's scheme specific
22342cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * part. E.g for 'tel:12345678', return '1-234-5678'.
22352cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @param uri A 'tel:' URI with the gateway phone number.
22362cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * @return the provider's address (from the gateway uri) formatted
22372cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     * for user display. null if uri was null or its scheme was not 'tel:'.
22382cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania     */
22392cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /* package */ static String formatProviderUri(Uri uri) {
22402cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        if (null != uri) {
22412cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            if ("tel".equals(uri.getScheme())) {
22422cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania                return PhoneNumberUtils.formatNumber(uri.getSchemeSpecificPart());
22432cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            } else {
22442cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania                return uri.toString();
22452cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania            }
22462cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        }
22472cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania        return null;
22482cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    }
22492cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania
22502cbf80dfbbc28ae24e093fb089973b3e59d4508aNicolas Catania    /**
225162ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * Check if a phone number can be route through a 3rd party
225262ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * gateway. The number must be a global phone number in numerical
225362ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * form (1-800-666-SEXY won't work).
225462ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     *
225562ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * MMI codes and the like cannot be used as a dial number for the
225662ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * gateway either.
225762ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     *
225862ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * @param number To be dialed via a 3rd party gateway.
225962ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     * @return true If the number can be routed through the 3rd party network.
226062ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania     */
226162ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania    /* package */ static boolean isRoutableViaGateway(String number) {
226262ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        if (TextUtils.isEmpty(number)) {
226362ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania            return false;
226462ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        }
226562ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        number = PhoneNumberUtils.stripSeparators(number);
226662ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        if (!number.equals(PhoneNumberUtils.convertKeypadLettersToDigits(number))) {
226762ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania            return false;
226862ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        }
226962ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        number = PhoneNumberUtils.extractNetworkPortion(number);
227062ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania        return PhoneNumberUtils.isGlobalPhoneNumber(number);
227162ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania    }
227262ce1135ff91e303d80cac0434ed5232edb63c86Nicolas Catania
22732eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu   /**
22742eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    * This function is called when phone answers or places a call.
22752eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    * Check if the phone is in a car dock or desk dock.
22762eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    * If yes, turn on the speaker, when no wired or BT headsets are connected.
22772eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    * Otherwise do nothing.
22782eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    */
22792eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    private static void activateSpeakerIfDocked(Phone phone) {
22802eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu        if (DBG) log("activateSpeakerIfDocked()...");
22812eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu
22822eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu        if (PhoneApp.mDockState == Intent.EXTRA_DOCK_STATE_DESK ||
22832eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                PhoneApp.mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
22847f63f08c5c88d604abba447032ed42f4f972f3efDavid Brown            if (DBG) log("activateSpeakerIfDocked(): In a dock -> may need to turn on speaker.");
22852eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu            PhoneApp app = PhoneApp.getInstance();
22862eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu            BluetoothHandsfree bthf = app.getBluetoothHandsfree();
22872eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu
22882eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu            if (!app.isHeadsetPlugged() && !(bthf != null && bthf.isAudioOn())) {
22892eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu                turnOnSpeaker(phone.getContext(), true, true);
22902eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu            }
22912eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu        }
22922eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu    }
22932eba6fabd0bedaf2a59da643ce475586b62f0ff9Peng Zhu
2294aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown
2295aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown    /**
2296aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown     * Returns whether the phone is in ECM ("Emergency Callback Mode") or not.
2297aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown     */
2298aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown    /* package */ static boolean isPhoneInEcm(Phone phone) {
22998343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        if ((phone != null) && TelephonyCapabilities.supportsEcm(phone)) {
23008343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // For phones that support ECM, return true iff PROPERTY_INECM_MODE == "true".
23018343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // TODO: There ought to be a better API for this than just
23028343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // exposing a system property all the way up to the app layer,
23038343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // probably a method like "inEcm()" provided by the telephony
23048343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            // layer.
2305aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown            String ecmMode =
2306aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown                    SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
2307aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown            if (ecmMode != null) {
23088343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                return ecmMode.equals("true");
23098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            }
23108343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        }
23118343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return false;
23128343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    }
23138343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
2314bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown    /**
2315bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * Returns the most appropriate Phone object to handle a call
2316bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * to the specified number.
2317bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     *
2318bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * @param cm the CallManager.
2319bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * @param scheme the scheme from the data URI that the number originally came from.
2320bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     * @param number the phone number, or SIP address.
2321bbc3b15705e4511da3c8fe3fc105ad99a85e1e0bDavid Brown     */
23222587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static Phone pickPhoneBasedOnNumber(CallManager cm,
23232587d9c6437b680911e252efecc73788e876de76Chung-yih Wang            String scheme, String number, String primarySipUri) {
23242587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        if (DBG) log("pickPhoneBasedOnNumber: scheme " + scheme
23252587d9c6437b680911e252efecc73788e876de76Chung-yih Wang                + ", number " + number + ", sipUri " + primarySipUri);
23262587d9c6437b680911e252efecc73788e876de76Chung-yih Wang
23272587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        if (primarySipUri != null) {
23282587d9c6437b680911e252efecc73788e876de76Chung-yih Wang            Phone phone = getSipPhoneFromUri(cm, primarySipUri);
23292587d9c6437b680911e252efecc73788e876de76Chung-yih Wang            if (phone != null) return phone;
23302587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        }
23312587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        return cm.getDefaultPhone();
23322587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    }
23332587d9c6437b680911e252efecc73788e876de76Chung-yih Wang
23342587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static Phone getSipPhoneFromUri(CallManager cm, String target) {
2335872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan        for (Phone phone : cm.getAllPhones()) {
2336872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan            if (phone.getPhoneType() == Phone.PHONE_TYPE_SIP) {
2337872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                String sipUri = ((SipPhone) phone).getSipUri();
23382587d9c6437b680911e252efecc73788e876de76Chung-yih Wang                if (target.equals(sipUri)) {
23392587d9c6437b680911e252efecc73788e876de76Chung-yih Wang                    if (DBG) log("- pickPhoneBasedOnNumber:" +
2340872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                            "found SipPhone! obj = " + phone + ", "
2341872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                            + phone.getClass());
2342872a3a7af50ce6a4efb180336614bddefe102ac5Hung-ying Tyan                    return phone;
23438343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                }
2344aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown            }
2345aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown        }
23462587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        return null;
2347aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown    }
2348f8396c51f11b1044d236415f2ee88750b4e40e1fJohn Wang
23498343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    public static boolean isRealIncomingCall(Call.State state) {
23508343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        return (state == Call.State.INCOMING && !PhoneApp.getInstance().mCM.hasActiveFgCall());
23518343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
23528343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    }
2353aa3d3cfb32c7350f72771db8756e751eb5c61b1eDavid Brown
23547a2ee085993bc9cae01bf9daa993b1551ed64a7bNicolas Catania    //
2355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // General phone and call state debugging/testing code
2356b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    //
2357b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2358b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan    private static void dumpStateForCall(Call call, String prefix) {
2359b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        StringBuilder b = new StringBuilder(128);
2360b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(prefix).append(call.getState());
2361b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" ").append(call.getPhone().getPhoneName());
2362b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" isAlive ").append(call.getState().isAlive());
2363b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" isRinging ").append(call.getState().isRinging());
2364b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" isDialing ").append(call.getState().isDialing());
2365b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" isIdle ").append(call.isIdle());
2366b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" hasConnections ").append(call.hasConnections());
2367b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Log.d(LOG_TAG, b.toString());
2368b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan    }
2369b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2370b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan    /* package */ static void dumpCallState() {
2371b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        PhoneApp app = PhoneApp.getInstance();
2372b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        CallManager cm = app.mCM;
2373b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Log.d(LOG_TAG, "dumpCallState():");
2374b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Log.d(LOG_TAG, "- Call state = " + cm.getState());
2375b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2376b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        dumpStateForCall(cm.getActiveFgCall(), "  - FG call: ");
2377b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        dumpStateForCall(cm.getFirstActiveBgCall(), "  - BG call: ");
2378b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        dumpStateForCall(cm.getFirstActiveRingingCall(), "  - RINGING call: ");
2379b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2380b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        final boolean hasRingingCall = cm.hasActiveRingingCall();
2381b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        final boolean hasActiveCall = cm.hasActiveFgCall();
2382b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        final boolean hasHoldingCall = cm.hasActiveBgCall();
2383b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
2384b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        StringBuilder b = new StringBuilder(128);
2385b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append("  - hasRingingCall ").append(hasRingingCall);
2386b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" hasActiveCall ").append(hasActiveCall);
2387b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" hasHoldingCall ").append(hasHoldingCall);
2388b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        b.append(" allLinesTaken ").append(allLinesTaken);
2389b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Log.d(LOG_TAG, b.toString());
2390b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2391b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Phone phone = cm.getDefaultPhone();
2392b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        // On CDMA phones, dump out the CdmaPhoneCallState too:
2393b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
2394b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan            if (app.cdmaPhoneCallState != null) {
2395b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan                Log.d(LOG_TAG, "  - CDMA call state: "
2396b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan                      + app.cdmaPhoneCallState.getCurrentCallState());
2397b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan            } else {
2398b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan                Log.d(LOG_TAG, "  - CDMA device, but null cdmaPhoneCallState!");
2399b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan            }
2400b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        }
2401b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2402b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        // Watch out: the isRinging() call below does NOT tell us anything
2403b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        // about the state of the telephony layer; it merely tells us whether
2404b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        // the Ringer manager is currently playing the ringtone.
2405b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        boolean ringing = app.getRinger().isRinging();
2406b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan        Log.d(LOG_TAG, "  - Ringer state: " + ringing);
2407b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan    }
2408b5190cc81c5cf5ea7bc8f92734b5824bf0b20854Hung-ying Tyan
2409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ static void dumpCallState(Phone phone) {
24100f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown        PhoneApp app = PhoneApp.getInstance();
24111e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, "dumpCallState():");
2412b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown        Log.d(LOG_TAG, "- Phone: " + phone + ", name = " + phone.getPhoneName()
2413b15bef0ddcb4f744dff92013a9b596f2fcc2a008David Brown              + ", state = " + phone.getState());
2414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
24151e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        StringBuilder b = new StringBuilder(128);
24161e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown
24171e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Call call = phone.getForegroundCall();
24181e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.setLength(0);
24191e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append("  - FG call: ").append(call.getState());
24201e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isAlive ").append(call.getState().isAlive());
24211e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isRinging ").append(call.getState().isRinging());
24221e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isDialing ").append(call.getState().isDialing());
24231e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isIdle ").append(call.isIdle());
24241e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" hasConnections ").append(call.hasConnections());
24251e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, b.toString());
24261e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown
24271e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        call = phone.getBackgroundCall();
24281e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.setLength(0);
24291e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append("  - BG call: ").append(call.getState());
24301e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isAlive ").append(call.getState().isAlive());
24311e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isRinging ").append(call.getState().isRinging());
24321e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isDialing ").append(call.getState().isDialing());
24331e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isIdle ").append(call.isIdle());
24341e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" hasConnections ").append(call.hasConnections());
24351e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, b.toString());
24361e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown
24371e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        call = phone.getRingingCall();
24381e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.setLength(0);
24391e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append("  - RINGING call: ").append(call.getState());
24401e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isAlive ").append(call.getState().isAlive());
24411e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isRinging ").append(call.getState().isRinging());
24421e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isDialing ").append(call.getState().isDialing());
24431e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" isIdle ").append(call.isIdle());
24441e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" hasConnections ").append(call.hasConnections());
24451e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, b.toString());
2446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
2449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
2450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
2451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
24521e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.setLength(0);
24531e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append("  - hasRingingCall ").append(hasRingingCall);
24541e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" hasActiveCall ").append(hasActiveCall);
24551e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" hasHoldingCall ").append(hasHoldingCall);
24561e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        b.append(" allLinesTaken ").append(allLinesTaken);
24571e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, b.toString());
2458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
24590f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown        // On CDMA phones, dump out the CdmaPhoneCallState too:
246079b9f6e30e8402b103f1ec3ed9dda1fcad2b1cd5Tammo Spalink        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
24610f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown            if (app.cdmaPhoneCallState != null) {
24621e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown                Log.d(LOG_TAG, "  - CDMA call state: "
24630f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown                      + app.cdmaPhoneCallState.getCurrentCallState());
24640f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown            } else {
24651e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown                Log.d(LOG_TAG, "  - CDMA device, but null cdmaPhoneCallState!");
24660f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown            }
24670f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown        }
24680f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown
2469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Watch out: the isRinging() call below does NOT tell us anything
2470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // about the state of the telephony layer; it merely tells us whether
2471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // the Ringer manager is currently playing the ringtone.
24720f68bb19e2cca0bb7f70e2fcf16e0747a0036885David Brown        boolean ringing = app.getRinger().isRinging();
24731e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown        Log.d(LOG_TAG, "  - Ringer state: " + ringing);
2474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
2475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static void log(String msg) {
2477796c70c99bc39295bf685061056f06ab8949c742David Brown        Log.d(LOG_TAG, msg);
2478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
24798343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
24808343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    static void dumpCallManager() {
24818343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Call call;
24828343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        CallManager cm = PhoneApp.getInstance().mCM;
24838343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        StringBuilder b = new StringBuilder(128);
24848343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
24858343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, "############### dumpCallManager() ##############");
24868343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, "CallManager: " + cm
24878343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                + ", state = " + cm.getState());
24888343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.setLength(0);
24898343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        call = cm.getActiveFgCall();
24908343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(" - FG call: ").append(cm.hasActiveFgCall()? "YES ": "NO ");
24918343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(call);
24928343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append( "  State: ").append(cm.getActiveFgCallState());
24938343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append( "  Conn: ").append(cm.getFgCallConnections());
24948343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, b.toString());
24958343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.setLength(0);
24968343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        call = cm.getFirstActiveBgCall();
24978343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(" - BG call: ").append(cm.hasActiveBgCall()? "YES ": "NO ");
24988343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(call);
24998343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append( "  State: ").append(cm.getFirstActiveBgCall().getState());
25008343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append( "  Conn: ").append(cm.getBgCallConnections());
25018343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, b.toString());
25028343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.setLength(0);
25038343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        call = cm.getFirstActiveRingingCall();
25048343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(" - RINGING call: ").append(cm.hasActiveRingingCall()? "YES ": "NO ");
25058343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append(call);
25068343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        b.append( "  State: ").append(cm.getFirstActiveRingingCall().getState());
25078343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, b.toString());
25088343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
25098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
25108343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
25118343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        for (Phone phone : CallManager.getInstance().getAllPhones()) {
25128343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (phone != null) {
25138343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                Log.d(LOG_TAG, "Phone: " + phone + ", name = " + phone.getPhoneName()
25148343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                        + ", state = " + phone.getState());
25158343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.setLength(0);
25168343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                call = phone.getForegroundCall();
25178343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append(" - FG call: ").append(call);
25188343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  State: ").append(call.getState());
25198343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  Conn: ").append(call.hasConnections());
25208343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                Log.d(LOG_TAG, b.toString());
25218343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.setLength(0);
25228343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                call = phone.getBackgroundCall();
25238343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append(" - BG call: ").append(call);
25248343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  State: ").append(call.getState());
25258343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  Conn: ").append(call.hasConnections());
25268343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                Log.d(LOG_TAG, b.toString());b.setLength(0);
25278343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                call = phone.getRingingCall();
25288343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append(" - RINGING call: ").append(call);
25298343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  State: ").append(call.getState());
25308343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                b.append( "  Conn: ").append(call.hasConnections());
25318343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                Log.d(LOG_TAG, b.toString());
25328343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            }
25338343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        }
25348343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
25358343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        Log.d(LOG_TAG, "############## END dumpCallManager() ###############");
25368343169cc89621d46dce86449f5ee1ff5d3a4919John Wang    }
25378343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
2538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
2539