blob: e6c07384321c4453c0f0213fd19734163a23d507 [file] [log] [blame]
Joseph Pirozzocaa94c62016-10-06 09:29:43 -07001/*
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
Anthony Chend12cd772018-04-16 16:20:44 -070019import android.Manifest;
Vasu Nori0ab0af52017-12-06 14:39:21 -080020import android.annotation.TargetApi;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070021import android.app.PendingIntent;
22import android.bluetooth.BluetoothAdapter;
23import android.bluetooth.BluetoothDevice;
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080024import android.bluetooth.BluetoothDevicePicker;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070025import android.bluetooth.BluetoothMapClient;
26import android.bluetooth.BluetoothProfile;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
Vasu Nori0ab0af52017-12-06 14:39:21 -080031import android.content.pm.PackageManager;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070032import android.net.Uri;
Vasu Nori0ab0af52017-12-06 14:39:21 -080033import android.os.Build;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070034import android.os.Bundle;
Vasu Nori0ab0af52017-12-06 14:39:21 -080035import android.telecom.PhoneAccount;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070036import android.util.Log;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.ViewGroup;
40import android.widget.Button;
41import android.widget.CheckBox;
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080042import android.widget.EditText;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070043import android.widget.TextView;
Vasu Nori0ab0af52017-12-06 14:39:21 -080044import android.widget.Toast;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070045
Anthony Chend12cd772018-04-16 16:20:44 -070046import androidx.annotation.Nullable;
47import androidx.fragment.app.Fragment;
48
Vasu Nori0ab0af52017-12-06 14:39:21 -080049import com.google.android.car.kitchensink.KitchenSinkActivity;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070050import com.google.android.car.kitchensink.R;
51
52import java.util.List;
53
Vasu Nori0ab0af52017-12-06 14:39:21 -080054@TargetApi(Build.VERSION_CODES.LOLLIPOP)
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070055public class MapMceTestFragment extends Fragment {
56 static final String MESSAGE_TO_SEND = "Im Busy Driving";
Vasu Nori0ab0af52017-12-06 14:39:21 -080057 static final String NEW_MESSAGE_TO_SEND = "This is new msg";
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070058 private static final String TAG = "CAR.BLUETOOTH.KS";
Vasu Nori0ab0af52017-12-06 14:39:21 -080059 private static final int SEND_SMS_PERMISSIONS_REQUEST = 1;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070060 BluetoothMapClient mMapProfile;
61 BluetoothAdapter mBluetoothAdapter;
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080062 Button mDevicePicker;
63 Button mDeviceDisconnect;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070064 TextView mMessage;
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080065 EditText mOriginator;
Vasu Nori0ab0af52017-12-06 14:39:21 -080066 EditText mSmsTelNum;
Joseph Pirozzoa90995a2016-10-13 09:48:50 -070067 TextView mOriginatorDisplayName;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070068 CheckBox mSent;
69 CheckBox mDelivered;
70 TextView mBluetoothDevice;
71 PendingIntent mSentIntent;
72 PendingIntent mDeliveredIntent;
73 NotificationReceiver mTransmissionStatusReceiver;
74 Object mLock = new Object();
Vasu Nori0ab0af52017-12-06 14:39:21 -080075 private KitchenSinkActivity mActivity;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070076 private Intent mSendIntent;
77 private Intent mDeliveryIntent;
Vasu Nori937352c2018-09-26 17:14:04 -070078 EditText mUploadingSupportedFeatureText;
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070079
80 @Override
81 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
82 @Nullable Bundle savedInstanceState) {
83 View v = inflater.inflate(R.layout.sms_received, container, false);
Vasu Nori0ab0af52017-12-06 14:39:21 -080084 mActivity = (KitchenSinkActivity) getHost();
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070085 Button reply = (Button) v.findViewById(R.id.reply);
86 Button checkMessages = (Button) v.findViewById(R.id.check_messages);
87 mBluetoothDevice = (TextView) v.findViewById(R.id.bluetoothDevice);
Vasu Nori0ab0af52017-12-06 14:39:21 -080088 Button sendNewMsg = (Button) v.findViewById(R.id.sms_new_message);
89 mSmsTelNum = (EditText) v.findViewById(R.id.sms_tel_num);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080090 mOriginator = (EditText) v.findViewById(R.id.messageOriginator);
Joseph Pirozzoa90995a2016-10-13 09:48:50 -070091 mOriginatorDisplayName = (TextView) v.findViewById(R.id.messageOriginatorDisplayName);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070092 mSent = (CheckBox) v.findViewById(R.id.sent_checkbox);
93 mDelivered = (CheckBox) v.findViewById(R.id.delivered_checkbox);
94 mSendIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
95 mDeliveryIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
96 mMessage = (TextView) v.findViewById(R.id.messageContent);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080097 mDevicePicker = (Button) v.findViewById(R.id.bluetooth_pick_device);
98 mDeviceDisconnect = (Button) v.findViewById(R.id.bluetooth_disconnect_device);
Vasu Nori937352c2018-09-26 17:14:04 -070099 Button uploadingFeatureValue = (Button) v.findViewById(R.id.uploading_supported_feature);
100 mUploadingSupportedFeatureText =
101 (EditText) v.findViewById(R.id.uploading_supported_feature_value);
102
103 uploadingFeatureValue.setOnClickListener(new View.OnClickListener() {
104 @Override
105 public void onClick(View view) {
106 int value = getUploadingFeatureValue();
107 mUploadingSupportedFeatureText.setText(value + "");
108 }
109 });
110
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700111 //TODO add manual entry option for phone number
112 reply.setOnClickListener(new View.OnClickListener() {
113 @Override
114 public void onClick(View view) {
115 sendMessage(new Uri[]{Uri.parse(mOriginator.getText().toString())},
116 MESSAGE_TO_SEND);
117 }
118 });
119
Vasu Nori0ab0af52017-12-06 14:39:21 -0800120 sendNewMsg.setOnClickListener(new View.OnClickListener() {
121 @Override
122 public void onClick(View view) {
123 String s = mSmsTelNum.getText().toString();
124 Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show();
125 Uri.Builder builder = new Uri.Builder();
126 Uri uri = builder.appendPath(s).scheme(PhoneAccount.SCHEME_TEL).build();
127 sendMessage(new Uri[]{uri}, NEW_MESSAGE_TO_SEND);
128 }
129 });
130
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700131 checkMessages.setOnClickListener(new View.OnClickListener() {
132 @Override
133 public void onClick(View view) {
134 getMessages();
135 }
136 });
137
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800138 // Pick a bluetooth device
139 mDevicePicker.setOnClickListener(new View.OnClickListener() {
140 @Override
141 public void onClick(View view) {
142 launchDevicePicker();
143 }
144 });
145 mDeviceDisconnect.setOnClickListener(new View.OnClickListener() {
146 @Override
147 public void onClick(View view) {
148 disconnectDevice(mBluetoothDevice.getText().toString());
149 }
150 });
151
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700152 mTransmissionStatusReceiver = new NotificationReceiver();
153 return v;
154 }
155
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800156 void launchDevicePicker() {
157 IntentFilter filter = new IntentFilter();
158 filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
159 getContext().registerReceiver(mPickerReceiver, filter);
160
161 Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
162 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
163 getContext().startActivity(intent);
164 }
165
166 void disconnectDevice(String device) {
167 mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice((device)));
168 }
169
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700170 @Override
171 public void onResume() {
172 super.onResume();
173
174 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
175 mBluetoothAdapter.getProfileProxy(getContext(), new MapServiceListener(),
176 BluetoothProfile.MAP_CLIENT);
177
178 IntentFilter intentFilter = new IntentFilter();
179 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
180 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
181 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800182 intentFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700183 getContext().registerReceiver(mTransmissionStatusReceiver, intentFilter);
184 }
185
186 @Override
187 public void onPause() {
188 super.onPause();
189 getContext().unregisterReceiver(mTransmissionStatusReceiver);
190 }
191
192 private void getMessages() {
193 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800194 BluetoothDevice remoteDevice;
195 try {
196 remoteDevice = mBluetoothAdapter.getRemoteDevice(
197 mBluetoothDevice.getText().toString());
198 } catch (java.lang.IllegalArgumentException e) {
199 Log.e(TAG, e.toString());
200 return;
201 }
202
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700203 if (mMapProfile != null) {
204 Log.d(TAG, "Getting Messages");
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800205 mMapProfile.getUnreadMessages(remoteDevice);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700206 }
207 }
208 }
209
Vasu Nori937352c2018-09-26 17:14:04 -0700210 private int getUploadingFeatureValue() {
211 synchronized (mLock) {
212 BluetoothDevice remoteDevice;
213 try {
214 remoteDevice = mBluetoothAdapter.getRemoteDevice(
215 mBluetoothDevice.getText().toString());
216 } catch (java.lang.IllegalArgumentException e) {
217 Log.e(TAG, e.toString());
218 return -1;
219 }
220
221 if (mMapProfile != null) {
222 Log.d(TAG, "getUploadingFeatureValue");
223 return (mMapProfile.isUploadingSupported(remoteDevice)) ? 1 : 0;
224 }
225 return -1;
226 }
227 }
228
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700229 private void sendMessage(Uri[] recipients, String message) {
Vasu Nori0ab0af52017-12-06 14:39:21 -0800230 if (mActivity.checkSelfPermission(Manifest.permission.SEND_SMS)
231 != PackageManager.PERMISSION_GRANTED) {
232 Log.d(TAG,"Don't have SMS permission in kitchesink app. Requesting it");
233 mActivity.requestPermissions(new String[]{Manifest.permission.SEND_SMS},
234 SEND_SMS_PERMISSIONS_REQUEST);
235 Toast.makeText(getContext(), "Try again after granting SEND_SMS perm!",
236 Toast.LENGTH_SHORT).show();
237 return;
238 }
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700239 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800240 BluetoothDevice remoteDevice;
241 try {
242 remoteDevice = mBluetoothAdapter.getRemoteDevice(
243 mBluetoothDevice.getText().toString());
244 } catch (java.lang.IllegalArgumentException e) {
245 Log.e(TAG, e.toString());
246 return;
247 }
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700248 mSent.setChecked(false);
249 mDelivered.setChecked(false);
250 if (mMapProfile != null) {
251 Log.d(TAG, "Sending reply");
252 if (recipients == null) {
253 Log.d(TAG, "Recipients is null");
254 return;
255 }
256 if (mBluetoothDevice == null) {
257 Log.d(TAG, "BluetoothDevice is null");
258 return;
259 }
260
261 mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent,
262 PendingIntent.FLAG_ONE_SHOT);
263 mDeliveredIntent = PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent,
264 PendingIntent.FLAG_ONE_SHOT);
Vasu Nori0ab0af52017-12-06 14:39:21 -0800265 Log.d(TAG,"Sending message in kitchesink app: " + message);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700266 mMapProfile.sendMessage(
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800267 remoteDevice,
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700268 recipients, message, mSentIntent, mDeliveredIntent);
269 }
270 }
271 }
272
Vasu Nori0ab0af52017-12-06 14:39:21 -0800273 @Override
274 public void onRequestPermissionsResult(int requestCode, String[] permissions,
275 int[] grantResults) {
276 Log.d(TAG, "onRequestPermissionsResult reqCode=" + requestCode);
277 if (SEND_SMS_PERMISSIONS_REQUEST == requestCode) {
278 for (int i=0; i<permissions.length; i++) {
279 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
280 if (permissions[i] == Manifest.permission.SEND_SMS) {
281 Log.d(TAG, "Got the SEND_SMS perm");
282 return;
283 }
284 }
285 }
286 }
287 }
288
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700289 class MapServiceListener implements BluetoothProfile.ServiceListener {
290 @Override
291 public void onServiceConnected(int profile, BluetoothProfile proxy) {
292 synchronized (mLock) {
293 mMapProfile = (BluetoothMapClient) proxy;
294 List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
295 if (connectedDevices.size() > 0) {
296 mBluetoothDevice.setText(connectedDevices.get(0).getAddress());
297 }
298 }
299 }
300
301 @Override
302 public void onServiceDisconnected(int profile) {
303 synchronized (mLock) {
304 mMapProfile = null;
305 }
306 }
307 }
308
309 private class NotificationReceiver extends BroadcastReceiver {
310 @Override
311 public void onReceive(Context context, Intent intent) {
312 String action = intent.getAction();
313 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800314 if (action.equals(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED)) {
315 if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
316 == BluetoothProfile.STATE_CONNECTED) {
317 mBluetoothDevice.setText(((BluetoothDevice) intent.getParcelableExtra(
318 BluetoothDevice.EXTRA_DEVICE)).getAddress());
319 } else if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
320 == BluetoothProfile.STATE_DISCONNECTED) {
321 mBluetoothDevice.setText("Disconnected");
322 }
323 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) {
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700324 mSent.setChecked(true);
325 } else if (action.equals(
326 BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) {
327 mDelivered.setChecked(true);
328 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) {
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800329 String senderUri =
330 intent.getStringExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_URI);
331 if (senderUri == null) {
332 senderUri = "<null>";
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700333 }
334
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800335 String senderName = intent.getStringExtra(
Srinivas Visvanathan6b90bbf2017-03-03 10:01:09 -0800336 BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME);
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800337 if (senderName == null) {
338 senderName = "<null>";
Joseph Pirozzoa90995a2016-10-13 09:48:50 -0700339 }
340
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700341 mMessage.setText(intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800342 mOriginator.setText(senderUri);
343 mOriginatorDisplayName.setText(senderName);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700344 }
345 }
346 }
347 }
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800348
349 private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() {
350 @Override
351 public void onReceive(Context context, Intent intent) {
352 String action = intent.getAction();
353
354 Log.v(TAG, "mPickerReceiver got " + action);
355
356 if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) {
357 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
358 Log.v(TAG, "mPickerReceiver got " + device);
359 mMapProfile.connect(device);
360
361 // The receiver can now be disabled.
362 getContext().unregisterReceiver(mPickerReceiver);
363 }
364 }
365 };
Anthony Chend12cd772018-04-16 16:20:44 -0700366}