Home | History | Annotate | Download | only in hfpclient
      1 /*
      2  * Copyright (c) 2017 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 /*
     18  * Defines the native inteface that is used by state machine/service to either or receive messages
     19  * from the native stack. This file is registered for the native methods in corresponding CPP file.
     20  */
     21 package com.android.bluetooth.hfpclient;
     22 
     23 import com.android.bluetooth.Utils;
     24 
     25 import android.bluetooth.BluetoothAdapter;
     26 import android.bluetooth.BluetoothDevice;
     27 import android.util.Log;
     28 
     29 class NativeInterface {
     30     private static String TAG = "NativeInterface";
     31     private static boolean DBG = false;
     32 
     33     NativeInterface() {}
     34 
     35     // Native methods that call into the JNI interface
     36     static native void classInitNative();
     37     static native void initializeNative();
     38     static native void cleanupNative();
     39     static native boolean connectNative(byte[] address);
     40     static native boolean disconnectNative(byte[] address);
     41     static native boolean connectAudioNative(byte[] address);
     42     static native boolean disconnectAudioNative(byte[] address);
     43     static native boolean startVoiceRecognitionNative(byte[] address);
     44     static native boolean stopVoiceRecognitionNative(byte[] address);
     45     static native boolean setVolumeNative(byte[] address, int volumeType, int volume);
     46     static native boolean dialNative(byte[] address, String number);
     47     static native boolean dialMemoryNative(byte[] address, int location);
     48     static native boolean handleCallActionNative(byte[] address, int action, int index);
     49     static native boolean queryCurrentCallsNative(byte[] address);
     50     static native boolean queryCurrentOperatorNameNative(byte[] address);
     51     static native boolean retrieveSubscriberInfoNative(byte[] address);
     52     static native boolean sendDtmfNative(byte[] address, byte code);
     53     static native boolean requestLastVoiceTagNumberNative(byte[] address);
     54     static native boolean sendATCmdNative(byte[] address, int atCmd, int val1,
     55             int val2, String arg);
     56 
     57     private BluetoothDevice getDevice(byte[] address) {
     58         return BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
     59     }
     60 
     61     // Callbacks from the native back into the java framework. All callbacks are routed via the
     62     // Service which will disambiguate which state machine the message should be routed through.
     63     private void onConnectionStateChanged(int state, int peer_feat, int chld_feat, byte[] address) {
     64         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
     65         event.valueInt = state;
     66         event.valueInt2 = peer_feat;
     67         event.valueInt3 = chld_feat;
     68         event.device = getDevice(address);
     69         // BluetoothAdapter.getDefaultAdapter().getRemoteDevice(Utils.getAddressStringFromByte(address));
     70         if (DBG) {
     71             Log.d(TAG, "Device addr "  + event.device.getAddress() + " State " + state);
     72         }
     73         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
     74         if (service != null) {
     75             service.messageFromNative(event);
     76         } else {
     77             Log.w(TAG, "Ignoring message because service not available: " + event);
     78         }
     79     }
     80 
     81     private void onAudioStateChanged(int state, byte[] address) {
     82         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
     83         event.valueInt = state;
     84         event.device = getDevice(address);
     85         if (DBG) {
     86             Log.d(TAG, "onAudioStateChanged: address " + address + " event "  + event);
     87         }
     88         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
     89         if (service != null) {
     90             service.messageFromNative(event);
     91         } else {
     92             Log.w(TAG, "onAudioStateChanged: Ignoring message because service not available: " + event);
     93         }
     94     }
     95 
     96     private void onVrStateChanged(int state) {
     97         Log.w(TAG, "onVrStateChanged not supported");
     98     }
     99 
    100     private void onNetworkState(int state, byte[] address) {
    101         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_STATE);
    102         event.valueInt = state;
    103         event.device = getDevice(address);
    104         if (DBG) {
    105             Log.d(TAG, "onVrStateChanged: address " + address + " event "  + event);
    106         }
    107 
    108         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    109         if (service != null) {
    110             service.messageFromNative(event);
    111         } else {
    112             Log.w(TAG, "onVrStateChanged: Ignoring message because service not available: " + event);
    113         }
    114     }
    115 
    116     private void onNetworkRoaming(int state, byte[] address) {
    117         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_ROAMING_STATE);
    118         event.valueInt = state;
    119         event.device = getDevice(address);
    120         if (DBG) {
    121             Log.d(TAG, "onNetworkRoaming: incoming: " + event);
    122         }
    123         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    124         if (service != null) {
    125             service.messageFromNative(event);
    126         } else {
    127             Log.w(TAG, "onNetworkRoaming: Ignoring message because service not available: " + event);
    128         }
    129     }
    130 
    131     private void onNetworkSignal(int signal, byte[] address) {
    132         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_SIGNAL);
    133         event.valueInt = signal;
    134         event.device = getDevice(address);
    135         if (DBG) {
    136             Log.d(TAG, "onNetworkSignal: address " + address + " event "  + event);
    137         }
    138         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    139         if (service != null) {
    140             service.messageFromNative(event);
    141         } else {
    142             Log.w(TAG, "onNetworkSignal: Ignoring message because service not available: " + event);
    143         }
    144     }
    145 
    146     private void onBatteryLevel(int level, byte[] address) {
    147         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_BATTERY_LEVEL);
    148         event.valueInt = level;
    149         event.device = getDevice(address);
    150         if (DBG) {
    151             Log.d(TAG, "onBatteryLevel: address " + address + " event "  + event);
    152         }
    153         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    154         if (service != null) {
    155             service.messageFromNative(event);
    156         } else {
    157             Log.w(TAG, "onBatteryLevel: Ignoring message because service not available: " + event);
    158         }
    159     }
    160 
    161     private void onCurrentOperator(String name, byte[] address) {
    162         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_OPERATOR_NAME);
    163         event.valueString = name;
    164         event.device = getDevice(address);
    165         if (DBG) {
    166             Log.d(TAG, "onCurrentOperator: address " + address + " event "  + event);
    167         }
    168         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    169         if (service != null) {
    170             service.messageFromNative(event);
    171         } else {
    172             Log.w(TAG, "onCurrentOperator: Ignoring message because service not available: " + event);
    173         }
    174     }
    175 
    176     private void onCall(int call, byte[] address) {
    177         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL);
    178         event.valueInt = call;
    179         event.device = getDevice(address);
    180         if (DBG) {
    181             Log.d(TAG, "onCall: address " + address + " event "  + event);
    182         }
    183         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    184         if (service != null) {
    185             service.messageFromNative(event);
    186         } else {
    187             Log.w(TAG, "onCall: Ignoring message because service not available: " + event);
    188         }
    189     }
    190 
    191     /**
    192      * CIEV (Call indicators) notifying if call(s) are getting set up.
    193      *
    194      * Values include:
    195      * 0 - No current call is in setup
    196      * 1 - Incoming call process ongoing
    197      * 2 - Outgoing call process ongoing
    198      * 3 - Remote party being alerted for outgoing call
    199      */
    200     private void onCallSetup(int callsetup, byte[] address) {
    201         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLSETUP);
    202         event.valueInt = callsetup;
    203         event.device = getDevice(address);
    204         if (DBG) {
    205             Log.d(TAG, "onCallSetup: addr " + address + " device" + event.device);
    206             Log.d(TAG, "onCallSetup: address " + address + " event "  + event);
    207         }
    208         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    209         if (service != null) {
    210             service.messageFromNative(event);
    211         } else {
    212             Log.w(TAG, "onCallSetup: Ignoring message because service not available: " + event);
    213         }
    214     }
    215 
    216     /**
    217      * CIEV (Call indicators) notifying call held states.
    218      *
    219      * Values include:
    220      * 0 - No calls held
    221      * 1 - Call is placed on hold or active/held calls wapped (The AG has both an ACTIVE and HELD
    222      * call)
    223      * 2 - Call on hold, no active call
    224      */
    225     private void onCallHeld(int callheld, byte[] address) {
    226         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLHELD);
    227         event.valueInt = callheld;
    228         event.device = getDevice(address);
    229         if (DBG) {
    230             Log.d(TAG, "onCallHeld: address " + address + " event "  + event);
    231         }
    232         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    233         if (service != null) {
    234             service.messageFromNative(event);
    235         } else {
    236             Log.w(TAG, "onCallHeld: Ignoring message because service not available: " + event);
    237         }
    238     }
    239 
    240     private void onRespAndHold(int resp_and_hold, byte[] address) {
    241         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RESP_AND_HOLD);
    242         event.valueInt = resp_and_hold;
    243         event.device = getDevice(address);
    244         if (DBG) {
    245             Log.d(TAG, "onRespAndHold: address " + address + " event "  + event);
    246         }
    247         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    248         if (service != null) {
    249             service.messageFromNative(event);
    250         } else {
    251             Log.w(TAG, "onRespAndHold: Ignoring message because service not available: " + event);
    252         }
    253     }
    254 
    255     private void onClip(String number, byte[] address) {
    256         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CLIP);
    257         event.valueString = number;
    258         event.device = getDevice(address);
    259         if (DBG) {
    260             Log.d(TAG, "onClip: address " + address + " event "  + event);
    261         }
    262         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    263         if (service != null) {
    264             service.messageFromNative(event);
    265         } else {
    266             Log.w(TAG, "onClip: Ignoring message because service not available: " + event);
    267         }
    268     }
    269 
    270     private void onCallWaiting(String number, byte[] address) {
    271         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL_WAITING);
    272         event.valueString = number;
    273         event.device = getDevice(address);
    274         if (DBG) {
    275             Log.d(TAG, "onCallWaiting: address " + address + " event "  + event);
    276         }
    277         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    278         if (service != null) {
    279             service.messageFromNative(event);
    280         } else {
    281             Log.w(TAG, "onCallWaiting: Ignoring message because service not available: " + event);
    282         }
    283     }
    284 
    285     private void onCurrentCalls(
    286             int index, int dir, int state, int mparty, String number, byte[] address) {
    287         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CURRENT_CALLS);
    288         event.valueInt = index;
    289         event.valueInt2 = dir;
    290         event.valueInt3 = state;
    291         event.valueInt4 = mparty;
    292         event.valueString = number;
    293         event.device = getDevice(address);
    294         if (DBG) {
    295             Log.d(TAG, "onCurrentCalls: address " + address + " event "  + event);
    296         }
    297         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    298         if (service != null) {
    299             service.messageFromNative(event);
    300         } else {
    301             Log.w(TAG, "onCurrentCalls: Ignoring message because service not available: " + event);
    302         }
    303     }
    304 
    305     private void onVolumeChange(int type, int volume, byte[] address) {
    306         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_VOLUME_CHANGED);
    307         event.valueInt = type;
    308         event.valueInt2 = volume;
    309         event.device = getDevice(address);
    310         if (DBG) {
    311             Log.d(TAG, "onVolumeChange: address " + address + " event "  + event);
    312         }
    313         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    314         // Ignore volume changes from the Phone. This is to avoid the scenario where we may have two
    315         // phones connected each tries to set different volumes.
    316         Log.w(TAG, "onVolumeChange: Ignoring message: " + event);
    317     }
    318 
    319     private void onCmdResult(int type, int cme, byte[] address) {
    320         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
    321         event.valueInt = type;
    322         event.valueInt2 = cme;
    323         event.device = getDevice(address);
    324         if (DBG) {
    325             Log.d(TAG, "onCmdResult: address " + address + " event "  + event);
    326         }
    327         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    328         if (service != null) {
    329             service.messageFromNative(event);
    330         } else {
    331             Log.w(TAG, "onCmdResult: Ignoring message because service not available: " + event);
    332         }
    333     }
    334 
    335     private void onSubscriberInfo(String number, int type, byte[] address) {
    336         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_SUBSCRIBER_INFO);
    337         event.valueInt = type;
    338         event.valueString = number;
    339         event.device = getDevice(address);
    340         if (DBG) {
    341             Log.d(TAG, "onSubscriberInfo: address " + address + " event "  + event);
    342         }
    343         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    344         if (service != null) {
    345             service.messageFromNative(event);
    346         } else {
    347             Log.w(TAG, "onSubscriberInfo: Ignoring message because service not available: " + event);
    348         }
    349     }
    350 
    351     private void onInBandRing(int in_band, byte[] address) {
    352         Log.w(TAG, "onInBandRing not supported");
    353     }
    354 
    355     private void onLastVoiceTagNumber(String number, byte[] address) {
    356         Log.w(TAG, "onLastVoiceTagNumber not supported");
    357     }
    358 
    359     private void onRingIndication(byte[] address) {
    360         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RING_INDICATION);
    361         event.device = getDevice(address);
    362         if (DBG) {
    363             Log.d(TAG, "onRingIndication: address " + address + " event "  + event);
    364         }
    365         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    366         if (service != null) {
    367             service.messageFromNative(event);
    368         } else {
    369             Log.w(TAG, "onRingIndication: Ignoring message because service not available: " + event);
    370         }
    371     }
    372 }
    373