1cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo/*
2cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * Copyright (C) 2016 The Android Open Source Project
3cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo *
4cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * Licensed under the Apache License, Version 2.0 (the "License");
5cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * you may not use this file except in compliance with the License.
6cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * You may obtain a copy of the License at
7cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo *
8cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo *      http://www.apache.org/licenses/LICENSE-2.0
9cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo *
10cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * Unless required by applicable law or agreed to in writing, software
11cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * distributed under the License is distributed on an "AS IS" BASIS,
12cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * See the License for the specific language governing permissions and
14cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * limitations under the License.
15cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo */
16cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
17cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzopackage android.bluetooth;
18cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
19cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.content.ComponentName;
20cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.content.Context;
21cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.content.Intent;
22cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.content.ServiceConnection;
230a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkeyimport android.os.Binder;
24cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.os.IBinder;
25a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack Heimport android.os.RemoteException;
26cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzoimport android.util.Log;
27cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
28a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack Heimport java.util.ArrayList;
29a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack Heimport java.util.List;
30a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He
31cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo/**
32cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo * This class provides the APIs to control the Bluetooth PBAP Client Profile.
33a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He *
34a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He * @hide
35cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo */
36cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzopublic final class BluetoothPbapClient implements BluetoothProfile {
37cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
38cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private static final String TAG = "BluetoothPbapClient";
39cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private static final boolean DBG = false;
40cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private static final boolean VDBG = false;
41cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
42cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public static final String ACTION_CONNECTION_STATE_CHANGED =
4337ab815c96737ecbd6a4c807a42bbab5c661e521Jack He            "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
44cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
4516eeac356c68f3674677169b618774718ec982b2Jack He    private volatile IBluetoothPbapClient mService;
46cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private final Context mContext;
47cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private ServiceListener mServiceListener;
48cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private BluetoothAdapter mAdapter;
49cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
50cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /** There was an error trying to obtain the state */
51a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He    public static final int STATE_ERROR = -1;
52cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
53cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public static final int RESULT_FAILURE = 0;
54cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public static final int RESULT_SUCCESS = 1;
55cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /** Connection canceled before completion. */
56cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public static final int RESULT_CANCELED = 2;
57cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
582992cd084cd5cfd9ef253c37ef269d6c75e7e144Jack He    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
59cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            new IBluetoothStateChangeCallback.Stub() {
60cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                public void onBluetoothStateChange(boolean up) {
61cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    if (DBG) {
62cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        Log.d(TAG, "onBluetoothStateChange: PBAP CLIENT up=" + up);
63cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    }
64cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    if (!up) {
65cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        if (VDBG) {
66a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                            Log.d(TAG, "Unbinding service...");
67cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        }
68cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        synchronized (mConnection) {
69cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            try {
70cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                mService = null;
71cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                mContext.unbindService(mConnection);
72cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            } catch (Exception re) {
73a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                                Log.e(TAG, "", re);
74cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            }
75cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        }
76cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    } else {
77cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        synchronized (mConnection) {
78cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            try {
79cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                if (mService == null) {
80cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                    if (VDBG) {
81a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                                        Log.d(TAG, "Binding service...");
82cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                    }
83cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                    doBind();
84cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                                }
85cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            } catch (Exception re) {
86a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                                Log.e(TAG, "", re);
87cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                            }
88cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                        }
89cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    }
90cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                }
91a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He            };
92cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
93cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
94cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Create a BluetoothPbapClient proxy object.
95cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
96cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    BluetoothPbapClient(Context context, ServiceListener l) {
97cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
98cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.d(TAG, "Create BluetoothPbapClient proxy object");
99cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
100cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        mContext = context;
101cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        mServiceListener = l;
102cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        mAdapter = BluetoothAdapter.getDefaultAdapter();
103cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        IBluetoothManager mgr = mAdapter.getBluetoothManager();
104cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (mgr != null) {
105cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
106cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
107cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
108a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                Log.e(TAG, "", e);
109cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
110cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
111cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        doBind();
112cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
113cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
114cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private boolean doBind() {
115cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        Intent intent = new Intent(IBluetoothPbapClient.class.getName());
116cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
117cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        intent.setComponent(comp);
118cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
119ad357d1839760849fcbcb8cbdce34003e8831acdJeff Sharkey                mContext.getUser())) {
120cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent);
121cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            return false;
122cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
123cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return true;
124cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
125cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
126cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    protected void finalize() throws Throwable {
127cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        try {
128cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            close();
129cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        } finally {
130cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            super.finalize();
131cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
132cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
133cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
134cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
135cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Close the connection to the backing service.
136cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Other public functions of BluetoothPbapClient will return default error
137cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * results once close() has been called. Multiple invocations of close()
138cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * are ok.
139cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
140cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public synchronized void close() {
141cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        IBluetoothManager mgr = mAdapter.getBluetoothManager();
142cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (mgr != null) {
143cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
144cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
145cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (Exception e) {
146a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                Log.e(TAG, "", e);
147cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
148cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
149cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
150cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        synchronized (mConnection) {
151cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            if (mService != null) {
152cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                try {
153cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    mService = null;
154cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                    mContext.unbindService(mConnection);
155cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                } catch (Exception re) {
156a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                    Log.e(TAG, "", re);
157cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                }
158cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
159cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
160cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        mServiceListener = null;
161cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
162cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
163cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
164cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Initiate connection.
165cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Upon successful connection to remote PBAP server the Client will
166cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * attempt to automatically download the users phonebook and call log.
167cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     *
168a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He     * @param device a remote device we want connect to
169a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He     * @return <code>true</code> if command has been issued successfully; <code>false</code>
170a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He     * otherwise;
171cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
172cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public boolean connect(BluetoothDevice device) {
173cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
174cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            log("connect(" + device + ") for PBAP Client.");
175cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
17616eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
17716eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled() && isValidDevice(device)) {
178cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
17916eeac356c68f3674677169b618774718ec982b2Jack He                return service.connect(device);
180cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
181cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
182cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                return false;
183cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
184cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
18516eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
186cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
187cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
188cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return false;
189cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
190cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
191cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
192cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Initiate disconnect.
193cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     *
194cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * @param device Remote Bluetooth Device
195a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He     * @return false on error, true otherwise
196cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
197563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    public boolean disconnect(BluetoothDevice device) {
198cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
199a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He            log("disconnect(" + device + ")" + new Exception());
200cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
20116eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
20216eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled() && isValidDevice(device)) {
203cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
20416eeac356c68f3674677169b618774718ec982b2Jack He                service.disconnect(device);
205cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                return true;
206cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
207a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                Log.e(TAG, Log.getStackTraceString(new Throwable()));
208a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                return false;
209cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
210cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
21116eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
212cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
213cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
214cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return false;
215cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
216cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
217cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
218cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Get the list of connected devices.
219cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Currently at most one.
220cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     *
221cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * @return list of connected devices
222cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
223cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    @Override
224cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public List<BluetoothDevice> getConnectedDevices() {
225cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
226cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            log("getConnectedDevices()");
227cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
22816eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
22916eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled()) {
230cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
23116eeac356c68f3674677169b618774718ec982b2Jack He                return service.getConnectedDevices();
232cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
233cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
234cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                return new ArrayList<BluetoothDevice>();
235cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
236cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
23716eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
238cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
239cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
240cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return new ArrayList<BluetoothDevice>();
241cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
242cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
243cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
244cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Get the list of devices matching specified states. Currently at most one.
245cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     *
246cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * @return list of matching devices
247cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
248cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    @Override
249cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
250cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
251cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            log("getDevicesMatchingStates()");
252cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
25316eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
25416eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled()) {
255cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
25616eeac356c68f3674677169b618774718ec982b2Jack He                return service.getDevicesMatchingConnectionStates(states);
257cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
258cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
259cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                return new ArrayList<BluetoothDevice>();
260cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
261cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
26216eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
263cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
264cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
265cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return new ArrayList<BluetoothDevice>();
266cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
267cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
268cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    /**
269cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * Get connection state of device
270cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     *
271cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     * @return device connection state
272cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo     */
273cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    @Override
274cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    public int getConnectionState(BluetoothDevice device) {
275cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (DBG) {
276cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            log("getConnectionState(" + device + ")");
277cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
27816eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
27916eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled() && isValidDevice(device)) {
280cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            try {
28116eeac356c68f3674677169b618774718ec982b2Jack He                return service.getConnectionState(device);
282cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            } catch (RemoteException e) {
283cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
284cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                return BluetoothProfile.STATE_DISCONNECTED;
285cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
286cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
28716eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
288cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
289cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
290cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return BluetoothProfile.STATE_DISCONNECTED;
291cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
292cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
293cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private final ServiceConnection mConnection = new ServiceConnection() {
294cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        public void onServiceConnected(ComponentName className, IBinder service) {
295cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            if (DBG) {
296cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                log("Proxy object connected");
297cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
2980a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey            mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
299cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            if (mServiceListener != null) {
300a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT,
301a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                        BluetoothPbapClient.this);
302cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
303cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
304a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He
305cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        public void onServiceDisconnected(ComponentName className) {
306cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            if (DBG) {
307cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                log("Proxy object disconnected");
308cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
309cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            mService = null;
310cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            if (mServiceListener != null) {
311cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo                mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP_CLIENT);
312cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            }
313cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
314cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    };
315cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
316cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private static void log(String msg) {
317cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        Log.d(TAG, msg);
318cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
319cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
320cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    private boolean isEnabled() {
321cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
322cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
323cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo            return true;
324cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        }
325cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        log("Bluetooth is Not enabled");
326cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo        return false;
327cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
328cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo
32916eeac356c68f3674677169b618774718ec982b2Jack He    private static boolean isValidDevice(BluetoothDevice device) {
33016eeac356c68f3674677169b618774718ec982b2Jack He        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
331cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo    }
332563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo
333563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    /**
334563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * Set priority of the profile
335563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     *
336563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * <p> The device should already be paired.
337a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He     * Priority can be one of {@link #PRIORITY_ON} or
338563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * {@link #PRIORITY_OFF},
339563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     *
340563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * @param device Paired bluetooth device
34116eeac356c68f3674677169b618774718ec982b2Jack He     * @param priority Priority of this profile
342563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * @return true if priority is set, false on error
343563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     */
344563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    public boolean setPriority(BluetoothDevice device, int priority) {
345563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        if (DBG) {
346563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            log("setPriority(" + device + ", " + priority + ")");
347563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
34816eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
34916eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled() && isValidDevice(device)) {
3502992cd084cd5cfd9ef253c37ef269d6c75e7e144Jack He            if (priority != BluetoothProfile.PRIORITY_OFF
3512992cd084cd5cfd9ef253c37ef269d6c75e7e144Jack He                    && priority != BluetoothProfile.PRIORITY_ON) {
352a355e5efaf45a534ee6437aa4bae7d30f18c0ec2Jack He                return false;
353563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            }
354563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            try {
35516eeac356c68f3674677169b618774718ec982b2Jack He                return service.setPriority(device, priority);
356563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            } catch (RemoteException e) {
357563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
358563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo                return false;
359563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            }
360563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
36116eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
362563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
363563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
364563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        return false;
365563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    }
366563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo
367563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    /**
368563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * Get the priority of the profile.
369563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     *
370563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * <p> The priority can be any of:
371563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
372563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
373563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     *
374563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * @param device Bluetooth device
375563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     * @return priority of the device
376563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo     */
377563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    public int getPriority(BluetoothDevice device) {
378563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        if (VDBG) {
379563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            log("getPriority(" + device + ")");
380563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
38116eeac356c68f3674677169b618774718ec982b2Jack He        final IBluetoothPbapClient service = mService;
38216eeac356c68f3674677169b618774718ec982b2Jack He        if (service != null && isEnabled() && isValidDevice(device)) {
383563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            try {
38416eeac356c68f3674677169b618774718ec982b2Jack He                return service.getPriority(device);
385563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            } catch (RemoteException e) {
386563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo                Log.e(TAG, Log.getStackTraceString(new Throwable()));
387563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo                return PRIORITY_OFF;
388563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            }
389563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
39016eeac356c68f3674677169b618774718ec982b2Jack He        if (service == null) {
391563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo            Log.w(TAG, "Proxy not attached to service");
392563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        }
393563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo        return PRIORITY_OFF;
394563c700f7025d2f792a52b7483725b3d58eaa7a6Joseph Pirozzo    }
395cfa8a6469463ace9c3336e3686d950792a2c7ad4Joseph Pirozzo}
396