1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.developeroptions.sound; 18 19 import static android.media.AudioManager.STREAM_MUSIC; 20 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 21 22 import android.bluetooth.BluetoothDevice; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.media.AudioManager; 26 import android.text.TextUtils; 27 28 import androidx.preference.Preference; 29 30 import com.android.car.developeroptions.R; 31 import com.android.settingslib.Utils; 32 import com.android.settingslib.bluetooth.A2dpProfile; 33 import com.android.settingslib.bluetooth.HearingAidProfile; 34 import com.android.settingslib.media.MediaOutputSliceConstants; 35 36 import java.util.List; 37 38 /** 39 * This class allows launching MediaOutputSlice to switch output device. 40 * Preference would hide only when 41 * - Bluetooth = OFF 42 * - Bluetooth = ON and Connected Devices = 0 and Previously Connected = 0 43 * - Media stream captured by remote device 44 * - During a call. 45 */ 46 public class MediaOutputPreferenceController extends AudioSwitchPreferenceController { 47 MediaOutputPreferenceController(Context context, String key)48 public MediaOutputPreferenceController(Context context, String key) { 49 super(context, key); 50 } 51 52 @Override updateState(Preference preference)53 public void updateState(Preference preference) { 54 if (preference == null) { 55 // In case UI is not ready. 56 return; 57 } 58 59 if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) { 60 // In cast mode, disable switch entry. 61 mPreference.setVisible(false); 62 preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable)); 63 return; 64 } 65 66 if (Utils.isAudioModeOngoingCall(mContext)) { 67 // Ongoing call status, switch entry for media will be disabled. 68 mPreference.setVisible(false); 69 preference.setSummary( 70 mContext.getText(R.string.media_out_summary_ongoing_call_state)); 71 return; 72 } 73 74 boolean deviceConnectable = false; 75 BluetoothDevice activeDevice = null; 76 // Show preference if there is connected or previously connected device 77 // Find active device and set its name as the preference's summary 78 List<BluetoothDevice> connectableA2dpDevices = getConnectableA2dpDevices(); 79 List<BluetoothDevice> connectableHADevices = getConnectableHearingAidDevices(); 80 if (mAudioManager.getMode() == AudioManager.MODE_NORMAL 81 && ((connectableA2dpDevices != null && !connectableA2dpDevices.isEmpty()) 82 || (connectableHADevices != null && !connectableHADevices.isEmpty()))) { 83 deviceConnectable = true; 84 activeDevice = findActiveDevice(); 85 } 86 mPreference.setVisible(deviceConnectable); 87 mPreference.setSummary((activeDevice == null) ? 88 mContext.getText(R.string.media_output_default_summary) : 89 activeDevice.getAlias()); 90 } 91 92 @Override findActiveDevice()93 public BluetoothDevice findActiveDevice() { 94 BluetoothDevice activeDevice = findActiveHearingAidDevice(); 95 final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); 96 97 if (activeDevice == null && a2dpProfile != null) { 98 activeDevice = a2dpProfile.getActiveDevice(); 99 } 100 return activeDevice; 101 } 102 103 /** 104 * Find active hearing aid device 105 */ 106 @Override findActiveHearingAidDevice()107 protected BluetoothDevice findActiveHearingAidDevice() { 108 final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); 109 110 if (hearingAidProfile != null) { 111 List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices(); 112 for (BluetoothDevice btDevice : activeDevices) { 113 if (btDevice != null) { 114 return btDevice; 115 } 116 } 117 } 118 return null; 119 } 120 121 @Override handlePreferenceTreeClick(Preference preference)122 public boolean handlePreferenceTreeClick(Preference preference) { 123 if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { 124 final Intent intent = new Intent() 125 .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) 126 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 127 mContext.startActivity(intent); 128 return true; 129 } 130 return false; 131 } 132 } 133