1 /* 2 * Copyright (C) 2019 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 18 package com.android.internal.telephony; 19 20 import android.app.PendingIntent; 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothMapClient; 24 import android.bluetooth.BluetoothProfile; 25 import android.content.Context; 26 import android.net.Uri; 27 import android.telecom.PhoneAccount; 28 import android.telephony.Rlog; 29 import android.telephony.SmsManager; 30 import android.telephony.SubscriptionInfo; 31 import android.util.Log; 32 33 import java.util.Collection; 34 import java.util.Collections; 35 36 37 /** 38 * BtSmsInterfaceManager to provide a mechanism for sending SMS over Bluetooth 39 */ 40 public class BtSmsInterfaceManager { 41 42 private static final String LOG_TAG = "BtSmsInterfaceManager"; 43 44 /** 45 * Sends text through connected Bluetooth device 46 */ sendText(Context context, String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, SubscriptionInfo info)47 public void sendText(Context context, String destAddr, String text, PendingIntent sentIntent, 48 PendingIntent deliveryIntent, SubscriptionInfo info) { 49 BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); 50 if (btAdapter == null) { 51 // No bluetooth service on this platform? 52 sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_NO_BLUETOOTH_SERVICE); 53 return; 54 } 55 BluetoothDevice device = btAdapter.getRemoteDevice(info.getIccId()); 56 if (device == null) { 57 Log.d(LOG_TAG, "Bluetooth device addr invalid: " + Rlog.pii(LOG_TAG, info.getIccId())); 58 sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS); 59 return; 60 } 61 if (btAdapter.getProfileProxy(context.getApplicationContext(), 62 new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent), 63 BluetoothProfile.MAP_CLIENT)) { 64 return; 65 } 66 throw new RuntimeException("Can't send message through BluetoothMapClient"); 67 } 68 sendErrorInPendingIntent(PendingIntent intent, int errorCode)69 private void sendErrorInPendingIntent(PendingIntent intent, int errorCode) { 70 if (intent == null) { 71 return; 72 } 73 try { 74 intent.send(errorCode); 75 } catch (PendingIntent.CanceledException e) { 76 // PendingIntent is cancelled. ignore sending this error code back to 77 // caller. 78 Log.d(LOG_TAG, "PendingIntent.CanceledException: " + e.getMessage()); 79 } 80 } 81 82 private class MapMessageSender implements BluetoothProfile.ServiceListener { 83 84 final Collection<Uri> mDestAddr; 85 private String mMessage; 86 final BluetoothDevice mDevice; 87 final PendingIntent mSentIntent; 88 final PendingIntent mDeliveryIntent; 89 MapMessageSender(final String destAddr, final String message, final BluetoothDevice device, final PendingIntent sentIntent, final PendingIntent deliveryIntent)90 MapMessageSender(final String destAddr, final String message, final BluetoothDevice device, 91 final PendingIntent sentIntent, final PendingIntent deliveryIntent) { 92 super(); 93 mDestAddr = Collections.singleton(new Uri.Builder() 94 .appendPath(destAddr) 95 .scheme(PhoneAccount.SCHEME_TEL) 96 .build()); 97 mMessage = message; 98 mDevice = device; 99 mSentIntent = sentIntent; 100 mDeliveryIntent = deliveryIntent; 101 } 102 103 @Override onServiceConnected(int profile, BluetoothProfile proxy)104 public void onServiceConnected(int profile, BluetoothProfile proxy) { 105 Log.d(LOG_TAG, "Service connected"); 106 if (profile != BluetoothProfile.MAP_CLIENT) { 107 return; 108 } 109 BluetoothMapClient mapProfile = (BluetoothMapClient) proxy; 110 if (mMessage != null) { 111 Log.d(LOG_TAG, "Sending message thru bluetooth"); 112 mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent); 113 mMessage = null; 114 } 115 BluetoothAdapter.getDefaultAdapter() 116 .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile); 117 } 118 119 @Override onServiceDisconnected(int profile)120 public void onServiceDisconnected(int profile) { 121 if (mMessage != null) { 122 Log.d(LOG_TAG, "Bluetooth disconnected before sending the message"); 123 sendErrorInPendingIntent(mSentIntent, SmsManager.RESULT_BLUETOOTH_DISCONNECTED); 124 mMessage = null; 125 } 126 } 127 } 128 } 129