Merge "Fix StrictMode violations" into androidx-main
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index a3108ff..60f3519 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -20,6 +20,7 @@
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/demos_label"
+ android:name=".DemoApplication"
android:supportsRtl="true">
<activity
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/DemoApplication.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/DemoApplication.kt
new file mode 100644
index 0000000..1eb82f6
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/DemoApplication.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.appwidget.demos
+
+import android.app.Application
+import android.os.StrictMode
+
+class DemoApplication : Application() {
+ override fun onCreate() {
+ StrictMode.enableDefaults()
+ super.onCreate()
+ }
+}
\ No newline at end of file
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
index 57c941fa..8cdae1e 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ScrollableAppWidget.kt
@@ -20,8 +20,7 @@
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.os.Handler
-import android.widget.Toast
+import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
@@ -108,7 +107,6 @@
@Composable
private fun ScrollColumn(modifier: GlanceModifier) {
- val context = LocalContext.current
LazyColumn(modifier) {
item {
SectionHeading(
@@ -159,13 +157,7 @@
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.clickable {
- Handler(context.mainLooper).post {
- Toast.makeText(
- context,
- "Click from list item $index",
- Toast.LENGTH_SHORT
- ).show()
- }
+ Log.i("ScrollableAppWidget", "Click from list item $index")
}
)
}
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
index a57500f..e175204 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
@@ -66,7 +66,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
fun Dp.toPx() = toPixels(list.context.resources.displayMetrics)
assertThat(list.paddingStart).isEqualTo(5.dp.toPx())
assertThat(list.paddingTop).isEqualTo(6.dp.toPx())
@@ -86,7 +86,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val adapter = list.adapter!!
assertThat(adapter.hasStableIds()).isFalse()
assertThat(adapter.count).isEqualTo(2)
@@ -106,7 +106,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val adapter = list.adapter!!
assertThat(adapter.hasStableIds()).isTrue()
assertThat(adapter.count).isEqualTo(2)
@@ -125,7 +125,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val adapter = list.adapter!!
assertThat(adapter.count).isEqualTo(3)
assertThat(adapter.hasStableIds()).isFalse()
@@ -146,7 +146,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val adapter = list.adapter!!
assertThat(adapter.count).isEqualTo(4)
assertThat(adapter.hasStableIds()).isTrue()
@@ -169,7 +169,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val textView0 = list.getUnboxedListItem<TextView>(0)
val textView1 = list.getUnboxedListItem<TextView>(1)
val textView2 = list.getUnboxedListItem<TextView>(2)
@@ -193,7 +193,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val textView0 = list.getUnboxedListItem<TextView>(0)
val textView1 = list.getUnboxedListItem<TextView>(1)
val textView2 = list.getUnboxedListItem<TextView>(2)
@@ -217,7 +217,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
list.getUnboxedListItem<TextView>(0)
}
}
@@ -234,7 +234,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
list.getUnboxedListItem<TextView>(0)
}
}
@@ -251,7 +251,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val listItem = list.getUnboxedListItem<FrameLayout>(0)
val layoutParams =
assertIs<FrameLayout.LayoutParams>(listItem.notGoneChildren.first().layoutParams)
@@ -271,7 +271,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val listItem = list.getUnboxedListItem<FrameLayout>(0)
val layoutParams =
assertIs<FrameLayout.LayoutParams>(listItem.notGoneChildren.first().layoutParams)
@@ -292,7 +292,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val row = list.getUnboxedListItem<FrameLayout>(0)
val (rowItem0, rowItem1) = row.notGoneChildren.toList()
assertIs<TextView>(rowItem0)
@@ -312,7 +312,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
// The adapter may report more layout types than the provider declared, e.g. adding a
// loading layout
assertThat(list.adapter.viewTypeCount).isAtLeast(TopLevelLayoutsCount)
@@ -338,7 +338,7 @@
mHostRule.startHost()
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
val row = list.getUnboxedListItem<FrameLayout>(0)
val (rowItem0, rowItem1) = row.notGoneChildren.toList()
// All items with actions are wrapped in FrameLayout
@@ -369,7 +369,7 @@
mHostRule.startHost()
val buttons = arrayOfNulls<FrameLayout>(5)
- waitForListViewChildren { list ->
+ mHostRule.waitForListViewChildren { list ->
for (it in 0..4) {
val button = list.getUnboxedListItem<FrameLayout>(it)
buttons[it] = assertIs<FrameLayout>(button)
@@ -383,32 +383,32 @@
assertThat(lastClicked).isEqualTo(index)
}
}
+}
- private fun waitForListViewChildren(action: (list: ListView) -> Unit = {}) {
- mHostRule.onHostView { }
+internal fun AppWidgetHostRule.waitForListViewChildren(action: (list: ListView) -> Unit = {}) {
+ onHostView { }
- mHostRule.runAndObserveUntilDraw(condition = "ListView did not load in time") {
- mHostRule.mHostView.let { host ->
- val list = host.findChildByType<ListView>()
- host.childCount > 0 &&
- list?.let { it.childCount > 0 && it.adapter != null } ?: false
- }
+ runAndObserveUntilDraw(condition = "ListView did not load in time") {
+ mHostView.let { host ->
+ val list = host.findChildByType<ListView>()
+ host.childCount > 0 &&
+ list?.let { it.childCount > 0 && it.adapter != null } ?: false
}
-
- mHostRule.onUnboxedHostView(action)
}
- private inline fun <reified T : View> ListView.getUnboxedListItem(position: Int): T {
- val remoteViewFrame = assertIs<FrameLayout>(getChildAt(position))
- // Each list item frame has an explicit focusable = true, see
- // "Glance.AppWidget.Theme.ListChildren" style.
- assertThat(remoteViewFrame.isFocusable).isTrue()
+ onUnboxedHostView(action)
+}
- // Android S- have a RemoteViewsAdapter$RemoteViewsFrameLayout first, Android T+ do not.
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
- return remoteViewFrame.getChildAt(0).getTargetView()
- }
- val frame = assertIs<FrameLayout>(remoteViewFrame.getChildAt(0))
- return frame.getChildAt(0).getTargetView()
+internal inline fun <reified T : View> ListView.getUnboxedListItem(position: Int): T {
+ val remoteViewFrame = assertIs<FrameLayout>(getChildAt(position))
+ // Each list item frame has an explicit focusable = true, see
+ // "Glance.AppWidget.Theme.ListChildren" style.
+ assertThat(remoteViewFrame.isFocusable).isTrue()
+
+ // Android S- have a RemoteViewsAdapter$RemoteViewsFrameLayout first, Android T+ do not.
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
+ return remoteViewFrame.getChildAt(0).getTargetView()
}
+ val frame = assertIs<FrameLayout>(remoteViewFrame.getChildAt(0))
+ return frame.getChildAt(0).getTargetView()
}
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
new file mode 100644
index 0000000..ee9bb39
--- /dev/null
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.appwidget
+
+import android.os.Build
+import android.os.StrictMode
+import android.util.Log
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.TextView
+import androidx.annotation.RequiresApi
+import androidx.glance.Button
+import androidx.glance.GlanceModifier
+import androidx.glance.action.actionParametersOf
+import androidx.glance.action.clickable
+import androidx.glance.appwidget.action.actionRunCallback
+import androidx.glance.appwidget.action.allowUnsafeIntentLaunch
+import androidx.glance.appwidget.lazy.LazyColumn
+import androidx.glance.layout.Column
+import androidx.glance.text.Text
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import junit.framework.TestCase.fail
+import kotlin.test.assertIs
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+@RequiresApi(Build.VERSION_CODES.S)
+class StrictModeTest {
+ @get:Rule
+ val mHostRule = AppWidgetHostRule()
+
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext!!
+ private val executor = Executors.newSingleThreadExecutor()
+ private lateinit var previousPolicy: StrictMode.VmPolicy
+
+ @Before
+ fun setUp() {
+ previousPolicy = StrictMode.getVmPolicy()
+ StrictMode.setVmPolicy(
+ StrictMode.VmPolicy.Builder()
+ .detectAll()
+ .penaltyListener(executor) {
+ fail("Received violation: $it")
+ Log.e("WIDGET", "$it")
+ }.build()
+ )
+ }
+
+ @After
+ fun cleanUp() {
+ executor.shutdown()
+ StrictMode.setVmPolicy(previousPolicy)
+ }
+
+ @Test
+ fun actionRunCallback() {
+ TestGlanceAppWidget.uiDefinition = {
+ Column {
+ Text(
+ "text1",
+ modifier = GlanceModifier.clickable(
+ actionRunCallback<CallbackTest>(
+ actionParametersOf(CallbackTest.key to 1)
+ )
+ )
+ )
+ Text(
+ "text2",
+ modifier = GlanceModifier.clickable(
+ actionRunCallback<CallbackTest>(
+ actionParametersOf(CallbackTest.key to 2)
+ )
+ )
+ )
+ }
+ }
+
+ mHostRule.startHost()
+
+ CallbackTest.received.set(emptyList())
+ CallbackTest.latch = CountDownLatch(2)
+ mHostRule.onHostView { root ->
+ checkNotNull(
+ root.findChild<TextView> { it.text.toString() == "text1" }?.parent as? View
+ )
+ .performClick()
+ checkNotNull(
+ root.findChild<TextView> { it.text.toString() == "text2" }?.parent as? View
+ )
+ .performClick()
+ }
+ Truth.assertThat(CallbackTest.latch.await(5, TimeUnit.SECONDS)).isTrue()
+ Truth.assertThat(CallbackTest.received.get()).containsExactly(1, 2)
+ }
+
+ @Test
+ fun lazyColumn_actionRunCallback() {
+ TestGlanceAppWidget.uiDefinition = {
+ LazyColumn {
+ item {
+ Text(
+ "Text",
+ modifier = GlanceModifier.clickable(
+ actionRunCallback<CallbackTest>(
+ actionParametersOf(CallbackTest.key to 1)
+ )
+ )
+ )
+ Button(
+ "Button",
+ >
+ actionParametersOf(CallbackTest.key to 2)
+ )
+
+ )
+ }
+ }
+ }
+
+ mHostRule.startHost()
+
+ CallbackTest.received.set(emptyList())
+ CallbackTest.latch = CountDownLatch(2)
+ mHostRule.waitForListViewChildren { list ->
+ val row = list.getUnboxedListItem<FrameLayout>(0)
+ val (rowItem0, _) = row.notGoneChildren.toList()
+ // All items with actions are wrapped in FrameLayout
+ assertIs<FrameLayout>(rowItem0)
+ Truth.assertThat(rowItem0.hasOnClickListeners()).isTrue()
+ // We must allow unsafe intent launches here because the AppWidgetHost will always
+ // launch PendingIntents that are read from a RemoteViews parcel.
+ allowUnsafeIntentLaunch { rowItem0.performClick() }
+ }
+ mHostRule.waitForListViewChildren { list ->
+ val row = list.getUnboxedListItem<FrameLayout>(0)
+ val (_, rowItem1) = row.notGoneChildren.toList()
+ assertIs<FrameLayout>(rowItem1)
+ Truth.assertThat(rowItem1.hasOnClickListeners()).isTrue()
+ allowUnsafeIntentLaunch { rowItem1.performClick() }
+ }
+
+ Truth.assertThat(CallbackTest.latch.await(5, TimeUnit.SECONDS)).isTrue()
+ Truth.assertThat(CallbackTest.received.get()).containsExactly(1, 2)
+ }
+}
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ActionTrampoline.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ActionTrampoline.kt
index 12457db..0dae0d6 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ActionTrampoline.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ActionTrampoline.kt
@@ -21,6 +21,7 @@
import android.content.Intent
import android.net.Uri
import android.os.Build
+import android.os.StrictMode
import android.widget.RemoteViews
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
@@ -98,24 +99,41 @@
val type = requireNotNull(intent.getStringExtra(ActionTypeKey)) {
"List adapter activity trampoline invoked without trampoline type"
}
- when (ActionTrampolineType.valueOf(type)) {
- ActionTrampolineType.ACTIVITY -> startActivity(actionIntent)
- ActionTrampolineType.BROADCAST, ActionTrampolineType.CALLBACK -> sendBroadcast(actionIntent)
- ActionTrampolineType.SERVICE -> startService(actionIntent)
- ActionTrampolineType.FOREGROUND_SERVICE -> {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- ListAdapterTrampolineApi26Impl.startForegroundService(
- context = this,
- intent = actionIntent
- )
- } else {
- startService(actionIntent)
+ allowUnsafeIntentLaunch {
+ when (ActionTrampolineType.valueOf(type)) {
+ ActionTrampolineType.ACTIVITY -> startActivity(actionIntent)
+ ActionTrampolineType.BROADCAST, ActionTrampolineType.CALLBACK ->
+ sendBroadcast(actionIntent)
+ ActionTrampolineType.SERVICE -> startService(actionIntent)
+ ActionTrampolineType.FOREGROUND_SERVICE -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ListAdapterTrampolineApi26Impl.startForegroundService(
+ context = this,
+ intent = actionIntent
+ )
+ } else {
+ startService(actionIntent)
+ }
}
}
}
finish()
}
+internal fun allowUnsafeIntentLaunch(block: () -> Unit) {
+ val previous = StrictMode.getVmPolicy()
+ val newPolicy = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ StrictModeVmPolicyApi31Impl.permitUnsafeIntentLaunch(
+ StrictMode.VmPolicy.Builder(previous)
+ ).build()
+ } else {
+ StrictMode.VmPolicy.Builder().build()
+ }
+ StrictMode.setVmPolicy(newPolicy)
+ block()
+ StrictMode.setVmPolicy(previous)
+}
+
private const val ActionTypeKey = "ACTION_TYPE"
private const val ActionIntentKey = "ACTION_INTENT"
@@ -126,3 +144,10 @@
context.startForegroundService(intent)
}
}
+
+@RequiresApi(Build.VERSION_CODES.S)
+private object StrictModeVmPolicyApi31Impl {
+ @DoNotInline
+ fun permitUnsafeIntentLaunch(builder: StrictMode.VmPolicy.Builder) =
+ builder.permitUnsafeIntentLaunch()
+}
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ApplyAction.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ApplyAction.kt
index 0b2947c..2a5d2b4 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ApplyAction.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/ApplyAction.kt
@@ -79,25 +79,33 @@
when (action) {
is StartActivityAction -> {
val params = editParams(action.parameters)
- val intent = getStartActivityIntent(action, translationContext, params)
- val finalIntent = if (action !is StartActivityIntentAction && !params.isEmpty()) {
- intent.applyTrampolineIntent(
- translationContext,
- viewId,
- ActionTrampolineType.ACTIVITY,
- )
- } else {
- intent
- }
return PendingIntent.getActivity(
translationContext.context,
0,
- finalIntent,
+ getStartActivityIntent(action, translationContext, params).apply {
+ // If there is no data URI set already, add a unique URI to ensure we get a
+ // distinct PendingIntent.
+ if (data == null) {
+ data = createUniqueUri(
+ translationContext,
+ viewId,
+ ActionTrampolineType.CALLBACK,
+ )
+ }
+ },
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
)
}
is StartServiceAction -> {
- val intent = getServiceIntent(action, translationContext)
+ val intent = getServiceIntent(action, translationContext).apply {
+ if (data == null) {
+ data = createUniqueUri(
+ translationContext,
+ viewId,
+ ActionTrampolineType.CALLBACK,
+ )
+ }
+ }
return if (action.isForegroundService &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
) {
@@ -118,7 +126,15 @@
return PendingIntent.getBroadcast(
translationContext.context,
0,
- getBroadcastReceiverIntent(action, translationContext),
+ getBroadcastReceiverIntent(action, translationContext).apply {
+ if (data == null) {
+ data = createUniqueUri(
+ translationContext,
+ viewId,
+ ActionTrampolineType.CALLBACK,
+ )
+ }
+ },
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
)
}
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/StartActivityIntentAction.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/StartActivityIntentAction.kt
index 304c2bb..ed387ab 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/StartActivityIntentAction.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/action/StartActivityIntentAction.kt
@@ -41,9 +41,8 @@
* (the PendingIntent created by the first call to actionStartActivity will be overwritten by the
* second). A simple way to avoid this is to set a unique data URI on these intents, so that they
* are distinct as defined by [Intent.filterEquals]. There is more information in the class
- * documentation for [PendingIntent]. This is taken care of by the library for the
- * [androidx.glance.action.actionStartActivity] overloads defined in the androidx.glance.action
- * package.
+ * documentation for [PendingIntent]. If you do not set one, the library will add a unique URI on
+ * the intent you provide here.
*
* @param intent the intent used to launch the activity
* @param parameters the parameters associated with the action. Parameter values will be added to
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
index 14f45b3..6c02991 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
@@ -57,9 +57,7 @@
check(!translationContext.isLazyCollectionDescendant) {
"Glance does not support nested list views."
}
- // TODO(b/205868100): Remove [FILL_IN_COMPONENT] flag and set target component here when all
- // click actions on descendants are exclusively [StartActivityAction] or exclusively not
- // [StartActivityAction].
+ // TODO(b/205868100): Add FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for api 34
setPendingIntentTemplate(
viewDef.mainViewId,
PendingIntent.getActivity(
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
index bb51edd..b81a8c9 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
@@ -70,6 +70,7 @@
"Only counts from 1 to 5 are supported."
}
}
+ // TODO(b/205868100): Add FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for api 34
setPendingIntentTemplate(
viewDef.mainViewId,
PendingIntent.getActivity(