MapMceTestFragment.java revision 0ab0af545dcc2cc34e540778da5db926bb593163
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.annotation.TargetApi; 20import android.app.PendingIntent; 21import android.bluetooth.BluetoothAdapter; 22import android.bluetooth.BluetoothDevice; 23import android.bluetooth.BluetoothDevicePicker; 24import android.bluetooth.BluetoothMapClient; 25import android.bluetooth.BluetoothProfile; 26import android.content.BroadcastReceiver; 27import android.content.Context; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.content.pm.PackageManager; 31import android.Manifest; 32import android.net.Uri; 33import android.net.Uri.Builder; 34import android.os.Build; 35import android.os.Bundle; 36import android.provider.ContactsContract.PhoneLookup; 37import android.support.annotation.Nullable; 38import android.support.v4.app.Fragment; 39import android.telecom.PhoneAccount; 40import android.util.Log; 41import android.view.LayoutInflater; 42import android.view.View; 43import android.view.ViewGroup; 44import android.widget.Button; 45import android.widget.CheckBox; 46import android.widget.EditText; 47import android.widget.TextView; 48import android.widget.Toast; 49 50import com.google.android.car.kitchensink.KitchenSinkActivity; 51import com.google.android.car.kitchensink.R; 52 53import java.util.List; 54 55@TargetApi(Build.VERSION_CODES.LOLLIPOP) 56public class MapMceTestFragment extends Fragment { 57 static final String MESSAGE_TO_SEND = "Im Busy Driving"; 58 static final String NEW_MESSAGE_TO_SEND = "This is new msg"; 59 private static final String TAG = "CAR.BLUETOOTH.KS"; 60 private static final int SEND_SMS_PERMISSIONS_REQUEST = 1; 61 BluetoothMapClient mMapProfile; 62 BluetoothAdapter mBluetoothAdapter; 63 Button mDevicePicker; 64 Button mDeviceDisconnect; 65 TextView mMessage; 66 EditText mOriginator; 67 EditText mSmsTelNum; 68 TextView mOriginatorDisplayName; 69 CheckBox mSent; 70 CheckBox mDelivered; 71 TextView mBluetoothDevice; 72 PendingIntent mSentIntent; 73 PendingIntent mDeliveredIntent; 74 NotificationReceiver mTransmissionStatusReceiver; 75 Object mLock = new Object(); 76 private KitchenSinkActivity mActivity; 77 private Intent mSendIntent; 78 private Intent mDeliveryIntent; 79 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); 84 mActivity = (KitchenSinkActivity) getHost(); 85 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); 88 Button sendNewMsg = (Button) v.findViewById(R.id.sms_new_message); 89 mSmsTelNum = (EditText) v.findViewById(R.id.sms_tel_num); 90 mOriginator = (EditText) v.findViewById(R.id.messageOriginator); 91 mOriginatorDisplayName = (TextView) v.findViewById(R.id.messageOriginatorDisplayName); 92 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); 97 mDevicePicker = (Button) v.findViewById(R.id.bluetooth_pick_device); 98 mDeviceDisconnect = (Button) v.findViewById(R.id.bluetooth_disconnect_device); 99 //TODO add manual entry option for phone number 100 reply.setOnClickListener(new View.OnClickListener() { 101 @Override 102 public void onClick(View view) { 103 sendMessage(new Uri[]{Uri.parse(mOriginator.getText().toString())}, 104 MESSAGE_TO_SEND); 105 } 106 }); 107 108 sendNewMsg.setOnClickListener(new View.OnClickListener() { 109 @Override 110 public void onClick(View view) { 111 String s = mSmsTelNum.getText().toString(); 112 Toast.makeText(getContext(), "sending msg to " + s, Toast.LENGTH_SHORT).show(); 113 Uri.Builder builder = new Uri.Builder(); 114 Uri uri = builder.appendPath(s).scheme(PhoneAccount.SCHEME_TEL).build(); 115 sendMessage(new Uri[]{uri}, NEW_MESSAGE_TO_SEND); 116 } 117 }); 118 119 checkMessages.setOnClickListener(new View.OnClickListener() { 120 @Override 121 public void onClick(View view) { 122 getMessages(); 123 } 124 }); 125 126 // Pick a bluetooth device 127 mDevicePicker.setOnClickListener(new View.OnClickListener() { 128 @Override 129 public void onClick(View view) { 130 launchDevicePicker(); 131 } 132 }); 133 mDeviceDisconnect.setOnClickListener(new View.OnClickListener() { 134 @Override 135 public void onClick(View view) { 136 disconnectDevice(mBluetoothDevice.getText().toString()); 137 } 138 }); 139 140 mTransmissionStatusReceiver = new NotificationReceiver(); 141 return v; 142 } 143 144 void launchDevicePicker() { 145 IntentFilter filter = new IntentFilter(); 146 filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED); 147 getContext().registerReceiver(mPickerReceiver, filter); 148 149 Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH); 150 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 151 getContext().startActivity(intent); 152 } 153 154 void disconnectDevice(String device) { 155 mMapProfile.disconnect(mBluetoothAdapter.getRemoteDevice((device))); 156 } 157 158 @Override 159 public void onResume() { 160 super.onResume(); 161 162 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 163 mBluetoothAdapter.getProfileProxy(getContext(), new MapServiceListener(), 164 BluetoothProfile.MAP_CLIENT); 165 166 IntentFilter intentFilter = new IntentFilter(); 167 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY); 168 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY); 169 intentFilter.addAction(BluetoothMapClient.ACTION_MESSAGE_RECEIVED); 170 intentFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED); 171 getContext().registerReceiver(mTransmissionStatusReceiver, intentFilter); 172 } 173 174 @Override 175 public void onPause() { 176 super.onPause(); 177 getContext().unregisterReceiver(mTransmissionStatusReceiver); 178 } 179 180 private void getMessages() { 181 synchronized (mLock) { 182 BluetoothDevice remoteDevice; 183 try { 184 remoteDevice = mBluetoothAdapter.getRemoteDevice( 185 mBluetoothDevice.getText().toString()); 186 } catch (java.lang.IllegalArgumentException e) { 187 Log.e(TAG, e.toString()); 188 return; 189 } 190 191 if (mMapProfile != null) { 192 Log.d(TAG, "Getting Messages"); 193 mMapProfile.getUnreadMessages(remoteDevice); 194 } 195 } 196 } 197 198 private void sendMessage(Uri[] recipients, String message) { 199 if (mActivity.checkSelfPermission(Manifest.permission.SEND_SMS) 200 != PackageManager.PERMISSION_GRANTED) { 201 Log.d(TAG,"Don't have SMS permission in kitchesink app. Requesting it"); 202 mActivity.requestPermissions(new String[]{Manifest.permission.SEND_SMS}, 203 SEND_SMS_PERMISSIONS_REQUEST); 204 Toast.makeText(getContext(), "Try again after granting SEND_SMS perm!", 205 Toast.LENGTH_SHORT).show(); 206 return; 207 } 208 synchronized (mLock) { 209 BluetoothDevice remoteDevice; 210 try { 211 remoteDevice = mBluetoothAdapter.getRemoteDevice( 212 mBluetoothDevice.getText().toString()); 213 } catch (java.lang.IllegalArgumentException e) { 214 Log.e(TAG, e.toString()); 215 return; 216 } 217 mSent.setChecked(false); 218 mDelivered.setChecked(false); 219 if (mMapProfile != null) { 220 Log.d(TAG, "Sending reply"); 221 if (recipients == null) { 222 Log.d(TAG, "Recipients is null"); 223 return; 224 } 225 if (mBluetoothDevice == null) { 226 Log.d(TAG, "BluetoothDevice is null"); 227 return; 228 } 229 230 mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent, 231 PendingIntent.FLAG_ONE_SHOT); 232 mDeliveredIntent = PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent, 233 PendingIntent.FLAG_ONE_SHOT); 234 Log.d(TAG,"Sending message in kitchesink app: " + message); 235 mMapProfile.sendMessage( 236 remoteDevice, 237 recipients, message, mSentIntent, mDeliveredIntent); 238 } 239 } 240 } 241 242 @Override 243 public void onRequestPermissionsResult(int requestCode, String[] permissions, 244 int[] grantResults) { 245 Log.d(TAG, "onRequestPermissionsResult reqCode=" + requestCode); 246 if (SEND_SMS_PERMISSIONS_REQUEST == requestCode) { 247 for (int i=0; i<permissions.length; i++) { 248 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { 249 if (permissions[i] == Manifest.permission.SEND_SMS) { 250 Log.d(TAG, "Got the SEND_SMS perm"); 251 return; 252 } 253 } 254 } 255 } 256 } 257 258 class MapServiceListener implements BluetoothProfile.ServiceListener { 259 @Override 260 public void onServiceConnected(int profile, BluetoothProfile proxy) { 261 synchronized (mLock) { 262 mMapProfile = (BluetoothMapClient) proxy; 263 List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices(); 264 if (connectedDevices.size() > 0) { 265 mBluetoothDevice.setText(connectedDevices.get(0).getAddress()); 266 } 267 } 268 } 269 270 @Override 271 public void onServiceDisconnected(int profile) { 272 synchronized (mLock) { 273 mMapProfile = null; 274 } 275 } 276 } 277 278 private class NotificationReceiver extends BroadcastReceiver { 279 @Override 280 public void onReceive(Context context, Intent intent) { 281 String action = intent.getAction(); 282 synchronized (mLock) { 283 if (action.equals(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED)) { 284 if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0) 285 == BluetoothProfile.STATE_CONNECTED) { 286 mBluetoothDevice.setText(((BluetoothDevice) intent.getParcelableExtra( 287 BluetoothDevice.EXTRA_DEVICE)).getAddress()); 288 } else if (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0) 289 == BluetoothProfile.STATE_DISCONNECTED) { 290 mBluetoothDevice.setText("Disconnected"); 291 } 292 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_SENT_SUCCESSFULLY)) { 293 mSent.setChecked(true); 294 } else if (action.equals( 295 BluetoothMapClient.ACTION_MESSAGE_DELIVERED_SUCCESSFULLY)) { 296 mDelivered.setChecked(true); 297 } else if (action.equals(BluetoothMapClient.ACTION_MESSAGE_RECEIVED)) { 298 String senderUri = 299 intent.getStringExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_URI); 300 if (senderUri == null) { 301 senderUri = "<null>"; 302 } 303 304 String senderName = intent.getStringExtra( 305 BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME); 306 if (senderName == null) { 307 senderName = "<null>"; 308 } 309 310 mMessage.setText(intent.getStringExtra(android.content.Intent.EXTRA_TEXT)); 311 mOriginator.setText(senderUri); 312 mOriginatorDisplayName.setText(senderName); 313 } 314 } 315 } 316 } 317 318 private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() { 319 @Override 320 public void onReceive(Context context, Intent intent) { 321 String action = intent.getAction(); 322 323 Log.v(TAG, "mPickerReceiver got " + action); 324 325 if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) { 326 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 327 Log.v(TAG, "mPickerReceiver got " + device); 328 mMapProfile.connect(device); 329 330 // The receiver can now be disabled. 331 getContext().unregisterReceiver(mPickerReceiver); 332 } 333 } 334 }; 335}