diff --git a/res/values/strings.xml b/res/values/strings.xml index dd9746610ae..fad70361b06 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -129,7 +129,9 @@ For all available hearing devices - Shortcuts & hearing aid compatibility + Hearing device settings + + Audio output, shortcut, hearing aid compatibility For this device diff --git a/res/xml/bluetooth_audio_routing_fragment.xml b/res/xml/accessibility_audio_routing_fragment.xml similarity index 85% rename from res/xml/bluetooth_audio_routing_fragment.xml rename to res/xml/accessibility_audio_routing_fragment.xml index 5edf6cdca41..12e75f22ab1 100644 --- a/res/xml/bluetooth_audio_routing_fragment.xml +++ b/res/xml/accessibility_audio_routing_fragment.xml @@ -31,7 +31,7 @@ android:key="audio_routing_ringtone" android:persistent="false" android:title="@string/bluetooth_ringtone_title" - settings:controller="com.android.settings.bluetooth.HearingDeviceRingtoneRoutingPreferenceController" /> + settings:controller="com.android.settings.accessibility.HearingDeviceRingtoneRoutingPreferenceController" /> + settings:controller="com.android.settings.accessibility.HearingDeviceCallRoutingPreferenceController" /> + settings:controller="com.android.settings.accessibility.HearingDeviceMediaRoutingPreferenceController" /> + settings:controller="com.android.settings.accessibility.HearingDeviceSystemSoundsRoutingPreferenceController" /> + + + - - + android:key="device_controls_general" /> diff --git a/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java new file mode 100644 index 00000000000..6eb2112d294 --- /dev/null +++ b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; + +import android.app.settings.SettingsEnums; + +import com.android.settings.R; +import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; + +/** Settings fragment containing bluetooth audio routing. */ +public class AccessibilityAudioRoutingFragment extends RestrictedDashboardFragment { + private static final String TAG = "AccessibilityAudioRoutingFragment"; + + public AccessibilityAudioRoutingFragment() { + super(DISALLOW_CONFIG_BLUETOOTH); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.HEARING_AID_AUDIO_ROUTING; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.accessibility_audio_routing_fragment; + } + + @Override + protected String getLogTag() { + return TAG; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.accessibility_audio_routing_fragment); +} diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java index cd76b47c22b..e4611fe97b3 100644 --- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java +++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java @@ -17,7 +17,6 @@ package com.android.settings.accessibility; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothLeAudio; @@ -41,20 +40,14 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.HapClientProfile; import com.android.settingslib.bluetooth.HearingAidInfo; -import com.android.settingslib.bluetooth.HearingAidProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; -import java.util.ArrayList; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; /** * Controller that shows and updates the bluetooth device name @@ -73,10 +66,8 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC }; private final LocalBluetoothManager mLocalBluetoothManager; - private final BluetoothAdapter mBluetoothAdapter; private final LocalBluetoothProfileManager mProfileManager; - private final CachedBluetoothDeviceManager mCachedDeviceManager; - + private final HearingAidHelper mHelper; private FragmentManager mFragmentManager; public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) { @@ -84,8 +75,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC mLocalBluetoothManager = com.android.settings.bluetooth.Utils.getLocalBluetoothManager( context); mProfileManager = mLocalBluetoothManager.getProfileManager(); - mCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mHelper = new HearingAidHelper(context); } @Override @@ -96,7 +86,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @Override public int getAvailabilityStatus() { - return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return mHelper.isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override @@ -111,7 +101,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC // Can't get connected hearing aids when hearing aids related profiles are not ready. The // profiles will be ready after the services are connected. Needs to add listener and // updates the information when all hearing aids related services are connected. - if (isAnyHearingAidRelatedProfilesNotReady()) { + if (!mHelper.isAllHearingAidRelatedProfilesReady()) { mProfileManager.addServiceListener(this); } } @@ -126,7 +116,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @Override public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { - final CachedBluetoothDevice device = getConnectedHearingAidDevice(); + final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice(); if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE)) { launchHearingAidPage(); @@ -144,10 +134,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @Override public CharSequence getSummary() { - if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { - return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary); - } - final CachedBluetoothDevice device = getConnectedHearingAidDevice(); + final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice(); if (device == null) { return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary); } @@ -203,7 +190,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC @Override public void onServiceConnected() { - if (!isAnyHearingAidRelatedProfilesNotReady()) { + if (mHelper.isAllHearingAidRelatedProfilesReady()) { updateState(mHearingAidPreference); mProfileManager.removeServiceListener(this); } @@ -218,53 +205,8 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC mFragmentManager = fragmentManager; } - @VisibleForTesting - CachedBluetoothDevice getConnectedHearingAidDevice() { - final List deviceList = getConnectedHearingAidDeviceList(); - return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0)); - } - private int getConnectedHearingAidDeviceNum() { - return getConnectedHearingAidDeviceList().size(); - } - - private List getConnectedHearingAidDeviceList() { - if (!isHearingAidSupported()) { - return new ArrayList<>(); - } - final List deviceList = new ArrayList<>(); - final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile(); - if (hapClientProfile != null) { - deviceList.addAll(hapClientProfile.getConnectedDevices()); - } - final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); - if (hearingAidProfile != null) { - deviceList.addAll(hearingAidProfile.getConnectedDevices()); - } - return deviceList.stream() - .distinct() - .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList()); - } - - private boolean isHearingAidSupported() { - if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { - return false; - } - final List supportedList = mBluetoothAdapter.getSupportedProfiles(); - return supportedList.contains(BluetoothProfile.HEARING_AID) - || supportedList.contains(BluetoothProfile.HAP_CLIENT); - } - - private boolean isAnyHearingAidRelatedProfilesNotReady() { - HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); - if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) { - return true; - } - HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile(); - if (hapClientProfile != null && !hapClientProfile.isProfileReady()) { - return true; - } - return false; + return mHelper.getConnectedHearingAidDeviceList().size(); } @VisibleForTesting(otherwise = VisibleForTesting.NONE) diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java index 547c4568991..33fef62f205 100644 --- a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java +++ b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java @@ -39,7 +39,7 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe private static final String TAG = "AccessibilityHearingAidsFragment"; private static final String KEY_HEARING_OPTIONS_CATEGORY = "hearing_options_category"; - private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1; + private static final int SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX = 20; private String mFeatureName; public AccessibilityHearingAidsFragment() { @@ -65,7 +65,7 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe final View view = super.onCreateView(inflater, container, savedInstanceState); final PreferenceCategory controlCategory = findPreference(KEY_HEARING_OPTIONS_CATEGORY); // To move the shortcut preference under controlCategory need to remove the original added. - mShortcutPreference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX); + mShortcutPreference.setOrder(SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX); getPreferenceScreen().removePreference(mShortcutPreference); controlCategory.addPreference(mShortcutPreference); return view; diff --git a/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java new file mode 100644 index 00000000000..54022ef7f9e --- /dev/null +++ b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import android.content.Context; +import android.util.FeatureFlagUtils; + +import com.android.settings.core.BasePreferenceController; + +/** + * The controller of the audio routing. + */ +public class HearingAidAudioRoutingPreferenceController extends BasePreferenceController { + public HearingAidAudioRoutingPreferenceController(Context context, + String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING) + ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/accessibility/HearingAidHelper.java b/src/com/android/settings/accessibility/HearingAidHelper.java new file mode 100644 index 00000000000..66a37f8dd58 --- /dev/null +++ b/src/com/android/settings/accessibility/HearingAidHelper.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.HapClientProfile; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A helper class to get and check hearing aids and its status. + */ +public class HearingAidHelper { + + private final BluetoothAdapter mBluetoothAdapter; + private final LocalBluetoothProfileManager mProfileManager; + private final CachedBluetoothDeviceManager mCachedDeviceManager; + + public HearingAidHelper(Context context) { + final LocalBluetoothManager localBluetoothManager = + com.android.settings.bluetooth.Utils.getLocalBluetoothManager(context); + mProfileManager = localBluetoothManager.getProfileManager(); + mCachedDeviceManager = localBluetoothManager.getCachedDeviceManager(); + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + + /** + * Gets the connected hearing aids device whose profiles are + * {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}. + * + * @return a list of hearing aids {@link BluetoothDevice} objects + */ + public List getConnectedHearingAidDeviceList() { + if (!isHearingAidSupported()) { + return new ArrayList<>(); + } + final List deviceList = new ArrayList<>(); + final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile(); + if (hapClientProfile != null) { + deviceList.addAll(hapClientProfile.getConnectedDevices()); + } + final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); + if (hearingAidProfile != null) { + deviceList.addAll(hearingAidProfile.getConnectedDevices()); + } + return deviceList.stream() + .distinct() + .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList()); + } + + /** + * Gets the first connected hearing aids device. + * + * @return a {@link CachedBluetoothDevice} that is hearing aids device + */ + public CachedBluetoothDevice getConnectedHearingAidDevice() { + final List deviceList = getConnectedHearingAidDeviceList(); + return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0)); + } + + /** + * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT} + * supported. + */ + public boolean isHearingAidSupported() { + if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { + return false; + } + final List supportedList = mBluetoothAdapter.getSupportedProfiles(); + return supportedList.contains(BluetoothProfile.HEARING_AID) + || supportedList.contains(BluetoothProfile.HAP_CLIENT); + } + + /** + * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT} + * profiles all ready. + */ + public boolean isAllHearingAidRelatedProfilesReady() { + HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); + if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) { + return false; + } + HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile(); + if (hapClientProfile != null && !hapClientProfile.isProfileReady()) { + return false; + } + return true; + } +} diff --git a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java similarity index 79% rename from src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java rename to src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java index e93863ae064..3599f4874c4 100644 --- a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java +++ b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import android.content.ContentResolver; import android.content.Context; @@ -47,19 +47,24 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends private static final String TAG = "HARoutingBasePreferenceController"; private static final boolean DEBUG = false; - private final HearingAidAudioRoutingHelper mHelper; + private final HearingAidAudioRoutingHelper mAudioRoutingHelper; + private final HearingAidHelper mHearingAidHelper; public HearingDeviceAudioRoutingBasePreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - mHelper = new HearingAidAudioRoutingHelper(context); + this(context, preferenceKey, + new HearingAidAudioRoutingHelper(context), + new HearingAidHelper(context)); } @VisibleForTesting public HearingDeviceAudioRoutingBasePreferenceController(Context context, - String preferenceKey, HearingAidAudioRoutingHelper helper) { + String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper, + HearingAidHelper hearingAidHelper) { super(context, preferenceKey); - mHelper = helper; + + mAudioRoutingHelper = audioRoutingHelper; + mHearingAidHelper = hearingAidHelper; } @Override @@ -81,7 +86,11 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends final Integer routingValue = Ints.tryParse((String) newValue); saveRoutingValue(mContext, routingValue); - trySetAudioRoutingConfig(getSupportedAttributeList(), getHearingDevice(), routingValue); + final CachedBluetoothDevice device = mHearingAidHelper.getConnectedHearingAidDevice(); + if (device != null) { + trySetAudioRoutingConfig(getSupportedAttributeList(), + mHearingAidHelper.getConnectedHearingAidDevice(), routingValue); + } return true; } @@ -89,10 +98,10 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends private void trySetAudioRoutingConfig(int[] audioAttributes, CachedBluetoothDevice hearingDevice, @HearingAidAudioRoutingConstants.RoutingValue int routingValue) { - final List supportedStrategies = mHelper.getSupportedStrategies( - audioAttributes); + final List supportedStrategies = + mAudioRoutingHelper.getSupportedStrategies(audioAttributes); final AudioDeviceAttributes hearingDeviceAttributes = - mHelper.getMatchedHearingDeviceAttributes(hearingDevice); + mAudioRoutingHelper.getMatchedHearingDeviceAttributes(hearingDevice); if (hearingDeviceAttributes == null) { if (DEBUG) { Log.d(TAG, @@ -103,8 +112,8 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends return; } - final boolean status = mHelper.setPreferredDeviceRoutingStrategies(supportedStrategies, - hearingDeviceAttributes, routingValue); + final boolean status = mAudioRoutingHelper.setPreferredDeviceRoutingStrategies( + supportedStrategies, hearingDeviceAttributes, routingValue); if (!status) { final List strategiesName = supportedStrategies.stream() @@ -121,12 +130,6 @@ public abstract class HearingDeviceAudioRoutingBasePreferenceController extends */ protected abstract int[] getSupportedAttributeList(); - /** - * Gets the {@link CachedBluetoothDevice} hearing device that is used to configure audio - * routing. - */ - protected abstract CachedBluetoothDevice getHearingDevice(); - /** * Saves the routing value. * diff --git a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java similarity index 81% rename from src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java rename to src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java index 4e5e1937b11..8ca266359c2 100644 --- a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java +++ b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import android.content.Context; import android.provider.Settings; @@ -35,15 +35,6 @@ public class HearingDeviceCallRoutingPreferenceController extends super(context, preferenceKey); } - /** - * Initializes objects in this controller. Need to call this before using the controller. - * - * @param cachedBluetoothDevice the hearing device to configure audio routing - */ - public void init(CachedBluetoothDevice cachedBluetoothDevice) { - mHearingDevice = cachedBluetoothDevice; - } - @Override public int getAvailabilityStatus() { return Utils.isVoiceCapable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; @@ -54,11 +45,6 @@ public class HearingDeviceCallRoutingPreferenceController extends return HearingAidAudioRoutingConstants.CALL_ROUTING_ATTRIBUTES; } - @Override - protected CachedBluetoothDevice getHearingDevice() { - return mHearingDevice; - } - @Override protected void saveRoutingValue(Context context, int routingValue) { Settings.Secure.putInt(context.getContentResolver(), diff --git a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java similarity index 79% rename from src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java rename to src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java index 1ea36c783e2..cd99ce0c0d0 100644 --- a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java +++ b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import android.content.Context; import android.provider.Settings; @@ -34,26 +34,12 @@ public class HearingDeviceMediaRoutingPreferenceController extends super(context, preferenceKey); } - /** - * Initializes objects in this controller. Need to call this before using the controller. - * - * @param cachedBluetoothDevice the hearing device to configure audio routing - */ - public void init(CachedBluetoothDevice cachedBluetoothDevice) { - mHearingDevice = cachedBluetoothDevice; - } - @Override protected int[] getSupportedAttributeList() { return HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES; } - @Override - protected CachedBluetoothDevice getHearingDevice() { - return mHearingDevice; - } - @Override protected void saveRoutingValue(Context context, int routingValue) { Settings.Secure.putInt(context.getContentResolver(), diff --git a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java similarity index 80% rename from src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java rename to src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java index 006cb6b217a..3e8f79cec29 100644 --- a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java +++ b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import android.content.Context; import android.provider.Settings; @@ -34,26 +34,12 @@ public class HearingDeviceRingtoneRoutingPreferenceController extends super(context, preferenceKey); } - /** - * Initializes objects in this controller. Need to call this before using the controller. - * - * @param cachedBluetoothDevice the hearing device to configure audio routing - */ - public void init(CachedBluetoothDevice cachedBluetoothDevice) { - mHearingDevice = cachedBluetoothDevice; - } - @Override protected int[] getSupportedAttributeList() { return HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE; } - @Override - protected CachedBluetoothDevice getHearingDevice() { - return mHearingDevice; - } - @Override protected void saveRoutingValue(Context context, int routingValue) { Settings.Secure.putInt(context.getContentResolver(), diff --git a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java similarity index 80% rename from src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java rename to src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java index a66cfab93a0..1bc0090c7e9 100644 --- a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java +++ b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import android.content.Context; import android.provider.Settings; @@ -35,26 +35,12 @@ public class HearingDeviceSystemSoundsRoutingPreferenceController extends super(context, preferenceKey); } - /** - * Initializes objects in this controller. Need to call this before using the controller. - * - * @param cachedBluetoothDevice the hearing device to configure audio routing - */ - public void init(CachedBluetoothDevice cachedBluetoothDevice) { - mHearingDevice = cachedBluetoothDevice; - } - @Override protected int[] getSupportedAttributeList() { return HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES; } - @Override - protected CachedBluetoothDevice getHearingDevice() { - return mHearingDevice; - } - @Override protected void saveRoutingValue(Context context, int routingValue) { Settings.Secure.putInt(context.getContentResolver(), diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java deleted file mode 100644 index 91221a33ba9..00000000000 --- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.bluetooth; - -import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS; - -import android.content.Context; -import android.os.Bundle; -import android.util.FeatureFlagUtils; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.core.lifecycle.Lifecycle; - -/** - * The controller of the audio routing in the bluetooth detail settings. - */ -public class BluetoothDetailsAudioRoutingController extends BluetoothDetailsController { - - private static final String KEY_DEVICE_CONTROLS_SPECIFIC_GROUP = "device_controls_specific"; - @VisibleForTesting - static final String KEY_AUDIO_ROUTING = "audio_routing"; - - public BluetoothDetailsAudioRoutingController(Context context, - PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle) { - super(context, fragment, device, lifecycle); - } - - @Override - public boolean isAvailable() { - return mCachedDevice.isHearingAidDevice() && FeatureFlagUtils.isEnabled(mContext, - FeatureFlagUtils.SETTINGS_AUDIO_ROUTING); - } - - @Override - protected void init(PreferenceScreen screen) { - if (!mCachedDevice.isHearingAidDevice()) { - return; - } - - final PreferenceCategory prefCategory = screen.findPreference(getPreferenceKey()); - final Preference pref = createAudioRoutingPreference(prefCategory.getContext()); - prefCategory.addPreference(pref); - } - - @Override - protected void refresh() {} - - @Override - public String getPreferenceKey() { - return KEY_DEVICE_CONTROLS_SPECIFIC_GROUP; - } - - private Preference createAudioRoutingPreference(Context context) { - final Preference preference = new Preference(context); - - preference.setKey(KEY_AUDIO_ROUTING); - preference.setTitle(context.getString(R.string.bluetooth_audio_routing_title)); - preference.setSummary(context.getString(R.string.bluetooth_audio_routing_summary)); - final Bundle extras = preference.getExtras(); - extras.putString(KEY_DEVICE_ADDRESS, mCachedDevice.getAddress()); - preference.setFragment(BluetoothDetailsAudioRoutingFragment.class.getName()); - - return preference; - } -} diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java deleted file mode 100644 index 6c435a27cd2..00000000000 --- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.bluetooth; - -import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; - -import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS; - -import android.app.settings.SettingsEnums; -import android.bluetooth.BluetoothDevice; -import android.content.Context; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; - -import com.android.settings.R; -import com.android.settings.dashboard.RestrictedDashboardFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.LocalBluetoothManager; - -/** Settings fragment containing bluetooth audio routing. */ -public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFragment { - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.bluetooth_audio_routing_fragment); - private static final String TAG = "BluetoothDetailsAudioRoutingFragment"; - @VisibleForTesting - CachedBluetoothDevice mCachedDevice; - - public BluetoothDetailsAudioRoutingFragment() { - super(DISALLOW_CONFIG_BLUETOOTH); - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - final LocalBluetoothManager localBtMgr = Utils.getLocalBtManager(context); - final CachedBluetoothDeviceManager cachedDeviceMgr = localBtMgr.getCachedDeviceManager(); - final BluetoothDevice bluetoothDevice = localBtMgr.getBluetoothAdapter().getRemoteDevice( - getArguments().getString(KEY_DEVICE_ADDRESS)); - - mCachedDevice = cachedDeviceMgr.findDevice(bluetoothDevice); - if (mCachedDevice == null) { - // Close this page if device is null with invalid device mac address - Log.w(TAG, "onAttach() CachedDevice is null! Can not find address: " - + bluetoothDevice.getAnonymizedAddress()); - finish(); - return; - } - - use(HearingDeviceRingtoneRoutingPreferenceController.class).init(mCachedDevice); - use(HearingDeviceCallRoutingPreferenceController.class).init(mCachedDevice); - use(HearingDeviceMediaRoutingPreferenceController.class).init(mCachedDevice); - use(HearingDeviceSystemSoundsRoutingPreferenceController.class).init(mCachedDevice); - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.BLUETOOTH_AUDIO_ROUTING; - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.bluetooth_audio_routing_fragment; - } - - @Override - protected String getLogTag() { - return TAG; - } -} diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java index a3b1105015d..c4a422186dd 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java @@ -34,7 +34,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import com.google.common.annotations.VisibleForTesting; /** - * The controller of the hearing device controls in the bluetooth detail settings. + * The controller of the hearing device settings to launch Hearing device page. */ public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController implements Preference.OnPreferenceClickListener { @@ -87,6 +87,7 @@ public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDe final Preference preference = new Preference(context); preference.setKey(KEY_HEARING_DEVICE_CONTROLS); preference.setTitle(context.getString(R.string.bluetooth_device_controls_title)); + preference.setSummary(context.getString(R.string.bluetooth_device_controls_summary)); preference.setOnPreferenceClickListener(this); return preference; diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java index 2a94b1e077e..99f3e3187cb 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java @@ -314,8 +314,6 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment lifecycle)); controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this, mCachedDevice, lifecycle)); - controllers.add(new BluetoothDetailsAudioRoutingController(context, this, mCachedDevice, - lifecycle)); } return controllers; } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java index 5ee7ab3d13c..c68e90bdc17 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java @@ -24,25 +24,22 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; -import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.bluetooth.Utils; -import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; -import com.android.settings.utils.ActivityControllerWrapper; import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; @@ -55,11 +52,12 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.After; import org.junit.Before; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.Robolectric; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; @@ -74,6 +72,9 @@ import java.util.Set; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) public class AccessibilityHearingAidPreferenceControllerTest { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2"; private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME"; @@ -82,7 +83,8 @@ public class AccessibilityHearingAidPreferenceControllerTest { private BluetoothAdapter mBluetoothAdapter; private ShadowBluetoothAdapter mShadowBluetoothAdapter; private BluetoothDevice mBluetoothDevice; - private Activity mContext; + private final Context mContext = ApplicationProvider.getApplicationContext(); + private Preference mHearingAidPreference; private AccessibilityHearingAidPreferenceController mPreferenceController; private ShadowApplication mShadowApplication; @@ -106,11 +108,7 @@ public class AccessibilityHearingAidPreferenceControllerTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); mShadowApplication = ShadowApplication.getInstance(); - - mContext = spy((Activity) ActivityControllerWrapper.setup( - Robolectric.buildActivity(Activity.class)).get()); setupEnvironment(); mHearingAidPreference = new Preference(mContext); @@ -274,65 +272,6 @@ public class AccessibilityHearingAidPreferenceControllerTest { verify(mPreferenceController).launchBluetoothDeviceDetailSetting(mCachedBluetoothDevice); } - @Test - public void onSupportHearingAidProfile_isAvailable() { - mShadowBluetoothAdapter.clearSupportedProfiles(); - mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); - mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext, - HEARING_AID_PREFERENCE); - mPreferenceController.setPreference(mHearingAidPreference); - - assertThat(mPreferenceController.isAvailable()).isTrue(); - } - - @Test - public void onSupportHapClientProfile_isAvailable() { - mShadowBluetoothAdapter.clearSupportedProfiles(); - mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT); - mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext, - HEARING_AID_PREFERENCE); - mPreferenceController.setPreference(mHearingAidPreference); - - assertThat(mPreferenceController.isAvailable()).isTrue(); - } - - @Test - public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() { - mShadowBluetoothAdapter.clearSupportedProfiles(); - mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext, - HEARING_AID_PREFERENCE); - mPreferenceController.setPreference(mHearingAidPreference); - - assertThat(mPreferenceController.isAvailable()).isFalse(); - } - - @Test - public void getConnectedHearingAidDevice_doNotReturnSubDevice() { - when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList()); - when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(mBluetoothDevice)) - .thenReturn(true); - - assertThat(mPreferenceController.getConnectedHearingAidDevice()).isNull(); - } - - @Test - @Config(shadows = ShadowAlertDialogCompat.class) - public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() { - final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class); - when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); - when(mCachedBluetoothDevice.getDeviceMode()).thenReturn( - HearingAidInfo.DeviceMode.MODE_BINAURAL); - when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( - HearingAidInfo.DeviceSide.SIDE_LEFT); - mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager()); - - mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice, - BluetoothProfile.HEARING_AID); - - final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); - assertThat(dialog.isShowing()).isTrue(); - } - @Test public void onServiceConnected_onHearingAidProfileConnected_updateSummary() { when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java new file mode 100644 index 00000000000..d16bc4351c3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.util.FeatureFlagUtils; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link HearingAidAudioRoutingPreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class HearingAidAudioRoutingPreferenceControllerTest { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + + private HearingAidAudioRoutingPreferenceController mController; + + @Before + public void setUp() { + mController = new HearingAidAudioRoutingPreferenceController(mContext, "test_key"); + } + + @Test + public void getAvailabilityStatus_audioRoutingNotSupported_returnUnsupported() { + FeatureFlagUtils.setEnabled(mContext, + FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, false); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getAvailabilityStatus_audioRoutingNotSupported_available() { + FeatureFlagUtils.setEnabled(mContext, + FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java new file mode 100644 index 00000000000..194b766dd75 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.bluetooth.Utils; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.HapClientProfile; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +import java.util.ArrayList; +import java.util.Collections; + +/** Tests for {@link HearingAidHelper}. */ +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) +public class HearingAidHelperTest { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + private final Context mContext = ApplicationProvider.getApplicationContext(); + private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; + + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private LocalBluetoothProfileManager mLocalBluetoothProfileManager; + @Mock + private CachedBluetoothDeviceManager mCachedDeviceManager; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private HearingAidProfile mHearingAidProfile; + @Mock + private HapClientProfile mHapClientProfile; + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + private BluetoothAdapter mBluetoothAdapter; + private BluetoothDevice mBluetoothDevice; + private HearingAidHelper mHelper; + + @Before + public void setUp() { + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; + mLocalBluetoothManager = Utils.getLocalBtManager(mContext); + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter); + mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS); + when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); + when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice); + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); + when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); + + mHelper = new HearingAidHelper(mContext); + } + + @Test + public void isHearingAidSupported_supported_returnTrue() { + mBluetoothAdapter.enable(); + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); + + assertThat(mHelper.isHearingAidSupported()).isTrue(); + } + + @Test + public void isHearingAidSupported_bluetoothOff_returnFalse() { + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); + mBluetoothAdapter.disable(); + + assertThat(mHelper.isHearingAidSupported()).isFalse(); + } + + + @Test + public void isAllHearingAidRelatedProfilesReady_allReady_returnTrue() { + when(mHearingAidProfile.isProfileReady()).thenReturn(true); + when(mHapClientProfile.isProfileReady()).thenReturn(true); + + assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isTrue(); + } + + @Test + public void isAllHearingAidRelatedProfilesReady_notFullReady_returnFalse() { + when(mHearingAidProfile.isProfileReady()).thenReturn(false); + when(mHapClientProfile.isProfileReady()).thenReturn(true); + + assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isFalse(); + } + + @Test + public void getConnectedHearingAidDeviceList_oneDeviceAdded_getOneDevice() { + mBluetoothAdapter.enable(); + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); + when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>( + Collections.singletonList(mBluetoothDevice))); + + assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(1); + } + + @Test + public void getConnectedHearingAidDeviceList_oneSubDeviceAdded_getZeroDevice() { + mBluetoothAdapter.enable(); + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); + when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>( + Collections.singletonList(mBluetoothDevice))); + when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice( + mBluetoothDevice)).thenReturn(true); + + assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(0); + } + + @Test + public void getConnectedHearingAidDevice_getExpectedCachedBluetoothDevice() { + mBluetoothAdapter.enable(); + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); + when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>( + Collections.singletonList(mBluetoothDevice))); + + assertThat(mHelper.getConnectedHearingAidDevice()).isEqualTo(mCachedBluetoothDevice); + assertThat(mCachedBluetoothDevice.getAddress()).isEqualTo(mBluetoothDevice.getAddress()); + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java similarity index 70% rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java index 105da6546ad..4decf68d68c 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -37,9 +38,15 @@ import androidx.preference.ListPreference; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.bluetooth.Utils; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants; import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.Before; import org.junit.Rule; @@ -50,11 +57,13 @@ import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; import java.util.List; /** Tests for {@link HearingDeviceAudioRoutingBasePreferenceController}. */ @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) public class HearingDeviceAudioRoutingBasePreferenceControllerTest { @Rule @@ -63,8 +72,14 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { @Spy private final Context mContext = ApplicationProvider.getApplicationContext(); private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; - private static final String FAKE_KEY = "fake_key"; + private final ListPreference mListPreference = new ListPreference(mContext); + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private LocalBluetoothProfileManager mLocalBluetoothProfileManager; + @Mock + private CachedBluetoothDeviceManager mCachedDeviceManager; @Mock private AudioProductStrategy mAudioProductStrategyMedia; @Mock @@ -72,8 +87,10 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { @Mock private BluetoothDevice mBluetoothDevice; @Spy - private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext); - private final ListPreference mListPreference = new ListPreference(mContext); + private HearingAidAudioRoutingHelper mAudioRoutingHelper = + new HearingAidAudioRoutingHelper(mContext); + @Mock + private HearingAidHelper mHearingAidHelper; private TestHearingDeviceAudioRoutingBasePreferenceController mController; @Before @@ -83,19 +100,23 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { AudioDeviceInfo.TYPE_HEARING_AID, TEST_DEVICE_ADDRESS); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; + mLocalBluetoothManager = Utils.getLocalBtManager(mContext); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(TEST_DEVICE_ADDRESS); when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS); - when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(hearingDeviceAttribute); + doReturn(hearingDeviceAttribute).when( + mAudioRoutingHelper).getMatchedHearingDeviceAttributes(any()); when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType( - AudioManager.STREAM_MUSIC)) - .thenReturn((new AudioAttributes.Builder()).build()); - when(mHelper.getAudioProductStrategies()).thenReturn(List.of(mAudioProductStrategyMedia)); + AudioManager.STREAM_MUSIC)).thenReturn((new AudioAttributes.Builder()).build()); + when(mAudioRoutingHelper.getAudioProductStrategies()).thenReturn( + List.of(mAudioProductStrategyMedia)); - mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, FAKE_KEY, - mHelper); - TestHearingDeviceAudioRoutingBasePreferenceController.setupForTesting( - mCachedBluetoothDevice); + mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, + "test_key", + mAudioRoutingHelper, mHearingAidHelper); mListPreference.setEntries(R.array.bluetooth_audio_routing_titles); mListPreference.setEntryValues(R.array.bluetooth_audio_routing_values); mListPreference.setSummary("%s"); @@ -122,20 +143,21 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { @Test public void onPreferenceChange_noMatchedDeviceAttributes_notCallSetStrategies() { - when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null); + when(mAudioRoutingHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null); - verify(mHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), anyInt()); + verify(mAudioRoutingHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), + anyInt()); } private static class TestHearingDeviceAudioRoutingBasePreferenceController extends HearingDeviceAudioRoutingBasePreferenceController { - private static CachedBluetoothDevice sCachedBluetoothDevice; private static int sSavedRoutingValue; TestHearingDeviceAudioRoutingBasePreferenceController(Context context, - String preferenceKey, HearingAidAudioRoutingHelper helper) { - super(context, preferenceKey, helper); + String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper, + HearingAidHelper hearingAidHelper) { + super(context, preferenceKey, audioRoutingHelper, hearingAidHelper); } @Override @@ -143,11 +165,6 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { return new int[]{AudioAttributes.USAGE_MEDIA}; } - @Override - protected CachedBluetoothDevice getHearingDevice() { - return sCachedBluetoothDevice; - } - @Override protected void saveRoutingValue(Context context, int routingValue) { sSavedRoutingValue = routingValue; @@ -157,9 +174,5 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { protected int restoreRoutingValue(Context context) { return sSavedRoutingValue; } - - public static void setupForTesting(CachedBluetoothDevice cachedBluetoothDevice) { - sCachedBluetoothDevice = cachedBluetoothDevice; - } } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java similarity index 98% rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java index dec4cc4bb01..8eed2940984 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.bluetooth; +package com.android.settings.accessibility; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java deleted file mode 100644 index ea65856de61..00000000000 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.bluetooth; - -import static com.android.settings.bluetooth.BluetoothDetailsAudioRoutingController.KEY_AUDIO_ROUTING; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; - -import android.util.FeatureFlagUtils; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.robolectric.RobolectricTestRunner; - -/** Tests for {@link BluetoothDetailsAudioRoutingController}. */ -@RunWith(RobolectricTestRunner.class) -public class BluetoothDetailsAudioRoutingControllerTest extends - BluetoothDetailsControllerTestBase { - @Rule - public final MockitoRule mockito = MockitoJUnit.rule(); - - private static final String TEST_ADDRESS = "55:66:77:88:99:AA"; - - private BluetoothDetailsAudioRoutingController mController; - - @Override - public void setUp() { - super.setUp(); - - mController = new BluetoothDetailsAudioRoutingController(mContext, mFragment, mCachedDevice, - mLifecycle); - final PreferenceCategory preferenceCategory = new PreferenceCategory(mContext); - preferenceCategory.setKey(mController.getPreferenceKey()); - mScreen.addPreference(preferenceCategory); - } - - @Test - public void isAvailable_isHearingAidDevice_available() { - FeatureFlagUtils.setEnabled(mContext, - FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true); - when(mCachedDevice.isHearingAidDevice()).thenReturn(true); - - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - public void isAvailable_isNotHearingAidDevice_notAvailable() { - FeatureFlagUtils.setEnabled(mContext, - FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true); - when(mCachedDevice.isHearingAidDevice()).thenReturn(false); - - assertThat(mController.isAvailable()).isFalse(); - } - - @Test - public void init_isHearingAidDevice_expectedAudioRoutingPreference() { - when(mCachedDevice.isHearingAidDevice()).thenReturn(true); - when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); - - mController.init(mScreen); - final Preference preference = mScreen.findPreference(KEY_AUDIO_ROUTING); - final String address = preference.getExtras().getString( - BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS); - final String fragment = preference.getFragment(); - - assertThat(address).isEqualTo(TEST_ADDRESS); - assertThat(fragment).isEqualTo(BluetoothDetailsAudioRoutingFragment.class.getName()); - - } -} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java deleted file mode 100644 index 9bd4f1b8d84..00000000000 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.bluetooth; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.when; - -import android.bluetooth.BluetoothDevice; -import android.content.Context; -import android.os.Bundle; - -import androidx.test.core.app.ApplicationProvider; - -import com.android.settings.testutils.shadow.ShadowBluetoothUtils; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.LocalBluetoothAdapter; -import com.android.settingslib.bluetooth.LocalBluetoothManager; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -/** Tests for {@link BluetoothDetailsAudioRoutingFragment}. */ -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowBluetoothUtils.class}) -public class BluetoothDetailsAudioRoutingFragmentTest { - - @Rule - public MockitoRule mMockitoRule = MockitoJUnit.rule(); - - private static final String TEST_ADDRESS = "55:66:77:88:99:AA"; - - private final Context mContext = ApplicationProvider.getApplicationContext(); - - private BluetoothDetailsAudioRoutingFragment mFragment; - @Mock - private LocalBluetoothManager mLocalBluetoothManager; - @Mock - private CachedBluetoothDeviceManager mCachedDeviceManager; - @Mock - private LocalBluetoothAdapter mLocalBluetoothAdapter; - @Mock - private BluetoothDevice mBluetoothDevice; - @Mock - private CachedBluetoothDevice mCachedDevice; - - @Before - public void setUp() { - setupEnvironment(); - - when(mLocalBluetoothAdapter.getRemoteDevice(TEST_ADDRESS)).thenReturn(mBluetoothDevice); - when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); - when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice); - - mFragment = new BluetoothDetailsAudioRoutingFragment(); - } - - @Test - public void onAttach_setArgumentsWithAddress_expectedCachedDeviceWithAddress() { - final Bundle args = new Bundle(); - args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS); - mFragment.setArguments(args); - - mFragment.onAttach(mContext); - - assertThat(mFragment.mCachedDevice.getAddress()).isEqualTo(TEST_ADDRESS); - } - - private void setupEnvironment() { - ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; - when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); - when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter); - } -}