Loading android/app/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.pbapclient; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Process; import android.util.Log; import java.io.IOException; import javax.obex.ClientSession; import javax.obex.HeaderSet; import javax.obex.ResponseCodes; /* Bluetooth/pbapclient/PbapClientConnectionHandler is responsible * for connecting, disconnecting and downloading contacts from the * PBAP PSE when commanded. It receives all direction from the * controlling state machine. */ class PbapClientConnectionHandler extends Handler { static final String TAG = "PBAP PCE handler"; static final boolean DBG = true; static final int MSG_CONNECT = 1; static final int MSG_DISCONNECT = 2; static final int MSG_DOWNLOAD = 3; private static final byte[] PBAP_TARGET = new byte[] { 0x79, 0x61, 0x35, (byte) 0xf0, (byte) 0xf0, (byte) 0xc5, 0x11, (byte) 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 }; public static final String PB_PATH = "telecom/pb.vcf"; public static final String MCH_PATH = "telecom/mch.vcf"; public static final byte VCARD_TYPE_21 = 0; private BluetoothSocket mSocket; private final BluetoothAdapter mAdapter; private final BluetoothDevice mDevice; private ClientSession mObexSession; private BluetoothPbapObexAuthenticator mAuth = null; private final PbapClientStateMachine mPbapClientStateMachine; PbapClientConnectionHandler(Looper looper, PbapClientStateMachine stateMachine, BluetoothDevice device) { super(looper); mAdapter = BluetoothAdapter.getDefaultAdapter(); mDevice = device; mPbapClientStateMachine = stateMachine; mAuth = new BluetoothPbapObexAuthenticator(this); } @Override public void handleMessage(Message msg) { if (DBG) Log.d(TAG,"Handling Message = " +msg.what); switch(msg.what) { case MSG_CONNECT: boolean connectionSuccessful = false; try { /* To establish a connection first open a socket, establish a OBEX Transport * abstraction, establish a Bluetooth Authenticator, and finally attempt to * connect via an OBEX session */ mSocket = mDevice.createRfcommSocketToServiceRecord( BluetoothUuid.PBAP_PSE.getUuid()); mSocket.connect(); BluetoothPbapObexTransport transport; transport = new BluetoothPbapObexTransport(mSocket); mObexSession = new ClientSession(transport); mObexSession.setAuthenticator(mAuth); HeaderSet connectionRequest = new HeaderSet(); connectionRequest.setHeader(HeaderSet.TARGET, PBAP_TARGET); HeaderSet connectionResponse = mObexSession.connect(connectionRequest); connectionSuccessful = (connectionResponse.getResponseCode() == ResponseCodes.OBEX_HTTP_OK); if (DBG) Log.d(TAG,"Success = " + Boolean.toString(connectionSuccessful)); } catch (IOException e) { Log.w(TAG,"CONNECT Failure " + e.toString()); closeSocket(); } if (connectionSuccessful) { mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_COMPLETE).sendToTarget(); } else { mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_FAILED).sendToTarget(); } break; case MSG_DISCONNECT: try { if (mObexSession != null) { mObexSession.disconnect(null); } } catch (IOException e) { Log.w(TAG,"DISCONNECT Failure " + e.toString()); } mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_CLOSED).sendToTarget(); break; case MSG_DOWNLOAD: try { BluetoothPbapRequestPullPhoneBook request = new BluetoothPbapRequestPullPhoneBook(PB_PATH, null, 0, VCARD_TYPE_21, 0, 0); request.execute(mObexSession); if (DBG) Log.d(TAG,"Download success? " + request.isSuccess()); } catch (IOException e) { Log.w(TAG,"DOWNLOAD_CONTACTS Failure" + e.toString()); } break; default: Log.w(TAG,"Received Unexpected Message"); } return; } public void abort() { closeSocket(); } private void closeSocket() { try { if (mSocket != null) { mSocket.close(); mSocket = null; } } catch (IOException e) { Log.e(TAG, "Error when closing socket", e); } } } android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java +34 −53 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.Utils; import com.android.vcard.VCardEntry; import java.lang.IllegalArgumentException; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.ArrayList; Loading @@ -56,9 +56,7 @@ import java.util.HashMap; public class PbapClientService extends ProfileService { private static final boolean DBG = false; private static final String TAG = "PbapClientService"; private PbapPCEClient mClient; private HandlerThread mHandlerThread; private AccountManager mAccountManager; private PbapClientStateMachine mPbapClientStateMachine; private static PbapClientService sPbapClientService; private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver(); Loading @@ -68,43 +66,39 @@ public class PbapClientService extends ProfileService { } @Override public synchronized IProfileServiceBinder initBinder() { public IProfileServiceBinder initBinder() { return new BluetoothPbapClientBinder(this); } @Override protected synchronized boolean start() { protected boolean start() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); try { registerReceiver(mPbapBroadcastReceiver, filter); } catch (Exception e) { Log.w(TAG,"Unable to register pbapclient receiver",e); } mClient = new PbapPCEClient(this); mAccountManager = AccountManager.get(this); mPbapClientStateMachine = new PbapClientStateMachine(this); setPbapClientService(this); mClient.start(); mPbapClientStateMachine.start(); return true; } @Override protected synchronized boolean stop() { protected boolean stop() { try { unregisterReceiver(mPbapBroadcastReceiver); } catch (Exception e) { Log.w(TAG,"Unable to unregister sap receiver",e); } if (mClient != null) { mClient.disconnect(null); Log.w(TAG,"Unable to unregister pbapclient receiver",e); } mPbapClientStateMachine.disconnect(null); return true; } @Override protected synchronized boolean cleanup() { sPbapClientService = null; protected boolean cleanup() { clearPbapClientService(); return true; } Loading @@ -113,12 +107,7 @@ public class PbapClientService extends ProfileService { public void onReceive(Context context, Intent intent) { Log.v(TAG, "onReceive"); String action = intent.getAction(); if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if(getPriority(device) >= BluetoothProfile.PRIORITY_ON) { connect(device); } } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); disconnect(device); } Loading Loading @@ -252,30 +241,35 @@ public class PbapClientService extends ProfileService { } } private static synchronized void clearPbapClientService() { sPbapClientService = null; } public boolean connect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Log.d(TAG,"Received request to ConnectPBAPPhonebook " + device.getAddress()); int connectionState = mClient.getConnectionState(); int connectionState = mPbapClientStateMachine.getConnectionState(); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { Log.w(TAG,"Received connect request while already connecting/connected."); return false; } if (getPriority(device) > BluetoothProfile.PRIORITY_OFF) { mClient.connect(device); mPbapClientStateMachine.connect(device); return true; } return false; } private boolean disconnect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mClient.disconnect(device); boolean disconnect(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mPbapClientStateMachine.disconnect(device); return true; } private List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int[] desiredStates = {BluetoothProfile.STATE_CONNECTED}; return getDevicesMatchingConnectionStates(desiredStates); Loading @@ -283,31 +277,18 @@ public class PbapClientService extends ProfileService { private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int clientState = mClient.getConnectionState(); Log.d(TAG,"getDevicesMatchingConnectionStates " + Arrays.toString(states) + " == " + clientState); List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); for (int state : states) { if (clientState == state) { BluetoothDevice currentDevice = mClient.getDevice(); if (currentDevice != null) { deviceList.add(currentDevice); } } } return deviceList; return mPbapClientStateMachine.getDevicesMatchingConnectionStates(states); } int getConnectionState(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (device == mClient.getDevice()) { return mClient.getConnectionState(); } return BluetoothProfile.STATE_DISCONNECTED; return mPbapClientStateMachine.getConnectionState(device); } public boolean setPriority(BluetoothDevice device, int priority) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); Settings.Global.putInt(getContentResolver(), Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()), priority); Loading @@ -318,8 +299,8 @@ public class PbapClientService extends ProfileService { } public int getPriority(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); int priority = Settings.Global.getInt(getContentResolver(), Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()), BluetoothProfile.PRIORITY_UNDEFINED); Loading android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java 0 → 100644 +373 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
android/app/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.pbapclient; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Process; import android.util.Log; import java.io.IOException; import javax.obex.ClientSession; import javax.obex.HeaderSet; import javax.obex.ResponseCodes; /* Bluetooth/pbapclient/PbapClientConnectionHandler is responsible * for connecting, disconnecting and downloading contacts from the * PBAP PSE when commanded. It receives all direction from the * controlling state machine. */ class PbapClientConnectionHandler extends Handler { static final String TAG = "PBAP PCE handler"; static final boolean DBG = true; static final int MSG_CONNECT = 1; static final int MSG_DISCONNECT = 2; static final int MSG_DOWNLOAD = 3; private static final byte[] PBAP_TARGET = new byte[] { 0x79, 0x61, 0x35, (byte) 0xf0, (byte) 0xf0, (byte) 0xc5, 0x11, (byte) 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 }; public static final String PB_PATH = "telecom/pb.vcf"; public static final String MCH_PATH = "telecom/mch.vcf"; public static final byte VCARD_TYPE_21 = 0; private BluetoothSocket mSocket; private final BluetoothAdapter mAdapter; private final BluetoothDevice mDevice; private ClientSession mObexSession; private BluetoothPbapObexAuthenticator mAuth = null; private final PbapClientStateMachine mPbapClientStateMachine; PbapClientConnectionHandler(Looper looper, PbapClientStateMachine stateMachine, BluetoothDevice device) { super(looper); mAdapter = BluetoothAdapter.getDefaultAdapter(); mDevice = device; mPbapClientStateMachine = stateMachine; mAuth = new BluetoothPbapObexAuthenticator(this); } @Override public void handleMessage(Message msg) { if (DBG) Log.d(TAG,"Handling Message = " +msg.what); switch(msg.what) { case MSG_CONNECT: boolean connectionSuccessful = false; try { /* To establish a connection first open a socket, establish a OBEX Transport * abstraction, establish a Bluetooth Authenticator, and finally attempt to * connect via an OBEX session */ mSocket = mDevice.createRfcommSocketToServiceRecord( BluetoothUuid.PBAP_PSE.getUuid()); mSocket.connect(); BluetoothPbapObexTransport transport; transport = new BluetoothPbapObexTransport(mSocket); mObexSession = new ClientSession(transport); mObexSession.setAuthenticator(mAuth); HeaderSet connectionRequest = new HeaderSet(); connectionRequest.setHeader(HeaderSet.TARGET, PBAP_TARGET); HeaderSet connectionResponse = mObexSession.connect(connectionRequest); connectionSuccessful = (connectionResponse.getResponseCode() == ResponseCodes.OBEX_HTTP_OK); if (DBG) Log.d(TAG,"Success = " + Boolean.toString(connectionSuccessful)); } catch (IOException e) { Log.w(TAG,"CONNECT Failure " + e.toString()); closeSocket(); } if (connectionSuccessful) { mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_COMPLETE).sendToTarget(); } else { mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_FAILED).sendToTarget(); } break; case MSG_DISCONNECT: try { if (mObexSession != null) { mObexSession.disconnect(null); } } catch (IOException e) { Log.w(TAG,"DISCONNECT Failure " + e.toString()); } mPbapClientStateMachine.obtainMessage( PbapClientStateMachine.MSG_CONNECTION_CLOSED).sendToTarget(); break; case MSG_DOWNLOAD: try { BluetoothPbapRequestPullPhoneBook request = new BluetoothPbapRequestPullPhoneBook(PB_PATH, null, 0, VCARD_TYPE_21, 0, 0); request.execute(mObexSession); if (DBG) Log.d(TAG,"Download success? " + request.isSuccess()); } catch (IOException e) { Log.w(TAG,"DOWNLOAD_CONTACTS Failure" + e.toString()); } break; default: Log.w(TAG,"Received Unexpected Message"); } return; } public void abort() { closeSocket(); } private void closeSocket() { try { if (mSocket != null) { mSocket.close(); mSocket = null; } } catch (IOException e) { Log.e(TAG, "Error when closing socket", e); } } }
android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java +34 −53 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.Utils; import com.android.vcard.VCardEntry; import java.lang.IllegalArgumentException; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.ArrayList; Loading @@ -56,9 +56,7 @@ import java.util.HashMap; public class PbapClientService extends ProfileService { private static final boolean DBG = false; private static final String TAG = "PbapClientService"; private PbapPCEClient mClient; private HandlerThread mHandlerThread; private AccountManager mAccountManager; private PbapClientStateMachine mPbapClientStateMachine; private static PbapClientService sPbapClientService; private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver(); Loading @@ -68,43 +66,39 @@ public class PbapClientService extends ProfileService { } @Override public synchronized IProfileServiceBinder initBinder() { public IProfileServiceBinder initBinder() { return new BluetoothPbapClientBinder(this); } @Override protected synchronized boolean start() { protected boolean start() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); try { registerReceiver(mPbapBroadcastReceiver, filter); } catch (Exception e) { Log.w(TAG,"Unable to register pbapclient receiver",e); } mClient = new PbapPCEClient(this); mAccountManager = AccountManager.get(this); mPbapClientStateMachine = new PbapClientStateMachine(this); setPbapClientService(this); mClient.start(); mPbapClientStateMachine.start(); return true; } @Override protected synchronized boolean stop() { protected boolean stop() { try { unregisterReceiver(mPbapBroadcastReceiver); } catch (Exception e) { Log.w(TAG,"Unable to unregister sap receiver",e); } if (mClient != null) { mClient.disconnect(null); Log.w(TAG,"Unable to unregister pbapclient receiver",e); } mPbapClientStateMachine.disconnect(null); return true; } @Override protected synchronized boolean cleanup() { sPbapClientService = null; protected boolean cleanup() { clearPbapClientService(); return true; } Loading @@ -113,12 +107,7 @@ public class PbapClientService extends ProfileService { public void onReceive(Context context, Intent intent) { Log.v(TAG, "onReceive"); String action = intent.getAction(); if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if(getPriority(device) >= BluetoothProfile.PRIORITY_ON) { connect(device); } } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); disconnect(device); } Loading Loading @@ -252,30 +241,35 @@ public class PbapClientService extends ProfileService { } } private static synchronized void clearPbapClientService() { sPbapClientService = null; } public boolean connect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Log.d(TAG,"Received request to ConnectPBAPPhonebook " + device.getAddress()); int connectionState = mClient.getConnectionState(); int connectionState = mPbapClientStateMachine.getConnectionState(); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { Log.w(TAG,"Received connect request while already connecting/connected."); return false; } if (getPriority(device) > BluetoothProfile.PRIORITY_OFF) { mClient.connect(device); mPbapClientStateMachine.connect(device); return true; } return false; } private boolean disconnect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mClient.disconnect(device); boolean disconnect(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); mPbapClientStateMachine.disconnect(device); return true; } private List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int[] desiredStates = {BluetoothProfile.STATE_CONNECTED}; return getDevicesMatchingConnectionStates(desiredStates); Loading @@ -283,31 +277,18 @@ public class PbapClientService extends ProfileService { private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int clientState = mClient.getConnectionState(); Log.d(TAG,"getDevicesMatchingConnectionStates " + Arrays.toString(states) + " == " + clientState); List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); for (int state : states) { if (clientState == state) { BluetoothDevice currentDevice = mClient.getDevice(); if (currentDevice != null) { deviceList.add(currentDevice); } } } return deviceList; return mPbapClientStateMachine.getDevicesMatchingConnectionStates(states); } int getConnectionState(BluetoothDevice device) { if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (device == mClient.getDevice()) { return mClient.getConnectionState(); } return BluetoothProfile.STATE_DISCONNECTED; return mPbapClientStateMachine.getConnectionState(device); } public boolean setPriority(BluetoothDevice device, int priority) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); Settings.Global.putInt(getContentResolver(), Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()), priority); Loading @@ -318,8 +299,8 @@ public class PbapClientService extends ProfileService { } public int getPriority(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (device == null) throw new IllegalArgumentException("Null device"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); int priority = Settings.Global.getInt(getContentResolver(), Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()), BluetoothProfile.PRIORITY_UNDEFINED); Loading
android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java 0 → 100644 +373 −0 File added.Preview size limit exceeded, changes collapsed. Show changes