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

Commit f14f9cba authored by Willie Koomson's avatar Willie Koomson
Browse files

Update Glanceable Hub's AppWidgetHostListener impl for widget events

This change updates GlanceableHub's custom AppWidgetHostListener
implementation to add support for the new collectWidgetEvents method.
This enables event reporting for the hub's widgets.

Bug: 364655296
Test: Manual, use widgets on mobile hub and confirm that they are
 reported
Test: GlanceableHubWidgetManagerServiceTest
Flag: android.appwidget.flags.engagement_metrics

Change-Id: Ic7d69e149d11d8ba03c8c76eaf00f514d5f93418
parent 4790d334
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Looper;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -1043,11 +1044,16 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
     * This function returns the current set of widget event data being tracked by this widget. The
     * tracked data is cleared is returned here.
     *
     * This should always be called on the main thread.
     *
     * @hide
     */
    @FlaggedApi(FLAG_ENGAGEMENT_METRICS)
    @Override
    public AppWidgetEvent collectWidgetEvent() {
        if (!Looper.getMainLooper().isCurrentThread()) {
            throw new IllegalStateException("collectWidgetEvent must be called from main thread");
        }
        return mInteractionLogger.collectWidgetEvent();
    }

+14 −1
Original line number Diff line number Diff line
@@ -45,8 +45,10 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -143,7 +145,15 @@ class GlanceableHubWidgetManagerServiceTest : SysuiTestCase() {
            val service = IGlanceableHubWidgetManagerService.Stub.asInterface(binder)

            // Set listener
            val listener = mock<IGlanceableHubWidgetManagerService.IAppWidgetHostListener>()
            val listener =
                mock<IGlanceableHubWidgetManagerService.IAppWidgetHostListener> {
                    on { collectWidgetEvent(any()) } doAnswer
                        {
                            (it.arguments[0]
                                    as IGlanceableHubWidgetManagerService.IAppWidgetEventCallback)
                                .onResult(null)
                        }
                }
            service.setAppWidgetHostListener(1, listener)

            // Verify a listener is set on the host
@@ -164,6 +174,9 @@ class GlanceableHubWidgetManagerServiceTest : SysuiTestCase() {

            appWidgetHostListener.onViewDataChanged(1)
            verify(listener).onViewDataChanged(1)

            appWidgetHostListener.collectWidgetEvent()
            verify(listener).collectWidgetEvent(any())
        }

    @Test
+19 −0
Original line number Diff line number Diff line
@@ -16,14 +16,17 @@

package com.android.systemui.communal.widgets

import android.appwidget.AppWidgetEvent
import android.appwidget.AppWidgetHost.AppWidgetHostListener
import android.appwidget.AppWidgetProviderInfo
import android.os.Looper
import android.widget.RemoteViews
import com.android.app.tracing.coroutines.launchTraced
import com.android.systemui.dagger.qualifiers.Application
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.CompletableFuture
import kotlinx.coroutines.CoroutineScope

/**
@@ -55,4 +58,20 @@ constructor(
    override fun onViewDataChanged(viewId: Int) {
        mainScope.launchTraced("$tag#onViewDataChanged") { listener.onViewDataChanged(viewId) }
    }

    override fun collectWidgetEvent(): AppWidgetEvent? {
        if (!android.appwidget.flags.Flags.engagementMetrics()) {
            return null
        }

        if (Looper.getMainLooper().isCurrentThread()) {
            return listener.collectWidgetEvent()
        }

        val future = CompletableFuture<AppWidgetEvent?>()
        mainScope.launchTraced("$tag#collectWidgetEvent") {
            future.complete(listener.collectWidgetEvent())
        }
        return future.get()
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.server.servicewatcher.ServiceWatcher
import com.android.server.servicewatcher.ServiceWatcher.ServiceListener
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetEventCallback
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetHostListener
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IConfigureWidgetCallback
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IGlanceableHubWidgetsListener
@@ -212,6 +213,10 @@ constructor(
            override fun onViewDataChanged(viewId: Int) {
                listener.onViewDataChanged(viewId)
            }

            override fun collectWidgetEvent(callback: IAppWidgetEventCallback) {
                callback.onResult(listener.collectWidgetEvent())
            }
        }
    }

+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.communal.widgets

import android.appwidget.AppWidgetEvent
import android.appwidget.AppWidgetHost.AppWidgetHostListener
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
@@ -30,12 +31,14 @@ import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetEventCallback
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IAppWidgetHostListener
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IConfigureWidgetCallback
import com.android.systemui.communal.widgets.IGlanceableHubWidgetManagerService.IGlanceableHubWidgetsListener
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import java.util.concurrent.CompletableFuture
import javax.inject.Inject
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Job
@@ -260,6 +263,27 @@ constructor(
                    }
                }
            }

            override fun collectWidgetEvent(): AppWidgetEvent? {
                if (!android.appwidget.flags.Flags.engagementMetrics()) return null

                val future = CompletableFuture<AppWidgetEvent?>()
                val callback =
                    object : IAppWidgetEventCallback.Stub() {
                        override fun onResult(event: AppWidgetEvent?) {
                            future.complete(event)
                        }
                    }
                return try {
                    listener.collectWidgetEvent(callback)
                    future.get()
                } catch (e: RemoteException) {
                    logger.e({ "Error collecting widget event: $str1" }) {
                        str1 = e.localizedMessage
                    }
                    null
                }
            }
        }
    }

Loading