Skip to content

Commit d762f06

Browse files
author
Jaikumar Ganesh
committed
DO NOT MERGE Incoming Bluetooth Connection requests - dialog.
This sends the intents to the Settings app to show the dialogs for the incoming connection requests. Change-Id: Ibe267f7cda28ce2a46c25800df2e8ac685b0b9e6
1 parent c7b8776 commit d762f06

11 files changed

Lines changed: 493 additions & 43 deletions

core/java/android/bluetooth/BluetoothA2dp.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,22 @@ public int getSinkPriority(BluetoothDevice device) {
269269
}
270270
}
271271

272+
/**
273+
* Allow or disallow incoming connection
274+
* @param device Sink
275+
* @param value True / False
276+
* @return Success or Failure of the binder call.
277+
*/
278+
public boolean allowIncomingConnect(BluetoothDevice device, boolean value) {
279+
if (DBG) log("allowIncomingConnect(" + device + ":" + value + ")");
280+
try {
281+
return mService.allowIncomingConnect(device, value);
282+
} catch (RemoteException e) {
283+
Log.e(TAG, "", e);
284+
return false;
285+
}
286+
}
287+
272288
/** Helper for converting a state to a string.
273289
* For debug use only - strings are not internationalized.
274290
* @hide

core/java/android/bluetooth/BluetoothDevice.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,33 @@ public final class BluetoothDevice implements Parcelable {
276276
public static final String ACTION_PAIRING_CANCEL =
277277
"android.bluetooth.device.action.PAIRING_CANCEL";
278278

279+
/** @hide */
280+
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
281+
public static final String ACTION_CONNECTION_ACCESS_REQUEST =
282+
"android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
283+
284+
/** @hide */
285+
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
286+
public static final String ACTION_CONNECTION_ACCESS_REPLY =
287+
"android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
288+
289+
/** @hide */
290+
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
291+
public static final String ACTION_CONNECTION_ACCESS_CANCEL =
292+
"android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
293+
/**
294+
* Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
295+
* @hide
296+
*/
297+
public static final String EXTRA_CONNECTION_ACCESS_RESULT =
298+
"android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
299+
300+
/**@hide*/
301+
public static final int CONNECTION_ACCESS_YES = 1;
302+
303+
/**@hide*/
304+
public static final int CONNECTION_ACCESS_NO = 2;
305+
279306
/** A bond attempt succeeded
280307
* @hide */
281308
public static final int BOND_SUCCESS = 0;

core/java/android/bluetooth/BluetoothDeviceProfileState.java

Lines changed: 238 additions & 8 deletions
Large diffs are not rendered by default.

core/java/android/bluetooth/BluetoothHeadset.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,23 @@ public boolean createIncomingConnect(BluetoothDevice device) {
456456
return false;
457457
}
458458

459+
/**
460+
* Reject the incoming connection.
461+
* @hide
462+
*/
463+
public boolean rejectIncomingConnect(BluetoothDevice device) {
464+
if (DBG) log("rejectIncomingConnect");
465+
if (mService != null) {
466+
try {
467+
return mService.rejectIncomingConnect(device);
468+
} catch (RemoteException e) {Log.e(TAG, e.toString());}
469+
} else {
470+
Log.w(TAG, "Proxy not attached to service");
471+
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
472+
}
473+
return false;
474+
}
475+
459476
/**
460477
* Connect to a Bluetooth Headset.
461478
* Note: This is an internal function and shouldn't be exposed

core/java/android/bluetooth/IBluetoothA2dp.aidl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ interface IBluetoothA2dp {
3636

3737
boolean connectSinkInternal(in BluetoothDevice device);
3838
boolean disconnectSinkInternal(in BluetoothDevice device);
39+
boolean allowIncomingConnect(in BluetoothDevice device, boolean value);
40+
3941
}

core/java/android/bluetooth/IBluetoothHeadset.aidl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ interface IBluetoothHeadset {
3737

3838
boolean createIncomingConnect(in BluetoothDevice device);
3939
boolean acceptIncomingConnect(in BluetoothDevice device);
40+
boolean rejectIncomingConnect(in BluetoothDevice device);
4041
boolean cancelConnectThread();
4142
boolean connectHeadsetInternal(in BluetoothDevice device);
4243
boolean disconnectHeadsetInternal(in BluetoothDevice device);

core/java/android/server/BluetoothA2dpService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,22 @@ public synchronized boolean setSinkPriority(BluetoothDevice device, int priority
457457
Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority);
458458
}
459459

460+
public synchronized boolean allowIncomingConnect(BluetoothDevice device, boolean value) {
461+
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
462+
"Need BLUETOOTH_ADMIN permission");
463+
String address = device.getAddress();
464+
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
465+
return false;
466+
}
467+
Integer data = mBluetoothService.getAuthorizationAgentRequestData(address);
468+
if (data == null) {
469+
Log.w(TAG, "allowIncomingConnect(" + device + ") called but no native data available");
470+
return false;
471+
}
472+
log("allowIncomingConnect: A2DP: " + device + ":" + value);
473+
return mBluetoothService.setAuthorizationNative(address, value, data.intValue());
474+
}
475+
460476
private synchronized void onSinkPropertyChanged(String path, String []propValues) {
461477
if (!mBluetoothService.isEnabled()) {
462478
return;

core/java/android/server/BluetoothEventLoop.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class BluetoothEventLoop {
4848
private boolean mInterrupted;
4949

5050
private final HashMap<String, Integer> mPasskeyAgentRequestData;
51+
private final HashMap<String, Integer> mAuthorizationAgentRequestData;
5152
private final BluetoothService mBluetoothService;
5253
private final BluetoothAdapter mAdapter;
5354
private final Context mContext;
@@ -104,6 +105,7 @@ public void handleMessage(Message msg) {
104105
mBluetoothService = bluetoothService;
105106
mContext = context;
106107
mPasskeyAgentRequestData = new HashMap();
108+
mAuthorizationAgentRequestData = new HashMap<String, Integer>();
107109
mAdapter = adapter;
108110
initializeNativeDataNative();
109111
}
@@ -120,6 +122,10 @@ protected void finalize() throws Throwable {
120122
return mPasskeyAgentRequestData;
121123
}
122124

125+
/* package */ HashMap<String, Integer> getAuthorizationAgentRequestData() {
126+
return mAuthorizationAgentRequestData;
127+
}
128+
123129
/* package */ void start() {
124130

125131
if (!isEventLoopRunningNative()) {
@@ -491,34 +497,38 @@ private void onRequestOobData(String objectPath , int nativeData) {
491497
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
492498
}
493499

494-
private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
500+
private void onAgentAuthorize(String objectPath, String deviceUuid, int nativeData) {
495501
String address = mBluetoothService.getAddressFromObjectPath(objectPath);
496502
if (address == null) {
497503
Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
498-
return false;
504+
return;
499505
}
500506

501507
boolean authorized = false;
502508
ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
503509
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
504510

511+
BluetoothDevice device = mAdapter.getRemoteDevice(address);
512+
mAuthorizationAgentRequestData.put(address, new Integer(nativeData));
513+
505514
// Bluez sends the UUID of the local service being accessed, _not_ the
506515
// remote service
507516
if (mBluetoothService.isEnabled() &&
508517
(BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
509518
|| BluetoothUuid.isAdvAudioDist(uuid)) &&
510519
!isOtherSinkInNonDisconnectingState(address)) {
511-
BluetoothDevice device = mAdapter.getRemoteDevice(address);
512520
authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
513521
if (authorized) {
514-
Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
522+
Log.i(TAG, "First check pass for incoming A2DP / AVRCP connection from " + address);
515523
// Some headsets try to connect AVCTP before AVDTP - against the recommendation
516524
// If AVCTP connection fails, we get stuck in IncomingA2DP state in the state
517525
// machine. We don't handle AVCTP signals currently. We only send
518526
// intents for AVDTP state changes. We need to handle both of them in
519527
// some cases. For now, just don't move to incoming state in this case.
520528
if (!BluetoothUuid.isAvrcpTarget(uuid)) {
521529
mBluetoothService.notifyIncomingA2dpConnection(address);
530+
} else {
531+
a2dp.allowIncomingConnect(device, authorized);
522532
}
523533
} else {
524534
Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
@@ -527,7 +537,7 @@ private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
527537
Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
528538
}
529539
log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
530-
return authorized;
540+
if (!authorized) a2dp.allowIncomingConnect(device, authorized);
531541
}
532542

533543
private boolean onAgentOutOfBandDataAvailable(String objectPath) {

core/java/android/server/BluetoothService.java

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import android.bluetooth.BluetoothAdapter;
2828
import android.bluetooth.BluetoothClass;
2929
import android.bluetooth.BluetoothDevice;
30-
import android.bluetooth.BluetoothHeadset;
3130
import android.bluetooth.BluetoothDeviceProfileState;
31+
import android.bluetooth.BluetoothHeadset;
3232
import android.bluetooth.BluetoothProfileState;
3333
import android.bluetooth.BluetoothSocket;
3434
import android.bluetooth.BluetoothUuid;
@@ -67,6 +67,7 @@
6767
import java.io.IOException;
6868
import java.io.InputStreamReader;
6969
import java.io.PrintWriter;
70+
import java.io.RandomAccessFile;
7071
import java.io.UnsupportedEncodingException;
7172
import java.util.ArrayList;
7273
import java.util.Arrays;
@@ -143,6 +144,11 @@ public class BluetoothService extends IBluetooth.Stub {
143144
private static String mDockAddress;
144145
private String mDockPin;
145146

147+
private static final String INCOMING_CONNECTION_FILE =
148+
"/data/misc/bluetooth/incoming_connection.conf";
149+
private HashMap<String, Pair<Integer, String>> mIncomingConnections;
150+
151+
146152
private static class RemoteService {
147153
public String address;
148154
public ParcelUuid uuid;
@@ -210,6 +216,7 @@ public BluetoothService(Context context) {
210216

211217
filter.addAction(Intent.ACTION_DOCK_EVENT);
212218
mContext.registerReceiver(mReceiver, filter);
219+
mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
213220
}
214221

215222
public static synchronized String readDockBluetoothAddress() {
@@ -743,8 +750,6 @@ public synchronized void setBondState(String address, int state, int reason) {
743750

744751
if (state == BluetoothDevice.BOND_BONDED) {
745752
addProfileState(address);
746-
} else if (state == BluetoothDevice.BOND_NONE) {
747-
removeProfileState(address);
748753
}
749754

750755
if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
@@ -1326,6 +1331,8 @@ public synchronized boolean removeBond(String address) {
13261331
}
13271332

13281333
public synchronized boolean removeBondInternal(String address) {
1334+
// Unset the trusted device state and then unpair
1335+
setTrust(address, false);
13291336
return removeDeviceNative(getObjectPathFromAddress(address));
13301337
}
13311338

@@ -2175,10 +2182,6 @@ private BluetoothDeviceProfileState addProfileState(String address) {
21752182
return state;
21762183
}
21772184

2178-
private void removeProfileState(String address) {
2179-
mDeviceProfileState.remove(address);
2180-
}
2181-
21822185
private void initProfileState() {
21832186
String []bonds = null;
21842187
String val = getPropertyInternal("Devices");
@@ -2227,6 +2230,11 @@ public boolean notifyIncomingConnection(String address) {
22272230
mA2dpService = a2dpService;
22282231
}
22292232

2233+
/*package*/ Integer getAuthorizationAgentRequestData(String address) {
2234+
Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address);
2235+
return data;
2236+
}
2237+
22302238
public void sendProfileStateMessage(int profile, int cmd) {
22312239
Message msg = new Message();
22322240
msg.what = cmd;
@@ -2237,6 +2245,116 @@ public void sendProfileStateMessage(int profile, int cmd) {
22372245
}
22382246
}
22392247

2248+
private void createIncomingConnectionStateFile() {
2249+
File f = new File(INCOMING_CONNECTION_FILE);
2250+
if (!f.exists()) {
2251+
try {
2252+
f.createNewFile();
2253+
} catch (IOException e) {
2254+
Log.e(TAG, "IOException: cannot create file");
2255+
}
2256+
}
2257+
}
2258+
2259+
/** @hide */
2260+
public Pair<Integer, String> getIncomingState(String address) {
2261+
if (mIncomingConnections.isEmpty()) {
2262+
createIncomingConnectionStateFile();
2263+
readIncomingConnectionState();
2264+
}
2265+
return mIncomingConnections.get(address);
2266+
}
2267+
2268+
private void readIncomingConnectionState() {
2269+
synchronized(mIncomingConnections) {
2270+
FileInputStream fstream = null;
2271+
try {
2272+
fstream = new FileInputStream(INCOMING_CONNECTION_FILE);
2273+
DataInputStream in = new DataInputStream(fstream);
2274+
BufferedReader file = new BufferedReader(new InputStreamReader(in));
2275+
String line;
2276+
while((line = file.readLine()) != null) {
2277+
line = line.trim();
2278+
if (line.length() == 0) continue;
2279+
String[] value = line.split(",");
2280+
if (value != null && value.length == 3) {
2281+
Integer val1 = Integer.parseInt(value[1]);
2282+
Pair<Integer, String> val = new Pair(val1, value[2]);
2283+
mIncomingConnections.put(value[0], val);
2284+
}
2285+
}
2286+
} catch (FileNotFoundException e) {
2287+
log("FileNotFoundException: readIncomingConnectionState" + e.toString());
2288+
} catch (IOException e) {
2289+
log("IOException: readIncomingConnectionState" + e.toString());
2290+
} finally {
2291+
if (fstream != null) {
2292+
try {
2293+
fstream.close();
2294+
} catch (IOException e) {
2295+
// Ignore
2296+
}
2297+
}
2298+
}
2299+
}
2300+
}
2301+
2302+
private void truncateIncomingConnectionFile() {
2303+
RandomAccessFile r = null;
2304+
try {
2305+
r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw");
2306+
r.setLength(0);
2307+
} catch (FileNotFoundException e) {
2308+
log("FileNotFoundException: truncateIncomingConnectionState" + e.toString());
2309+
} catch (IOException e) {
2310+
log("IOException: truncateIncomingConnectionState" + e.toString());
2311+
} finally {
2312+
if (r != null) {
2313+
try {
2314+
r.close();
2315+
} catch (IOException e) {
2316+
// ignore
2317+
}
2318+
}
2319+
}
2320+
}
2321+
2322+
/** @hide */
2323+
public void writeIncomingConnectionState(String address, Pair<Integer, String> data) {
2324+
synchronized(mIncomingConnections) {
2325+
mIncomingConnections.put(address, data);
2326+
2327+
truncateIncomingConnectionFile();
2328+
BufferedWriter out = null;
2329+
StringBuilder value = new StringBuilder();
2330+
try {
2331+
out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true));
2332+
for (String devAddress: mIncomingConnections.keySet()) {
2333+
Pair<Integer, String> val = mIncomingConnections.get(devAddress);
2334+
value.append(devAddress);
2335+
value.append(",");
2336+
value.append(val.first.toString());
2337+
value.append(",");
2338+
value.append(val.second);
2339+
value.append("\n");
2340+
}
2341+
out.write(value.toString());
2342+
} catch (FileNotFoundException e) {
2343+
log("FileNotFoundException: writeIncomingConnectionState" + e.toString());
2344+
} catch (IOException e) {
2345+
log("IOException: writeIncomingConnectionState" + e.toString());
2346+
} finally {
2347+
if (out != null) {
2348+
try {
2349+
out.close();
2350+
} catch (IOException e) {
2351+
// Ignore
2352+
}
2353+
}
2354+
}
2355+
}
2356+
}
2357+
22402358
private static void log(String msg) {
22412359
Log.d(TAG, msg);
22422360
}
@@ -2287,4 +2405,5 @@ private native int addRfcommServiceRecordNative(String name, long uuidMsb, long
22872405
short channel);
22882406
private native boolean removeServiceRecordNative(int handle);
22892407
private native boolean setLinkTimeoutNative(String path, int num_slots);
2408+
native boolean setAuthorizationNative(String address, boolean value, int data);
22902409
}

0 commit comments

Comments
 (0)