From 03756131ca33e62d2fb3ad37574a63164ac817c8 Mon Sep 17 00:00:00 2001 From: Michal Brzezinski Date: Tue, 6 Jun 2023 11:47:22 +0200 Subject: [PATCH] Moving setIsRootNamespace in notification one level higher setIsRootNamespace was used to avoiding conflicts when we look for view by id but custom notifications layout happens to have view with the same id (b/13421971). Unfortunately it also breaks keyboard navigation - once user enters notification with keyboard, they can't leave it. The solution is to override focusSearch method but that can't be done on root view (id status_bar_latest_event_content) because it's coming from framework. That's why setIsRootNamespace is called on view one level higher - NotificationContentView and then we override focusSearch. Bug: 285554136 Test: PlatformScenarioTests:TabingThroughSplitShade Change-Id: I8a6f0bc9012df8f55eb1ad1cb4c3d44af537b18c --- .../NotificationRemoteInputManager.java | 2 +- .../row/NotificationContentInflater.java | 2 -- .../row/NotificationContentView.java | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index c5191154377a9..406db18c43dd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -402,7 +402,7 @@ public class NotificationRemoteInputManager implements Dumpable { while (p != null) { if (p instanceof View) { View pv = (View) p; - if (pv.isRootNamespace()) { + if (pv.getId() == com.android.internal.R.id.status_bar_latest_event_content) { riv = findRemoteInputView(pv); row = (ExpandableNotificationRow) pv.getTag(R.id.row_tag_for_content_view); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index b4bfded58e4b5..13d1978ec8ff1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -474,7 +474,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder parentLayout, remoteViewClickHandler); validateView(v, entry, row.getResources()); - v.setIsRootNamespace(true); applyCallback.setResultView(v); } else { newContentView.reapply( @@ -511,7 +510,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder return; } if (isNewView) { - v.setIsRootNamespace(true); applyCallback.setResultView(v); } else if (existingWrapper != null) { existingWrapper.onReinflated(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 124df8c3b8156..20f4429f294bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -208,6 +208,23 @@ public class NotificationContentView extends FrameLayout implements Notification mSmartReplyConstants = smartReplyConstants; mSmartReplyController = smartReplyController; mStatusBarService = statusBarService; + // We set root namespace so that we avoid searching children for id. Notification might + // contain custom view and their ids may clash with ids already existing in shade or + // notification panel + setIsRootNamespace(true); + } + + @Override + public View focusSearch(View focused, int direction) { + // This implementation is copied from ViewGroup but with removed special handling of + // setIsRootNamespace. This view is set as tree root using setIsRootNamespace and it + // causes focus to be stuck inside of it. We need to be root to avoid id conflicts + // but we don't want to behave like root when it comes to focusing. + if (mParent != null) { + return mParent.focusSearch(focused, direction); + } + Log.wtf(TAG, "NotificationContentView doesn't have parent"); + return null; } public void reinflate() {