Repository: flutter/flutter
File: engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java (Java)

Code before:

    boolean hasCheckedState = semanticsNode.hasFlag(Flag.HAS_CHECKED_STATE);
    boolean hasToggledState = semanticsNode.hasFlag(Flag.HAS_TOGGLED_STATE);
    if (BuildConfig.DEBUG && (hasCheckedState && hasToggledState)) {
      Log.e(TAG, "Expected semanticsNode to have checked state and toggled state.");
    }
    result.setCheckable(hasCheckedState || hasToggledState);
    if (hasCheckedState) {
      result.setChecked(semanticsNode.hasFlag(Flag.IS_CHECKED));
      if (semanticsNode.hasFlag(Flag.IS_IN_MUTUALLY_EXCLUSIVE_GROUP)) {
        result.setClassName("android.widget.RadioButton");
      } else {
        result.setClassName("android.widget.CheckBox");
      }
    } else if (hasToggledState) {
      result.setChecked(semanticsNode.hasFlag(Flag.IS_TOGGLED));
      result.setClassName("android.widget.Switch");
    }
    result.setSelected(semanticsNode.hasFlag(Flag.IS_SELECTED));

    // Starting on API level 36. setChecked takes int instead.
    if (Build.VERSION.SDK_INT >= API_LEVELS.API_36) {
      if (hasCheckedState) {
        result.setChecked(
            semanticsNode.hasFlag(Flag.IS_CHECKED)
                ? AccessibilityNodeInfo.CHECKED_STATE_TRUE
                : AccessibilityNodeInfo.CHECKED_STATE_FALSE);
      } else if (hasToggledState) {
        result.setChecked(
            semanticsNode.hasFlag(Flag.IS_TOGGLED)
                ? AccessibilityNodeInfo.CHECKED_STATE_TRUE
                : AccessibilityNodeInfo.CHECKED_STATE_FALSE);
      }
    }
    if (Build.VERSION.SDK_INT >= API_LEVELS.API_36) {
      if (semanticsNode.hasFlag(Flag.HAS_EXPANDED_STATE)) {
        final boolean isExpanded = semanticsNode.hasFlag(Flag.IS_EXPANDED);
        result.setExpandedState(
            isExpanded
                ? AccessibilityNodeInfo.EXPANDED_STATE_FULL
                : AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED);
        if (semanticsNode.hasAction(Action.EXPAND)) {
          result.addAction(AccessibilityNodeInfo.ACTION_EXPAND);
        }
        if (semanticsNode.hasAction(Action.COLLAPSE)) {
          result.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
        }
      }
    }

    // Heading support

Review comment (suggestion):
looking at the new api, there is also CHECKED_STATE_PARTIAL, which i think also translate to https://api.flutter.dev/flutter/semantics/SemanticsProperties/mixed.html

I think we should also consider setting this state

Code after:

    boolean hasCheckedState = semanticsNode.hasFlag(Flag.HAS_CHECKED_STATE);
    boolean hasToggledState = semanticsNode.hasFlag(Flag.HAS_TOGGLED_STATE);
    if (BuildConfig.DEBUG && (hasCheckedState && hasToggledState)) {
      Log.e(TAG, "Expected semanticsNode to have checked state and toggled state.");
    }
    result.setCheckable(hasCheckedState || hasToggledState);
    if (hasCheckedState) {
      if (semanticsNode.hasFlag(Flag.IS_IN_MUTUALLY_EXCLUSIVE_GROUP)) {
        result.setClassName("android.widget.RadioButton");
      } else {
        result.setClassName("android.widget.CheckBox");
      }
      // Starting on API level 36, setChecked takes int instead.
      if (Build.VERSION.SDK_INT >= API_LEVELS.API_36) {
        result.setChecked(
            semanticsNode.hasFlag(Flag.IS_CHECK_STATE_MIXED)
                ? AccessibilityNodeInfo.CHECKED_STATE_PARTIAL
                : semanticsNode.hasFlag(Flag.IS_CHECKED)
                    ? AccessibilityNodeInfo.CHECKED_STATE_TRUE
                    : AccessibilityNodeInfo.CHECKED_STATE_FALSE);
      } else {
        result.setChecked(semanticsNode.hasFlag(Flag.IS_CHECKED));
      }
    } else if (hasToggledState) {
      result.setClassName("android.widget.Switch");
      // Starting on API level 36, setChecked takes int instead.
      if (Build.VERSION.SDK_INT >= API_LEVELS.API_36) {
        result.setChecked(
            semanticsNode.hasFlag(Flag.IS_TOGGLED)
                ? AccessibilityNodeInfo.CHECKED_STATE_TRUE
                : AccessibilityNodeInfo.CHECKED_STATE_FALSE);
      } else {
        result.setChecked(semanticsNode.hasFlag(Flag.IS_TOGGLED));
      }
    }
    result.setSelected(semanticsNode.hasFlag(Flag.IS_SELECTED));
    if (Build.VERSION.SDK_INT >= API_LEVELS.API_36) {
      if (semanticsNode.hasFlag(Flag.HAS_EXPANDED_STATE)) {
        final boolean isExpanded = semanticsNode.hasFlag(Flag.IS_EXPANDED);
        result.setExpandedState(
            isExpanded
                ? AccessibilityNodeInfo.EXPANDED_STATE_FULL
                : AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED);
        if (semanticsNode.hasAction(Action.EXPAND)) {
          result.addAction(AccessibilityNodeInfo.ACTION_EXPAND);
        }
        if (semanticsNode.hasAction(Action.COLLAPSE)) {
          result.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
        }
      }