16fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang/*
26fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * Copyright (C) 2008 The Android Open Source Project
36fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang *
46fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * Licensed under the Apache License, Version 2.0 (the "License");
56fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * you may not use this file except in compliance with the License.
66fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * You may obtain a copy of the License at
76fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang *
86fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang *      http://www.apache.org/licenses/LICENSE-2.0
96fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang *
106fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * Unless required by applicable law or agreed to in writing, software
116fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * distributed under the License is distributed on an "AS IS" BASIS,
126fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * See the License for the specific language governing permissions and
146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang * limitations under the License.
156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang */
166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
176fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changpackage android.bluetooth;
186fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
196fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.annotation.SdkConstant;
206fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.annotation.SdkConstant.SdkConstantType;
210f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.ComponentName;
226fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.content.Context;
230f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.Intent;
240f42037eb7b5118015c2caca635538324ccf0ccffredcimport android.content.ServiceConnection;
250a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkeyimport android.os.Binder;
266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.os.IBinder;
275a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport android.os.RemoteException;
286fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.util.Log;
296fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
305a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.ArrayList;
315a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang/**
3474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh * This class provides the APIs to control the Bluetooth Pan
3574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh * Profile.
3674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh *
3774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh *<p>BluetoothPan is a proxy object for controlling the Bluetooth
3874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
3974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh * the BluetoothPan proxy object.
4074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh *
4174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh *<p>Each method is protected with its appropriate permission.
4274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh *@hide
436fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang */
4474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganeshpublic final class BluetoothPan implements BluetoothProfile {
456fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private static final String TAG = "BluetoothPan";
460f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final boolean DBG = true;
47563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = false;
486fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
4974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
5074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * Intent used to broadcast the change in connection state of the Pan
5174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * profile.
5274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *
5374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * <p>This intent will have 4 extras:
5474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * <ul>
5574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
5674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
5774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
5874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *   <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is
5974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *   bound to. </li>
6074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * </ul>
6174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *
6274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
6374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
6474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
6574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *
6674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
6774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@link #LOCAL_PANU_ROLE}
6874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
6974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * receive.
7074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
7174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
7274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public static final String ACTION_CONNECTION_STATE_CHANGED =
7374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
746fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
7574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
7674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent
7774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * The local role of the PAN profile that the remote device is bound to.
7874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
7974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
805200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
815200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh
820f42037eb7b5118015c2caca635538324ccf0ccffredc    public static final int PAN_ROLE_NONE = 0;
8374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
8474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * The local device is acting as a Network Access Point.
8574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
865200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    public static final int LOCAL_NAP_ROLE = 1;
870f42037eb7b5118015c2caca635538324ccf0ccffredc    public static final int REMOTE_NAP_ROLE = 1;
885200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh
895200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    /**
9074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * The local device is acting as a PAN User.
916fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     */
9274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public static final int LOCAL_PANU_ROLE = 2;
930f42037eb7b5118015c2caca635538324ccf0ccffredc    public static final int REMOTE_PANU_ROLE = 2;
946fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
95fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    /**
96fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh     * Return codes for the connect and disconnect Bluez / Dbus calls.
9774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * @hide
98fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh     */
99fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
100fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh
10174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
10274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * @hide
10374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
104fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
105fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh
10674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
10774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * @hide
10874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
109fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
110fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh
11174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
11274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * @hide
11374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
114fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
115fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh
11674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
11774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * @hide
11874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
119fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh    public static final int PAN_OPERATION_SUCCESS = 1004;
120fbe807d064ada99211b102914df514aa562256f8Jaikumar Ganesh
1210f42037eb7b5118015c2caca635538324ccf0ccffredc    private Context mContext;
12274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private ServiceListener mServiceListener;
12374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private BluetoothAdapter mAdapter;
1240146463d70355592da85c3605aaaef4cf0b7335eJack He    private volatile IBluetoothPan mPanService;
1256fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    /**
1276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     * Create a BluetoothPan proxy object for interacting with the local
12874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * Bluetooth Service which handles the Pan profile
12974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     *
1306fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     */
1310f42037eb7b5118015c2caca635538324ccf0ccffredc    /*package*/ BluetoothPan(Context context, ServiceListener l) {
1320f42037eb7b5118015c2caca635538324ccf0ccffredc        mContext = context;
13374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mServiceListener = l;
13474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
135903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        try {
136903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback);
137903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        } catch (RemoteException re) {
138903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
139903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        }
140221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        if (VDBG) Log.d(TAG, "BluetoothPan() call bindService");
141221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        doBind();
142221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    }
143221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn
144221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    boolean doBind() {
145221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        Intent intent = new Intent(IBluetoothPan.class.getName());
146221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
147221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        intent.setComponent(comp);
148466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
149466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn                android.os.Process.myUserHandle())) {
150221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            Log.e(TAG, "Could not bind to Bluetooth Pan Service with " + intent);
151221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            return false;
1526fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
153221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        return true;
1546fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
1556fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1569bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    /*package*/ void close() {
157563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("close()");
1589b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie
1599b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie        IBluetoothManager mgr = mAdapter.getBluetoothManager();
1609b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie        if (mgr != null) {
1619b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie            try {
1629b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                mgr.unregisterStateChangeCallback(mStateChangeCallback);
1639b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie            } catch (RemoteException re) {
1649b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re);
1659b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie            }
1660f42037eb7b5118015c2caca635538324ccf0ccffredc        }
1679b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie
1689b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie        synchronized (mConnection) {
1699b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie            if (mPanService != null) {
1709b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                try {
1719b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    mPanService = null;
1729b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    mContext.unbindService(mConnection);
1739b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                } catch (Exception re) {
1749b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                    Log.e(TAG,"",re);
1759b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie                }
1769b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie            }
177903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        }
1789b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie        mServiceListener = null;
179903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc    }
180903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc
181903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc    protected void finalize() {
182903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        close();
1839bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    }
1849bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
1859b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    final private IBluetoothStateChangeCallback mStateChangeCallback = new IBluetoothStateChangeCallback.Stub() {
186903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc
187903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        @Override
1881f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure        public void onBluetoothStateChange(boolean on) {
1891f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure            // Handle enable request to bind again.
1901f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure            Log.d(TAG, "onBluetoothStateChange on: " + on);
191903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            if (on) {
1921f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                try {
1931f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                    if (mPanService == null) {
1941f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                        if (VDBG) Log.d(TAG, "onBluetoothStateChange calling doBind()");
1951f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                        doBind();
1961f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                    }
1971f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure
1981f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                } catch (IllegalStateException e) {
1991f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                    Log.e(TAG,"onBluetoothStateChange: could not bind to PAN service: ", e);
2001f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure
2011f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                } catch (SecurityException e) {
2021f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                    Log.e(TAG,"onBluetoothStateChange: could not bind to PAN service: ", e);
2031f8b844870eb9acb334b541b0b41de37e000d2f0Nitin Shivpure                }
204903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            } else {
205563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                if (VDBG) Log.d(TAG,"Unbinding service...");
206903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                synchronized (mConnection) {
207903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                    try {
208903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                        mPanService = null;
209903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                        mContext.unbindService(mConnection);
210903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                    } catch (Exception re) {
211903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                        Log.e(TAG,"",re);
212903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                    }
213903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc                }
214903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc            }
215903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc        }
216903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc    };
217903ac6f399dcd4f574bf388daa7b5f5907d448d3fredc
2186fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    /**
219f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate connection to a profile of the remote bluetooth device.
220f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
221f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API returns false in scenarios like the profile on the
222f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * device is already connected or Bluetooth is not turned on.
223f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * When this API returns true, it is guaranteed that
224f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * connection state intent for the profile will be broadcasted with
225f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * the state. Users can get the connection state of the profile
226f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * from this intent.
227f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
228f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
229f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
230f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
231f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
232f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
233f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
2346fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     * @hide
2356fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     */
2366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public boolean connect(BluetoothDevice device) {
2376fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("connect(" + device + ")");
2380146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
2390146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
24074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            try {
2410146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.connect(device);
24274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } catch (RemoteException e) {
24374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
24474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return false;
2450f42037eb7b5118015c2caca635538324ccf0ccffredc            }
2466fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
2470146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
24874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return false;
2496fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
2506fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
2516fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    /**
252f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Initiate disconnection from a profile
253f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
254f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> This API will return false in scenarios like the profile on the
255f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * Bluetooth device is not in connected state etc. When this API returns,
256f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * true, it is guaranteed that the connection state change
257f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * intent will be broadcasted with the state. Users can get the
258f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * disconnection state of the profile from this intent.
259f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
260f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p> If the disconnection is initiated by a remote device, the state
261f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * will transition from {@link #STATE_CONNECTED} to
262f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
263f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * host (local) device the state will transition from
264f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
265f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * state {@link #STATE_DISCONNECTED}. The transition to
266f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * {@link #STATE_DISCONNECTING} can be used to distinguish between the
267f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * two scenarios.
268f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
269f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
270f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * permission.
271f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *
272f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @param device Remote Bluetooth Device
273f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     * @return false on immediate error,
274f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh     *               true otherwise
2756fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     * @hide
2766fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang     */
2776fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public boolean disconnect(BluetoothDevice device) {
2786fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("disconnect(" + device + ")");
2790146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
2800146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
28174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            try {
2820146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.disconnect(device);
28374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } catch (RemoteException e) {
28474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
28574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return false;
2860f42037eb7b5118015c2caca635538324ccf0ccffredc            }
2876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
2880146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
28974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return false;
2906fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
2916fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
2925200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    /**
29374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@inheritDoc}
2945200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh     */
29574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
296563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getConnectedDevices()");
2970146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
2980146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
29974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            try {
3000146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getConnectedDevices();
30174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } catch (RemoteException e) {
30274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
30374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return new ArrayList<BluetoothDevice>();
3040f42037eb7b5118015c2caca635538324ccf0ccffredc            }
3055200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh        }
3060146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
30774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return new ArrayList<BluetoothDevice>();
3085200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    }
3095200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh
3105200c8ab721b56025340306bdecca651e6bf2f12Jaikumar Ganesh    /**
31174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@inheritDoc}
31274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
31374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
314563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getDevicesMatchingStates()");
3150146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
3160146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
31774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            try {
3180146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getDevicesMatchingConnectionStates(states);
31974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } catch (RemoteException e) {
32074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
32174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return new ArrayList<BluetoothDevice>();
3220f42037eb7b5118015c2caca635538324ccf0ccffredc            }
32374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        }
3240146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
32574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return new ArrayList<BluetoothDevice>();
32674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
32774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
32874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    /**
32974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     * {@inheritDoc}
33074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh     */
33174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
332563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("getState(" + device + ")");
3330146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
3340146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
33574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            try {
3360146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getConnectionState(device);
33774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } catch (RemoteException e) {
33874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
33974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return BluetoothProfile.STATE_DISCONNECTED;
3400f42037eb7b5118015c2caca635538324ccf0ccffredc            }
34174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        }
3420146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
34374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return BluetoothProfile.STATE_DISCONNECTED;
34474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
34574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
346b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh    public void setBluetoothTethering(boolean value) {
34774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (DBG) log("setBluetoothTethering(" + value + ")");
3480146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
3490146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
35058fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            try {
3510146463d70355592da85c3605aaaef4cf0b7335eJack He                service.setBluetoothTethering(value);
35258fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            } catch (RemoteException e) {
35358fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
35458fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            }
3550f42037eb7b5118015c2caca635538324ccf0ccffredc        }
3566fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
3576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
3586fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public boolean isTetheringOn() {
359563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("isTetheringOn()");
3600146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothPan service = mPanService;
3610146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
36258fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            try {
3630146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.isTetheringOn();
36458fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            } catch (RemoteException e) {
36558fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
36658fbffc36f71fbccbf510bfd17797760dc738133Hemant Gupta            }
3670f42037eb7b5118015c2caca635538324ccf0ccffredc        }
368e4caddbb7a3b39fd6a1ccf107c7dbf09bc8978e8Jaikumar Ganesh        return false;
3696fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
37074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
3719b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    private final ServiceConnection mConnection = new ServiceConnection() {
3720f42037eb7b5118015c2caca635538324ccf0ccffredc        public void onServiceConnected(ComponentName className, IBinder service) {
3730f42037eb7b5118015c2caca635538324ccf0ccffredc            if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
3740a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey            mPanService = IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service));
3750f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mServiceListener != null) {
3760f42037eb7b5118015c2caca635538324ccf0ccffredc                mServiceListener.onServiceConnected(BluetoothProfile.PAN,
3770f42037eb7b5118015c2caca635538324ccf0ccffredc                                                    BluetoothPan.this);
3780f42037eb7b5118015c2caca635538324ccf0ccffredc            }
3790f42037eb7b5118015c2caca635538324ccf0ccffredc        }
3800f42037eb7b5118015c2caca635538324ccf0ccffredc        public void onServiceDisconnected(ComponentName className) {
3810f42037eb7b5118015c2caca635538324ccf0ccffredc            if (DBG) Log.d(TAG, "BluetoothPAN Proxy object disconnected");
3820f42037eb7b5118015c2caca635538324ccf0ccffredc            mPanService = null;
3830f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mServiceListener != null) {
3840f42037eb7b5118015c2caca635538324ccf0ccffredc                mServiceListener.onServiceDisconnected(BluetoothProfile.PAN);
3850f42037eb7b5118015c2caca635538324ccf0ccffredc            }
3860f42037eb7b5118015c2caca635538324ccf0ccffredc        }
3870f42037eb7b5118015c2caca635538324ccf0ccffredc    };
3880f42037eb7b5118015c2caca635538324ccf0ccffredc
38974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private boolean isEnabled() {
3900146463d70355592da85c3605aaaef4cf0b7335eJack He        return mAdapter.getState() == BluetoothAdapter.STATE_ON;
39174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
39274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
3930146463d70355592da85c3605aaaef4cf0b7335eJack He    private static boolean isValidDevice(BluetoothDevice device) {
3940146463d70355592da85c3605aaaef4cf0b7335eJack He        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
39574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
39674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
39774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private static void log(String msg) {
39874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh      Log.d(TAG, msg);
39974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
4009bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh}
401