From bfbe46198cb2f718862fa870509ec7f16f8f6c46 Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Mon, 7 Jun 2021 14:46:52 +0000 Subject: [PATCH] Fix handling for onItemClick of fixed collection items The onItemClick handling code assumed that the item would be nested at least one layer deep due to the RemoteViewsAdapter adding a wrapper view group. Rather than add another case to that logic, I've refactored this to traverse the view's children looking for a view with the tag. As the tag is internal, there should only ever be one child with it and we'll always want that one to handle the click. Fix: 190353630 Test: locally Test: atest RemoteViewsFixedCollectionAdapterTest Change-Id: I22057f148d33482ad84fff592b9f7f554fa2bfad --- core/java/android/widget/RemoteViews.java | 48 ++++++++++++----------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 25c84ba9d440b..73d56daab6fbf 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -114,6 +114,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -812,29 +813,8 @@ public class RemoteViews implements Parcelable, Filter { AdapterView av = (AdapterView) target; // The PendingIntent template is stored in the view's tag. OnItemClickListener listener = (parent, view, position, id) -> { - // The view should be a frame layout - if (view instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) view; - - // AdapterViews contain their children in a frame - // so we need to go one layer deeper here. - if (parent instanceof AdapterViewAnimator) { - vg = (ViewGroup) vg.getChildAt(0); - } - if (vg == null) return; - - RemoteResponse response = null; - int childCount = vg.getChildCount(); - for (int i = 0; i < childCount; i++) { - Object tag = vg.getChildAt(i).getTag(R.id.fillInIntent); - if (tag instanceof RemoteResponse) { - response = (RemoteResponse) tag; - break; - } - } - if (response == null) return; - response.handleViewInteraction(view, handler); - } + RemoteResponse response = findRemoteResponseTag(view); + response.handleViewInteraction(view, handler); }; av.setOnItemClickListener(listener); av.setTag(pendingIntentTemplate); @@ -845,6 +825,28 @@ public class RemoteViews implements Parcelable, Filter { } } + @Nullable + private RemoteResponse findRemoteResponseTag(@Nullable View rootView) { + if (rootView == null) return null; + + ArrayDeque viewsToCheck = new ArrayDeque<>(); + viewsToCheck.addLast(rootView); + + while (!viewsToCheck.isEmpty()) { + View view = viewsToCheck.removeFirst(); + Object tag = view.getTag(R.id.fillInIntent); + if (tag instanceof RemoteResponse) return (RemoteResponse) tag; + if (!(view instanceof ViewGroup)) continue; + + ViewGroup viewGroup = (ViewGroup) view; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + viewsToCheck.addLast(viewGroup.getChildAt(i)); + } + } + + return null; + } + @Override public int getActionTag() { return SET_PENDING_INTENT_TEMPLATE_TAG;