Home | History | Annotate | Download | only in telecom
      1 /*
      2  * Copyright (C) 2014 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.server.telecom;
     18 
     19 import android.os.Handler;
     20 import android.os.Message;
     21 import android.telecom.PhoneAccountHandle;
     22 
     23 import com.android.internal.os.SomeArgs;
     24 import com.android.internal.telecom.IInCallAdapter;
     25 
     26 /**
     27  * Receives call commands and updates from in-call app and passes them through to CallsManager.
     28  * {@link InCallController} creates an instance of this class and passes it to the in-call app after
     29  * binding to it. This adapter can receive commands and updates until the in-call app is unbound.
     30  */
     31 class InCallAdapter extends IInCallAdapter.Stub {
     32     private static final int MSG_ANSWER_CALL = 0;
     33     private static final int MSG_REJECT_CALL = 1;
     34     private static final int MSG_PLAY_DTMF_TONE = 2;
     35     private static final int MSG_STOP_DTMF_TONE = 3;
     36     private static final int MSG_POST_DIAL_CONTINUE = 4;
     37     private static final int MSG_DISCONNECT_CALL = 5;
     38     private static final int MSG_HOLD_CALL = 6;
     39     private static final int MSG_UNHOLD_CALL = 7;
     40     private static final int MSG_MUTE = 8;
     41     private static final int MSG_SET_AUDIO_ROUTE = 9;
     42     private static final int MSG_CONFERENCE = 10;
     43     private static final int MSG_SPLIT_FROM_CONFERENCE = 11;
     44     private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 12;
     45     private static final int MSG_PHONE_ACCOUNT_SELECTED = 13;
     46     private static final int MSG_TURN_ON_PROXIMITY_SENSOR = 14;
     47     private static final int MSG_TURN_OFF_PROXIMITY_SENSOR = 15;
     48     private static final int MSG_MERGE_CONFERENCE = 16;
     49     private static final int MSG_SWAP_CONFERENCE = 17;
     50 
     51     private final class InCallAdapterHandler extends Handler {
     52         @Override
     53         public void handleMessage(Message msg) {
     54             Call call;
     55             switch (msg.what) {
     56                 case MSG_ANSWER_CALL: {
     57                     SomeArgs args = (SomeArgs) msg.obj;
     58                     try {
     59                         call = mCallIdMapper.getCall(args.arg1);
     60                         int videoState = (int) args.arg2;
     61                         if (call != null) {
     62                             mCallsManager.answerCall(call, videoState);
     63                         } else {
     64                             Log.w(this, "answerCall, unknown call id: %s", msg.obj);
     65                         }
     66                     } finally {
     67                         args.recycle();
     68                     }
     69                     break;
     70                 }
     71                 case MSG_REJECT_CALL: {
     72                     SomeArgs args = (SomeArgs) msg.obj;
     73                     try {
     74                         call = mCallIdMapper.getCall(args.arg1);
     75                         boolean rejectWithMessage = args.argi1 == 1;
     76                         String textMessage = (String) args.arg2;
     77                         if (call != null) {
     78                             mCallsManager.rejectCall(call, rejectWithMessage, textMessage);
     79                         } else {
     80                             Log.w(this, "setRingback, unknown call id: %s", args.arg1);
     81                         }
     82                     } finally {
     83                         args.recycle();
     84                     }
     85                     break;
     86                 }
     87                 case MSG_PLAY_DTMF_TONE:
     88                     call = mCallIdMapper.getCall(msg.obj);
     89                     if (call != null) {
     90                         mCallsManager.playDtmfTone(call, (char) msg.arg1);
     91                     } else {
     92                         Log.w(this, "playDtmfTone, unknown call id: %s", msg.obj);
     93                     }
     94                     break;
     95                 case MSG_STOP_DTMF_TONE:
     96                     call = mCallIdMapper.getCall(msg.obj);
     97                     if (call != null) {
     98                         mCallsManager.stopDtmfTone(call);
     99                     } else {
    100                         Log.w(this, "stopDtmfTone, unknown call id: %s", msg.obj);
    101                     }
    102                     break;
    103                 case MSG_POST_DIAL_CONTINUE:
    104                     call = mCallIdMapper.getCall(msg.obj);
    105                     mCallsManager.postDialContinue(call, msg.arg1 == 1);
    106                     call = mCallIdMapper.getCall(msg.obj);
    107                     if (call != null) {
    108                         mCallsManager.postDialContinue(call, msg.arg1 == 1);
    109                     } else {
    110                         Log.w(this, "postDialContinue, unknown call id: %s", msg.obj);
    111                     }
    112                     break;
    113                 case MSG_DISCONNECT_CALL:
    114                     call = mCallIdMapper.getCall(msg.obj);
    115                     if (call != null) {
    116                         mCallsManager.disconnectCall(call);
    117                     } else {
    118                         Log.w(this, "disconnectCall, unknown call id: %s", msg.obj);
    119                     }
    120                     break;
    121                 case MSG_HOLD_CALL:
    122                     call = mCallIdMapper.getCall(msg.obj);
    123                     if (call != null) {
    124                         mCallsManager.holdCall(call);
    125                     } else {
    126                         Log.w(this, "holdCall, unknown call id: %s", msg.obj);
    127                     }
    128                     break;
    129                 case MSG_UNHOLD_CALL:
    130                     call = mCallIdMapper.getCall(msg.obj);
    131                     if (call != null) {
    132                         mCallsManager.unholdCall(call);
    133                     } else {
    134                         Log.w(this, "unholdCall, unknown call id: %s", msg.obj);
    135                     }
    136                     break;
    137                 case MSG_PHONE_ACCOUNT_SELECTED: {
    138                     SomeArgs args = (SomeArgs) msg.obj;
    139                     try {
    140                         call = mCallIdMapper.getCall(args.arg1);
    141                         if (call != null) {
    142                             mCallsManager.phoneAccountSelected(call, (PhoneAccountHandle) args.arg2);
    143                         } else {
    144                             Log.w(this, "phoneAccountSelected, unknown call id: %s", args.arg1);
    145                         }
    146                     } finally {
    147                         args.recycle();
    148                     }
    149                     break;
    150                 }
    151                 case MSG_MUTE:
    152                     mCallsManager.mute(msg.arg1 == 1);
    153                     break;
    154                 case MSG_SET_AUDIO_ROUTE:
    155                     mCallsManager.setAudioRoute(msg.arg1);
    156                     break;
    157                 case MSG_CONFERENCE: {
    158                     SomeArgs args = (SomeArgs) msg.obj;
    159                     try {
    160                         call = mCallIdMapper.getCall(args.arg1);
    161                         Call otherCall = mCallIdMapper.getCall(args.arg2);
    162                         if (call != null && otherCall != null) {
    163                             mCallsManager.conference(call, otherCall);
    164                         } else {
    165                             Log.w(this, "conference, unknown call id: %s", msg.obj);
    166                         }
    167                     } finally {
    168                         args.recycle();
    169                     }
    170                     break;
    171                 }
    172                 case MSG_SPLIT_FROM_CONFERENCE:
    173                     call = mCallIdMapper.getCall(msg.obj);
    174                     if (call != null) {
    175                         call.splitFromConference();
    176                     } else {
    177                         Log.w(this, "splitFromConference, unknown call id: %s", msg.obj);
    178                     }
    179                     break;
    180                 case MSG_TURN_ON_PROXIMITY_SENSOR:
    181                     mCallsManager.turnOnProximitySensor();
    182                     break;
    183                 case MSG_TURN_OFF_PROXIMITY_SENSOR:
    184                     mCallsManager.turnOffProximitySensor((boolean) msg.obj);
    185                     break;
    186                 case MSG_MERGE_CONFERENCE:
    187                     call = mCallIdMapper.getCall(msg.obj);
    188                     if (call != null) {
    189                         call.mergeConference();
    190                     } else {
    191                         Log.w(this, "mergeConference, unknown call id: %s", msg.obj);
    192                     }
    193                     break;
    194                 case MSG_SWAP_CONFERENCE:
    195                     call = mCallIdMapper.getCall(msg.obj);
    196                     if (call != null) {
    197                         call.swapConference();
    198                     } else {
    199                         Log.w(this, "swapConference, unknown call id: %s", msg.obj);
    200                     }
    201                     break;
    202             }
    203         }
    204     }
    205 
    206     private final CallsManager mCallsManager;
    207     private final Handler mHandler = new InCallAdapterHandler();
    208     private final CallIdMapper mCallIdMapper;
    209 
    210     /** Persists the specified parameters. */
    211     public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper) {
    212         ThreadUtil.checkOnMainThread();
    213         mCallsManager = callsManager;
    214         mCallIdMapper = callIdMapper;
    215     }
    216 
    217     @Override
    218     public void answerCall(String callId, int videoState) {
    219         Log.d(this, "answerCall(%s,%d)", callId, videoState);
    220         if (mCallIdMapper.isValidCallId(callId)) {
    221             SomeArgs args = SomeArgs.obtain();
    222             args.arg1 = callId;
    223             args.arg2 = videoState;
    224             mHandler.obtainMessage(MSG_ANSWER_CALL, args).sendToTarget();
    225         }
    226     }
    227 
    228     @Override
    229     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
    230         Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
    231         if (mCallIdMapper.isValidCallId(callId)) {
    232             SomeArgs args = SomeArgs.obtain();
    233             args.arg1 = callId;
    234             args.argi1 = rejectWithMessage ? 1 : 0;
    235             args.arg2 = textMessage;
    236             mHandler.obtainMessage(MSG_REJECT_CALL, args).sendToTarget();
    237         }
    238     }
    239 
    240     @Override
    241     public void playDtmfTone(String callId, char digit) {
    242         Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
    243         if (mCallIdMapper.isValidCallId(callId)) {
    244             mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, (int) digit, 0, callId).sendToTarget();
    245         }
    246     }
    247 
    248     @Override
    249     public void stopDtmfTone(String callId) {
    250         Log.d(this, "stopDtmfTone(%s)", callId);
    251         if (mCallIdMapper.isValidCallId(callId)) {
    252             mHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
    253         }
    254     }
    255 
    256     @Override
    257     public void postDialContinue(String callId, boolean proceed) {
    258         Log.d(this, "postDialContinue(%s)", callId);
    259         if (mCallIdMapper.isValidCallId(callId)) {
    260             mHandler.obtainMessage(MSG_POST_DIAL_CONTINUE, proceed ? 1 : 0, 0, callId).sendToTarget();
    261         }
    262     }
    263 
    264     @Override
    265     public void disconnectCall(String callId) {
    266         Log.v(this, "disconnectCall: %s", callId);
    267         if (mCallIdMapper.isValidCallId(callId)) {
    268             mHandler.obtainMessage(MSG_DISCONNECT_CALL, callId).sendToTarget();
    269         }
    270     }
    271 
    272     @Override
    273     public void holdCall(String callId) {
    274         if (mCallIdMapper.isValidCallId(callId)) {
    275             mHandler.obtainMessage(MSG_HOLD_CALL, callId).sendToTarget();
    276         }
    277     }
    278 
    279     @Override
    280     public void unholdCall(String callId) {
    281         if (mCallIdMapper.isValidCallId(callId)) {
    282             mHandler.obtainMessage(MSG_UNHOLD_CALL, callId).sendToTarget();
    283         }
    284     }
    285 
    286     @Override
    287     public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle) {
    288         if (mCallIdMapper.isValidCallId(callId)) {
    289             SomeArgs args = SomeArgs.obtain();
    290             args.arg1 = callId;
    291             args.arg2 = accountHandle;
    292             mHandler.obtainMessage(MSG_PHONE_ACCOUNT_SELECTED, args).sendToTarget();
    293         }
    294     }
    295 
    296     @Override
    297     public void mute(boolean shouldMute) {
    298         mHandler.obtainMessage(MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
    299     }
    300 
    301     @Override
    302     public void setAudioRoute(int route) {
    303         mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget();
    304     }
    305 
    306     @Override
    307     public void conference(String callId, String otherCallId) {
    308         if (mCallIdMapper.isValidCallId(callId) &&
    309                 mCallIdMapper.isValidCallId(otherCallId)) {
    310             SomeArgs args = SomeArgs.obtain();
    311             args.arg1 = callId;
    312             args.arg2 = otherCallId;
    313             mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
    314         }
    315     }
    316 
    317     @Override
    318     public void splitFromConference(String callId) {
    319         if (mCallIdMapper.isValidCallId(callId)) {
    320             mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
    321         }
    322     }
    323 
    324     @Override
    325     public void mergeConference(String callId) {
    326         if (mCallIdMapper.isValidCallId(callId)) {
    327             mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget();
    328         }
    329     }
    330 
    331     @Override
    332     public void swapConference(String callId) {
    333         if (mCallIdMapper.isValidCallId(callId)) {
    334             mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget();
    335         }
    336     }
    337 
    338     @Override
    339     public void turnOnProximitySensor() {
    340         mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget();
    341     }
    342 
    343     @Override
    344     public void turnOffProximitySensor(boolean screenOnImmediately) {
    345         mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget();
    346     }
    347 }
    348