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                     if (call != null) {
    106                         mCallsManager.postDialContinue(call, msg.arg1 == 1);
    107                     } else {
    108                         Log.w(this, "postDialContinue, unknown call id: %s", msg.obj);
    109                     }
    110                     break;
    111                 case MSG_DISCONNECT_CALL:
    112                     call = mCallIdMapper.getCall(msg.obj);
    113                     if (call != null) {
    114                         mCallsManager.disconnectCall(call);
    115                     } else {
    116                         Log.w(this, "disconnectCall, unknown call id: %s", msg.obj);
    117                     }
    118                     break;
    119                 case MSG_HOLD_CALL:
    120                     call = mCallIdMapper.getCall(msg.obj);
    121                     if (call != null) {
    122                         mCallsManager.holdCall(call);
    123                     } else {
    124                         Log.w(this, "holdCall, unknown call id: %s", msg.obj);
    125                     }
    126                     break;
    127                 case MSG_UNHOLD_CALL:
    128                     call = mCallIdMapper.getCall(msg.obj);
    129                     if (call != null) {
    130                         mCallsManager.unholdCall(call);
    131                     } else {
    132                         Log.w(this, "unholdCall, unknown call id: %s", msg.obj);
    133                     }
    134                     break;
    135                 case MSG_PHONE_ACCOUNT_SELECTED: {
    136                     SomeArgs args = (SomeArgs) msg.obj;
    137                     try {
    138                         call = mCallIdMapper.getCall(args.arg1);
    139                         if (call != null) {
    140                             mCallsManager.phoneAccountSelected(call,
    141                                     (PhoneAccountHandle) args.arg2, args.argi1 == 1);
    142                         } else {
    143                             Log.w(this, "phoneAccountSelected, unknown call id: %s", args.arg1);
    144                         }
    145                     } finally {
    146                         args.recycle();
    147                     }
    148                     break;
    149                 }
    150                 case MSG_MUTE:
    151                     mCallsManager.mute(msg.arg1 == 1);
    152                     break;
    153                 case MSG_SET_AUDIO_ROUTE:
    154                     mCallsManager.setAudioRoute(msg.arg1);
    155                     break;
    156                 case MSG_CONFERENCE: {
    157                     SomeArgs args = (SomeArgs) msg.obj;
    158                     try {
    159                         call = mCallIdMapper.getCall(args.arg1);
    160                         Call otherCall = mCallIdMapper.getCall(args.arg2);
    161                         if (call != null && otherCall != null) {
    162                             mCallsManager.conference(call, otherCall);
    163                         } else {
    164                             Log.w(this, "conference, unknown call id: %s", msg.obj);
    165                         }
    166                     } finally {
    167                         args.recycle();
    168                     }
    169                     break;
    170                 }
    171                 case MSG_SPLIT_FROM_CONFERENCE:
    172                     call = mCallIdMapper.getCall(msg.obj);
    173                     if (call != null) {
    174                         call.splitFromConference();
    175                     } else {
    176                         Log.w(this, "splitFromConference, unknown call id: %s", msg.obj);
    177                     }
    178                     break;
    179                 case MSG_TURN_ON_PROXIMITY_SENSOR:
    180                     mCallsManager.turnOnProximitySensor();
    181                     break;
    182                 case MSG_TURN_OFF_PROXIMITY_SENSOR:
    183                     mCallsManager.turnOffProximitySensor((boolean) msg.obj);
    184                     break;
    185                 case MSG_MERGE_CONFERENCE:
    186                     call = mCallIdMapper.getCall(msg.obj);
    187                     if (call != null) {
    188                         call.mergeConference();
    189                     } else {
    190                         Log.w(this, "mergeConference, unknown call id: %s", msg.obj);
    191                     }
    192                     break;
    193                 case MSG_SWAP_CONFERENCE:
    194                     call = mCallIdMapper.getCall(msg.obj);
    195                     if (call != null) {
    196                         call.swapConference();
    197                     } else {
    198                         Log.w(this, "swapConference, unknown call id: %s", msg.obj);
    199                     }
    200                     break;
    201             }
    202         }
    203     }
    204 
    205     private final CallsManager mCallsManager;
    206     private final Handler mHandler = new InCallAdapterHandler();
    207     private final CallIdMapper mCallIdMapper;
    208 
    209     /** Persists the specified parameters. */
    210     public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper) {
    211         ThreadUtil.checkOnMainThread();
    212         mCallsManager = callsManager;
    213         mCallIdMapper = callIdMapper;
    214     }
    215 
    216     @Override
    217     public void answerCall(String callId, int videoState) {
    218         Log.d(this, "answerCall(%s,%d)", callId, videoState);
    219         if (mCallIdMapper.isValidCallId(callId)) {
    220             SomeArgs args = SomeArgs.obtain();
    221             args.arg1 = callId;
    222             args.arg2 = videoState;
    223             mHandler.obtainMessage(MSG_ANSWER_CALL, args).sendToTarget();
    224         }
    225     }
    226 
    227     @Override
    228     public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
    229         Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage);
    230         if (mCallIdMapper.isValidCallId(callId)) {
    231             SomeArgs args = SomeArgs.obtain();
    232             args.arg1 = callId;
    233             args.argi1 = rejectWithMessage ? 1 : 0;
    234             args.arg2 = textMessage;
    235             mHandler.obtainMessage(MSG_REJECT_CALL, args).sendToTarget();
    236         }
    237     }
    238 
    239     @Override
    240     public void playDtmfTone(String callId, char digit) {
    241         Log.d(this, "playDtmfTone(%s,%c)", callId, digit);
    242         if (mCallIdMapper.isValidCallId(callId)) {
    243             mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, (int) digit, 0, callId).sendToTarget();
    244         }
    245     }
    246 
    247     @Override
    248     public void stopDtmfTone(String callId) {
    249         Log.d(this, "stopDtmfTone(%s)", callId);
    250         if (mCallIdMapper.isValidCallId(callId)) {
    251             mHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
    252         }
    253     }
    254 
    255     @Override
    256     public void postDialContinue(String callId, boolean proceed) {
    257         Log.d(this, "postDialContinue(%s)", callId);
    258         if (mCallIdMapper.isValidCallId(callId)) {
    259             mHandler.obtainMessage(MSG_POST_DIAL_CONTINUE, proceed ? 1 : 0, 0, callId).sendToTarget();
    260         }
    261     }
    262 
    263     @Override
    264     public void disconnectCall(String callId) {
    265         Log.v(this, "disconnectCall: %s", callId);
    266         if (mCallIdMapper.isValidCallId(callId)) {
    267             mHandler.obtainMessage(MSG_DISCONNECT_CALL, callId).sendToTarget();
    268         }
    269     }
    270 
    271     @Override
    272     public void holdCall(String callId) {
    273         if (mCallIdMapper.isValidCallId(callId)) {
    274             mHandler.obtainMessage(MSG_HOLD_CALL, callId).sendToTarget();
    275         }
    276     }
    277 
    278     @Override
    279     public void unholdCall(String callId) {
    280         if (mCallIdMapper.isValidCallId(callId)) {
    281             mHandler.obtainMessage(MSG_UNHOLD_CALL, callId).sendToTarget();
    282         }
    283     }
    284 
    285     @Override
    286     public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
    287             boolean setDefault) {
    288         if (mCallIdMapper.isValidCallId(callId)) {
    289             SomeArgs args = SomeArgs.obtain();
    290             args.arg1 = callId;
    291             args.arg2 = accountHandle;
    292             args.argi1 = setDefault? 1 : 0;
    293             mHandler.obtainMessage(MSG_PHONE_ACCOUNT_SELECTED, args).sendToTarget();
    294         }
    295     }
    296 
    297     @Override
    298     public void mute(boolean shouldMute) {
    299         mHandler.obtainMessage(MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
    300     }
    301 
    302     @Override
    303     public void setAudioRoute(int route) {
    304         mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget();
    305     }
    306 
    307     @Override
    308     public void conference(String callId, String otherCallId) {
    309         if (mCallIdMapper.isValidCallId(callId) &&
    310                 mCallIdMapper.isValidCallId(otherCallId)) {
    311             SomeArgs args = SomeArgs.obtain();
    312             args.arg1 = callId;
    313             args.arg2 = otherCallId;
    314             mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
    315         }
    316     }
    317 
    318     @Override
    319     public void splitFromConference(String callId) {
    320         if (mCallIdMapper.isValidCallId(callId)) {
    321             mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
    322         }
    323     }
    324 
    325     @Override
    326     public void mergeConference(String callId) {
    327         if (mCallIdMapper.isValidCallId(callId)) {
    328             mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget();
    329         }
    330     }
    331 
    332     @Override
    333     public void swapConference(String callId) {
    334         if (mCallIdMapper.isValidCallId(callId)) {
    335             mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget();
    336         }
    337     }
    338 
    339     @Override
    340     public void turnOnProximitySensor() {
    341         mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget();
    342     }
    343 
    344     @Override
    345     public void turnOffProximitySensor(boolean screenOnImmediately) {
    346         mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget();
    347     }
    348 }
    349