• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BluetoothLeAudioContentMetadata;
20 import android.bluetooth.BluetoothLeBroadcastMetadata;
21 import android.bluetooth.BluetoothLeBroadcastReceiveState;
22 import android.bluetooth.BluetoothLeBroadcastSubgroup;
23 import android.content.Context;
24 import android.graphics.drawable.Drawable;
25 import android.text.TextUtils;
26 import android.view.View;
27 import android.widget.ImageButton;
28 import android.widget.ImageView;
29 
30 import androidx.annotation.NonNull;
31 import androidx.preference.Preference;
32 import androidx.preference.PreferenceViewHolder;
33 
34 import com.android.settings.R;
35 import com.android.settingslib.Utils;
36 
37 import java.util.List;
38 
39 /**
40  * Preference to display a broadcast source in the Broadcast Source List.
41  */
42 class BluetoothBroadcastSourcePreference extends Preference {
43 
44     private static final int RESOURCE_ID_UNKNOWN_PROGRAM_INFO = R.string.device_info_default;
45     private static final int RESOURCE_ID_ICON = R.drawable.settings_input_antenna;
46 
47     private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
48     private BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState;
49     private ImageView mFrictionImageView;
50     private String mTitle;
51     private boolean mStatus;
52     private boolean mIsEncrypted;
53 
BluetoothBroadcastSourcePreference(@onNull Context context)54     BluetoothBroadcastSourcePreference(@NonNull Context context) {
55         super(context);
56         initUi();
57     }
58 
59     @Override
onBindViewHolder(final PreferenceViewHolder view)60     public void onBindViewHolder(final PreferenceViewHolder view) {
61         super.onBindViewHolder(view);
62         view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
63         final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button);
64         imageButton.setVisibility(View.GONE);
65         mFrictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
66         updateStatusButton();
67     }
68 
initUi()69     private void initUi() {
70         setLayoutResource(R.layout.preference_access_point);
71         setWidgetLayoutResource(R.layout.access_point_friction_widget);
72         mTitle = getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
73         mStatus = false;
74         final Drawable drawable = getContext().getDrawable(RESOURCE_ID_ICON);
75         if (drawable != null) {
76             drawable.setTint(Utils.getColorAttrDefaultColor(getContext(),
77                     android.R.attr.colorControlNormal));
78             setIcon(drawable);
79         }
80     }
81 
updateStatusButton()82     private void updateStatusButton() {
83         if (mFrictionImageView == null) {
84             return;
85         }
86         if (mStatus || mIsEncrypted) {
87             Drawable drawable;
88             if (mStatus) {
89                 drawable = getContext().getDrawable(R.drawable.bluetooth_broadcast_dialog_done);
90             } else {
91                 drawable = getContext().getDrawable(R.drawable.ic_friction_lock_closed);
92             }
93             if (drawable != null) {
94                 drawable.setTint(Utils.getColorAttrDefaultColor(getContext(),
95                         android.R.attr.colorControlNormal));
96                 mFrictionImageView.setImageDrawable(drawable);
97             }
98             mFrictionImageView.setVisibility(View.VISIBLE);
99         } else {
100             mFrictionImageView.setVisibility(View.GONE);
101         }
102     }
103 
104     /**
105      * Updates the title and status from BluetoothLeBroadcastMetadata.
106      */
updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status)107     public void updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status) {
108         mBluetoothLeBroadcastMetadata = source;
109         mTitle = getProgramInfo();
110         mIsEncrypted = mBluetoothLeBroadcastMetadata.isEncrypted();
111         mStatus = status || mBluetoothLeBroadcastReceiveState != null;
112 
113         refresh();
114     }
115 
116     /**
117      * Updates the title and status from BluetoothLeBroadcastReceiveState.
118      */
updateReceiveStateAndRefreshUi(BluetoothLeBroadcastReceiveState receiveState)119     public void updateReceiveStateAndRefreshUi(BluetoothLeBroadcastReceiveState receiveState) {
120         mBluetoothLeBroadcastReceiveState = receiveState;
121         mTitle = getProgramInfo();
122         mStatus = true;
123 
124         refresh();
125     }
126 
127     /**
128      * Gets the BluetoothLeBroadcastMetadata.
129      */
getBluetoothLeBroadcastMetadata()130     public BluetoothLeBroadcastMetadata getBluetoothLeBroadcastMetadata() {
131         return mBluetoothLeBroadcastMetadata;
132     }
133 
refresh()134     private void refresh() {
135         setTitle(mTitle);
136         updateStatusButton();
137     }
138 
getProgramInfo()139     private String getProgramInfo() {
140         if (mBluetoothLeBroadcastReceiveState != null) {
141             List<BluetoothLeAudioContentMetadata> bluetoothLeAudioContentMetadata =
142                     mBluetoothLeBroadcastReceiveState.getSubgroupMetadata();
143             if (!bluetoothLeAudioContentMetadata.isEmpty()) {
144                 return bluetoothLeAudioContentMetadata.stream()
145                         .map(i -> i.getProgramInfo())
146                         .findFirst().orElse(
147                                 getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
148             }
149         }
150         if (mBluetoothLeBroadcastMetadata == null) {
151             return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
152         }
153         final List<BluetoothLeBroadcastSubgroup> subgroups =
154                 mBluetoothLeBroadcastMetadata.getSubgroups();
155         if (subgroups.isEmpty()) {
156             return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
157         }
158         return subgroups.stream()
159                 .map(i -> i.getContentMetadata().getProgramInfo())
160                 .filter(i -> !TextUtils.isEmpty(i))
161                 .findFirst().orElse(getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
162     }
163 
164     /**
165      * Whether the broadcast source is encrypted or not.
166      * @return If true, the broadcast source needs the broadcast code. If false, the broadcast
167      * source does not need the broadcast code.
168      */
isEncrypted()169     public boolean isEncrypted() {
170         return mIsEncrypted;
171     }
172 
173     /**
174      * Clear the BluetoothLeBroadcastReceiveState and reset the state when the user clicks the
175      * "leave broadcast" button.
176      */
clearReceiveState()177     public void clearReceiveState() {
178         mBluetoothLeBroadcastReceiveState = null;
179         mTitle = getProgramInfo();
180         mStatus = false;
181         refresh();
182     }
183 }
184