194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood/*
294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * Copyright (C) 2014 The Android Open Source Project
394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *
494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * you may not use this file except in compliance with the License.
694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * You may obtain a copy of the License at
794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *
894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *
1094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * Unless required by applicable law or agreed to in writing, software
1194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * See the License for the specific language governing permissions and
1494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * limitations under the License.
1594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood */
1694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
1794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodpackage android.bluetooth;
1894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
1994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.content.ComponentName;
2094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.content.Context;
2194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.content.Intent;
2294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.content.ServiceConnection;
231bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwalimport android.media.MediaMetadata;
241bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwalimport android.media.session.PlaybackState;
2594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.os.IBinder;
2694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.os.RemoteException;
2794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport android.util.Log;
2894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
2994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport java.util.ArrayList;
3094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodimport java.util.List;
3194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
3294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood/**
331bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently
341bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal * supports player information, playback support and track metadata.
3594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *
3694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
3794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
3894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * the BluetoothAvrcpController proxy object.
3994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood *
4094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood * {@hide}
4194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood */
4294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwoodpublic final class BluetoothAvrcpController implements BluetoothProfile {
4394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private static final String TAG = "BluetoothAvrcpController";
441bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    private static final boolean DBG = false;
4594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private static final boolean VDBG = false;
4694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
4794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /**
4894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * Intent used to broadcast the change in connection state of the AVRCP Controller
4994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * profile.
5094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *
5194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * <p>This intent will have 3 extras:
5294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * <ul>
5394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
5494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
5594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
5694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * </ul>
5794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *
5894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
5994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
6094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
6194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *
6294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
6394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * receive.
6494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     */
6594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public static final String ACTION_CONNECTION_STATE_CHANGED =
661bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
671bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
681bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
691bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Intent used to broadcast the change in metadata state of playing track on the AVRCP
701bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * AG.
711bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *
721bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * <p>This intent will have the two extras:
731bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * <ul>
741bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *    <li> {@link #EXTRA_METADATA} - {@link MediaMetadata} containing the current metadata.</li>
751bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *    <li> {@link #EXTRA_PLAYBACK} - {@link PlaybackState} containing the current playback
761bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *    state. </li>
771bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * </ul>
781bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
791bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final String ACTION_TRACK_EVENT =
801bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";
811bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
821bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
831bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
841bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Intent used to broadcast the change in player application setting state on AVRCP AG.
851bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *
861bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * <p>This intent will have the following extras:
871bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * <ul>
881bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *    <li> {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the
891bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *    most recent player setting. </li>
901bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * </ul>
911bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
921bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final String ACTION_PLAYER_SETTING =
931bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
941bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
951bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final String EXTRA_METADATA =
961bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            "android.bluetooth.avrcp-controller.profile.extra.METADATA";
971bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
981bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final String EXTRA_PLAYBACK =
991bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";
1001bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
1011bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final String EXTRA_PLAYER_SETTING =
1021bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
1031bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
1041bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /*
1051bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * KeyCoded for Pass Through Commands
1061bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
1071bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_PLAY = 0x44;
1081bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_PAUSE = 0x46;
1091bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41;
1101bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42;
1111bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_STOP = 0x45;
1121bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_FF = 0x49;
1131bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_REWIND = 0x48;
1141bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B;
1151bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C;
1161bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /* Key State Variables */
1171bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int KEY_STATE_PRESSED = 0;
1181bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int KEY_STATE_RELEASED = 1;
1191bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /* Group Navigation Key Codes */
1201bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00;
1211bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01;
1221bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
12394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
12494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private Context mContext;
12594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private ServiceListener mServiceListener;
12694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private IBluetoothAvrcpController mService;
12794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private BluetoothAdapter mAdapter;
12894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
12994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
1301bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        new IBluetoothStateChangeCallback.Stub() {
1311bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            public void onBluetoothStateChange(boolean up) {
1321bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
1331bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                if (!up) {
1341bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                    if (VDBG) Log.d(TAG,"Unbinding service...");
1351bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                    synchronized (mConnection) {
1361bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                        try {
1371bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                            mService = null;
1381bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                            mContext.unbindService(mConnection);
1391bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                        } catch (Exception re) {
1401bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                            Log.e(TAG,"",re);
14194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                        }
1421bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                    }
1431bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                } else {
1441bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                    synchronized (mConnection) {
1451bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                        try {
1461bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                            if (mService == null) {
1471bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                                if (VDBG) Log.d(TAG,"Binding service...");
1481bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                                doBind();
14994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                            }
1501bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                        } catch (Exception re) {
1511bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                            Log.e(TAG,"",re);
15294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                        }
15394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                    }
15494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                }
1551bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
1561bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal      };
15794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
15894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /**
15994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * Create a BluetoothAvrcpController proxy object for interacting with the local
16094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * Bluetooth AVRCP service.
16194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     *
16294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     */
16394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {
16494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        mContext = context;
16594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        mServiceListener = l;
16694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        mAdapter = BluetoothAdapter.getDefaultAdapter();
16794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        IBluetoothManager mgr = mAdapter.getBluetoothManager();
16894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mgr != null) {
16994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
17094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
17194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (RemoteException e) {
17294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG,"",e);
17394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
17494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
17594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
17694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        doBind();
17794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
17894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
17994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    boolean doBind() {
18094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
18194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
18294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        intent.setComponent(comp);
18394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
18494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                android.os.Process.myUserHandle())) {
18594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
18694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            return false;
18794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
18894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        return true;
18994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
19094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
19194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /*package*/ void close() {
19294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        mServiceListener = null;
19394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        IBluetoothManager mgr = mAdapter.getBluetoothManager();
19494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mgr != null) {
19594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
19694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
19794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (Exception e) {
19894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG,"",e);
19994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
20094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
20194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
20294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        synchronized (mConnection) {
20394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            if (mService != null) {
20494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                try {
20594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                    mService = null;
20694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                    mContext.unbindService(mConnection);
20794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                } catch (Exception re) {
20894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                    Log.e(TAG,"",re);
20994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                }
21094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
21194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
21294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
21394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
21494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public void finalize() {
21594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        close();
21694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
21794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
21894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /**
21994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * {@inheritDoc}
22094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     */
22194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public List<BluetoothDevice> getConnectedDevices() {
22294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (VDBG) log("getConnectedDevices()");
22394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService != null && isEnabled()) {
22494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
22594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return mService.getConnectedDevices();
22694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (RemoteException e) {
22794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
22894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return new ArrayList<BluetoothDevice>();
22994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
23094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
23194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService == null) Log.w(TAG, "Proxy not attached to service");
23294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        return new ArrayList<BluetoothDevice>();
23394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
23494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
23594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /**
23694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * {@inheritDoc}
23794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     */
23894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
23994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (VDBG) log("getDevicesMatchingStates()");
24094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService != null && isEnabled()) {
24194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
24294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return mService.getDevicesMatchingConnectionStates(states);
24394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (RemoteException e) {
24494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
24594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return new ArrayList<BluetoothDevice>();
24694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
24794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
24894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService == null) Log.w(TAG, "Proxy not attached to service");
24994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        return new ArrayList<BluetoothDevice>();
25094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
25194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
25294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    /**
25394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     * {@inheritDoc}
25494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood     */
25594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public int getConnectionState(BluetoothDevice device) {
25694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (VDBG) log("getState(" + device + ")");
25794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService != null && isEnabled()
25894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            && isValidDevice(device)) {
25994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
26094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return mService.getConnectionState(device);
26194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (RemoteException e) {
26294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
26394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return BluetoothProfile.STATE_DISCONNECTED;
26494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
26594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
26694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService == null) Log.w(TAG, "Proxy not attached to service");
26794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        return BluetoothProfile.STATE_DISCONNECTED;
26894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
26994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
27094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
27194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (DBG) Log.d(TAG, "sendPassThroughCmd");
27294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService != null && isEnabled()) {
27394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            try {
27494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                mService.sendPassThroughCmd(device, keyCode, keyState);
27594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return;
27694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            } catch (RemoteException e) {
27794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
27894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                return;
27994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
28094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
28194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        if (mService == null) Log.w(TAG, "Proxy not attached to service");
28294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
28394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
2841bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
2851bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Gets the player application settings.
2861bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *
2871bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error.
2881bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
2891bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
2901bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (DBG) Log.d(TAG, "getPlayerSettings");
2911bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        BluetoothAvrcpPlayerSettings settings = null;
2921bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService != null && isEnabled()) {
2931bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            try {
2941bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                settings = mService.getPlayerSettings(device);
2951bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            } catch (RemoteException e) {
2961bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
2971bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return null;
2981bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
2991bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        }
3001bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        return settings;
3011bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    }
3021bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
3031bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
3041bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Gets the metadata for the current track.
3051bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *
3061bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * This should be usually called when application UI needs to be updated, eg. when the track
3071bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * changes or immediately after connecting and getting the current state.
3081bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * @return the {@link MediaMetadata} or {@link null} if there is an error.
3091bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
3101bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public MediaMetadata getMetadata(BluetoothDevice device) {
3111bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (DBG) Log.d(TAG, "getMetadata");
3121bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        MediaMetadata metadata = null;
3131bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService != null && isEnabled()) {
3141bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            try {
3151bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                metadata = mService.getMetadata(device);
3161bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            } catch (RemoteException e) {
3171bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
3181bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return null;
3191bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
3201bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        }
3211bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        return metadata;
3221bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    }
3231bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
3241bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
3251bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Gets the playback state for current track.
3261bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     *
3271bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * When the application is first connecting it can use current track state to get playback info.
3281bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * For all further updates it should listen to notifications.
3291bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * @return the {@link PlaybackState} or {@link null} if there is an error.
3301bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
3311bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public PlaybackState getPlaybackState(BluetoothDevice device) {
3321bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (DBG) Log.d(TAG, "getPlaybackState");
3331bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        PlaybackState playbackState = null;
3341bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService != null && isEnabled()) {
3351bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            try {
3361bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                playbackState = mService.getPlaybackState(device);
3371bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            } catch (RemoteException e) {
3381bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                Log.e(TAG,
3391bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                    "Error talking to BT service in getPlaybackState() " + e);
3401bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return null;
3411bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
3421bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        }
3431bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        return playbackState;
3441bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    }
3451bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
3461bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /**
3471bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Sets the player app setting for current player.
3481bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * returns true in case setting is supported by remote, false otherwise
3491bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
3501bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
3511bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
3521bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService != null && isEnabled()) {
3531bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            try {
3541bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return mService.setPlayerApplicationSetting(plAppSetting);
3551bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            } catch (RemoteException e) {
3561bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e);
3571bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return false;
3581bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
3591bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        }
3601bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3611bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        return false;
3621bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    }
3631bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
3641bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    /*
3651bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * Send Group Navigation Command to Remote.
3661bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     * possible keycode values: next_grp, previous_grp defined above
3671bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal     */
3681bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
3691bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState);
3701bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService != null && isEnabled()) {
3711bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            try {
3721bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                mService.sendGroupNavigationCmd(device, keyCode, keyState);
3731bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return;
3741bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            } catch (RemoteException e) {
3751bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e);
3761bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal                return;
3771bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal            }
3781bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        }
3791bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3801bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal    }
3811bec6a5b0d67f120b7013572f6b1a4f1e1b3c584Sanket Agarwal
38294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private final ServiceConnection mConnection = new ServiceConnection() {
38394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        public void onServiceConnected(ComponentName className, IBinder service) {
38494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            if (DBG) Log.d(TAG, "Proxy object connected");
38594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            mService = IBluetoothAvrcpController.Stub.asInterface(service);
38694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
38794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            if (mServiceListener != null) {
38894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
38994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                        BluetoothAvrcpController.this);
39094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
39194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
39294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        public void onServiceDisconnected(ComponentName className) {
39394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            if (DBG) Log.d(TAG, "Proxy object disconnected");
39494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            mService = null;
39594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            if (mServiceListener != null) {
39694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood                mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
39794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood            }
39894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood        }
39994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    };
40094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
40194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private boolean isEnabled() {
40294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood       if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
40394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood       return false;
40494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
40594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
40694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private boolean isValidDevice(BluetoothDevice device) {
40794b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood       if (device == null) return false;
40894b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
40994b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
41094b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood       return false;
41194b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
41294b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood
41394b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    private static void log(String msg) {
41494b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood      Log.d(TAG, msg);
41594b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood    }
41694b59de852df7b6ce16aef73a9b2c11be8f3102dMike Lockwood}
417