PageRenderTime 21ms CodeModel.GetById 6ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/TalkBack/src/com/google/android/marvin/talkback/BluetoothHandler.java

http://eyes-free.googlecode.com/
Java | 218 lines | 140 code | 26 blank | 52 comment | 30 complexity | e9b075d792990bda73ceb20111ed8c05 MD5 | raw file
  1/*
  2 * Copyright (C) 2011 Google Inc.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16
 17package com.google.android.marvin.talkback;
 18
 19import android.bluetooth.BluetoothAdapter;
 20import android.bluetooth.BluetoothDevice;
 21import android.bluetooth.BluetoothHeadset;
 22import android.bluetooth.BluetoothProfile;
 23import android.content.Context;
 24import android.os.Handler;
 25import android.os.Message;
 26import android.util.Log;
 27
 28import java.util.List;
 29
 30/**
 31 * A helper class for handling the Bluetooth headset.
 32 */
 33class BluetoothHandler {
 34    private static final String TAG = BluetoothHandler.class.getSimpleName();
 35
 36    private static final boolean DBG = true;
 37
 38    private static final int MSG_START_BLUETOOTH = 1;
 39    private static final int MSG_STOP_BLUETOOTH = 2;
 40    private static final int MSG_CANCEL_BLUETOOTH = 3;
 41
 42    private final Listener mListener;
 43    private final int mStartupTimeoutMillis;
 44    private final BluetoothAdapter mBluetoothAdapter;
 45    private final Handler mHandler;
 46    private final BluetoothHeadset.ServiceListener mBluetoothHeadsetServiceListener;
 47
 48    private BluetoothDevice mBluetoothDevice;
 49    private BluetoothHeadset mBluetoothProxy;
 50    private BluetoothHeadsetCompatWrapper mBluetoothProxyCompat;
 51
 52    private boolean mBluetoothConnectionCanceled = false;
 53
 54    /**
 55     * Creates the Bluetooth handler. No connection to a device is made in the
 56     * constructor.
 57     *
 58     * @param listener the listener that will be notified about the bluetooth
 59     *            connection state changes
 60     */
 61    public BluetoothHandler(int startupTimeoutMillis, Listener listener) {
 62        mListener = listener;
 63        mStartupTimeoutMillis = startupTimeoutMillis;
 64        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 65        mHandler = new Handler() {
 66            @Override
 67            public void handleMessage(Message msg) {
 68                switch (msg.what) {
 69                    case MSG_START_BLUETOOTH:
 70                        startBluetooth((BluetoothHeadset) msg.obj);
 71                        break;
 72                    case MSG_STOP_BLUETOOTH:
 73                        stop();
 74                        break;
 75                    case MSG_CANCEL_BLUETOOTH:
 76                        cancel();
 77                        break;
 78                }
 79                super.handleMessage(msg);
 80            }
 81        };
 82        mBluetoothHeadsetServiceListener = new BluetoothHeadset.ServiceListener() {
 83            @Override
 84            public void onServiceConnected(int profile, BluetoothProfile proxy) {
 85                if (DBG)
 86                    Log.d(TAG, "BluetoothHeadset.ServiceListener.onServiceConnected");
 87                Message.obtain(mHandler, MSG_START_BLUETOOTH, proxy).sendToTarget();
 88            }
 89
 90            @Override
 91            public void onServiceDisconnected(int profile) {
 92                if (DBG)
 93                    Log.d(TAG, "BluetoothHeadset.ServiceListener.onServiceDisconnected");
 94                Message.obtain(mHandler, MSG_STOP_BLUETOOTH).sendToTarget();
 95            }
 96        };
 97    }
 98
 99    private void startWatchdog() {
100        stopWatchdog();
101        mBluetoothConnectionCanceled = false;
102        mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_CANCEL_BLUETOOTH),
103                mStartupTimeoutMillis);
104    }
105
106    private void stopWatchdog() {
107        mHandler.removeMessages(MSG_CANCEL_BLUETOOTH);
108    }
109
110    private void startBluetooth(BluetoothHeadset proxy) {
111        stopWatchdog();
112        if (mBluetoothConnectionCanceled) {
113            mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy);
114            return;
115        }
116        List<BluetoothDevice> devices = proxy.getConnectedDevices();
117        if (devices.size() > 0) {
118            mBluetoothDevice = devices.get(0);
119            mBluetoothProxy = proxy;
120            mBluetoothProxyCompat = new BluetoothHeadsetCompatWrapper(proxy);
121            Log.i(TAG, "Connected to a bluetooth device.");
122        } else {
123            if (DBG)
124                Log.d(TAG, "No device is connected, closing bluetooth proxy.");
125            mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy);
126        }
127        mListener.onConnectionComplete();
128    }
129
130    private void cancel() {
131        mListener.onConnectionComplete();
132        stop();
133    }
134
135    /**
136     * Closes the connection to the Bluetooth proxy. This method must be called
137     * to prevent resource leakage.
138     */
139    public void stop() {
140        if (DBG)
141            Log.d(TAG, "Closing bluetooth proxy:" + mBluetoothProxy);
142        mBluetoothConnectionCanceled = true;
143        stopWatchdog();
144        if (mBluetoothProxy != null) {
145            mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothProxy);
146            mBluetoothProxy = null;
147            mBluetoothProxyCompat = null;
148            mBluetoothDevice = null;
149        }
150    }
151
152    /**
153     * @return {@code false} if no devices are available or the
154     *         {@link BluetoothAdapter} is turned off.
155     */
156    public boolean isBluetoothAvailable() {
157        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
158                && mBluetoothAdapter.getBondedDevices() != null
159                && mBluetoothAdapter.getBondedDevices().size() > 0;
160    }
161
162    /**
163     * Initiates an asynchronous connection to a bluetooth device. This function
164     * should be called on the main thread.
165     * {@link Listener#onConnectionComplete} will be called on the main thread
166     * after invoking this method.
167     *
168     * @param context the {@link Context} in which the handler is created
169     */
170    public void start(Context context) {
171        if (mBluetoothProxy != null) {
172            if (DBG)
173                Log.d(TAG, "BluetoothHandler.start() was called without closing the proxy.");
174            mListener.onConnectionComplete();
175            return;
176        }
177        startWatchdog();
178        mBluetoothAdapter.getProfileProxy(context, mBluetoothHeadsetServiceListener,
179                BluetoothProfile.HEADSET);
180    }
181
182    public boolean startSco() {
183        if (mBluetoothProxy == null || mBluetoothDevice == null)
184            return false;
185
186        return mBluetoothProxyCompat.startScoUsingVirtualVoiceCall(mBluetoothDevice);
187    }
188
189    public boolean stopSco() {
190        if (mBluetoothProxy == null || mBluetoothDevice == null)
191            return false;
192
193        return mBluetoothProxyCompat.stopScoUsingVirtualVoiceCall(mBluetoothDevice);
194    }
195
196    public boolean isAudioConnected() {
197        if (mBluetoothProxy == null || mBluetoothDevice == null)
198            return false;
199
200        return mBluetoothProxy.isAudioConnected(mBluetoothDevice);
201    }
202
203    /**
204     * An interface for the bluetooth callbacks.
205     */
206    public interface Listener {
207
208        /**
209         * Called when a bluetooth headset connection establishment is complete.
210         * If the connection to a bluetooth headset was successful,
211         * {@link BluetoothHeadset#startVoiceRecognition} is called before this
212         * callback to redirect the input audio to the headset, otherwise the
213         * audio input will be received from the mic. This call is done on the
214         * main thread.
215         */
216        void onConnectionComplete();
217    }
218}