blob: 2d9df69b68a239a7b2416c70513f24c5b4fde18a [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;
78
79 @Override
80 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
81 @Nullable Bundle savedInstanceState) {
82 View v = inflater.inflate(R.layout.sms_received, container, false);
Vasu Nori0ab0af52017-12-06 14:39:21 -080083 mActivity = (KitchenSinkActivity) getHost();
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070084 Button reply = (Button) v.findViewById(R.id.reply);
85 Button checkMessages = (Button) v.findViewById(R.id.check_messages);
86 mBluetoothDevice = (TextView) v.findViewById(R.id.bluetoothDevice);
Vasu Nori0ab0af52017-12-06 14:39:21 -080087 Button sendNewMsg = (Button) v.findViewById(R.id.sms_new_message);
88 mSmsTelNum = (EditText) v.findViewById(R.id.sms_tel_num);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080089 mOriginator = (EditText) v.findViewById(R.id.messageOriginator);
Joseph Pirozzoa90995a2016-10-13 09:48:50 -070090 mOriginatorDisplayName = (TextView) v.findViewById(R.id.messageOriginatorDisplayName);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070091 mSent = (CheckBox) v.findViewById(R.id.sent_checkbox);
92 mDelivered = (CheckBox) v.findViewById(R.id.delivered_checkbox);
93 mSendIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
94 mDeliveryIntent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
95 mMessage = (TextView) v.findViewById(R.id.messageContent);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -080096 mDevicePicker = (Button) v.findViewById(R.id.bluetooth_pick_device);
97 mDeviceDisconnect = (Button) v.findViewById(R.id.bluetooth_disconnect_device);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -070098 //TODO add manual entry option for phone number
99 reply.setOnClickListener(new View.OnClickListener() {
100 @Override
101 public void onClick(View view) {
102 sendMessage(new Uri[]{Uri.parse(mOriginator.getText().toString())},
103 MESSAGE_TO_SEND);
104 }
105 });
106
Vasu Nori0ab0af52017-12-06 14:39:21 -0800107 sendNewMsg.setOnClickListener(new View.OnClickListener() {
108 @Override
109 public void onClick(View view) {
110 String s = mSmsTelNum.getText().toString();
111 Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show();
112 Uri.Builder builder = new Uri.Builder();
113 Uri uri = builder.appendPath(s).scheme(PhoneAccount.SCHEME_TEL).build();
114 sendMessage(new Uri[]{uri}, NEW_MESSAGE_TO_SEND);
115 }
116 });
117
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700118 checkMessages.setOnClickListener(new View.OnClickListener() {
119 @Override
120 public void onClick(View view) {
121 getMessages();
122 }
123 });
124
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800125 // Pick a bluetooth device
126 mDevicePicker.setOnClickListener(new View.OnClickListener() {
127 @Override
128 public void onClick(View view) {
129 launchDevicePicker();
130 }
131 });
132 mDeviceDisconnect.setOnClickListener(new View.OnClickListener() {
133 @Override
134 public void onClick(View view) {
135 disconnectDevice(mBluetoothDevice.getText().toString());
136 }
137 });
138
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700139 mTransmissionStatusReceiver = new NotificationReceiver();
140 return v;
141 }
142
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800143 void launchDevicePicker() {
144 IntentFilter filter = new IntentFilter();
145 filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
146 getContext().registerReceiver(mPickerReceiver, filter);
147
148 Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
149 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
150 getContext().startActivity(intent);
151 }
152
153 void disconnectDevice(String device) {
154 mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice((device)));
155 }
156
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700157 @Override
158 public void onResume() {
159 super.onResume();
160
161 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
162 mBluetoothAdapter.getProfileProxy(getContext(), new MapServiceListener(),
163 BluetoothProfile.MAP_CLIENT);
164
165 IntentFilter intentFilter = new IntentFilter();
166 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY);
167 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY);
168 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED);
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800169 intentFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700170 getContext().registerReceiver(mTransmissionStatusReceiver, intentFilter);
171 }
172
173 @Override
174 public void onPause() {
175 super.onPause();
176 getContext().unregisterReceiver(mTransmissionStatusReceiver);
177 }
178
179 private void getMessages() {
180 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800181 BluetoothDevice remoteDevice;
182 try {
183 remoteDevice = mBluetoothAdapter.getRemoteDevice(
184 mBluetoothDevice.getText().toString());
185 } catch (java.lang.IllegalArgumentException e) {
186 Log.e(TAG, e.toString());
187 return;
188 }
189
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700190 if (mMapProfile != null) {
191 Log.d(TAG, "Getting Messages");
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800192 mMapProfile.getUnreadMessages(remoteDevice);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700193 }
194 }
195 }
196
197 private void sendMessage(Uri[] recipients, String message) {
Vasu Nori0ab0af52017-12-06 14:39:21 -0800198 if (mActivity.checkSelfPermission(Manifest.permission.SEND_SMS)
199 != PackageManager.PERMISSION_GRANTED) {
200 Log.d(TAG,"Don't have SMS permission in kitchesink app. Requesting it");
201 mActivity.requestPermissions(new String[]{Manifest.permission.SEND_SMS},
202 SEND_SMS_PERMISSIONS_REQUEST);
203 Toast.makeText(getContext(), "Try again after granting SEND_SMS perm!",
204 Toast.LENGTH_SHORT).show();
205 return;
206 }
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700207 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800208 BluetoothDevice remoteDevice;
209 try {
210 remoteDevice = mBluetoothAdapter.getRemoteDevice(
211 mBluetoothDevice.getText().toString());
212 } catch (java.lang.IllegalArgumentException e) {
213 Log.e(TAG, e.toString());
214 return;
215 }
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700216 mSent.setChecked(false);
217 mDelivered.setChecked(false);
218 if (mMapProfile != null) {
219 Log.d(TAG, "Sending reply");
220 if (recipients == null) {
221 Log.d(TAG, "Recipients is null");
222 return;
223 }
224 if (mBluetoothDevice == null) {
225 Log.d(TAG, "BluetoothDevice is null");
226 return;
227 }
228
229 mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent,
230 PendingIntent.FLAG_ONE_SHOT);
231 mDeliveredIntent = PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent,
232 PendingIntent.FLAG_ONE_SHOT);
Vasu Nori0ab0af52017-12-06 14:39:21 -0800233 Log.d(TAG,"Sending message in kitchesink app: " + message);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700234 mMapProfile.sendMessage(
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800235 remoteDevice,
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700236 recipients, message, mSentIntent, mDeliveredIntent);
237 }
238 }
239 }
240
Vasu Nori0ab0af52017-12-06 14:39:21 -0800241 @Override
242 public void onRequestPermissionsResult(int requestCode, String[] permissions,
243 int[] grantResults) {
244 Log.d(TAG, "onRequestPermissionsResult reqCode=" + requestCode);
245 if (SEND_SMS_PERMISSIONS_REQUEST == requestCode) {
246 for (int i=0; i<permissions.length; i++) {
247 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
248 if (permissions[i] == Manifest.permission.SEND_SMS) {
249 Log.d(TAG, "Got the SEND_SMS perm");
250 return;
251 }
252 }
253 }
254 }
255 }
256
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700257 class MapServiceListener implements BluetoothProfile.ServiceListener {
258 @Override
259 public void onServiceConnected(int profile, BluetoothProfile proxy) {
260 synchronized (mLock) {
261 mMapProfile = (BluetoothMapClient) proxy;
262 List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
263 if (connectedDevices.size() > 0) {
264 mBluetoothDevice.setText(connectedDevices.get(0).getAddress());
265 }
266 }
267 }
268
269 @Override
270 public void onServiceDisconnected(int profile) {
271 synchronized (mLock) {
272 mMapProfile = null;
273 }
274 }
275 }
276
277 private class NotificationReceiver extends BroadcastReceiver {
278 @Override
279 public void onReceive(Context context, Intent intent) {
280 String action = intent.getAction();
281 synchronized (mLock) {
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800282 if (action.equals(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED)) {
283 if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
284 == BluetoothProfile.STATE_CONNECTED) {
285 mBluetoothDevice.setText(((BluetoothDevice) intent.getParcelableExtra(
286 BluetoothDevice.EXTRA_DEVICE)).getAddress());
287 } else if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)
288 == BluetoothProfile.STATE_DISCONNECTED) {
289 mBluetoothDevice.setText("Disconnected");
290 }
291 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) {
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700292 mSent.setChecked(true);
293 } else if (action.equals(
294 BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) {
295 mDelivered.setChecked(true);
296 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) {
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800297 String senderUri =
298 intent.getStringExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_URI);
299 if (senderUri == null) {
300 senderUri = "<null>";
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700301 }
302
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800303 String senderName = intent.getStringExtra(
Srinivas Visvanathan6b90bbf2017-03-03 10:01:09 -0800304 BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME);
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800305 if (senderName == null) {
306 senderName = "<null>";
Joseph Pirozzoa90995a2016-10-13 09:48:50 -0700307 }
308
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700309 mMessage.setText(intent.getStringExtra(android.content.Intent.EXTRA_TEXT));
Srinivas Visvanathan3bb97c62017-03-08 16:15:07 -0800310 mOriginator.setText(senderUri);
311 mOriginatorDisplayName.setText(senderName);
Joseph Pirozzocaa94c62016-10-06 09:29:43 -0700312 }
313 }
314 }
315 }
Joseph Pirozzo9cddbe92017-02-08 18:23:56 -0800316
317 private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() {
318 @Override
319 public void onReceive(Context context, Intent intent) {
320 String action = intent.getAction();
321
322 Log.v(TAG, "mPickerReceiver got " + action);
323
324 if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) {
325 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
326 Log.v(TAG, "mPickerReceiver got " + device);
327 mMapProfile.connect(device);
328
329 // The receiver can now be disabled.
330 getContext().unregisterReceiver(mPickerReceiver);
331 }
332 }
333 };
Anthony Chend12cd772018-04-16 16:20:44 -0700334}