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

Commit 3267e525 authored by Lucas Silva's avatar Lucas Silva
Browse files

Update app widget size when resized

Instead of relying on the passed-in size, we calculate the size of the
view after layout and update the widget with that size. This ensures the
widget is always up-to-date with the right size.

Bug: 368056517
Test: manually by expanding and shrinking widgets
Flag: com.android.systemui.communal_widget_resizing
Change-Id: Ief764b582df5e5784d63444d33a2171f6dd5e4be
parent b8178230
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
@@ -17,19 +17,30 @@
package com.android.systemui.communal.ui.binder

import android.content.Context
import android.os.Bundle
import android.util.SizeF
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.ui.unit.IntSize
import androidx.core.view.doOnLayout
import com.android.app.tracing.coroutines.flow.flowOn
import com.android.app.tracing.coroutines.launch
import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.common.ui.view.onLayoutChanged
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.util.WidgetViewFactory
import com.android.systemui.util.kotlin.DisposableHandles
import com.android.systemui.util.kotlin.toDp
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged

object CommunalAppWidgetHostViewBinder {
    private const val TAG = "CommunalAppWidgetHostViewBinder"
@@ -37,9 +48,11 @@ object CommunalAppWidgetHostViewBinder {
    fun bind(
        context: Context,
        applicationScope: CoroutineScope,
        mainContext: CoroutineContext,
        backgroundContext: CoroutineContext,
        container: FrameLayout,
        model: CommunalContentModel.WidgetContent.Widget,
        size: SizeF,
        size: SizeF?,
        factory: WidgetViewFactory,
    ): DisposableHandle {
        val disposables = DisposableHandles()
@@ -49,6 +62,22 @@ object CommunalAppWidgetHostViewBinder {
                val widget = factory.createWidget(context, model, size)
                waitForLayout(container)
                container.post { container.setView(widget) }
                if (communalWidgetResizing()) {
                    // Update the app widget size in the background.
                    launch("$TAG#updateSize", backgroundContext) {
                        container.sizeFlow().flowOn(mainContext).distinctUntilChanged().collect {
                            (width, height) ->
                            widget.updateAppWidgetSize(
                                /* newOptions = */ Bundle(),
                                /* minWidth = */ width,
                                /* minHeight = */ height,
                                /* maxWidth = */ width,
                                /* maxHeight = */ height,
                                /* ignorePadding = */ true,
                            )
                        }
                    }
                }
            }

        disposables += DisposableHandle { loadingJob.cancel() }
@@ -69,3 +98,13 @@ private fun ViewGroup.setView(view: View) {
    (view.parent as? ViewGroup)?.removeView(view)
    addView(view)
}

private fun View.sizeAsDp(): IntSize = IntSize(width.toDp(context), height.toDp(context))

private fun View.sizeFlow(): Flow<IntSize> = conflatedCallbackFlow {
    if (isLaidOut && !isLayoutRequested) {
        trySend(sizeAsDp())
    }
    val disposable = onLayoutChanged { trySend(sizeAsDp()) }
    awaitClose { disposable.dispose() }
}
+10 −2
Original line number Diff line number Diff line
@@ -25,13 +25,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.ui.binder.CommunalAppWidgetHostViewBinder
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.util.WidgetViewFactory
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.res.R
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle

@@ -39,6 +43,8 @@ class CommunalAppWidgetSection
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    @Main private val mainContext: CoroutineContext,
    @UiBackground private val backgroundContext: CoroutineContext,
    private val factory: WidgetViewFactory,
) {

@@ -76,10 +82,12 @@ constructor(
                            context = context,
                            container = this,
                            model = model,
                            size = size,
                            size = if (!communalWidgetResizing()) size else null,
                            factory = factory,
                            applicationScope = applicationScope,
                        )
                            mainContext = mainContext,
                            backgroundContext = backgroundContext,
                        ),
                    )

                    accessibilityDelegate = viewModel.widgetAccessibilityDelegate
+11 −9
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ constructor(
    suspend fun createWidget(
        context: Context,
        model: CommunalContentModel.WidgetContent.Widget,
        size: SizeF,
        size: SizeF?,
    ): CommunalAppWidgetHostView =
        withContext("$TAG#createWidget", uiBgContext) {
            val view =
@@ -54,6 +54,7 @@ constructor(
            // Instead of setting the view as the listener directly, we wrap the view in a delegate
            // which ensures the callbacks always get called on the main thread.
            appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
            if (size != null) {
                view.updateAppWidgetSize(
                    /* newOptions = */ Bundle(),
                    /* minWidth = */ size.width.toInt(),
@@ -62,6 +63,7 @@ constructor(
                    /* maxHeight = */ size.height.toInt(),
                    /* ignorePadding = */ true,
                )
            }
            view
        }