Loading res/xml/bluetooth_audio_streams_qr_code.xml 0 → 100644 +57 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:paddingLeft="25dp" android:paddingRight="25dp" android:gravity="center_horizontal" android:orientation="vertical"> <TextView android:id="@android:id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="start" android:textSize="15sp" android:textColor="?android:attr/textColorPrimary" android:text="Scan this QR code with another device connected to LE audio headphones to start sharing audio"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" android:paddingTop="70dp"> <ImageView android:id="@+id/qrcode_view" android:layout_width="@dimen/qrcode_size" android:layout_height="@dimen/qrcode_size" android:src="@android:color/transparent"/> </LinearLayout> </LinearLayout> </LinearLayout> No newline at end of file src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.connecteddevice.audiosharing; import android.app.settings.SettingsEnums; import android.content.Context; import android.util.AttributeSet; import android.widget.ImageButton; Loading @@ -23,6 +24,7 @@ import android.widget.ImageButton; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; import com.android.settings.widget.ValidatedEditTextPreference; public class AudioSharingNamePreference extends ValidatedEditTextPreference { Loading Loading @@ -60,5 +62,12 @@ public class AudioSharingNamePreference extends ValidatedEditTextPreference { super.onBindViewHolder(holder); final ImageButton shareButton = (ImageButton) holder.findViewById(R.id.button_icon); shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp)); shareButton.setOnClickListener( unused -> new SubSettingLauncher(getContext()) .setTitleText("Audio sharing QR code") .setDestination(AudioStreamsQrCodeFragment.class.getName()) .setSourceMetricsCategory(SettingsEnums.AUDIO_SHARING_SETTINGS) .launch()); } } src/com/android/settings/connecteddevice/audiosharing/AudioStreamsQrCodeFragment.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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.connecteddevice.audiosharing; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.graphics.Bitmap; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settings.core.InstrumentedFragment; import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.qrcode.QrCodeGenerator; import com.google.zxing.WriterException; import java.util.Optional; public class AudioStreamsQrCodeFragment extends InstrumentedFragment { private static final String TAG = "AudioStreamsQrCodeFragment"; @Override public int getMetricsCategory() { // TODO(chelseahao): update metrics id return 0; } @Override public final View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false); getQrCodeBitmap().ifPresent( bm -> ((ImageView) view.requireViewById(R.id.qrcode_view)).setImageBitmap(bm)); return view; } private Optional<Bitmap> getQrCodeBitmap() { String broadcastMetadata = getBroadcastMetadataQrCode(); if (broadcastMetadata.isEmpty()) { Log.d(TAG, "onCreateView: broadcastMetadata is empty!"); return Optional.empty(); } try { int qrcodeSize = getContext().getResources().getDimensionPixelSize(R.dimen.qrcode_size); Bitmap bitmap = QrCodeGenerator.encodeQrCode(broadcastMetadata, qrcodeSize); return Optional.of(bitmap); } catch (WriterException e) { Log.d(TAG, "onCreateView: broadcastMetadata " + broadcastMetadata + " qrCode generation exception " + e); } return Optional.empty(); } private String getBroadcastMetadataQrCode() { LocalBluetoothLeBroadcast localBluetoothLeBroadcast = Utils.getLocalBtManager(getActivity()) .getProfileManager() .getLeAudioBroadcastProfile(); if (localBluetoothLeBroadcast == null) { Log.d(TAG, "getBroadcastMetadataQrCode: localBluetoothLeBroadcast is null!"); return ""; } BluetoothLeBroadcastMetadata metadata = localBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata(); if (metadata == null) { Log.d(TAG, "getBroadcastMetadataQrCode: metadata is null!"); return ""; } return BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata); } } Loading
res/xml/bluetooth_audio_streams_qr_code.xml 0 → 100644 +57 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:paddingLeft="25dp" android:paddingRight="25dp" android:gravity="center_horizontal" android:orientation="vertical"> <TextView android:id="@android:id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="start" android:textSize="15sp" android:textColor="?android:attr/textColorPrimary" android:text="Scan this QR code with another device connected to LE audio headphones to start sharing audio"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" android:paddingTop="70dp"> <ImageView android:id="@+id/qrcode_view" android:layout_width="@dimen/qrcode_size" android:layout_height="@dimen/qrcode_size" android:src="@android:color/transparent"/> </LinearLayout> </LinearLayout> </LinearLayout> No newline at end of file
src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settings.connecteddevice.audiosharing; import android.app.settings.SettingsEnums; import android.content.Context; import android.util.AttributeSet; import android.widget.ImageButton; Loading @@ -23,6 +24,7 @@ import android.widget.ImageButton; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; import com.android.settings.widget.ValidatedEditTextPreference; public class AudioSharingNamePreference extends ValidatedEditTextPreference { Loading Loading @@ -60,5 +62,12 @@ public class AudioSharingNamePreference extends ValidatedEditTextPreference { super.onBindViewHolder(holder); final ImageButton shareButton = (ImageButton) holder.findViewById(R.id.button_icon); shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp)); shareButton.setOnClickListener( unused -> new SubSettingLauncher(getContext()) .setTitleText("Audio sharing QR code") .setDestination(AudioStreamsQrCodeFragment.class.getName()) .setSourceMetricsCategory(SettingsEnums.AUDIO_SHARING_SETTINGS) .launch()); } }
src/com/android/settings/connecteddevice/audiosharing/AudioStreamsQrCodeFragment.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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.connecteddevice.audiosharing; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.graphics.Bitmap; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settings.core.InstrumentedFragment; import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.qrcode.QrCodeGenerator; import com.google.zxing.WriterException; import java.util.Optional; public class AudioStreamsQrCodeFragment extends InstrumentedFragment { private static final String TAG = "AudioStreamsQrCodeFragment"; @Override public int getMetricsCategory() { // TODO(chelseahao): update metrics id return 0; } @Override public final View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false); getQrCodeBitmap().ifPresent( bm -> ((ImageView) view.requireViewById(R.id.qrcode_view)).setImageBitmap(bm)); return view; } private Optional<Bitmap> getQrCodeBitmap() { String broadcastMetadata = getBroadcastMetadataQrCode(); if (broadcastMetadata.isEmpty()) { Log.d(TAG, "onCreateView: broadcastMetadata is empty!"); return Optional.empty(); } try { int qrcodeSize = getContext().getResources().getDimensionPixelSize(R.dimen.qrcode_size); Bitmap bitmap = QrCodeGenerator.encodeQrCode(broadcastMetadata, qrcodeSize); return Optional.of(bitmap); } catch (WriterException e) { Log.d(TAG, "onCreateView: broadcastMetadata " + broadcastMetadata + " qrCode generation exception " + e); } return Optional.empty(); } private String getBroadcastMetadataQrCode() { LocalBluetoothLeBroadcast localBluetoothLeBroadcast = Utils.getLocalBtManager(getActivity()) .getProfileManager() .getLeAudioBroadcastProfile(); if (localBluetoothLeBroadcast == null) { Log.d(TAG, "getBroadcastMetadataQrCode: localBluetoothLeBroadcast is null!"); return ""; } BluetoothLeBroadcastMetadata metadata = localBluetoothLeBroadcast.getLatestBluetoothLeBroadcastMetadata(); if (metadata == null) { Log.d(TAG, "getBroadcastMetadataQrCode: metadata is null!"); return ""; } return BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata); } }