1 /*
2  * Copyright (C) 2022 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.settings.bluetooth;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.content.Context;
21 
22 import androidx.preference.PreferenceFragmentCompat;
23 import androidx.preference.PreferenceScreen;
24 
25 import com.android.settings.R;
26 import com.android.settings.applications.SpacePreference;
27 import com.android.settings.core.SubSettingLauncher;
28 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
29 import com.android.settingslib.bluetooth.HearingAidInfo;
30 import com.android.settingslib.core.lifecycle.Lifecycle;
31 import com.android.settingslib.widget.ButtonPreference;
32 
33 import com.google.common.annotations.VisibleForTesting;
34 
35 import java.util.Set;
36 
37 /**
38  * This class handles button preference logic to display for hearing aid device.
39  */
40 public class BluetoothDetailsPairOtherController extends BluetoothDetailsController {
41     private static final String KEY_PAIR_OTHER = "hearing_aid_pair_other_button";
42     @VisibleForTesting
43     static final String KEY_SPACE = "hearing_aid_space_layout";
44 
45     private ButtonPreference mPreference;
46     private SpacePreference mSpacePreference;
47 
BluetoothDetailsPairOtherController(Context context, PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle)48     public BluetoothDetailsPairOtherController(Context context,
49             PreferenceFragmentCompat fragment,
50             CachedBluetoothDevice device,
51             Lifecycle lifecycle) {
52         super(context, fragment, device, lifecycle);
53         lifecycle.addObserver(this);
54     }
55 
56     @Override
isAvailable()57     public boolean isAvailable() {
58         return getButtonPreferenceVisibility(mCachedDevice);
59     }
60 
61     @Override
getPreferenceKey()62     public String getPreferenceKey() {
63         return KEY_PAIR_OTHER;
64     }
65 
66     @Override
init(PreferenceScreen screen)67     protected void init(PreferenceScreen screen) {
68         mPreference = screen.findPreference(getPreferenceKey());
69         mSpacePreference = screen.findPreference(KEY_SPACE);
70         updateButtonPreferenceTitle(mPreference);
71         setPreferencesVisibility(getButtonPreferenceVisibility(mCachedDevice));
72         mPreference.setOnClickListener(v -> launchPairingDetail());
73     }
74 
75     @Override
refresh()76     protected void refresh() {
77         updateButtonPreferenceTitle(mPreference);
78         setPreferencesVisibility(getButtonPreferenceVisibility(mCachedDevice));
79     }
80 
updateButtonPreferenceTitle(ButtonPreference preference)81     private void updateButtonPreferenceTitle(ButtonPreference preference) {
82         final int side = mCachedDevice.getDeviceSide();
83         final int stringRes = (side == HearingAidInfo.DeviceSide.SIDE_LEFT)
84                 ? R.string.bluetooth_pair_right_ear_button
85                 : R.string.bluetooth_pair_left_ear_button;
86 
87         preference.setTitle(stringRes);
88     }
89 
setPreferencesVisibility(boolean visible)90     private void setPreferencesVisibility(boolean visible) {
91         mPreference.setVisible(visible);
92         mSpacePreference.setVisible(visible);
93     }
94 
getButtonPreferenceVisibility(CachedBluetoothDevice cachedDevice)95     private boolean getButtonPreferenceVisibility(CachedBluetoothDevice cachedDevice) {
96         // The device is not connected yet. Don't show the button.
97         if (!cachedDevice.isConnectedHearingAidDevice()) {
98             return false;
99         }
100         return isBinauralMode(cachedDevice) && !isOtherSideBonded(cachedDevice);
101     }
102 
launchPairingDetail()103     private void launchPairingDetail() {
104         new SubSettingLauncher(mContext)
105                 .setDestination(BluetoothPairingDetail.class.getName())
106                 .setSourceMetricsCategory(
107                         ((BluetoothDeviceDetailsFragment) mFragment).getMetricsCategory())
108                 .launch();
109     }
110 
isBinauralMode(CachedBluetoothDevice cachedDevice)111     private boolean isBinauralMode(CachedBluetoothDevice cachedDevice) {
112         return cachedDevice.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL;
113     }
114 
isOtherSideBonded(CachedBluetoothDevice cachedDevice)115     private boolean isOtherSideBonded(CachedBluetoothDevice cachedDevice) {
116         final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
117         final boolean subDeviceBonded =
118                 subDevice != null && subDevice.getBondState() == BluetoothDevice.BOND_BONDED;
119 
120         final Set<CachedBluetoothDevice> memberDevice = cachedDevice.getMemberDevice();
121         final boolean allMemberDevicesBonded =
122                 !memberDevice.isEmpty() && memberDevice.stream().allMatch(
123                         device -> device.getBondState() == BluetoothDevice.BOND_BONDED);
124 
125         return subDeviceBonded || allMemberDevicesBonded;
126     }
127 }
128