• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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