1 /* 2 * 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 14 * limitations under the License 15 */ 16 17 package com.android.phone; 18 19 import android.bluetooth.IBluetoothHeadsetPhone; 20 import android.content.Context; 21 import android.os.RemoteException; 22 import android.os.SystemProperties; 23 import android.util.Log; 24 25 import com.android.internal.telephony.CallManager; 26 import com.android.internal.telephony.PhoneConstants; 27 import com.android.phone.CallModeler.CallResult; 28 import com.android.phone.NotificationMgr.StatusBarHelper; 29 import com.android.services.telephony.common.Call; 30 import com.android.services.telephony.common.ICallCommandService; 31 32 /** 33 * Service interface used by in-call ui to control phone calls using commands exposed as methods. 34 * Instances of this class are handed to in-call UI via CallMonitorService. 35 */ 36 class CallCommandService extends ICallCommandService.Stub { 37 private static final String TAG = CallCommandService.class.getSimpleName(); 38 private static final boolean DBG = 39 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1); 40 41 private final Context mContext; 42 private final CallManager mCallManager; 43 private final CallModeler mCallModeler; 44 private final DTMFTonePlayer mDtmfTonePlayer; 45 private final AudioRouter mAudioRouter; 46 47 public CallCommandService(Context context, CallManager callManager, CallModeler callModeler, 48 DTMFTonePlayer dtmfTonePlayer, AudioRouter audioRouter) { 49 mContext = context; 50 mCallManager = callManager; 51 mCallModeler = callModeler; 52 mDtmfTonePlayer = dtmfTonePlayer; 53 mAudioRouter = audioRouter; 54 } 55 56 /** 57 * TODO: Add a confirmation callback parameter. 58 */ 59 @Override 60 public void answerCall(int callId) { 61 try { 62 CallResult result = mCallModeler.getCallWithId(callId); 63 if (result != null) { 64 PhoneUtils.answerCall(result.getConnection().getCall()); 65 } 66 } catch (Exception e) { 67 Log.e(TAG, "Error during answerCall().", e); 68 } 69 } 70 71 /** 72 * TODO: Add a confirmation callback parameter. 73 */ 74 @Override 75 public void rejectCall(Call call, boolean rejectWithMessage, String message) { 76 try { 77 int callId = Call.INVALID_CALL_ID; 78 String phoneNumber = ""; 79 if (call != null) { 80 callId = call.getCallId(); 81 phoneNumber = call.getNumber(); 82 } 83 CallResult result = mCallModeler.getCallWithId(callId); 84 85 if (result != null) { 86 phoneNumber = result.getConnection().getAddress(); 87 88 Log.v(TAG, "Hanging up"); 89 PhoneUtils.hangupRingingCall(result.getConnection().getCall()); 90 } 91 92 if (rejectWithMessage && !phoneNumber.isEmpty()) { 93 RejectWithTextMessageManager.rejectCallWithMessage(phoneNumber, message); 94 } 95 } catch (Exception e) { 96 Log.e(TAG, "Error during rejectCall().", e); 97 } 98 } 99 100 @Override 101 public void disconnectCall(int callId) { 102 try { 103 CallResult result = mCallModeler.getCallWithId(callId); 104 if (DBG) Log.d(TAG, "disconnectCall " + result.getCall()); 105 106 if (result != null) { 107 int state = result.getCall().getState(); 108 if (Call.State.ACTIVE == state || 109 Call.State.ONHOLD == state || 110 Call.State.DIALING == state) { 111 result.getConnection().getCall().hangup(); 112 } else if (Call.State.CONFERENCED == state) { 113 result.getConnection().hangup(); 114 } 115 } 116 } catch (Exception e) { 117 Log.e(TAG, "Error during disconnectCall().", e); 118 } 119 } 120 121 @Override 122 public void separateCall(int callId) { 123 try { 124 CallResult result = mCallModeler.getCallWithId(callId); 125 if (DBG) Log.d(TAG, "disconnectCall " + result.getCall()); 126 127 if (result != null) { 128 int state = result.getCall().getState(); 129 if (Call.State.CONFERENCED == state) { 130 result.getConnection().separate(); 131 } 132 } 133 } catch (Exception e) { 134 Log.e(TAG, "Error trying to separate call.", e); 135 } 136 } 137 138 @Override 139 public void hold(int callId, boolean hold) { 140 try { 141 CallResult result = mCallModeler.getCallWithId(callId); 142 if (result != null) { 143 int state = result.getCall().getState(); 144 if (hold && Call.State.ACTIVE == state) { 145 PhoneUtils.switchHoldingAndActive(mCallManager.getFirstActiveBgCall()); 146 } else if (!hold && Call.State.ONHOLD == state) { 147 PhoneUtils.switchHoldingAndActive(result.getConnection().getCall()); 148 } 149 } 150 } catch (Exception e) { 151 Log.e(TAG, "Error trying to place call on hold.", e); 152 } 153 } 154 155 @Override 156 public void merge() { 157 if (PhoneUtils.okToMergeCalls(mCallManager)) { 158 PhoneUtils.mergeCalls(mCallManager); 159 } 160 } 161 162 @Override 163 public void addCall() { 164 // start new call checks okToAddCall() already 165 PhoneUtils.startNewCall(mCallManager); 166 } 167 168 169 @Override 170 public void swap() { 171 try { 172 PhoneUtils.swap(); 173 } catch (Exception e) { 174 Log.e(TAG, "Error during swap().", e); 175 } 176 } 177 178 @Override 179 public void mute(boolean onOff) { 180 try { 181 PhoneUtils.setMute(onOff); 182 } catch (Exception e) { 183 Log.e(TAG, "Error during mute().", e); 184 } 185 } 186 187 @Override 188 public void speaker(boolean onOff) { 189 try { 190 PhoneUtils.turnOnSpeaker(mContext, onOff, true); 191 } catch (Exception e) { 192 Log.e(TAG, "Error during speaker().", e); 193 } 194 } 195 196 @Override 197 public void playDtmfTone(char digit, boolean timedShortTone) { 198 try { 199 mDtmfTonePlayer.playDtmfTone(digit, timedShortTone); 200 } catch (Exception e) { 201 Log.e(TAG, "Error playing DTMF tone.", e); 202 } 203 } 204 205 @Override 206 public void stopDtmfTone() { 207 try { 208 mDtmfTonePlayer.stopDtmfTone(); 209 } catch (Exception e) { 210 Log.e(TAG, "Error stopping DTMF tone.", e); 211 } 212 } 213 214 @Override 215 public void setAudioMode(int mode) { 216 try { 217 mAudioRouter.setAudioMode(mode); 218 } catch (Exception e) { 219 Log.e(TAG, "Error setting the audio mode.", e); 220 } 221 } 222 223 @Override 224 public void postDialCancel(int callId) throws RemoteException { 225 final CallResult result = mCallModeler.getCallWithId(callId); 226 if (result != null) { 227 result.getConnection().cancelPostDial(); 228 } 229 } 230 231 @Override 232 public void postDialWaitContinue(int callId) throws RemoteException { 233 final CallResult result = mCallModeler.getCallWithId(callId); 234 if (result != null) { 235 result.getConnection().proceedAfterWaitChar(); 236 } 237 } 238 239 @Override 240 public void setSystemBarNavigationEnabled(boolean enable) { 241 try { 242 final StatusBarHelper statusBarHelper = PhoneGlobals.getInstance().notificationMgr. 243 statusBarHelper; 244 statusBarHelper.enableSystemBarNavigation(enable); 245 statusBarHelper.enableExpandedView(enable); 246 } catch (Exception e) { 247 Log.e(TAG, "Error enabling or disabling system bar navigation", e); 248 } 249 } 250 251 } 252