Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2016 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.google.android.car.kitchensink.bluetooth;
     18 
     19 import android.app.PendingIntent;
     20 import android.bluetooth.BluetoothAdapter;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.bluetooth.BluetoothDevicePicker;
     23 import android.bluetooth.BluetoothMapClient;
     24 import android.bluetooth.BluetoothProfile;
     25 import android.content.BroadcastReceiver;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.net.Uri;
     30 import android.os.Bundle;
     31 import android.support.annotation.Nullable;
     32 import android.support.v4.app.Fragment;
     33 import android.util.Log;
     34 import android.view.LayoutInflater;
     35 import android.view.View;
     36 import android.view.ViewGroup;
     37 import android.widget.Button;
     38 import android.widget.CheckBox;
     39 import android.widget.EditText;
     40 import android.widget.TextView;
     41 
     42 import com.google.android.car.kitchensink.R;
     43 
     44 import java.util.List;
     45 
     46 public class MapMceTestFragment extends Fragment {
     47     static final String MESSAGE_TO_SEND = "Im Busy Driving";
     48     private static final String TAG = "CAR.BLUETOOTH.KS";
     49     BluetoothMapClient mMapProfile;
     50     BluetoothAdapter mBluetoothAdapter;
     51     Button mDevicePicker;
     52     Button mDeviceDisconnect;
     53     TextView mMessage;
     54     EditText mOriginator;
     55     TextView mOriginatorDisplayName;
     56     CheckBox mSent;
     57     CheckBox mDelivered;
     58     TextView mBluetoothDevice;
     59     PendingIntent mSentIntent;
     60     PendingIntent mDeliveredIntent;
     61     NotificationReceiver mTransmissionStatusReceiver;
     62     Object mLock = new Object();
     63     private Intent mSendIntent;
     64     private Intent mDeliveryIntent;
     65 
     66     @Override
     67     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
     68             @Nullable Bundle savedInstanceState) {
     69         View v = inflater.inflate(R.layout.sms_received, container, false);
     70 
     71         Button reply = (Button) v.findViewById(R.id.reply);
     72         Button checkMessages = (Button) v.findViewById(R.id.check_messages);
     73         mBluetoothDevice = (TextView) v.findViewById(R.id.bluetoothDevice);
     74         mOriginator = (EditText) v.findViewById(R.id.messageOriginator);
     75         mOriginatorDisplayName = (TextView) v.findViewById(R.id.messageOriginatorDisplayName);
     76         mSent = (CheckBox) v.findViewById(R.id.sent_checkbox);
     77         mDelivered = (CheckBox) v.findViewById(R.id.delivered_checkbox);
     78         mSendIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
     79         mDeliveryIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
     80         mMessage = (TextView) v.findViewById(R.id.messageContent);
     81         mDevicePicker = (Button) v.findViewById(R.id.bluetooth_pick_device);
     82         mDeviceDisconnect = (Button) v.findViewById(R.id.bluetooth_disconnect_device);
     83         //TODO add manual entry option for phone number
     84         reply.setOnClickListener(new View.OnClickListener() {
     85             @Override
     86             public void onClick(View view) {
     87                 sendMessage(new Uri[]{Uri.parse(mOriginator.getText().toString())},
     88                         MESSAGE_TO_SEND);
     89             }
     90         });
     91 
     92         checkMessages.setOnClickListener(new View.OnClickListener() {
     93             @Override
     94             public void onClick(View view) {
     95                 getMessages();
     96             }
     97         });
     98 
     99         // Pick a bluetooth device
    100         mDevicePicker.setOnClickListener(new View.OnClickListener() {
    101             @Override
    102             public void onClick(View view) {
    103                 launchDevicePicker();
    104             }
    105         });
    106         mDeviceDisconnect.setOnClickListener(new View.OnClickListener() {
    107             @Override
    108             public void onClick(View view) {
    109                 disconnectDevice(mBluetoothDevice.getText().toString());
    110             }
    111         });
    112 
    113         mTransmissionStatusReceiver = new NotificationReceiver();
    114         return v;
    115     }
    116 
    117     void launchDevicePicker() {
    118         IntentFilter filter = new IntentFilter();
    119         filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
    120         getContext().registerReceiver(mPickerReceiver, filter);
    121 
    122         Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
    123         intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    124         getContext().startActivity(intent);
    125     }
    126 
    127     void disconnectDevice(String device) {
    128         mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice((device)));
    129     }
    130 
    131     @Override
    132     public void onResume() {
    133         super.onResume();
    134 
    135         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    136         mBluetoothAdapter.getProfileProxy(getContext(), new MapServiceListener(),
    137                 BluetoothProfile.MAP_CLIENT);
    138 
    139         IntentFilter intentFilter = new IntentFilter();
    140         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
    141         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
    142         intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED);
    143         intentFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
    144         getContext().registerReceiver(mTransmissionStatusReceiver, intentFilter);
    145     }
    146 
    147     @Override
    148     public void onPause() {
    149         super.onPause();
    150         getContext().unregisterReceiver(mTransmissionStatusReceiver);
    151     }
    152 
    153     private void getMessages() {
    154         synchronized (mLock) {
    155             BluetoothDevice remoteDevice;
    156             try {
    157                 remoteDevice = mBluetoothAdapter.getRemoteDevice(
    158                         mBluetoothDevice.getText().toString());
    159             } catch (java.lang.IllegalArgumentException e) {
    160                 Log.e(TAG, e.toString());
    161                 return;
    162             }
    163 
    164             if (mMapProfile != null) {
    165                 Log.d(TAG, "Getting Messages");
    166                 mMapProfile.getUnreadMessages(remoteDevice);
    167             }
    168         }
    169     }
    170 
    171     private void sendMessage(Uri[] recipients, String message) {
    172         synchronized (mLock) {
    173             BluetoothDevice remoteDevice;
    174             try {
    175                 remoteDevice = mBluetoothAdapter.getRemoteDevice(
    176                         mBluetoothDevice.getText().toString());
    177             } catch (java.lang.IllegalArgumentException e) {
    178                 Log.e(TAG, e.toString());
    179                 return;
    180             }
    181             mSent.setChecked(false);
    182             mDelivered.setChecked(false);
    183             if (mMapProfile != null) {
    184                 Log.d(TAG, "Sending reply");
    185                 if (recipients == null) {
    186                     Log.d(TAG, "Recipients is null");
    187                     return;
    188                 }
    189                 if (mBluetoothDevice == null) {
    190                     Log.d(TAG, "BluetoothDevice is null");
    191                     return;
    192                 }
    193 
    194                 mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent,
    195                         PendingIntent.FLAG_ONE_SHOT);
    196                 mDeliveredIntent = PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent,
    197                         PendingIntent.FLAG_ONE_SHOT);
    198                 mMapProfile.sendMessage(
    199                         remoteDevice,
    200                         recipients, message, mSentIntent, mDeliveredIntent);
    201             }
    202         }
    203     }
    204 
    205     class MapServiceListener implements BluetoothProfile.ServiceListener {
    206         @Override
    207         public void onServiceConnected(int profile, BluetoothProfile proxy) {
    208             synchronized (mLock) {
    209                 mMapProfile = (BluetoothMapClient) proxy;
    210                 List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
    211                 if (connectedDevices.size() > 0) {
    212                     mBluetoothDevice.setText(connectedDevices.get(0).getAddress());
    213                 }
    214             }
    215         }
    216 
    217         @Override
    218         public void onServiceDisconnected(int profile) {
    219             synchronized (mLock) {
    220                 mMapProfile = null;
    221             }
    222         }
    223     }
    224 
    225     private class NotificationReceiver extends BroadcastReceiver {
    226         @Override
    227         public void onReceive(Context context, Intent intent) {
    228             String action = intent.getAction();
    229             synchronized (mLock) {
    230                 if (action.equals(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED)) {
    231                     if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
    232                             == BluetoothProfile.STATE_CONNECTED) {
    233                         mBluetoothDevice.setText(((BluetoothDevice) intent.getParcelableExtra(
    234                                 BluetoothDevice.EXTRA_DEVICE)).getAddress());
    235                     } else if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
    236                             == BluetoothProfile.STATE_DISCONNECTED) {
    237                         mBluetoothDevice.setText("Disconnected");
    238                     }
    239                 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) {
    240                     mSent.setChecked(true);
    241                 } else if (action.equals(
    242                         BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) {
    243                     mDelivered.setChecked(true);
    244                 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) {
    245                     String senderUri =
    246                             intent.getStringExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_URI);
    247                     if (senderUri == null) {
    248                         senderUri = "<null>";
    249                     }
    250 
    251                     String senderName = intent.getStringExtra(
    252                             BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME);
    253                     if (senderName == null) {
    254                         senderName = "<null>";
    255                     }
    256 
    257                     mMessage.setText(intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
    258                     mOriginator.setText(senderUri);
    259                     mOriginatorDisplayName.setText(senderName);
    260                 }
    261             }
    262         }
    263     }
    264 
    265     private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() {
    266         @Override
    267         public void onReceive(Context context, Intent intent) {
    268             String action = intent.getAction();
    269 
    270             Log.v(TAG, "mPickerReceiver got " + action);
    271 
    272             if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) {
    273                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    274                 Log.v(TAG, "mPickerReceiver got " + device);
    275                 mMapProfile.connect(device);
    276 
    277                 // The receiver can now be disabled.
    278                 getContext().unregisterReceiver(mPickerReceiver);
    279             }
    280         }
    281     };
    282 }