Merge "[LeAudio] New QR code scanner UIs and modify local API"
diff --git a/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml b/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
new file mode 100644
index 0000000..f6f63c5
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_qr_code_scanner.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
+        android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M2,7V2H7V4H4V7ZM2,22V17H4V20H7V22ZM17,22V20H20V17H22V22ZM20,7V4H17V2H22V7ZM17.5,17.5H19V19H17.5ZM17.5,14.5H19V16H17.5ZM16,16H17.5V17.5H16ZM14.5,17.5H16V19H14.5ZM13,16H14.5V17.5H13ZM16,13H17.5V14.5H16ZM14.5,14.5H16V16H14.5ZM13,13H14.5V14.5H13ZM19,5V11H13V5ZM11,13V19H5V13ZM11,5V11H5V5ZM9.5,17.5V14.5H6.5V17.5ZM9.5,9.5V6.5H6.5V9.5ZM17.5,9.5V6.5H14.5V9.5Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml b/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
new file mode 100644
index 0000000..f0a182b
--- /dev/null
+++ b/packages/SettingsLib/res/layout/qrcode_scan_mode_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/fragment_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
new file mode 100644
index 0000000..bf22598
--- /dev/null
+++ b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="3"
+        android:layout_marginBottom="35dp">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
+            android:gravity="center"
+            android:orientation="vertical">
+            <ImageView
+                android:src="@drawable/ic_qr_code_scanner"
+                android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+                android:layout_width="@dimen/qrcode_icon_size"
+                android:layout_height="@dimen/qrcode_icon_size"
+                android:contentDescription="@null"/>
+
+            <TextView
+                style="@style/QrCodeScanner"
+                android:textSize="24sp"
+                android:text="@string/bt_le_audio_scan_qr_code"
+                android:gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="19dp"/>
+
+            <TextView
+                style="@style/QrCodeScanner"
+                android:text="@string/bt_le_audio_scan_qr_code_scanner"
+                android:gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"/>
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="7"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:gravity="center"
+            android:clipChildren="true">
+            <TextureView
+                android:id="@+id/preview_view"
+                android:layout_marginStart="@dimen/qrcode_preview_margin"
+                android:layout_marginEnd="@dimen/qrcode_preview_margin"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/qrcode_preview_size"/>
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/error_message"
+            style="@style/TextAppearance.ErrorText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:layout_marginStart="40dp"
+            android:layout_marginEnd="40dp"
+            android:gravity="center"
+            android:visibility="invisible"/>
+
+    </LinearLayout>
+
+
+</LinearLayout>
+
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index c439cf0..328527b 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -98,4 +98,9 @@
     <!-- Minimum width for the popup for updating a user's photo. -->
     <dimen name="update_user_photo_popup_min_width">300dp</dimen>
 
+    <!-- QR code picture size -->
+    <dimen name="qrcode_preview_size">360dp</dimen>
+    <dimen name="qrcode_preview_margin">40dp</dimen>
+    <dimen name="qrcode_preview_radius">30dp</dimen>
+    <dimen name="qrcode_icon_size">27dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6ca15c1..7299e4e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1531,4 +1531,11 @@
 
     <!-- Content description of the no calling for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_calling">No calling.</string>
+
+    <!-- [CHAR LIMIT=NONE] Le audio QR code scanner title -->
+    <string name="bt_le_audio_scan_qr_code">Scan QR code</string>
+    <!-- [CHAR LIMIT=NONE] Le audio QR code scanner sub-title -->
+    <string name="bt_le_audio_scan_qr_code_scanner">To start listening, center the QR code below</string>
+    <!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
+    <string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 015f52c..28cd27b 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -27,4 +27,16 @@
         <item name="android:background">@*android:drawable/btn_borderless_rect</item>
         <item name="android:gravity">center</item>
     </style>
+
+    <style name="TextAppearance.ErrorText"
+           parent="@*android:TextAppearance.DeviceDefault.Body1">
+        <item name="android:textColor">?android:attr/colorError</item>
+    </style>
+
+    <style name="QrCodeScanner">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textDirection">locale</item>
+    </style>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
index 3ce7a0e..1f72609 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java
@@ -18,7 +18,32 @@
 
 public final class BluetoothBroadcastUtils {
 
-    static final String SCHEME_BT_BROADCAST_METADATA = "BT:";
+    /**
+     * The fragment tag specified to FragmentManager for container activities to manage fragments.
+     */
+    public static final String TAG_FRAGMENT_QR_CODE_SCANNER = "qr_code_scanner_fragment";
+
+    /**
+     * Action for launching qr code scanner activity.
+     */
+    public static final String ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER =
+            "android.settings.BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER";
+
+    /**
+     * Extra for {@link android.bluetooth.BluetoothDevice}.
+     */
+    public static final String EXTRA_BLUETOOTH_DEVICE_SINK = "bluetooth_device_sink";
+
+    /**
+     * Extra for checking the {@link android.bluetooth.BluetoothLeBroadcastAssistant} should perform
+     * this operation for all coordinated set members throughout one session or not.
+     */
+    public static final String EXTRA_BLUETOOTH_SINK_IS_GROUP = "bluetooth_sink_is_group";
+
+    /**
+     * Bluetooth scheme.
+     */
+    public static final String SCHEME_BT_BROADCAST_METADATA = "BT:";
 
     // BluetoothLeBroadcastMetadata
     static final String PREFIX_BT_ADDRESS_TYPE = "T:";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
index d904265..60632b6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcast;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
@@ -71,7 +70,7 @@
         }
     };
 
-    LocalBluetoothLeBroadcastAssistant(Context context,
+    public LocalBluetoothLeBroadcastAssistant(Context context,
             LocalBluetoothProfileManager profileManager) {
         mProfileManager = profileManager;
         BluetoothAdapter.getDefaultAdapter().
@@ -80,6 +79,40 @@
         mBuilder = new BluetoothLeBroadcastMetadata.Builder();
     }
 
+    /**
+     * Add a Broadcast Source to the Broadcast Sink with {@link BluetoothLeBroadcastMetadata}.
+     *
+     * @param sink Broadcast Sink to which the Broadcast Source should be added
+     * @param metadata Broadcast Source metadata to be added to the Broadcast Sink
+     * @param isGroupOp {@code true} if Application wants to perform this operation for all
+     *                  coordinated set members throughout this session. Otherwise, caller
+     *                  would have to add, modify, and remove individual set members.
+     */
+    public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata metadata,
+            boolean isGroupOp) {
+        mBluetoothLeBroadcastAssistant.addSource(sink, metadata, isGroupOp);
+    }
+
+    /**
+     * Add a Broadcast Source to the Broadcast Sink with the information which are separated from
+     * the qr code string.
+     *
+     * @param sink Broadcast Sink to which the Broadcast Source should be added
+     * @param sourceAddressType hardware MAC Address of the device. See
+     *                          {@link BluetoothDevice.AddressType}.
+     * @param presentationDelayMicros presentation delay of this Broadcast Source in microseconds.
+     * @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source.
+     * @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source.
+     * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source,
+     *                       {@link BluetoothLeBroadcastMetadata#PA_SYNC_INTERVAL_UNKNOWN} if
+     *                       unknown.
+     * @param isEncrypted whether the Broadcast Source is encrypted.
+     * @param broadcastCode Broadcast Code for this Broadcast Source, null if code is not required.
+     * @param sourceDevice source advertiser address.
+     * @param isGroupOp {@code true} if Application wants to perform this operation for all
+     *                  coordinated set members throughout this session. Otherwise, caller
+     *                  would have to add, modify, and remove individual set members.
+     */
     public void addSource(@NonNull BluetoothDevice sink, int sourceAddressType,
             int presentationDelayMicros, int sourceAdvertisingSid, int broadcastId,
             int paSyncInterval, boolean isEncrypted, byte[] broadcastCode,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
index cf4ba8b..5b1fefb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java
@@ -83,6 +83,9 @@
         mSubgroupList = metadata.getSubgroups();
     }
 
+    public LocalBluetoothLeBroadcastMetadata() {
+    }
+
     public void setBroadcastCode(byte[] code) {
         mBroadcastCode = code;
     }