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

Commit 4a72ce33 authored by chelseahao's avatar chelseahao
Browse files

Add progress bar.

Test: atest -c com.android.systemui.qs.tiles.dialog.bluetooth
Bug: b/310135234
Change-Id: I1d270d884cffe6b8165f24dca6a43f9a00b9aa26
parent dac23fc8
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    android:id="@+id/root"
    style="@style/Widget.SliceView.Panel"
    android:layout_width="wrap_content"
@@ -53,17 +54,40 @@
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />

    <View
        android:id="@+id/bluetooth_tile_dialog_progress_background"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="@id/bluetooth_tile_dialog_progress_animation"
        app:layout_constraintStart_toStartOf="@id/bluetooth_tile_dialog_progress_animation"
        app:layout_constraintTop_toTopOf="@id/bluetooth_tile_dialog_progress_animation"
        app:layout_constraintBottom_toBottomOf="@id/bluetooth_tile_dialog_progress_animation"
        android:background="?androidprv:attr/colorSurfaceVariant" />

    <ProgressBar
        android:id="@+id/bluetooth_tile_dialog_progress_animation"
        android:layout_width="152dp"
        android:layout_height="4dp"
        android:layout_marginTop="16dp"
        style="@style/TrimmedHorizontalProgressBar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle"
        android:visibility="invisible"
        android:indeterminate="true" />

    <androidx.core.widget.NestedScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="21dp"
        android:minHeight="145dp"
        android:fillViewport="true"
        app:layout_constrainedHeight="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle">
        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_progress_animation">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/scroll_layout"
@@ -81,7 +105,7 @@
                android:paddingStart="36dp"
                android:text="@string/turn_on_bluetooth"
                android:clickable="false"
                android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
                android:textAppearance="@style/TextAppearance.Dialog.Title"
                android:textSize="16sp"
                app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
                app:layout_constraintStart_toStartOf="parent"
@@ -90,8 +114,7 @@
            <Switch
                android:id="@+id/bluetooth_toggle"
                android:layout_width="wrap_content"
                android:layout_height="48dp"
                android:paddingTop="10dp"
                android:layout_height="64dp"
                android:gravity="start|center_vertical"
                android:paddingEnd="40dp"
                android:contentDescription="@string/turn_on_bluetooth"
@@ -107,7 +130,6 @@
                android:id="@+id/device_list"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle"
+40 −0
Original line number Diff line number Diff line
@@ -22,12 +22,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.AccessibilityDelegate
import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.Switch
import android.widget.TextView
import androidx.recyclerview.widget.AsyncListDiffer
@@ -92,6 +94,8 @@ constructor(
    private lateinit var pairNewDeviceButton: View
    private lateinit var deviceListView: RecyclerView
    private lateinit var scrollViewContent: View
    private lateinit var progressBarAnimation: ProgressBar
    private lateinit var progressBarBackground: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
@@ -122,6 +126,8 @@ constructor(
            scrollViewContent = this
            layoutParams.height = cachedContentHeight
        }
        progressBarAnimation = requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
        progressBarBackground = requireViewById(R.id.bluetooth_tile_dialog_progress_background)
    }

    override fun start() {
@@ -135,6 +141,17 @@ constructor(
        super.dismiss()
    }

    internal suspend fun animateProgressBar(animate: Boolean) {
        withContext(mainDispatcher) {
            if (animate) {
                showProgressBar()
            } else {
                delay(PROGRESS_BAR_ANIMATION_DURATION_MS)
                hideProgressBar()
            }
        }
    }

    internal suspend fun onDeviceItemUpdated(
        deviceItem: List<DeviceItem>,
        showSeeAll: Boolean,
@@ -190,6 +207,28 @@ constructor(
        }
    }

    private fun showProgressBar() {
        if (
            ::progressBarAnimation.isInitialized &&
                ::progressBarBackground.isInitialized &&
                progressBarAnimation.visibility != VISIBLE
        ) {
            progressBarAnimation.visibility = VISIBLE
            progressBarBackground.visibility = INVISIBLE
        }
    }

    private fun hideProgressBar() {
        if (
            ::progressBarAnimation.isInitialized &&
                ::progressBarBackground.isInitialized &&
                progressBarAnimation.visibility != INVISIBLE
        ) {
            progressBarAnimation.visibility = INVISIBLE
            progressBarBackground.visibility = VISIBLE
        }
    }

    internal inner class Adapter(private val onClickCallback: BluetoothTileDialogCallback) :
        RecyclerView.Adapter<Adapter.DeviceItemViewHolder>() {

@@ -300,6 +339,7 @@ constructor(
        const val ACTION_PAIR_NEW_DEVICE = "android.settings.BLUETOOTH_PAIRING_SETTINGS"
        const val DISABLED_ALPHA = 0.3f
        const val ENABLED_ALPHA = 1f
        const val PROGRESS_BAR_ANIMATION_DURATION_MS = 1500L

        private fun Boolean.toInt(): Int {
            return if (this) 1 else 0
+34 −17
Original line number Diff line number Diff line
@@ -105,22 +105,29 @@ constructor(
                    deviceItemInteractor.updateDeviceItems(context, DeviceFetchTrigger.FIRST_LOAD)
                }

                bluetoothStateInteractor.bluetoothStateUpdate
                    .filterNotNull()
                // deviceItemUpdate is emitted when device item list is done fetching, update UI and
                // stop the progress bar.
                deviceItemInteractor.deviceItemUpdate
                    .onEach {
                        dialog.onBluetoothStateUpdated(it, getSubtitleResId(it))
                        updateDeviceItemJob?.cancel()
                        updateDeviceItemJob = launch {
                            deviceItemInteractor.updateDeviceItems(
                                context,
                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED
                        updateDialogUiJob?.cancel()
                        updateDialogUiJob = launch {
                            dialog.apply {
                                onDeviceItemUpdated(
                                    it.take(MAX_DEVICE_ITEM_ENTRY),
                                    showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY,
                                    showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled
                                )
                                animateProgressBar(false)
                            }
                        }
                    }
                    .launchIn(this)

                // deviceItemUpdateRequest is emitted when a bluetooth callback is called, re-fetch
                // the device item list and animiate the progress bar.
                deviceItemInteractor.deviceItemUpdateRequest
                    .onEach {
                        dialog.animateProgressBar(true)
                        updateDeviceItemJob?.cancel()
                        updateDeviceItemJob = launch {
                            deviceItemInteractor.updateDeviceItems(
@@ -131,27 +138,37 @@ constructor(
                    }
                    .launchIn(this)

                deviceItemInteractor.deviceItemUpdate
                // bluetoothStateUpdate is emitted when bluetooth on/off state is changed, re-fetch
                // the device item list.
                bluetoothStateInteractor.bluetoothStateUpdate
                    .filterNotNull()
                    .onEach {
                        updateDialogUiJob?.cancel()
                        updateDialogUiJob = launch {
                            dialog.onDeviceItemUpdated(
                                it.take(MAX_DEVICE_ITEM_ENTRY),
                                showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY,
                                showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled
                        dialog.onBluetoothStateUpdated(it, getSubtitleResId(it))
                        updateDeviceItemJob?.cancel()
                        updateDeviceItemJob = launch {
                            deviceItemInteractor.updateDeviceItems(
                                context,
                                DeviceFetchTrigger.BLUETOOTH_STATE_CHANGE_RECEIVED
                            )
                        }
                    }
                    .launchIn(this)

                // bluetoothStateToggle is emitted when user toggles the bluetooth state switch,
                // send the new value to the bluetoothStateInteractor and animate the progress bar.
                dialog.bluetoothStateToggle
                    .onEach { bluetoothStateInteractor.isBluetoothEnabled = it }
                    .onEach {
                        dialog.animateProgressBar(true)
                        bluetoothStateInteractor.isBluetoothEnabled = it
                    }
                    .launchIn(this)

                // deviceItemClick is emitted when user clicked on a device item.
                dialog.deviceItemClick
                    .onEach { deviceItemInteractor.updateDeviceItemOnClick(it) }
                    .launchIn(this)

                // contentHeight is emitted when the dialog is dismissed.
                dialog.contentHeight
                    .onEach {
                        withContext(backgroundDispatcher) {
+8 −6
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {

    @Test
    fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
        testScope.runTest {
            `when`(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
            bluetoothTileDialogViewModel.showDialog(context, null)

@@ -172,3 +173,4 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
            verify(activityStarter).postStartActivityDismissingKeyguard(any(), anyInt(), nullable())
        }
    }
}