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

Commit 16338fe6 authored by Luna Zhang's avatar Luna Zhang
Browse files

Update bluetooth details view's device row UI (part 1)

This cl updates the Ui of bluetooth device row, including the font and background. A follow up cl will update the background for connected devices.

Bug: b/378514021
Flag: com.android.systemui.qs_tile_detailed_view
Test: Manually tested
Change-Id: Idb1f6ffc91eb8532a3782db19bd7aa60acd32a81
parent 39e0cf54
Loading
Loading
Loading
Loading
+130 −12
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.systemui.bluetooth.qsdialog

import android.content.Intent
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -124,6 +126,10 @@ constructor(

    private var lastItemRow: Int = -1

    private var showSeeAll: Boolean = false

    private var lastConnectedDeviceIndex: Int = -1

    private lateinit var coroutineScope: CoroutineScope

    // UI Components
@@ -145,6 +151,13 @@ constructor(
    private var titleTextView: TextView? = null
    private var subtitleTextView: TextView? = null

    // UI Components that only exist in tile details view, but not in dialog.
    private var entryBackgroundActive: Drawable? = null
    private var entryBackgroundInactive: Drawable? = null
    private var entryBackgroundInactiveStart: Drawable? = null
    private var entryBackgroundInactiveEnd: Drawable? = null
    private var entryBackgroundInactiveMiddle: Drawable? = null

    @AssistedFactory
    interface Factory {
        fun create(
@@ -190,6 +203,17 @@ constructor(
            subtitleTextView = contentView.requireViewById(R.id.bluetooth_tile_dialog_subtitle)
            // If rendering with tile details view, done button shouldn't exist.
            doneButton = contentView.requireViewById(R.id.done_button)
        } else {
            entryBackgroundActive =
                contentView.context.getDrawable(R.drawable.settingslib_entry_bg_on)
            entryBackgroundInactive =
                contentView.context.getDrawable(R.drawable.settingslib_entry_bg_off)
            entryBackgroundInactiveStart =
                contentView.context.getDrawable(R.drawable.settingslib_entry_bg_off_start)
            entryBackgroundInactiveEnd =
                contentView.context.getDrawable(R.drawable.settingslib_entry_bg_off_end)
            entryBackgroundInactiveMiddle =
                contentView.context.getDrawable(R.drawable.settingslib_entry_bg_off_middle)
        }

        setupToggle()
@@ -316,6 +340,7 @@ constructor(
        showSeeAll: Boolean,
        showPairNewDevice: Boolean,
    ) {
        this.showSeeAll = showSeeAll
        withContext(mainDispatcher) {
            val start = systemClock.elapsedRealtime()
            val itemRow = deviceItem.size + showSeeAll.toInt() + showPairNewDevice.toInt()
@@ -331,6 +356,22 @@ constructor(
                    scrollViewContent.layoutParams.height = WRAP_CONTENT
                    lastUiUpdateMs = systemClock.elapsedRealtime()
                    lastItemRow = itemRow
                    if (!isInDialog) {
                        lastConnectedDeviceIndex = deviceItem.indexOfLast(::isDeviceConnected)
                        // The seeAllButton's UI will be grouped together with unconnected devices.
                        seeAllButton.background =
                            if (lastConnectedDeviceIndex != deviceItem.size - 1) {
                                // If the last device is unconnected, seeAllButton should use the
                                // end drawable.
                                entryBackgroundInactiveEnd
                            } else {
                                // If the last device is connected, seeAllButton will be the only
                                // item using the inactive drawable, so it should use the default
                                // inactive one.
                                entryBackgroundInactive
                            }
                        deviceListView.invalidateItemDecorations()
                    }
                    logger.logDeviceUiUpdate(lastUiUpdateMs - start, deviceItem)
                }
            }
@@ -399,6 +440,57 @@ constructor(
            layoutManager = LinearLayoutManager(contentView.context)
            adapter = deviceItemAdapter
        }
        if (!isInDialog) {
            deviceListView.addItemDecoration(
                object : RecyclerView.ItemDecoration() {
                    override fun onDraw(
                        c: Canvas,
                        parent: RecyclerView,
                        state: RecyclerView.State,
                    ) {
                        // `itemCount` represents the total number of items in your adapter's data
                        // set, regardless of what's visible.
                        val adapter = parent.adapter ?: return
                        val itemCount = adapter.itemCount

                        // `parent.childCount` is the number of child views currently visible on
                        // screen. Often less than itemCount since RecyclerView recycles views that
                        // scroll off-screen.
                        for (i in 0 until parent.childCount) {
                            val child = parent.getChildAt(i) ?: continue
                            val adapterPosition = parent.getChildAdapterPosition(child)
                            if (adapterPosition == RecyclerView.NO_POSITION) continue
                            val background: Drawable?
                            if (adapterPosition > lastConnectedDeviceIndex) {
                                // Set up background for unconnected devices
                                background =
                                    when {
                                        // Use the default inactive drawable, if there is only one
                                        // unconnected device and no seeAllButton.
                                        lastConnectedDeviceIndex + 1 == itemCount - 1 &&
                                            !showSeeAll -> entryBackgroundInactive
                                        // Use the start drawable, if this is the first unconnected
                                        // device.
                                        adapterPosition == lastConnectedDeviceIndex + 1 ->
                                            entryBackgroundInactiveStart
                                        // Use the end drawable, if this is the last unconnected
                                        // device and no seeAllButton.
                                        adapterPosition == itemCount - 1 && !showSeeAll ->
                                            entryBackgroundInactiveEnd

                                        else -> entryBackgroundInactiveMiddle
                                    }
                            } else {
                                // Set up background for connected devices
                                background = entryBackgroundActive
                            }
                            background?.setBounds(child.left, child.top, child.right, child.bottom)
                            background?.draw(c)
                        }
                    }
                }
            )
        }
    }

    private fun showProgressBar() {
@@ -482,6 +574,7 @@ constructor(
            private val divider = view.requireViewById<View>(R.id.divider)

            internal fun bind(item: DeviceItem) {
                val isDeviceConnected = isDeviceConnected(item)
                container.apply {
                    isEnabled = item.isEnabled
                    background = item.background?.let { context.getDrawable(it) }
@@ -493,10 +586,18 @@ constructor(

                    // updating icon colors
                    val tintColor =
                        if (isInDialog) {
                            context.getColor(
                                if (item.isActive) InternalR.color.materialColorOnPrimaryContainer
                                else InternalR.color.materialColorOnSurface
                            )
                        } else {
                            context.getColor(
                                if (isDeviceConnected)
                                    InternalR.color.materialColorOnPrimaryContainer
                                else InternalR.color.materialColorOnSurface
                            )
                        }

                    // update icons
                    iconView.apply {
@@ -514,6 +615,7 @@ constructor(
                    divider.setBackgroundColor(tintColor)

                    // update text styles
                    if (isInDialog) {
                        nameView.setTextAppearance(
                            if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
                            else R.style.TextAppearance_BluetoothTileDialog
@@ -522,6 +624,18 @@ constructor(
                            if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
                            else R.style.TextAppearance_BluetoothTileDialog
                        )
                    } else {
                        nameView.setTextAppearance(
                            if (isDeviceConnected)
                                R.style.TextAppearance_TileDetailsEntryTitle_Active
                            else R.style.TextAppearance_TileDetailsEntryTitle
                        )
                        summaryView.setTextAppearance(
                            if (isDeviceConnected)
                                R.style.TextAppearance_TileDetailsEntrySubTitle_Active
                            else R.style.TextAppearance_TileDetailsEntrySubTitle
                        )
                    }

                    accessibilityDelegate =
                        object : AccessibilityDelegate() {
@@ -552,6 +666,10 @@ constructor(
        }
    }

    private fun isDeviceConnected(item: DeviceItem): Boolean {
        return item.type == DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
    }

    internal companion object {
        private const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
        const val CONTENT_HEIGHT_PREF_KEY = Prefs.Key.BLUETOOTH_TILE_DIALOG_CONTENT_HEIGHT