/* * Copyright (C) 2015 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.switchaccess; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.os.Handler; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import com.android.talkback.R; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Node to display context menus. Context menus provide text-based options for situations where * highlighting Views doesn't provide enough information for users to make choices. Examples * include global actions, which aren't associated with any View, and situations where a View * exposes multiple actions, such as click and long click or scrolling forward vs backward. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ContextMenuNode extends OptionScanSelectionNode implements ContextMenuItem { public ContextMenuNode( ContextMenuItem child0, ContextMenuItem child1, ContextMenuItem... children) { super(child0, child1, children); } /** * Draw the menu and highlight options with the paint options */ @Override public void showSelections(final OverlayController overlayController, final Paint[] paints) { Context context = overlayController.getContext(); /* Create a layout to hold the Views */ LinearLayout menuLayout = new LinearLayout(context); menuLayout.setOrientation(LinearLayout.VERTICAL); menuLayout.setGravity(Gravity.CENTER); menuLayout.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); final List<List<View>> viewsForHighlight = new ArrayList<>(); LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); boolean optionScanningEnabled = SwitchAccessPreferenceActivity .isOptionScanningEnabled(context); for(int i = 0; i < getChildCount(); i++) { List<View> viewList = new ArrayList<>(); viewsForHighlight.add(viewList); /* Cast is safe because constructor only takes ContextMenuItems */ ContextMenuItem child = (ContextMenuItem) getChild(i); for (CharSequence actionLabel : child.getActionLabels(context)) { Button buttonForAction = (Button) layoutInflater .inflate(R.layout.switch_access_context_menu_button, null); buttonForAction.setText(actionLabel); menuLayout.addView(buttonForAction); viewList.add(buttonForAction); } if (optionScanningEnabled && (i == getChildCount() - 1)) { Button buttonForAction = (Button) layoutInflater .inflate(R.layout.switch_access_context_menu_button, null); buttonForAction.setText(context.getResources() .getString(android.R.string.cancel)); menuLayout.addView(buttonForAction); viewList.add(buttonForAction); } } overlayController.addViewAndShow(menuLayout); /** * Highlight the option Views in a separate pass after they are being shown (until they * are shown their locations are not known.) */ new Handler().post(new Runnable() { @Override public void run() { for (int i = 0; i < viewsForHighlight.size(); ++i) { Set<Rect> rectsToHighlight = new HashSet<>(); for (View view : viewsForHighlight.get(i)) { int[] locationOnScreen = new int[2]; view.getLocationOnScreen(locationOnScreen); Rect highlightRect = new Rect(locationOnScreen[0], locationOnScreen[1], locationOnScreen[0] + view.getWidth(), locationOnScreen[1] + view.getHeight()); rectsToHighlight.add(highlightRect); } overlayController.highlightPerimeterOfRects(rectsToHighlight, paints[i]); } } }); } public List<CharSequence> getActionLabels(Context context) { List<CharSequence> actionLabels = new ArrayList<>(); for (OptionScanNode child : mChildren) { /* Cast is safe because constructor only takes ContextMenuItems */ actionLabels.addAll(((ContextMenuItem) child).getActionLabels(context)); } return Collections.unmodifiableList(actionLabels); } }