com.android.talkback.menurules.RuleGranularity.java Source code

Java tutorial

Introduction

Here is the source code for com.android.talkback.menurules.RuleGranularity.java

Source

/*
 * Copyright (C) 2013 Google Inc.
 *
 * 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 com.android.talkback.menurules;

import android.view.Menu;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.MenuItem;
import com.android.talkback.CursorGranularity;
import com.android.talkback.CursorGranularityManager;
import com.android.talkback.R;
import com.google.android.marvin.talkback.TalkBackService;
import com.android.talkback.contextmenu.ContextMenuItem;
import com.android.talkback.contextmenu.ContextMenuItemBuilder;
import com.android.talkback.controller.CursorController;
import com.android.utils.WebInterfaceUtils;

import java.util.LinkedList;
import java.util.List;

/**
 * Adds supported granularities to the local context menu. If the target node
 * contains web content, adds web-specific granularities.
 */
public class RuleGranularity implements NodeMenuRule {
    @Override
    public boolean accept(TalkBackService service, AccessibilityNodeInfoCompat node) {
        return !CursorGranularityManager.getSupportedGranularities(service, node).isEmpty();
    }

    @Override
    public List<ContextMenuItem> getMenuItemsForNode(TalkBackService service,
            ContextMenuItemBuilder menuItemBuilder, AccessibilityNodeInfoCompat node) {
        final CursorController cursorController = service.getCursorController();
        final CursorGranularity current = cursorController.getGranularityAt(node);
        final List<ContextMenuItem> items = new LinkedList<>();
        final List<CursorGranularity> granularities = CursorGranularityManager.getSupportedGranularities(service,
                node);
        final boolean hasWebContent = WebInterfaceUtils.hasNavigableWebContent(service, node);

        // Don't populate the menu if only object is supported.
        if (granularities.size() == 1) {
            return items;
        }

        final GranularityMenuItemClickListener clickListener = new GranularityMenuItemClickListener(service, node,
                hasWebContent);

        for (CursorGranularity granularity : granularities) {
            ContextMenuItem item = menuItemBuilder.createMenuItem(service, Menu.NONE, granularity.resourceId,
                    Menu.NONE, service.getString(granularity.resourceId));
            item.setOnMenuItemClickListener(clickListener);
            item.setCheckable(true);
            item.setChecked(granularity.equals(current));

            // Items are added in "natural" order, e.g. object first.
            items.add(item);
        }

        if (hasWebContent) {
            // Web content support navigation at a pseudo granularity for
            // entering special content like math or tables. This must be
            // special cased as it doesn't fit the semantics of an actual
            // granularity.
            ContextMenuItem specialContent = menuItemBuilder.createMenuItem(service, Menu.NONE,
                    R.id.pseudo_web_special_content, Menu.NONE,
                    service.getString(R.string.granularity_pseudo_web_special_content));
            specialContent.setOnMenuItemClickListener(clickListener);
            items.add(specialContent);
        }

        return items;
    }

    @Override
    public CharSequence getUserFriendlyMenuName(Context context) {
        return context.getString(R.string.title_granularity);
    }

    @Override
    public boolean canCollapseMenu() {
        return true;
    }

    private static class GranularityMenuItemClickListener implements MenuItem.OnMenuItemClickListener {

        private final CursorController mCursorController;
        private final AccessibilityNodeInfoCompat mNode;
        private final boolean mHasWebContent;

        public GranularityMenuItemClickListener(TalkBackService service, AccessibilityNodeInfoCompat node,
                boolean hasWebContent) {
            mCursorController = service.getCursorController();
            mNode = AccessibilityNodeInfoCompat.obtain(node);
            mHasWebContent = hasWebContent;
        }

        @Override
        public boolean onMenuItemClick(MenuItem item) {
            try {
                if (item == null) {
                    return false;
                }

                final int itemId = item.getItemId();

                if (itemId == R.id.pseudo_web_special_content) {
                    // If the user chooses to enter special web content, notify
                    // ChromeVox that the user entered this navigation mode and
                    // send further navigation movements at the default
                    // granularity.
                    mCursorController.setGranularity(CursorGranularity.DEFAULT, false /* fromUser */);
                    WebInterfaceUtils.setSpecialContentModeEnabled(mNode, true);
                    return true;
                }

                final CursorGranularity granularity = CursorGranularity.fromResourceId(itemId);
                if (granularity == null) {
                    return false;
                } else if (mHasWebContent && granularity == CursorGranularity.DEFAULT) {
                    // When the user switches to default granularity, always
                    // inform ChromeVox of this change so it can exit special
                    // content navigation mode if applicable. Sending this even
                    // when that mode hasn't been entered is fine and is simply
                    // a no-op on the ChromeVox side.
                    WebInterfaceUtils.setSpecialContentModeEnabled(mNode, false);
                }

                return mCursorController.setGranularity(granularity, true /* fromUser */);
            } finally {
                mNode.recycle();
            }
        }
    }
}