| /* |
| * Copyright (C) 2013 Samsung System LSI |
| * 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.map; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.obex.ServerSession; |
| import android.app.Notification; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.app.Service; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.BluetoothDevice; |
| import android.bluetooth.BluetoothProfile; |
| import android.bluetooth.BluetoothServerSocket; |
| import android.bluetooth.IBluetooth; |
| import android.bluetooth.IBluetoothMap; |
| import android.bluetooth.BluetoothUuid; |
| import android.bluetooth.BluetoothMap; |
| import android.bluetooth.BluetoothSocket; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Message; |
| import android.os.PowerManager; |
| import android.os.ParcelUuid; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.provider.Settings; |
| import android.content.IntentFilter; |
| import android.content.BroadcastReceiver; |
| |
| import com.android.bluetooth.R; |
| import com.android.bluetooth.Utils; |
| import com.android.bluetooth.btservice.AdapterService; |
| import com.android.bluetooth.btservice.ProfileService; |
| import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; |
| |
| |
| public class BluetoothMapService extends ProfileService { |
| private static final String TAG = "BluetoothMapService"; |
| |
| /** |
| * To enable MAP DEBUG/VERBOSE logging - run below cmd in adb shell, and |
| * restart com.android.bluetooth process. only enable DEBUG log: |
| * "setprop log.tag.BluetoothMapService DEBUG"; enable both VERBOSE and |
| * DEBUG log: "setprop log.tag.BluetoothMapService VERBOSE" |
| */ |
| |
| public static final boolean DEBUG = true; |
| |
| public static final boolean VERBOSE = false; |
| |
| /** |
| * Intent indicating incoming obex authentication request which is from |
| * PCE(Carkit) |
| */ |
| public static final String AUTH_CHALL_ACTION = "com.android.bluetooth.map.authchall"; |
| |
| /** |
| * Intent indicating timeout for user confirmation, which is sent to |
| * BluetoothMapActivity |
| */ |
| public static final String USER_CONFIRM_TIMEOUT_ACTION = |
| "com.android.bluetooth.map.userconfirmtimeout"; |
| |
| /** |
| * Intent Extra name indicating session key which is sent from |
| * BluetoothMapActivity |
| */ |
| public static final String EXTRA_SESSION_KEY = "com.android.bluetooth.map.sessionkey"; |
| |
| public static final String THIS_PACKAGE_NAME = "com.android.bluetooth"; |
| |
| public static final int MSG_SERVERSESSION_CLOSE = 5000; |
| |
| public static final int MSG_SESSION_ESTABLISHED = 5001; |
| |
| public static final int MSG_SESSION_DISCONNECTED = 5002; |
| |
| public static final int MSG_OBEX_AUTH_CHALL = 5003; |
| |
| private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; |
| |
| private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; |
| |
| private static final int START_LISTENER = 1; |
| |
| private static final int USER_TIMEOUT = 2; |
| |
| private static final int DISCONNECT_MAP = 3; |
| |
| private PowerManager.WakeLock mWakeLock = null; |
| |
| private BluetoothAdapter mAdapter; |
| |
| private SocketAcceptThread mAcceptThread = null; |
| |
| private BluetoothMapAuthenticator mAuth = null; |
| |
| private BluetoothMapObexServer mMapServer; |
| |
| private ServerSession mServerSession = null; |
| |
| private BluetoothMnsObexClient mBluetoothMnsObexClient = null; |
| |
| private BluetoothServerSocket mServerSocket = null; |
| |
| private BluetoothSocket mConnSocket = null; |
| |
| private BluetoothDevice mRemoteDevice = null; |
| |
| private static String sRemoteDeviceName = null; |
| |
| private volatile boolean mInterrupted; |
| |
| private int mState; |
| |
| private boolean isWaitingAuthorization = false; |
| |
| // package and class name to which we send intent to check message access access permission |
| private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings"; |
| private static final String ACCESS_AUTHORITY_CLASS = |
| "com.android.settings.bluetooth.BluetoothPermissionRequest"; |
| |
| private static final ParcelUuid[] MAP_UUIDS = { |
| BluetoothUuid.MAP, |
| BluetoothUuid.MNS, |
| }; |
| |
| public BluetoothMapService() { |
| mState = BluetoothMap.STATE_DISCONNECTED; |
| } |
| |
| private void startRfcommSocketListener() { |
| if (DEBUG) Log.d(TAG, "Map Service startRfcommSocketListener"); |
| |
| if (mAcceptThread == null) { |
| mAcceptThread = new SocketAcceptThread(); |
| mAcceptThread.setName("BluetoothMapAcceptThread"); |
| mAcceptThread.start(); |
| } |
| } |
| |
| private final boolean initSocket() { |
| if (DEBUG) Log.d(TAG, "Map Service initSocket"); |
| |
| boolean initSocketOK = false; |
| final int CREATE_RETRY_TIME = 10; |
| |
| // It's possible that create will fail in some cases. retry for 10 times |
| for (int i = 0; (i < CREATE_RETRY_TIME) && !mInterrupted; i++) { |
| initSocketOK = true; |
| try { |
| // It is mandatory for MSE to support initiation of bonding and |
| // encryption. |
| mServerSocket = mAdapter.listenUsingEncryptedRfcommWithServiceRecord |
| ("MAP SMS/MMS", BluetoothUuid.MAS.getUuid()); |
| |
| } catch (IOException e) { |
| Log.e(TAG, "Error create RfcommServerSocket " + e.toString()); |
| initSocketOK = false; |
| } |
| if (!initSocketOK) { |
| // Need to break out of this loop if BT is being turned off. |
| if (mAdapter == null) break; |
| int state = mAdapter.getState(); |
| if ((state != BluetoothAdapter.STATE_TURNING_ON) && |
| (state != BluetoothAdapter.STATE_ON)) { |
| Log.w(TAG, "initServerSocket failed as BT is (being) turned off"); |
| break; |
| } |
| try { |
| if (VERBOSE) Log.v(TAG, "wait 300 ms"); |
| Thread.sleep(300); |
| } catch (InterruptedException e) { |
| Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); |
| } |
| } else { |
| break; |
| } |
| } |
| if (mInterrupted) { |
| initSocketOK = false; |
| // close server socket to avoid resource leakage |
| closeServerSocket(); |
| } |
| |
| if (initSocketOK) { |
| if (VERBOSE) Log.v(TAG, "Succeed to create listening socket "); |
| |
| } else { |
| Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try"); |
| } |
| return initSocketOK; |
| } |
| |
| private final synchronized void closeServerSocket() { |
| // exit SocketAcceptThread early |
| if (mServerSocket != null) { |
| try { |
| // this will cause mServerSocket.accept() return early with IOException |
| mServerSocket.close(); |
| mServerSocket = null; |
| } catch (IOException ex) { |
| Log.e(TAG, "Close Server Socket error: " + ex); |
| } |
| } |
| } |
| private final synchronized void closeConnectionSocket() { |
| if (mConnSocket != null) { |
| try { |
| mConnSocket.close(); |
| mConnSocket = null; |
| } catch (IOException e) { |
| Log.e(TAG, "Close Connection Socket error: " + e.toString()); |
| } |
| } |
| } |
| |
| private final void closeService() { |
| if (DEBUG) Log.d(TAG, "MAP Service closeService in"); |
| |
| // exit initSocket early |
| mInterrupted = true; |
| closeServerSocket(); |
| |
| if (mAcceptThread != null) { |
| try { |
| mAcceptThread.shutdown(); |
| mAcceptThread.join(); |
| mAcceptThread = null; |
| } catch (InterruptedException ex) { |
| Log.w(TAG, "mAcceptThread close error" + ex); |
| } |
| } |
| |
| if (mWakeLock != null) { |
| mWakeLock.release(); |
| mWakeLock = null; |
| } |
| |
| if (mServerSession != null) { |
| mServerSession.close(); |
| mServerSession = null; |
| } |
| |
| if (mBluetoothMnsObexClient != null) { |
| mBluetoothMnsObexClient.disconnect(); |
| mBluetoothMnsObexClient = null; |
| } |
| |
| closeConnectionSocket(); |
| |
| if (mSessionStatusHandler != null) { |
| mSessionStatusHandler.removeCallbacksAndMessages(null); |
| } |
| isWaitingAuthorization = false; |
| |
| if (VERBOSE) Log.v(TAG, "MAP Service closeService out"); |
| } |
| |
| private final void startObexServerSession() throws IOException { |
| if (DEBUG) Log.d(TAG, "Map Service startObexServerSession"); |
| |
| // acquire the wakeLock before start Obex transaction thread |
| if (mWakeLock == null) { |
| PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); |
| mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, |
| "StartingObexMapTransaction"); |
| mWakeLock.setReferenceCounted(false); |
| mWakeLock.acquire(); |
| } |
| |
| mBluetoothMnsObexClient = new BluetoothMnsObexClient(this, mRemoteDevice); |
| mMapServer = new BluetoothMapObexServer(mSessionStatusHandler, this, |
| mBluetoothMnsObexClient); |
| synchronized (this) { |
| // We need to get authentication now that obex server is up |
| mAuth = new BluetoothMapAuthenticator(mSessionStatusHandler); |
| mAuth.setChallenged(false); |
| mAuth.setCancelled(false); |
| } |
| // setup RFCOMM transport |
| BluetoothMapRfcommTransport transport = new BluetoothMapRfcommTransport(mConnSocket); |
| mServerSession = new ServerSession(transport, mMapServer, mAuth); |
| setState(BluetoothMap.STATE_CONNECTED); |
| if (VERBOSE) { |
| Log.v(TAG, "startObexServerSession() success!"); |
| } |
| } |
| |
| private void stopObexServerSession() { |
| if (DEBUG) Log.d(TAG, "MAP Service stopObexServerSession"); |
| |
| // Release the wake lock if obex transaction is over |
| if (mWakeLock != null) { |
| mWakeLock.release(); |
| mWakeLock = null; |
| } |
| |
| if (mServerSession != null) { |
| mServerSession.close(); |
| mServerSession = null; |
| } |
| |
| mAcceptThread = null; |
| |
| if(mBluetoothMnsObexClient != null) { |
| mBluetoothMnsObexClient.disconnect(); |
| mBluetoothMnsObexClient = null; |
| } |
| closeConnectionSocket(); |
| |
| // Last obex transaction is finished, we start to listen for incoming |
| // connection again |
| if (mAdapter.isEnabled()) { |
| startRfcommSocketListener(); |
| } |
| setState(BluetoothMap.STATE_DISCONNECTED); |
| } |
| |
| |
| |
| /** |
| * A thread that runs in the background waiting for remote rfcomm |
| * connect.Once a remote socket connected, this thread shall be |
| * shutdown.When the remote disconnect,this thread shall run again waiting |
| * for next request. |
| */ |
| private class SocketAcceptThread extends Thread { |
| |
| private boolean stopped = false; |
| |
| @Override |
| public void run() { |
| BluetoothServerSocket serverSocket; |
| if (mServerSocket == null) { |
| if (!initSocket()) { |
| return; |
| } |
| } |
| |
| while (!stopped) { |
| try { |
| if (DEBUG) Log.d(TAG, "Accepting socket connection..."); |
| serverSocket = mServerSocket; |
| if(serverSocket == null) { |
| Log.w(TAG, "mServerSocket is null"); |
| break; |
| } |
| mConnSocket = serverSocket.accept(); |
| if (DEBUG) Log.d(TAG, "Accepted socket connection..."); |
| synchronized (BluetoothMapService.this) { |
| if (mConnSocket == null) { |
| Log.w(TAG, "mConnSocket is null"); |
| break; |
| } |
| mRemoteDevice = mConnSocket.getRemoteDevice(); |
| } |
| if (mRemoteDevice == null) { |
| Log.i(TAG, "getRemoteDevice() = null"); |
| break; |
| } |
| |
| sRemoteDeviceName = mRemoteDevice.getName(); |
| // In case getRemoteName failed and return null |
| if (TextUtils.isEmpty(sRemoteDeviceName)) { |
| sRemoteDeviceName = getString(R.string.defaultname); |
| } |
| boolean trust = mRemoteDevice.getTrustState(); |
| if (DEBUG) Log.d(TAG, "GetTrustState() = " + trust); |
| |
| |
| if (trust) { |
| try { |
| if (DEBUG) Log.d(TAG, "incoming connection accepted from: " |
| + sRemoteDeviceName + " automatically as trusted device"); |
| startObexServerSession(); |
| } catch (IOException ex) { |
| Log.e(TAG, "catch exception starting obex server session" |
| + ex.toString()); |
| } |
| } else { |
| Intent intent = new |
| Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST); |
| intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS); |
| intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, |
| BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS); |
| intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); |
| |
| isWaitingAuthorization = true; |
| sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); |
| |
| if (DEBUG) Log.d(TAG, "waiting for authorization for connection from: " |
| + sRemoteDeviceName); |
| |
| } |
| stopped = true; // job done ,close this thread; |
| } catch (IOException ex) { |
| stopped=true; |
| if (VERBOSE) Log.v(TAG, "Accept exception: " + ex.toString()); |
| } |
| } |
| } |
| |
| void shutdown() { |
| stopped = true; |
| interrupt(); |
| } |
| } |
| |
| private final Handler mSessionStatusHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| if (VERBOSE) Log.v(TAG, "Handler(): got msg=" + msg.what); |
| |
| switch (msg.what) { |
| case START_LISTENER: |
| if (mAdapter.isEnabled()) { |
| startRfcommSocketListener(); |
| } |
| break; |
| case USER_TIMEOUT: |
| Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL); |
| intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS); |
| intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, |
| BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS); |
| sendBroadcast(intent); |
| isWaitingAuthorization = false; |
| stopObexServerSession(); |
| break; |
| case MSG_SERVERSESSION_CLOSE: |
| stopObexServerSession(); |
| break; |
| case MSG_SESSION_ESTABLISHED: |
| break; |
| case MSG_SESSION_DISCONNECTED: |
| // handled elsewhere |
| break; |
| case DISCONNECT_MAP: |
| disconnectMap((BluetoothDevice)msg.obj); |
| break; |
| default: |
| break; |
| } |
| } |
| }; |
| |
| |
| public int getState() { |
| return mState; |
| } |
| |
| public BluetoothDevice getRemoteDevice() { |
| return mRemoteDevice; |
| } |
| private void setState(int state) { |
| setState(state, BluetoothMap.RESULT_SUCCESS); |
| } |
| |
| private synchronized void setState(int state, int result) { |
| if (state != mState) { |
| if (DEBUG) Log.d(TAG, "Map state " + mState + " -> " + state + ", result = " |
| + result); |
| int prevState = mState; |
| mState = state; |
| Intent intent = new Intent(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); |
| intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); |
| intent.putExtra(BluetoothProfile.EXTRA_STATE, mState); |
| intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); |
| sendBroadcast(intent, BLUETOOTH_PERM); |
| AdapterService s = AdapterService.getAdapterService(); |
| if (s != null) { |
| s.onProfileConnectionStateChanged(mRemoteDevice, BluetoothProfile.MAP, |
| mState, prevState); |
| } |
| } |
| } |
| |
| public static String getRemoteDeviceName() { |
| return sRemoteDeviceName; |
| } |
| |
| public boolean disconnect(BluetoothDevice device) { |
| mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(DISCONNECT_MAP, 0, 0, device)); |
| return true; |
| } |
| |
| public boolean disconnectMap(BluetoothDevice device) { |
| boolean result = false; |
| if (DEBUG) Log.d(TAG, "disconnectMap"); |
| if (getRemoteDevice().equals(device)) { |
| switch (mState) { |
| case BluetoothMap.STATE_CONNECTED: |
| if (mServerSession != null) { |
| mServerSession.close(); |
| mServerSession = null; |
| } |
| if(mBluetoothMnsObexClient != null) { |
| mBluetoothMnsObexClient.disconnect(); //FIXME should use shutdown when implemented |
| mBluetoothMnsObexClient = null; |
| } |
| closeConnectionSocket(); |
| |
| setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED); |
| result = true; |
| break; |
| default: |
| break; |
| } |
| } |
| return result; |
| } |
| |
| public List<BluetoothDevice> getConnectedDevices() { |
| List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); |
| synchronized(this) { |
| if (mState == BluetoothMap.STATE_CONNECTED && mRemoteDevice != null) { |
| devices.add(mRemoteDevice); |
| } |
| } |
| return devices; |
| } |
| |
| public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { |
| List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); |
| Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); |
| int connectionState; |
| synchronized (this) { |
| for (BluetoothDevice device : bondedDevices) { |
| ParcelUuid[] featureUuids = device.getUuids(); |
| if (!BluetoothUuid.containsAnyUuid(featureUuids, MAP_UUIDS)) { |
| continue; |
| } |
| connectionState = getConnectionState(device); |
| for(int i = 0; i < states.length; i++) { |
| if (connectionState == states[i]) { |
| deviceList.add(device); |
| } |
| } |
| } |
| } |
| return deviceList; |
| } |
| |
| public int getConnectionState(BluetoothDevice device) { |
| synchronized(this) { |
| if (getState() == BluetoothMap.STATE_CONNECTED && getRemoteDevice().equals(device)) { |
| return BluetoothProfile.STATE_CONNECTED; |
| } else { |
| return BluetoothProfile.STATE_DISCONNECTED; |
| } |
| } |
| } |
| |
| public boolean setPriority(BluetoothDevice device, int priority) { |
| Settings.Global.putInt(getContentResolver(), |
| Settings.Global.getBluetoothMapPriorityKey(device.getAddress()), |
| priority); |
| if (DEBUG) Log.d(TAG, "Saved priority " + device + " = " + priority); |
| return true; |
| } |
| |
| public int getPriority(BluetoothDevice device) { |
| int priority = Settings.Global.getInt(getContentResolver(), |
| Settings.Global.getBluetoothMapPriorityKey(device.getAddress()), |
| BluetoothProfile.PRIORITY_UNDEFINED); |
| return priority; |
| } |
| |
| @Override |
| protected IProfileServiceBinder initBinder() { |
| return new BluetoothMapBinder(this); |
| } |
| |
| @Override |
| protected boolean start() { |
| if (DEBUG) Log.d(TAG, "start()"); |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); |
| filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); |
| try { |
| registerReceiver(mMapReceiver, filter); |
| } catch (Exception e) { |
| Log.w(TAG,"Unable to register map receiver",e); |
| } |
| mInterrupted = false; |
| mAdapter = BluetoothAdapter.getDefaultAdapter(); |
| // start RFCOMM listener |
| mSessionStatusHandler.sendMessage(mSessionStatusHandler |
| .obtainMessage(START_LISTENER)); |
| return true; |
| } |
| |
| @Override |
| protected boolean stop() { |
| if (DEBUG) Log.d(TAG, "stop()"); |
| try { |
| unregisterReceiver(mMapReceiver); |
| } catch (Exception e) { |
| Log.w(TAG,"Unable to unregister map receiver",e); |
| } |
| |
| setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED); |
| closeService(); |
| return true; |
| } |
| |
| public boolean cleanup() { |
| if (DEBUG) Log.d(TAG, "cleanup()"); |
| setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED); |
| closeService(); |
| return true; |
| } |
| |
| private MapBroadcastReceiver mMapReceiver = new MapBroadcastReceiver(); |
| |
| private class MapBroadcastReceiver extends BroadcastReceiver { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (DEBUG) Log.d(TAG, "onReceive"); |
| String action = intent.getAction(); |
| if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { |
| int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, |
| BluetoothAdapter.ERROR); |
| if (state == BluetoothAdapter.STATE_TURNING_OFF) { |
| if (DEBUG) Log.d(TAG, "STATE_TURNING_OFF"); |
| // Release all resources |
| closeService(); |
| } else if (state == BluetoothAdapter.STATE_ON) { |
| if (DEBUG) Log.d(TAG, "STATE_ON"); |
| mInterrupted = false; |
| // start RFCOMM listener |
| mSessionStatusHandler.sendMessage(mSessionStatusHandler |
| .obtainMessage(START_LISTENER)); |
| } |
| } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { |
| int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, |
| BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); |
| if (DEBUG) Log.d(TAG, "Received ACTION_CONNECTION_ACCESS_REPLY:" + |
| requestType + ":" + isWaitingAuthorization); |
| if ((!isWaitingAuthorization) || |
| (requestType != BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS)) { |
| // this reply is not for us |
| return; |
| } |
| |
| isWaitingAuthorization = false; |
| |
| if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, |
| BluetoothDevice.CONNECTION_ACCESS_NO) == |
| BluetoothDevice.CONNECTION_ACCESS_YES) { |
| //bluetooth connection accepted by user |
| if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { |
| boolean result = mRemoteDevice.setTrust(true); |
| if (DEBUG) Log.d(TAG, "setTrust() result=" + result); |
| } |
| try { |
| if (mConnSocket != null) { |
| // start obex server and rfcomm connection |
| startObexServerSession(); |
| } else { |
| stopObexServerSession(); |
| } |
| } catch (IOException ex) { |
| Log.e(TAG, "Caught the error: " + ex.toString()); |
| } |
| } else { |
| stopObexServerSession(); |
| } |
| } |
| } |
| }; |
| |
| //Binder object: Must be static class or memory leak may occur |
| /** |
| * This class implements the IBluetoothMap interface - or actually it validates the |
| * preconditions for calling the actual functionality in the MapService, and calls it. |
| */ |
| private static class BluetoothMapBinder extends IBluetoothMap.Stub |
| implements IProfileServiceBinder { |
| private BluetoothMapService mService; |
| |
| private BluetoothMapService getService() { |
| if (!Utils.checkCaller()) { |
| Log.w(TAG,"MAP call not allowed for non-active user"); |
| return null; |
| } |
| |
| if (mService != null && mService.isAvailable()) { |
| mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); |
| return mService; |
| } |
| return null; |
| } |
| |
| BluetoothMapBinder(BluetoothMapService service) { |
| if (VERBOSE) Log.v(TAG, "BluetoothMapBinder()"); |
| mService = service; |
| } |
| |
| public boolean cleanup() { |
| mService = null; |
| return true; |
| } |
| |
| public int getState() { |
| if (VERBOSE) Log.v(TAG, "getState()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return BluetoothMap.STATE_DISCONNECTED; |
| return getService().getState(); |
| } |
| |
| public BluetoothDevice getClient() { |
| if (VERBOSE) Log.v(TAG, "getClient()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return null; |
| Log.v(TAG, "getClient() - returning " + service.getRemoteDevice()); |
| return service.getRemoteDevice(); |
| } |
| |
| public boolean isConnected(BluetoothDevice device) { |
| if (VERBOSE) Log.v(TAG, "isConnected()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return false; |
| return service.getState() == BluetoothMap.STATE_CONNECTED && service.getRemoteDevice().equals(device); |
| } |
| |
| public boolean connect(BluetoothDevice device) { |
| if (VERBOSE) Log.v(TAG, "connect()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return false; |
| return false; |
| } |
| |
| public boolean disconnect(BluetoothDevice device) { |
| if (VERBOSE) Log.v(TAG, "disconnect()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return false; |
| return service.disconnect(device); |
| } |
| |
| public List<BluetoothDevice> getConnectedDevices() { |
| if (VERBOSE) Log.v(TAG, "getConnectedDevices()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return new ArrayList<BluetoothDevice>(0); |
| return service.getConnectedDevices(); |
| } |
| |
| public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { |
| if (VERBOSE) Log.v(TAG, "getDevicesMatchingConnectionStates()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return new ArrayList<BluetoothDevice>(0); |
| return service.getDevicesMatchingConnectionStates(states); |
| } |
| |
| public int getConnectionState(BluetoothDevice device) { |
| if (VERBOSE) Log.v(TAG, "getConnectionState()"); |
| BluetoothMapService service = getService(); |
| if (service == null) return BluetoothProfile.STATE_DISCONNECTED; |
| return service.getConnectionState(device); |
| } |
| |
| public boolean setPriority(BluetoothDevice device, int priority) { |
| BluetoothMapService service = getService(); |
| if (service == null) return false; |
| return service.setPriority(device, priority); |
| } |
| |
| public int getPriority(BluetoothDevice device) { |
| BluetoothMapService service = getService(); |
| if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; |
| return service.getPriority(device); |
| } |
| }; |
| } |