blob: f26fff727b37a51bbd9f5bf78eb9f5a53bb94d40 [file] [log] [blame]
Chiao Chenge41661c2013-07-23 13:28:26 -07001/*
Santos Cordoncba1b442013-07-18 12:43:58 -07002 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
Chiao Chenge41661c2013-07-23 13:28:26 -070014 * limitations under the License
Santos Cordoncba1b442013-07-18 12:43:58 -070015 */
16
17package com.android.phone;
18
Santos Cordoneead6ec2013-08-07 22:16:33 -070019import android.bluetooth.IBluetoothHeadsetPhone;
Chiao Chenge41661c2013-07-23 13:28:26 -070020import android.content.Context;
Santos Cordoneead6ec2013-08-07 22:16:33 -070021import android.os.RemoteException;
Santos Cordonb01deb52013-08-06 23:46:06 -070022import android.os.SystemProperties;
Chiao Chenge41661c2013-07-23 13:28:26 -070023import android.util.Log;
24
Santos Cordoncba1b442013-07-18 12:43:58 -070025import com.android.internal.telephony.CallManager;
Santos Cordoneead6ec2013-08-07 22:16:33 -070026import com.android.internal.telephony.PhoneConstants;
Santos Cordon249efd02013-08-05 03:33:56 -070027import com.android.phone.CallModeler.CallResult;
Yorke Lee362cec22013-09-18 15:20:26 -070028import com.android.phone.NotificationMgr.StatusBarHelper;
Santos Cordon9b7bac72013-08-06 08:04:52 -070029import com.android.services.telephony.common.AudioMode;
Santos Cordon249efd02013-08-05 03:33:56 -070030import com.android.services.telephony.common.Call;
Santos Cordoncba1b442013-07-18 12:43:58 -070031import com.android.services.telephony.common.ICallCommandService;
32
33/**
Chiao Chenge41661c2013-07-23 13:28:26 -070034 * Service interface used by in-call ui to control phone calls using commands exposed as methods.
35 * Instances of this class are handed to in-call UI via CallMonitorService.
Santos Cordoncba1b442013-07-18 12:43:58 -070036 */
37class CallCommandService extends ICallCommandService.Stub {
Chiao Chenge41661c2013-07-23 13:28:26 -070038 private static final String TAG = CallCommandService.class.getSimpleName();
Santos Cordonb01deb52013-08-06 23:46:06 -070039 private static final boolean DBG =
40 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
Chiao Chenge41661c2013-07-23 13:28:26 -070041
Santos Cordon249efd02013-08-05 03:33:56 -070042 private final Context mContext;
43 private final CallManager mCallManager;
44 private final CallModeler mCallModeler;
Santos Cordon2eaff902013-08-05 04:37:55 -070045 private final DTMFTonePlayer mDtmfTonePlayer;
Santos Cordon9b7bac72013-08-06 08:04:52 -070046 private final AudioRouter mAudioRouter;
Santos Cordoncba1b442013-07-18 12:43:58 -070047
Santos Cordon2eaff902013-08-05 04:37:55 -070048 public CallCommandService(Context context, CallManager callManager, CallModeler callModeler,
David Braun35272072013-09-24 17:19:26 -070049 DTMFTonePlayer dtmfTonePlayer, AudioRouter audioRouter) {
Chiao Chenge41661c2013-07-23 13:28:26 -070050 mContext = context;
Santos Cordoncba1b442013-07-18 12:43:58 -070051 mCallManager = callManager;
Santos Cordon249efd02013-08-05 03:33:56 -070052 mCallModeler = callModeler;
Santos Cordon2eaff902013-08-05 04:37:55 -070053 mDtmfTonePlayer = dtmfTonePlayer;
Santos Cordon9b7bac72013-08-06 08:04:52 -070054 mAudioRouter = audioRouter;
Santos Cordoncba1b442013-07-18 12:43:58 -070055 }
56
57 /**
Christine Chen91db67d2013-09-18 12:01:11 -070058 * TODO: Add a confirmation callback parameter.
Santos Cordoncba1b442013-07-18 12:43:58 -070059 */
60 @Override
61 public void answerCall(int callId) {
Chiao Chenge41661c2013-07-23 13:28:26 -070062 try {
Santos Cordon249efd02013-08-05 03:33:56 -070063 CallResult result = mCallModeler.getCallWithId(callId);
64 if (result != null) {
65 PhoneUtils.answerCall(result.getConnection().getCall());
66 }
Chiao Chenge41661c2013-07-23 13:28:26 -070067 } catch (Exception e) {
68 Log.e(TAG, "Error during answerCall().", e);
69 }
Santos Cordoncba1b442013-07-18 12:43:58 -070070 }
71
72 /**
Christine Chen91db67d2013-09-18 12:01:11 -070073 * TODO: Add a confirmation callback parameter.
Santos Cordoncba1b442013-07-18 12:43:58 -070074 */
75 @Override
Christine Chenee09a492013-08-06 16:02:29 -070076 public void rejectCall(int callId, boolean rejectWithMessage, String message) {
Chiao Chenge41661c2013-07-23 13:28:26 -070077 try {
Santos Cordon249efd02013-08-05 03:33:56 -070078 CallResult result = mCallModeler.getCallWithId(callId);
79 if (result != null) {
Yorke Lee814da302013-08-30 16:01:07 -070080 final String number = result.getConnection().getAddress();
Christine Chen0ce0e852013-08-09 18:26:31 -070081
Yorke Lee814da302013-08-30 16:01:07 -070082 if (rejectWithMessage) {
David Braun35272072013-09-24 17:19:26 -070083 RejectWithTextMessageManager.rejectCallWithMessage(
Christine Chen0ce0e852013-08-09 18:26:31 -070084 result.getConnection().getCall(), message);
Yorke Lee814da302013-08-30 16:01:07 -070085 }
David Braun35272072013-09-24 17:19:26 -070086
87 Log.v(TAG, "Hanging up");
88 PhoneUtils.hangupRingingCall(result.getConnection().getCall());
Santos Cordon249efd02013-08-05 03:33:56 -070089 }
Chiao Chenge41661c2013-07-23 13:28:26 -070090 } catch (Exception e) {
91 Log.e(TAG, "Error during rejectCall().", e);
92 }
Santos Cordoncba1b442013-07-18 12:43:58 -070093 }
94
95 @Override
96 public void disconnectCall(int callId) {
Chiao Chenge41661c2013-07-23 13:28:26 -070097 try {
Santos Cordon249efd02013-08-05 03:33:56 -070098 CallResult result = mCallModeler.getCallWithId(callId);
Santos Cordonb01deb52013-08-06 23:46:06 -070099 if (DBG) Log.d(TAG, "disconnectCall " + result.getCall());
100
Santos Cordon249efd02013-08-05 03:33:56 -0700101 if (result != null) {
102 int state = result.getCall().getState();
Santos Cordon4ad64cd2013-08-15 00:36:14 -0700103 if (Call.State.ACTIVE == state ||
104 Call.State.ONHOLD == state ||
Christine Chen45277022013-09-05 10:55:37 -0700105 Call.State.DIALING == state) {
Santos Cordon249efd02013-08-05 03:33:56 -0700106 result.getConnection().getCall().hangup();
Christine Chen45277022013-09-05 10:55:37 -0700107 } else if (Call.State.CONFERENCED == state) {
108 result.getConnection().hangup();
Santos Cordon249efd02013-08-05 03:33:56 -0700109 }
110 }
Chiao Chenge41661c2013-07-23 13:28:26 -0700111 } catch (Exception e) {
112 Log.e(TAG, "Error during disconnectCall().", e);
113 }
114 }
115
116 @Override
Christine Chen45277022013-09-05 10:55:37 -0700117 public void separateCall(int callId) {
118 try {
119 CallResult result = mCallModeler.getCallWithId(callId);
120 if (DBG) Log.d(TAG, "disconnectCall " + result.getCall());
121
122 if (result != null) {
123 int state = result.getCall().getState();
124 if (Call.State.CONFERENCED == state) {
125 result.getConnection().separate();
126 }
127 }
128 } catch (Exception e) {
129 Log.e(TAG, "Error trying to separate call.", e);
130 }
131 }
132
133 @Override
Santos Cordon2b65bf02013-07-29 14:09:44 -0700134 public void hold(int callId, boolean hold) {
135 try {
Santos Cordon249efd02013-08-05 03:33:56 -0700136 CallResult result = mCallModeler.getCallWithId(callId);
137 if (result != null) {
138 int state = result.getCall().getState();
Santos Cordon2eaff902013-08-05 04:37:55 -0700139 if (hold && Call.State.ACTIVE == state) {
Santos Cordon249efd02013-08-05 03:33:56 -0700140 PhoneUtils.switchHoldingAndActive(mCallManager.getFirstActiveBgCall());
141 } else if (!hold && Call.State.ONHOLD == state) {
142 PhoneUtils.switchHoldingAndActive(result.getConnection().getCall());
143 }
144 }
Santos Cordon2b65bf02013-07-29 14:09:44 -0700145 } catch (Exception e) {
146 Log.e(TAG, "Error trying to place call on hold.", e);
147 }
148 }
149
150 @Override
Santos Cordoneead6ec2013-08-07 22:16:33 -0700151 public void merge() {
152 if (PhoneUtils.okToMergeCalls(mCallManager)) {
153 PhoneUtils.mergeCalls(mCallManager);
154 }
155 }
156
157 @Override
158 public void addCall() {
159 // start new call checks okToAddCall() already
160 PhoneUtils.startNewCall(mCallManager);
161 }
162
163
164 @Override
165 public void swap() {
166 if (!PhoneUtils.okToSwapCalls(mCallManager)) {
167 // TODO: throw an error instead?
168 return;
169 }
170
171 // Swap the fg and bg calls.
172 // In the future we may provides some way for user to choose among
173 // multiple background calls, for now, always act on the first background calll.
174 PhoneUtils.switchHoldingAndActive(mCallManager.getFirstActiveBgCall());
175
176 final PhoneGlobals mApp = PhoneGlobals.getInstance();
177
178 // If we have a valid BluetoothPhoneService then since CDMA network or
179 // Telephony FW does not send us information on which caller got swapped
180 // we need to update the second call active state in BluetoothPhoneService internally
181 if (mCallManager.getBgPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
182 final IBluetoothHeadsetPhone btPhone = mApp.getBluetoothPhoneService();
183 if (btPhone != null) {
184 try {
185 btPhone.cdmaSwapSecondCallState();
186 } catch (RemoteException e) {
187 Log.e(TAG, Log.getStackTraceString(new Throwable()));
188 }
189 }
190 }
191 }
192
193 @Override
Chiao Chenge41661c2013-07-23 13:28:26 -0700194 public void mute(boolean onOff) {
195 try {
Santos Cordoneead6ec2013-08-07 22:16:33 -0700196 PhoneUtils.setMute(onOff);
Chiao Chenge41661c2013-07-23 13:28:26 -0700197 } catch (Exception e) {
198 Log.e(TAG, "Error during mute().", e);
199 }
200 }
201
202 @Override
203 public void speaker(boolean onOff) {
204 try {
Chiao Chenge41661c2013-07-23 13:28:26 -0700205 PhoneUtils.turnOnSpeaker(mContext, onOff, true);
206 } catch (Exception e) {
207 Log.e(TAG, "Error during speaker().", e);
208 }
Santos Cordoncba1b442013-07-18 12:43:58 -0700209 }
Santos Cordon2eaff902013-08-05 04:37:55 -0700210
211 @Override
Christine Chendaf7bf62013-08-05 19:12:31 -0700212 public void playDtmfTone(char digit, boolean timedShortTone) {
Santos Cordon2eaff902013-08-05 04:37:55 -0700213 try {
Christine Chendaf7bf62013-08-05 19:12:31 -0700214 mDtmfTonePlayer.playDtmfTone(digit, timedShortTone);
Santos Cordon2eaff902013-08-05 04:37:55 -0700215 } catch (Exception e) {
216 Log.e(TAG, "Error playing DTMF tone.", e);
217 }
218 }
219
220 @Override
221 public void stopDtmfTone() {
222 try {
223 mDtmfTonePlayer.stopDtmfTone();
224 } catch (Exception e) {
225 Log.e(TAG, "Error stopping DTMF tone.", e);
226 }
227 }
Santos Cordon9b7bac72013-08-06 08:04:52 -0700228
229 @Override
230 public void setAudioMode(int mode) {
231 try {
232 mAudioRouter.setAudioMode(mode);
233 } catch (Exception e) {
234 Log.e(TAG, "Error setting the audio mode.", e);
235 }
236 }
Chiao Cheng3f015c92013-09-06 15:56:27 -0700237
238 @Override
239 public void postDialCancel(int callId) throws RemoteException {
240 final CallResult result = mCallModeler.getCallWithId(callId);
241 if (result != null) {
242 result.getConnection().cancelPostDial();
243 }
244 }
245
246 @Override
247 public void postDialWaitContinue(int callId) throws RemoteException {
248 final CallResult result = mCallModeler.getCallWithId(callId);
249 if (result != null) {
250 result.getConnection().proceedAfterWaitChar();
251 }
252 }
Yorke Lee362cec22013-09-18 15:20:26 -0700253
254 @Override
255 public void setSystemBarNavigationEnabled(boolean enable) {
256 try {
257 final StatusBarHelper statusBarHelper = PhoneGlobals.getInstance().notificationMgr.
258 statusBarHelper;
259 statusBarHelper.enableSystemBarNavigation(enable);
260 statusBarHelper.enableExpandedView(enable);
261 } catch (Exception e) {
262 Log.e(TAG, "Error enabling or disabling system bar navigation", e);
263 }
264 }
265
Santos Cordoncba1b442013-07-18 12:43:58 -0700266}