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

Commit 5febd85c authored by András Kurucz's avatar András Kurucz
Browse files

Prepare ExpandableNotificationRow for new A11y expansion APIs

Expose the row's current expanded state to accessibility services by
using AccessibilityNodeInfo#setExpandedState.
When the expandable state changes, dispatch a new accessibility event.

Bug: 380027122
Test: expand/collapse Notifications with TalkBack
Flag: com.android.systemui.notification_row_accessibility_expanded
Change-Id: Iff1b198daab597f3427e439c8031b8243a5bf42c
parent c8f5b457
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -291,6 +291,17 @@ flag {
    bug: "294830092"
}

flag {
  name: "notification_row_accessibility_expanded"
  namespace: "systemui"
  description: "Prepare ExpandableNotificationRow for new A11y expansion APIs."
  bug: "380027122"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}


flag {
    name: "scene_container"
    namespace: "systemui"
+86 −25
Original line number Diff line number Diff line
@@ -19,9 +19,12 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.Flags.notificationsRedesignTemplates;
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_EXPANDED;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;

import static com.android.systemui.Flags.notificationRowTransparency;
import static com.android.systemui.Flags.notificationsPinnedHunInShade;
import static com.android.systemui.Flags.notificationRowAccessibilityExpanded;
import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE;
import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
@@ -403,10 +406,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
    }

    private void toggleExpansionState(View v, boolean shouldLogExpandClickMetric) {
        boolean isGroupRoot = NotificationBundleUi.isEnabled()
                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
                : mGroupMembershipManager.isGroupSummary(mEntry);
        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot) {
        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot()) {
            mGroupExpansionChanging = true;
            if (NotificationBundleUi.isEnabled()) {
                final boolean wasExpanded =  mGroupExpansionManager.isGroupExpanded(mEntryAdapter);
@@ -2757,7 +2757,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        return false;
    }


    public void applyLaunchAnimationParams(LaunchAnimationParameters params) {
        if (params == null) {
            // `null` params indicates the animation is over, which means we can't access
@@ -3176,6 +3175,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        return mGroupExpansionManager.isGroupExpanded(mEntry);
    }

    private boolean isGroupRoot() {
        return NotificationBundleUi.isEnabled()
                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
                : mGroupMembershipManager.isGroupSummary(mEntry);
    }

    private void onAttachedChildrenCountChanged() {
        final boolean wasSummary = mIsSummaryWithChildren;
        mIsSummaryWithChildren = mChildrenContainer != null
@@ -3253,6 +3258,27 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        return !mSaveSpaceOnLockscreen;
    }

    /**
     * Is this row currently showing an expanded state? This method is different from
     * {@link #isExpanded()}, because it also handles groups, and pinned notifications.
     */
    private boolean isShowingExpanded() {
        if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot()) {
            // is group and expanded?
            return isGroupExpanded();
        } else if (mEnableNonGroupedNotificationExpand) {
            if (isPinned()) {
                // is pinned and expanded?
                return mExpandedWhenPinned;
            } else {
                // is regular notification and expanded?
                return isExpanded();
            }
        } else {
            return false;
        }
    }

    /**
     * Check whether the view state is currently expanded. This is given by the system in {@link
     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
@@ -3935,9 +3961,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView

    public void onExpandedByGesture(boolean userExpanded) {
        int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
        if (NotificationBundleUi.isEnabled()
                ? mGroupMembershipManager.isGroupRoot(mEntryAdapter)
                : mGroupMembershipManager.isGroupSummary(mEntry)) {
        if (isGroupRoot()) {
            event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
        }
        mMetricsLogger.action(event, userExpanded);
@@ -3990,9 +4014,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
            if (mExpansionChangedListener != null) {
                mExpansionChangedListener.onExpansionChanged(nowExpanded);
            }
            if (notificationRowAccessibilityExpanded()) {
                notifyAccessibilityContentExpansionChanged();
            }
        }
    }

    private void notifyAccessibilityContentExpansionChanged() {
        AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOW_CONTENT_CHANGED);
        onPopulateAccessibilityEvent(event);
        event.setContentChangeTypes(CONTENT_CHANGE_TYPE_EXPANDED);
        sendAccessibilityEventUnchecked(event);
    }

    public void setOnExpansionChangedListener(@Nullable OnExpansionChangedListener listener) {
        mExpansionChangedListener = listener;
    }
@@ -4020,13 +4054,27 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        super.onInitializeAccessibilityNodeInfoInternal(info);
        final boolean isLongClickable = isNotificationRowLongClickable();
        if (isLongClickable) {
            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
            info.addAction(AccessibilityAction.ACTION_LONG_CLICK);
        }
        info.setLongClickable(isLongClickable);

        if (canViewBeDismissed() && !mIsSnoozed) {
            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
            info.addAction(AccessibilityAction.ACTION_DISMISS);
        }

        if (notificationRowAccessibilityExpanded()) {
            if (isAccessibilityExpandable()) {
                if (isShowingExpanded()) {
                    info.addAction(AccessibilityAction.ACTION_COLLAPSE);
                    info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_FULL);
                } else {
                    info.addAction(AccessibilityAction.ACTION_EXPAND);
                    info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED);
                }
            } else {
                info.setExpandedState(AccessibilityNodeInfo.EXPANDED_STATE_UNDEFINED);
            }
        } else {
            boolean expandable = shouldShowPublic();
            boolean isExpanded = false;
            if (!expandable) {
@@ -4040,13 +4088,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
                    isExpanded = isExpanded();
                }
            }
        if (expandable && !mIsSnoozed) {

            if (expandable) {
                if (isExpanded) {
                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
                    info.addAction(AccessibilityAction.ACTION_COLLAPSE);
                } else {
                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
                    info.addAction(AccessibilityAction.ACTION_EXPAND);
                }
            }
        }

        NotificationMenuRowPlugin provider = getProvider();
        if (provider != null) {
            MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext());
@@ -4059,6 +4110,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        }
    }

    /** @return whether this row's expansion state can be toggled by an accessibility action. */
    private boolean isAccessibilityExpandable() {
        // don't add expand accessibility actions to snoozed notifications
        return !mIsSnoozed && isContentExpandable();
    }

    @Override
    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
        if (super.performAccessibilityActionInternal(action, arguments)) {
@@ -4325,6 +4382,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
            if (PromotedNotificationUiForceExpanded.isEnabled()) {
                pw.print(", isPromotedOngoing: " + isPromotedOngoing());
            }
            if (notificationRowAccessibilityExpanded()) {
                pw.print(", isShowingExpanded: " + isShowingExpanded());
                pw.print(", isAccessibilityExpandable: " + isAccessibilityExpandable());
            }
            pw.print(", isExpandable: " + isExpandable());
            pw.print(", mExpandable: " + mExpandable);
            pw.print(", isUserExpanded: " + isUserExpanded());