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

Commit 6d7cf8b2 authored by Luna Zhang's avatar Luna Zhang Committed by Android (Google) Code Review
Browse files

Merge "Update bluetooth details view's device row UI (part 1)" into main

parents 786d01ec 16338fe6
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