AudioSwitchPreferenceController.java revision 63bdfa8998791eb08fb70c21ea37d23c910e5057
15738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project/*
25738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * Copyright (C) 2018 The Android Open Source Project
35b790feeeb211c42bf78ca3ae9c26aa30e516765Jakub Pawlowski *
45738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
55738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * you may not use this file except in compliance with the License.
65738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * You may obtain a copy of the License at
75738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
85738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
95738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project *
105738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
115738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
125738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * See the License for the specific language governing permissions and
145738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * limitations under the License.
155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project */
165738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
175738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectpackage com.android.settings.sound;
185738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
1949a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen
2049120dc867c7818511b5afec461dfc97d17eef58Marie Janssenimport static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION;
21f2af1c42ccb2f642b241c2261b42d0be61d45438Jack Heimport static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
22911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
235738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
245738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.content.BroadcastReceiver;
255738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.content.Context;
26aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Mantonimport android.content.Intent;
27aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Mantonimport android.content.IntentFilter;
285738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.media.AudioDeviceCallback;
29db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.media.AudioDeviceInfo;
30911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonimport android.media.AudioManager;
31aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Mantonimport android.media.MediaRouter;
32db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.media.MediaRouter.Callback;
33db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.os.Handler;
345738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.os.Looper;
355738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport android.support.v7.preference.ListPreference;
36911d1ae03efec2d54c3b1b605589d790d1745488Myles Watsonimport android.support.v7.preference.Preference;
37db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.support.v7.preference.PreferenceScreen;
38db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.text.TextUtils;
39db554581079863974af8e1289646f5deea6fc044Marie Janssenimport android.util.FeatureFlagUtils;
40db554581079863974af8e1289646f5deea6fc044Marie Janssen
419891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnsonimport com.android.internal.util.ArrayUtils;
42aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Mantonimport com.android.settings.R;
435738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport com.android.settings.bluetooth.Utils;
44f66f4e95f2b4bc8d36033f2d65b387e32601fcd8Pavlin Radoslavovimport com.android.settings.core.BasePreferenceController;
45d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenimport com.android.settings.core.FeatureFlags;
465738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport com.android.settingslib.bluetooth.BluetoothCallback;
475738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport com.android.settingslib.bluetooth.CachedBluetoothDevice;
48d19e0785e662e640191a075eda07acce61c2aedaMarie Janssenimport com.android.settingslib.bluetooth.LocalBluetoothManager;
495738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
505738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectimport com.android.settingslib.core.lifecycle.LifecycleObserver;
518843cc830b522cfe6f1e361297fc28fd331a1378Hemant Guptaimport com.android.settingslib.core.lifecycle.events.OnStart;
528843cc830b522cfe6f1e361297fc28fd331a1378Hemant Guptaimport com.android.settingslib.core.lifecycle.events.OnStop;
538843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta
548843cc830b522cfe6f1e361297fc28fd331a1378Hemant Guptaimport java.util.List;
558843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta
568843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta/**
578843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta * Abstract class for audio switcher controller to notify subclass
58ead3cde4bac0c3e32cd31f149093f004eef8ceebGanesh Ganapathi Batta * updating the current status of switcher entry. Subclasses must overwrite
595738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * {@link #setActiveBluetoothDevice(BluetoothDevice)} to set the
605738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project * active device for corresponding profile.
615738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project */
625738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Projectpublic abstract class AudioSwitchPreferenceController extends BasePreferenceController
635738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        implements Preference.OnPreferenceChangeListener, BluetoothCallback,
645738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        LifecycleObserver, OnStart, OnStop {
657a3819f092b17536e247b4d147cac6a8cdfd0138Gurpreet Ghai
665738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    private static final int INVALID_INDEX = -1;
675738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project
68911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    protected final AudioManager mAudioManager;
695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    protected final MediaRouter mMediaRouter;
705738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    protected final LocalBluetoothProfileManager mProfileManager;
715738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    protected int mSelectedIndex;
72aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    protected Preference mPreference;
73911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    protected List<BluetoothDevice> mConnectedDevices;
74911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
75911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback;
76911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    private final LocalBluetoothManager mLocalBluetoothManager;
77911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    private final MediaRouterCallback mMediaRouterCallback;
78911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    private final WiredHeadsetBroadcastReceiver mReceiver;
79911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    private final Handler mHandler;
80911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
81911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    public AudioSwitchPreferenceController(Context context, String preferenceKey) {
82911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        super(context, preferenceKey);
83aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
84aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
85aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
86aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mLocalBluetoothManager.setForegroundActivity(context);
875738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        mProfileManager = mLocalBluetoothManager.getProfileManager();
885738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        mHandler = new Handler(Looper.getMainLooper());
89aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mAudioManagerAudioDeviceCallback = new AudioManagerAudioDeviceCallback();
90911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        mReceiver = new WiredHeadsetBroadcastReceiver();
91911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        mMediaRouterCallback = new MediaRouterCallback();
92911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
93911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
94911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    /**
95911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * Make this method as final, ensure that subclass will checking
96911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * the feature flag and they could mistakenly break it via overriding.
97911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     */
98911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
99911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    public final int getAvailabilityStatus() {
100911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.AUDIO_SWITCHER_SETTINGS)
101911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                ? AVAILABLE : DISABLED_UNSUPPORTED;
102d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen    }
103911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
104911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
1055738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    public boolean onPreferenceChange(Preference preference, Object newValue) {
106911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        final String address = (String) newValue;
107911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        if (!(preference instanceof ListPreference)) {
1088843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta            return false;
1098843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta        }
1108843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta
1118843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta        final ListPreference listPreference = (ListPreference) preference;
112d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen        if (TextUtils.equals(address, mContext.getText(R.string.media_output_default_summary))) {
113911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            // Switch to default device which address is device name
114911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            mSelectedIndex = getDefaultDeviceIndex();
1155738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project            setActiveBluetoothDevice(null);
116911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            listPreference.setSummary(mContext.getText(R.string.media_output_default_summary));
117911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        } else {
118911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            // Switch to BT device which address is hardware address
119911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
1208843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta            if (connectedDeviceIndex == INVALID_INDEX) {
1218843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta                return false;
1228843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta            }
1238843cc830b522cfe6f1e361297fc28fd331a1378Hemant Gupta            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
124911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            mSelectedIndex = connectedDeviceIndex;
125911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            setActiveBluetoothDevice(btDevice);
126911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            listPreference.setSummary(btDevice.getName());
127911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        }
128911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        return true;
129911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
130911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
131911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    public abstract void setActiveBluetoothDevice(BluetoothDevice device);
132911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
133911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
134911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    public void displayPreference(PreferenceScreen screen) {
1357a3819f092b17536e247b4d147cac6a8cdfd0138Gurpreet Ghai        super.displayPreference(screen);
136aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        mPreference = screen.findPreference(mPreferenceKey);
137911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    }
138aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
139aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    @Override
140aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    public void onStart() {
141aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        register();
142aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    }
143aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
144911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
145aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    public void onStop() {
146db554581079863974af8e1289646f5deea6fc044Marie Janssen        unregister();
147aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    }
148aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
149db554581079863974af8e1289646f5deea6fc044Marie Janssen    /**
150aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton     * Only concerned about whether the local adapter is connected to any profile of any device and
151aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton     * are not really concerned about which profile.
152aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton     */
153db554581079863974af8e1289646f5deea6fc044Marie Janssen    @Override
154aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
155aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton        updateState(mPreference);
156db554581079863974af8e1289646f5deea6fc044Marie Janssen    }
157aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
158aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    @Override
1599ca07091a1f07ea201cee0504dab6a1d7073d429Myles Watson    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
1605d700dd909645dd1fe120014d817041aaed43b8dMyles Watson        updateState(mPreference);
1615d700dd909645dd1fe120014d817041aaed43b8dMyles Watson    }
162aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
163aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    @Override
164aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    public void onAudioModeChanged() {
1655738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project        updateState(mPreference);
166aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    }
167aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
168911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
1695738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    public void onBluetoothStateChanged(int bluetoothState) {
170aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    }
171aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
172aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    /**
173aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton     * The local Bluetooth adapter has started the remote device discovery process.
174911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     */
175aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    @Override
176aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    public void onScanningStateChanged(boolean started) {
177aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    }
178aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton
179aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton    /**
180911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson     * Indicates a change in the bond state of a remote
181aa0f6ecc4cfd5c401e6278ee7139ce0cacc40483Chris Manton     * device. For example, if a device is bonded (paired).
18278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov     */
1835738f83aeb59361a0a2eda2460113f6dc919427The Android Open Source Project    @Override
1849891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
185911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        updateState(mPreference);
186f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He    }
1879891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson
188911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
189911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
190f3fb316634973d26cc4b4f55656b86e2a15bd69cJakub Pawlowski    }
191f3fb316634973d26cc4b4f55656b86e2a15bd69cJakub Pawlowski
192911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson    @Override
19395f6f1bed91aa523ba280667d109ee67bd6def0bEagle Kang    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
19495f6f1bed91aa523ba280667d109ee67bd6def0bEagle Kang    }
195911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson
1969891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    protected boolean isOngoingCallStatus() {
1979891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        int audioMode = mAudioManager.getMode();
1989891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        return audioMode == AudioManager.MODE_RINGTONE
199911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                || audioMode == AudioManager.MODE_IN_CALL
200911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                || audioMode == AudioManager.MODE_IN_COMMUNICATION;
2019891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    }
202db554581079863974af8e1289646f5deea6fc044Marie Janssen
2039891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    int getDefaultDeviceIndex() {
2049891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        // Default device is after all connected devices.
2059891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        return ArrayUtils.size(mConnectedDevices);
20675b83661eaecceeb48c73891ced70904bf0ce01bJakub Pawlowski    }
20775b83661eaecceeb48c73891ced70904bf0ce01bJakub Pawlowski
2089891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
2099891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson            BluetoothDevice activeDevice) {
2109891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        // default to current device
2119891f32471b5c01cf58e4d7dadb04cb3024a9a88Zach Johnson        mSelectedIndex = getDefaultDeviceIndex();
212b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov        // default device is after all connected devices.
213911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        mediaOutputs[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
214911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        // use default device name as address
215911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        mediaValues[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
216911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
217911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            final BluetoothDevice btDevice = mConnectedDevices.get(i);
218911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson            mediaOutputs[i] = btDevice.getName();
219            mediaValues[i] = btDevice.getAddress();
220            if (btDevice.equals(activeDevice)) {
221                // select the active connected device.
222                mSelectedIndex = i;
223            }
224        }
225    }
226
227    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
228            Preference preference) {
229        final ListPreference listPreference = (ListPreference) preference;
230        listPreference.setEntries(mediaOutputs);
231        listPreference.setEntryValues(mediaValues);
232        listPreference.setValueIndex(mSelectedIndex);
233        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
234    }
235
236    private int getConnectedDeviceIndex(String hardwareAddress) {
237        if (mConnectedDevices != null) {
238            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
239                final BluetoothDevice btDevice = mConnectedDevices.get(i);
240                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
241                    return i;
242                }
243            }
244        }
245        return INVALID_INDEX;
246    }
247
248    private void register() {
249        mLocalBluetoothManager.getEventManager().registerCallback(this);
250        mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
251        mMediaRouter.addCallback(ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback);
252
253        // Register for misc other intent broadcasts.
254        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
255        intentFilter.addAction(STREAM_DEVICES_CHANGED_ACTION);
256        mContext.registerReceiver(mReceiver, intentFilter);
257    }
258
259    private void unregister() {
260        mLocalBluetoothManager.getEventManager().unregisterCallback(this);
261        mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback);
262        mMediaRouter.removeCallback(mMediaRouterCallback);
263        mContext.unregisterReceiver(mReceiver);
264    }
265
266    /** Callback for headset plugged and unplugged events. */
267    private class AudioManagerAudioDeviceCallback extends AudioDeviceCallback {
268        @Override
269        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
270            updateState(mPreference);
271        }
272
273        @Override
274        public void onAudioDevicesRemoved(AudioDeviceInfo[] devices) {
275            updateState(mPreference);
276        }
277    }
278
279    /** Receiver for wired headset plugged and unplugged events. */
280    private class WiredHeadsetBroadcastReceiver extends BroadcastReceiver {
281        @Override
282        public void onReceive(Context context, Intent intent) {
283            final String action = intent.getAction();
284            if (AudioManager.ACTION_HEADSET_PLUG.equals(action) ||
285                    AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
286                updateState(mPreference);
287            }
288        }
289    }
290
291    /** Callback for cast device events. */
292    private class MediaRouterCallback extends Callback {
293        @Override
294        public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
295        }
296
297        @Override
298        public void onRouteUnselected(MediaRouter router, int type, MediaRouter.RouteInfo info) {
299        }
300
301        @Override
302        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
303            if (info != null && !info.isDefault()) {
304                // cast mode
305                updateState(mPreference);
306            }
307        }
308
309        @Override
310        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
311        }
312
313        @Override
314        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
315            if (info != null && !info.isDefault()) {
316                // cast mode
317                updateState(mPreference);
318            }
319        }
320
321        @Override
322        public void onRouteGrouped(MediaRouter router, MediaRouter.RouteInfo info,
323                MediaRouter.RouteGroup group, int index) {
324        }
325
326        @Override
327        public void onRouteUngrouped(MediaRouter router, MediaRouter.RouteInfo info,
328                MediaRouter.RouteGroup group) {
329        }
330
331        @Override
332        public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo info) {
333        }
334    }
335}
336