MapMceTestFragment.java revision 3bb97c6a1dc4862c17ec484a56d0fd6efc5456fd
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
17package com.google.android.car.kitchensink.bluetooth;
18
19import android.app.PendingIntent;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothDevicePicker;
23import android.bluetooth.BluetoothMapClient;
24import android.bluetooth.BluetoothProfile;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.net.Uri;
30import android.os.Bundle;
31import android.support.annotation.Nullable;
32import android.support.v4.app.Fragment;
33import android.util.Log;
34import android.view.LayoutInflater;
35import android.view.View;
36import android.view.ViewGroup;
37import android.widget.Button;
38import android.widget.CheckBox;
39import android.widget.EditText;
40import android.widget.TextView;
41
42import com.google.android.car.kitchensink.R;
43
44import java.util.List;
45
46public 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}