1510203ee5e3350758dae4bf9af05b1585029af7dWally Yau/*
2510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * Copyright (C) 2014 The Android Open Source Project
3510203ee5e3350758dae4bf9af05b1585029af7dWally Yau *
4510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * Licensed under the Apache License, Version 2.0 (the "License");
5510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * you may not use this file except in compliance with the License.
6510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * You may obtain a copy of the License at
7510203ee5e3350758dae4bf9af05b1585029af7dWally Yau *
8510203ee5e3350758dae4bf9af05b1585029af7dWally Yau *      http://www.apache.org/licenses/LICENSE-2.0
9510203ee5e3350758dae4bf9af05b1585029af7dWally Yau *
10510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * Unless required by applicable law or agreed to in writing, software
11510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * distributed under the License is distributed on an "AS IS" BASIS,
12510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * See the License for the specific language governing permissions and
14510203ee5e3350758dae4bf9af05b1585029af7dWally Yau * limitations under the License.
15510203ee5e3350758dae4bf9af05b1585029af7dWally Yau */
16510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
17510203ee5e3350758dae4bf9af05b1585029af7dWally Yaupackage com.android.tv.settings.accessories;
18510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
19510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.bluetooth.BluetoothA2dp;
20510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.bluetooth.BluetoothAdapter;
21510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.bluetooth.BluetoothDevice;
22510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.bluetooth.BluetoothProfile;
23510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.content.BroadcastReceiver;
24510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.content.Context;
25510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.content.Intent;
26510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.content.IntentFilter;
27510203ee5e3350758dae4bf9af05b1585029af7dWally Yauimport android.util.Log;
28510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
29510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
30510203ee5e3350758dae4bf9af05b1585029af7dWally Yaupublic class BluetoothA2dpConnector implements BluetoothDevicePairer.BluetoothConnector {
31510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
3280ce1531cd5ea91a5332f923b9a434d79e81e22fTony Mantler    public static final String TAG = "BluetoothA2dpConnector";
33510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
34510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private static final boolean DEBUG = false;
35510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
36510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private Context mContext;
37510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BluetoothDevice mTarget;
38510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BluetoothDevicePairer.OpenConnectionCallback mOpenConnectionCallback;
39510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BluetoothA2dp mA2dpProfile;
40510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private boolean mConnectionStateReceiverRegistered = false;
41510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
42510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() {
43510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        @Override
44510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        public void onReceive(Context context, Intent intent) {
45510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(
46510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    BluetoothDevice.EXTRA_DEVICE);
47510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            if (DEBUG) {
48510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                Log.d(TAG, "There was a connection status change for: " + device.getAddress());
49510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            }
50510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
51510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            if (device.equals(mTarget)) {
52510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                int previousState = intent.getIntExtra(
53510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        BluetoothA2dp.EXTRA_PREVIOUS_STATE,
54510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        BluetoothA2dp.STATE_CONNECTING);
55510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE,
56510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        BluetoothA2dp.STATE_CONNECTING);
57510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
58510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                if (DEBUG) {
59510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    Log.d(TAG, "Connection states: old = " + previousState + ", new = " + state);
60510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                }
61510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
62510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                if (previousState == BluetoothA2dp.STATE_CONNECTING) {
63510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    if (state == BluetoothA2dp.STATE_CONNECTED) {
64510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        mOpenConnectionCallback.succeeded();
65510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    } else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
66510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        Log.d(TAG, "Failed to connect");
67510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                        mOpenConnectionCallback.failed();
68510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    }
69510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
70510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    unregisterConnectionStateReceiver();
71510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                    closeA2dpProfileProxy();
72510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                }
73510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            }
74510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
75510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    };
76510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
77510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BluetoothProfile.ServiceListener mServiceConnection =
78510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            new BluetoothProfile.ServiceListener() {
79510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
80510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        @Override
81510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        public void onServiceDisconnected(int profile) {
82510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            Log.w(TAG, "Service disconnected, perhaps unexpectedly");
83510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            unregisterConnectionStateReceiver();
84510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            closeA2dpProfileProxy();
85510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mOpenConnectionCallback.failed();
86510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
87510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
88510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        @Override
89510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        public void onServiceConnected(int profile, BluetoothProfile proxy) {
90510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            if (DEBUG) {
91510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                Log.d(TAG, "Connection made to bluetooth proxy." );
92510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            }
93510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            BluetoothA2dp mA2dpProfile = (BluetoothA2dp) proxy;
94510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            if (DEBUG) {
95510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                Log.d(TAG, "Connecting to target: " + mTarget.getAddress());
96510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            }
97510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
98510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            registerConnectionStateReceiver();
99510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
100510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            // TODO need to start a timer, otherwise if the connection fails we might be
101510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            // stuck here forever
102510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mA2dpProfile.connect(mTarget);
103510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
104510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            // must set PRIORITY_AUTO_CONNECT or auto-connection will not
105510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            // occur, however this setting does not appear to be sticky
106510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            // across a reboot
107510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mA2dpProfile.setPriority(mTarget, BluetoothProfile.PRIORITY_AUTO_CONNECT);
108510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
109510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    };
110510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
111510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private BluetoothA2dpConnector() {
112510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
113510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
114510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    public BluetoothA2dpConnector(Context context, BluetoothDevice target,
115510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                                  BluetoothDevicePairer.OpenConnectionCallback callback) {
116510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        mContext = context;
117510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        mTarget = target;
118510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        mOpenConnectionCallback = callback;
119510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
120510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
121510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    @Override
122510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    public void openConnection(BluetoothAdapter adapter) {
123510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        if (DEBUG) {
124510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            Log.d(TAG, "opening connection");
125510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
126510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        if (!adapter.getProfileProxy(mContext, mServiceConnection, BluetoothProfile.A2DP)) {
127510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mOpenConnectionCallback.failed();
128510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
129510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
130510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
131510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private void closeA2dpProfileProxy() {
132510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        if (mA2dpProfile != null) {
133510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            try {
134510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
135510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                adapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpProfile);
136510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                mA2dpProfile = null;
137510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            } catch (Throwable t) {
138510203ee5e3350758dae4bf9af05b1585029af7dWally Yau                Log.w(TAG, "Error cleaning up A2DP proxy", t);
139510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            }
140510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
141510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
142510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
143510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private void registerConnectionStateReceiver() {
144510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        if (DEBUG) Log.d(TAG, "registerConnectionStateReceiver()");
145510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        IntentFilter filter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
146510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        mContext.registerReceiver(mConnectionStateReceiver, filter);
147510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        mConnectionStateReceiverRegistered = true;
148510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
149510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
150510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    private void unregisterConnectionStateReceiver() {
151510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        if (mConnectionStateReceiverRegistered) {
152510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            if (DEBUG) Log.d(TAG, "unregisterConnectionStateReceiver()");
153510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mContext.unregisterReceiver(mConnectionStateReceiver);
154510203ee5e3350758dae4bf9af05b1585029af7dWally Yau            mConnectionStateReceiverRegistered = false;
155510203ee5e3350758dae4bf9af05b1585029af7dWally Yau        }
156510203ee5e3350758dae4bf9af05b1585029af7dWally Yau    }
157510203ee5e3350758dae4bf9af05b1585029af7dWally Yau
158510203ee5e3350758dae4bf9af05b1585029af7dWally Yau}
159