Home | History | Annotate | Download | only in phone
      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         if (!PhoneUtils.okToSwapCalls(mCallManager)) {
    172             // TODO: throw an error instead?
    173             return;
    174         }
    175 
    176         // Swap the fg and bg calls.
    177         // In the future we may provides some way for user to choose among
    178         // multiple background calls, for now, always act on the first background calll.
    179         PhoneUtils.switchHoldingAndActive(mCallManager.getFirstActiveBgCall());
    180 
    181         final PhoneGlobals mApp = PhoneGlobals.getInstance();
    182 
    183         // If we have a valid BluetoothPhoneService then since CDMA network or
    184         // Telephony FW does not send us information on which caller got swapped
    185         // we need to update the second call active state in BluetoothPhoneService internally
    186         if (mCallManager.getBgPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
    187             final IBluetoothHeadsetPhone btPhone = mApp.getBluetoothPhoneService();
    188             if (btPhone != null) {
    189                 try {
    190                     btPhone.cdmaSwapSecondCallState();
    191                 } catch (RemoteException e) {
    192                     Log.e(TAG, Log.getStackTraceString(new Throwable()));
    193                 }
    194             }
    195         }
    196     }
    197 
    198     @Override
    199     public void mute(boolean onOff) {
    200         try {
    201             PhoneUtils.setMute(onOff);
    202         } catch (Exception e) {
    203             Log.e(TAG, "Error during mute().", e);
    204         }
    205     }
    206 
    207     @Override
    208     public void speaker(boolean onOff) {
    209         try {
    210             PhoneUtils.turnOnSpeaker(mContext, onOff, true);
    211         } catch (Exception e) {
    212             Log.e(TAG, "Error during speaker().", e);
    213         }
    214     }
    215 
    216     @Override
    217     public void playDtmfTone(char digit, boolean timedShortTone) {
    218         try {
    219             mDtmfTonePlayer.playDtmfTone(digit, timedShortTone);
    220         } catch (Exception e) {
    221             Log.e(TAG, "Error playing DTMF tone.", e);
    222         }
    223     }
    224 
    225     @Override
    226     public void stopDtmfTone() {
    227         try {
    228             mDtmfTonePlayer.stopDtmfTone();
    229         } catch (Exception e) {
    230             Log.e(TAG, "Error stopping DTMF tone.", e);
    231         }
    232     }
    233 
    234     @Override
    235     public void setAudioMode(int mode) {
    236         try {
    237             mAudioRouter.setAudioMode(mode);
    238         } catch (Exception e) {
    239             Log.e(TAG, "Error setting the audio mode.", e);
    240         }
    241     }
    242 
    243     @Override
    244     public void postDialCancel(int callId) throws RemoteException {
    245         final CallResult result = mCallModeler.getCallWithId(callId);
    246         if (result != null) {
    247             result.getConnection().cancelPostDial();
    248         }
    249     }
    250 
    251     @Override
    252     public void postDialWaitContinue(int callId) throws RemoteException {
    253         final CallResult result = mCallModeler.getCallWithId(callId);
    254         if (result != null) {
    255             result.getConnection().proceedAfterWaitChar();
    256         }
    257     }
    258 
    259     @Override
    260     public void setSystemBarNavigationEnabled(boolean enable) {
    261         try {
    262             final StatusBarHelper statusBarHelper = PhoneGlobals.getInstance().notificationMgr.
    263                     statusBarHelper;
    264             statusBarHelper.enableSystemBarNavigation(enable);
    265             statusBarHelper.enableExpandedView(enable);
    266         } catch (Exception e) {
    267             Log.e(TAG, "Error enabling or disabling system bar navigation", e);
    268         }
    269     }
    270 
    271 }
    272