diff options
Diffstat (limited to 'core/java/android/bluetooth/BluetoothDun.java')
-rw-r--r-- | core/java/android/bluetooth/BluetoothDun.java | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/core/java/android/bluetooth/BluetoothDun.java b/core/java/android/bluetooth/BluetoothDun.java new file mode 100644 index 0000000..0912061 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothDun.java @@ -0,0 +1,296 @@ +/* +*Copyright (c) 2013, The Linux Foundation. All rights reserved. +* +*Redistribution and use in source and binary forms, with or without +*modification, are permitted provided that the following conditions are +*met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +package android.bluetooth; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides the APIs to control the Bluetooth Dun + * Profile. + * + *<p>BluetoothDun is a proxy object for controlling the Bluetooth DUN + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothDun proxy object. + * + *<p>Each method is protected with its appropriate permission. + *@hide + */ +public final class BluetoothDun implements BluetoothProfile { + private static final String TAG = "BluetoothDun"; + private static final boolean DBG = false; + private static final boolean VDBG = false; + + /** + * Intent used to broadcast the change in connection state of the Dun + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTED}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CONNECTION_STATE_CHANGED = + "codeaurora.bluetooth.dun.profile.action.CONNECTION_STATE_CHANGED"; + + private Context mContext; + private ServiceListener mServiceListener; + private BluetoothAdapter mAdapter; + private IBluetoothDun mDunService; + + /** + * Create a BluetoothDun proxy object for interacting with the local + * Bluetooth Service which handles the Dun profile + * + */ + /*package*/ BluetoothDun(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + try { + mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback); + } catch (RemoteException re) { + Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re); + } + Log.d(TAG, "BluetoothDun() call bindService"); + doBind(); + } + + boolean doBind() { + Intent intent = new Intent(IBluetoothDun.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth Dun Service with " + intent); + return false; + } + return true; + } + + + /*package*/ void close() { + if (VDBG) log("close()"); + mServiceListener = null; + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mStateChangeCallback); + } catch (RemoteException re) { + Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re); + } + } + + synchronized (mConnection) { + if ( mDunService != null) { + try { + mDunService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + + protected void finalize() { + close(); + } + + private IBluetoothStateChangeCallback mStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + + @Override + public void onBluetoothStateChange(boolean on) { + //Handle enable request to bind again. + Log.d(TAG, "onBluetoothStateChange on: " + on); + if (on) { + try { + if (mDunService == null) { + Log.d(TAG, "onBluetoothStateChange call bindService"); + doBind(); + } + } catch (IllegalStateException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e); + } catch (SecurityException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e); + } + } else { + if (VDBG) Log.d(TAG,"Unbinding service..."); + synchronized (mConnection) { + if ( mDunService != null) { + try { + mDunService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + } + }; + + /** + * Initiate disconnection from DUN server. + * + * <p> Once the disconnection is initiated by any device either local host + * or remote device, the state will transition from {@link #STATE_CONNECTED} + * to {@link #STATE_DISCONNECTED}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, + * true otherwise + * @hide + */ + public boolean disconnect(BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + if (mDunService != null && isEnabled() && + isValidDevice(device)) { + try { + return mDunService.disconnect(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mDunService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + if (mDunService != null && isEnabled()) { + try { + return mDunService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mDunService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + if (mDunService != null && isEnabled()) { + try { + return mDunService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mDunService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + if (mDunService != null && isEnabled() + && isValidDevice(device)) { + try { + return mDunService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mDunService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "BluetoothDUN Proxy object connected"); + mDunService = IBluetoothDun.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.DUN, + BluetoothDun.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "BluetoothDUN Proxy object disconnected"); + mDunService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.DUN); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} |