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

Commit 4d7e9d87 authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge "Handle DeadObjectException from AppWidgetHost#setListener." into main

parents 0f103e6c 00e1438a
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.content.pm.UserInfo
import android.os.Bundle
import android.os.DeadObjectException
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -40,7 +41,6 @@ import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import java.util.Optional
@@ -53,6 +53,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -375,6 +376,34 @@ class CommunalWidgetHostTest : SysuiTestCase() {
            assertThat(providerInfo).containsExactlyEntriesIn(mapOf(Pair(2, providerInfo2)))
        }

    @Test
    fun refreshProviderInfo_handlesDeadObjectException() =
        kosmos.runTest {
            val providerInfoValues by collectLastValue(underTest.appWidgetProviders)

            whenever(appWidgetHost.appWidgetIds).thenReturn(intArrayOf(1, 2))
            whenever(appWidgetHost.setListener(eq(1), org.mockito.kotlin.any())).thenAnswer {
                throw DeadObjectException()
            }
            whenever(appWidgetManager.getAppWidgetInfo(1)).thenReturn(providerInfo1)
            whenever(appWidgetManager.getAppWidgetInfo(2)).thenReturn(providerInfo2)
            underTest.refreshProviders()

            with(providerInfoValues!!) {
                assertThat(size).isEqualTo(1)
                assertThat(containsKey(2)).isTrue()
            }
        }

    @Test
    fun onAllocateAppWidgetId_handlesDeadObjectException() =
        kosmos.runTest {
            whenever(appWidgetHost.setListener(eq(1), org.mockito.kotlin.any())).thenAnswer {
                throw DeadObjectException()
            }
            underTest.onAllocateAppWidgetId(1)
        }

    private fun selectUser() {
        kosmos.fakeUserRepository.selectedUser.value =
            SelectedUserModel(
+8 −1
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.communal.ui.viewmodel
import android.appwidget.AppWidgetHost.AppWidgetHostListener
import android.appwidget.AppWidgetHostView
import android.os.Bundle
import android.os.DeadObjectException
import android.util.Log
import android.util.SizeF
import com.android.app.tracing.coroutines.coroutineScopeTraced
import com.android.app.tracing.coroutines.withContextTraced
@@ -83,7 +85,12 @@ constructor(
        coroutineScopeTraced("$TAG#onActivated") {
            requests.receiveAsFlow().collect { request ->
                when (request) {
                    is SetListener -> handleSetListener(request.appWidgetId, request.listener)
                    is SetListener ->
                        try {
                            handleSetListener(request.appWidgetId, request.listener)
                        } catch (exception: DeadObjectException) {
                            Log.e(TAG, "could not set listener", exception)
                        }
                    is UpdateSize -> handleUpdateSize(request.size, request.view)
                }
            }
+16 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTI
import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
import android.content.ComponentName
import android.os.Bundle
import android.os.DeadObjectException
import android.os.UserHandle
import android.widget.RemoteViews
import androidx.annotation.WorkerThread
@@ -149,11 +150,16 @@ constructor(
        bgScope.launch {
            val newProviders = mutableMapOf<Int, AppWidgetProviderInfo?>()
            appWidgetHost.appWidgetIds.forEach { appWidgetId ->
                try {
                    // Listen for updates from each bound widget
                    addListener(appWidgetId)

                    // Fetch provider info of the widget
                    newProviders[appWidgetId] = getAppWidgetInfo(appWidgetId)
                } catch (exception: DeadObjectException) {
                    logger.e("failed to add listener for $appWidgetId", exception)
                    newProviders.remove(appWidgetId)
                }
            }

            _appWidgetProviders.value = newProviders.toMap()
@@ -175,7 +181,11 @@ constructor(
    }

    override fun onAllocateAppWidgetId(appWidgetId: Int) {
        try {
            addListener(appWidgetId)
        } catch (exception: DeadObjectException) {
            logger.e("Could not add listener upon allocation", exception)
        }
    }

    override fun onDeleteAppWidgetId(appWidgetId: Int) {