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

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

Merge "Add progress bar." into main

parents e67dc7f8 4a72ce33
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())
        }
    }
}