Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f074795d authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge "Resolved some TODOs." into main

parents 8b221ae6 b1a3482e
Loading
Loading
Loading
Loading
+26 −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.
  -->

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:attr/colorControlHighlight">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="@android:color/white"/>
            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
        </shape>
    </item>
</ripple>
 No newline at end of file
+25 −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.
  -->

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape>
            <solid android:color="?android:attr/colorControlHighlight" />
            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
        </shape>
    </item>
</layer-list>
 No newline at end of file
+63 −70
Original line number Diff line number Diff line
@@ -14,22 +14,16 @@
  ~ limitations under the License.
  -->

<!-- TODO(b/298124674) remove this root -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bluetooth_device_list_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_marginBottom="4dp">

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bluetooth_device_row"
    style="@style/BluetoothTileDialog.Device"
    android:layout_width="match_parent"
    android:layout_height="@dimen/bluetooth_dialog_device_height"
    android:paddingEnd="24dp"
    android:paddingStart="20dp"
        android:baselineAligned="false">
    android:layout_marginBottom="4dp">

    <ImageView
        android:id="@+id/bluetooth_device_icon"
@@ -41,15 +35,6 @@
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_gravity="center_vertical" />

        <View
            android:id="@+id/bluetooth_device"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="@+id/bluetooth_device_name"
            app:layout_constraintBottom_toBottomOf="@+id/bluetooth_device_summary"
            app:layout_constraintStart_toStartOf="@+id/bluetooth_device_name"
            app:layout_constraintEnd_toEndOf="@+id/bluetooth_device_name" />

    <TextView
        android:layout_width="0dp"
        android:id="@+id/bluetooth_device_name"
@@ -77,8 +62,17 @@
        app:layout_constraintBottom_toBottomOf="parent"
        android:gravity="center_vertical" />

        <ImageView
    <View
        android:id="@+id/gear_icon"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
        app:layout_constraintEnd_toEndOf="@+id/gear_icon_image"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

    <ImageView
        android:id="@+id/gear_icon_image"
        android:src="@drawable/ic_settings_24dp"
        android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
        android:layout_width="0dp"
@@ -91,4 +85,3 @@
        android:gravity="center_vertical"
        android:paddingStart="10dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
 No newline at end of file
</LinearLayout>
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ constructor(
    @Application private val coroutineScope: CoroutineScope,
) {

    internal val updateBluetoothStateFlow: StateFlow<Boolean?> =
    internal val bluetoothStateUpdate: StateFlow<Boolean?> =
        conflatedCallbackFlow {
                val listener =
                    object : BluetoothCallback {
+50 −35
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Switch
import android.widget.TextView
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.logging.UiEventLogger
@@ -42,24 +44,26 @@ import kotlinx.coroutines.flow.asStateFlow
internal class BluetoothTileDialog
constructor(
    private val bluetoothToggleInitialValue: Boolean,
    private val subtitleResIdInitialValue: Int,
    private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
    private val uiEventLogger: UiEventLogger,
    context: Context,
) : SystemUIDialog(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK) {

    private val mutableBluetoothStateSwitchedFlow: MutableStateFlow<Boolean> =
    private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> =
        MutableStateFlow(bluetoothToggleInitialValue)
    internal val bluetoothStateSwitchedFlow
        get() = mutableBluetoothStateSwitchedFlow.asStateFlow()
    internal val bluetoothStateToggle
        get() = mutableBluetoothStateToggle.asStateFlow()

    private val mutableClickedFlow: MutableSharedFlow<Pair<DeviceItem, Int>> =
    private val mutableDeviceItemClick: MutableSharedFlow<DeviceItem> =
        MutableSharedFlow(extraBufferCapacity = 1)
    internal val deviceItemClickedFlow
        get() = mutableClickedFlow.asSharedFlow()
    internal val deviceItemClick
        get() = mutableDeviceItemClick.asSharedFlow()

    private val deviceItemAdapter: Adapter = Adapter(bluetoothTileDialogCallback)

    private lateinit var toggleView: Switch
    private lateinit var subtitleTextView: TextView
    private lateinit var doneButton: View
    private lateinit var seeAllViewGroup: View
    private lateinit var pairNewDeviceViewGroup: View
@@ -74,6 +78,7 @@ constructor(
        setContentView(LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null))

        toggleView = requireViewById(R.id.bluetooth_toggle)
        subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView
        doneButton = requireViewById(R.id.done_button)
        seeAllViewGroup = requireViewById(R.id.see_all_layout_group)
        pairNewDeviceViewGroup = requireViewById(R.id.pair_new_device_layout_group)
@@ -84,6 +89,7 @@ constructor(
        setupToggle()
        setupRecyclerView()

        subtitleTextView.text = context.getString(subtitleResIdInitialValue)
        doneButton.setOnClickListener { dismiss() }
        seeAllText.setOnClickListener { bluetoothTileDialogCallback.onSeeAllClicked(it) }
        pairNewDeviceText.setOnClickListener {
@@ -91,7 +97,6 @@ constructor(
        }
    }

    // TODO(b/298124674): use DiffUtil or AsyncListDiffer to avoid updating the whole list
    internal fun onDeviceItemUpdated(
        deviceItem: List<DeviceItem>,
        showSeeAll: Boolean,
@@ -102,18 +107,15 @@ constructor(
        deviceItemAdapter.refreshDeviceItemList(deviceItem)
    }

    internal fun onDeviceItemUpdatedAtPosition(deviceItem: DeviceItem, position: Int) {
        deviceItemAdapter.refreshDeviceItem(deviceItem, position)
    }

    internal fun onBluetoothStateUpdated(isEnabled: Boolean) {
    internal fun onBluetoothStateUpdated(isEnabled: Boolean, subtitleResId: Int) {
        toggleView.isChecked = isEnabled
        subtitleTextView.text = context.getString(subtitleResId)
    }

    private fun setupToggle() {
        toggleView.isChecked = bluetoothToggleInitialValue
        toggleView.setOnCheckedChangeListener { _, isChecked ->
            mutableBluetoothStateSwitchedFlow.value = isChecked
            mutableBluetoothStateToggle.value = isChecked
            uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
        }
    }
@@ -128,7 +130,32 @@ constructor(
    internal inner class Adapter(private val onClickCallback: BluetoothTileDialogCallback) :
        RecyclerView.Adapter<Adapter.DeviceItemViewHolder>() {

        private val deviceItem: MutableList<DeviceItem> = mutableListOf()
        private val diffUtilCallback =
            object : DiffUtil.ItemCallback<DeviceItem>() {
                override fun areItemsTheSame(
                    deviceItem1: DeviceItem,
                    deviceItem2: DeviceItem
                ): Boolean {
                    return deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice
                }

                override fun areContentsTheSame(
                    deviceItem1: DeviceItem,
                    deviceItem2: DeviceItem
                ): Boolean {
                    return deviceItem1.type == deviceItem2.type &&
                        deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice &&
                        deviceItem1.deviceName == deviceItem2.deviceName &&
                        deviceItem1.connectionSummary == deviceItem2.connectionSummary &&
                        // Ignored the icon drawable
                        deviceItem1.iconWithDescription?.second ==
                            deviceItem2.iconWithDescription?.second &&
                        deviceItem1.background == deviceItem2.background &&
                        deviceItem1.isEnabled == deviceItem2.isEnabled
                }
            }

        private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback)

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder {
            val view =
@@ -137,29 +164,21 @@ constructor(
            return DeviceItemViewHolder(view)
        }

        override fun getItemCount() = deviceItem.size
        override fun getItemCount() = asyncListDiffer.currentList.size

        override fun onBindViewHolder(holder: DeviceItemViewHolder, position: Int) {
            val item = getItem(position)
            holder.bind(item, position, onClickCallback)
            holder.bind(item, onClickCallback)
        }

        internal fun getItem(position: Int) = deviceItem[position]
        internal fun getItem(position: Int) = asyncListDiffer.currentList[position]

        internal fun refreshDeviceItemList(updated: List<DeviceItem>) {
            deviceItem.clear()
            deviceItem.addAll(updated)
            notifyDataSetChanged()
        }

        internal fun refreshDeviceItem(updated: DeviceItem, position: Int) {
            deviceItem[position] = updated
            notifyItemChanged(position)
            asyncListDiffer.submitList(updated)
        }

        internal inner class DeviceItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            private val container = view.requireViewById<View>(R.id.bluetooth_device_row)
            private val deviceView = view.requireViewById<View>(R.id.bluetooth_device)
            private val nameView = view.requireViewById<TextView>(R.id.bluetooth_device_name)
            private val summaryView = view.requireViewById<TextView>(R.id.bluetooth_device_summary)
            private val iconView = view.requireViewById<ImageView>(R.id.bluetooth_device_icon)
@@ -167,18 +186,16 @@ constructor(

            internal fun bind(
                item: DeviceItem,
                position: Int,
                deviceItemOnClickCallback: BluetoothTileDialogCallback
            ) {
                container.apply {
                    isEnabled = item.isEnabled
                    alpha = item.alpha
                    background = item.background
                }
                deviceView.setOnClickListener {
                    mutableClickedFlow.tryEmit(Pair(item, position))
                    background = item.background?.let { context.getDrawable(it) }
                    setOnClickListener {
                        mutableDeviceItemClick.tryEmit(item)
                        uiEventLogger.log(BluetoothTileDialogUiEvent.DEVICE_CLICKED)
                    }
                }
                nameView.text = item.deviceName
                summaryView.text = item.connectionSummary
                iconView.apply {
@@ -195,8 +212,6 @@ constructor(
    }

    internal companion object {
        const val ENABLED_ALPHA = 1.0f
        const val DISABLED_ALPHA = 0.3f
        const val MAX_DEVICE_ITEM_ENTRY = 3
        const val ACTION_BLUETOOTH_DEVICE_DETAILS =
            "com.android.settings.BLUETOOTH_DEVICE_DETAIL_SETTINGS"
Loading