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