fiore@0: /*
fiore@0: CCmI Diagram Editor for Android
fiore@0:
fiore@0: Copyright (C) 2012 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
fiore@0:
fiore@0: This program is free software: you can redistribute it and/or modify
fiore@0: it under the terms of the GNU General Public License as published by
fiore@0: the Free Software Foundation, either version 3 of the License, or
fiore@0: (at your option) any later version.
fiore@0:
fiore@0: This program is distributed in the hope that it will be useful,
fiore@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
fiore@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fiore@0: GNU General Public License for more details.
fiore@0:
fiore@0: You should have received a copy of the GNU General Public License
fiore@0: along with this program. If not, see .
fiore@0: */
fiore@0: package uk.ac.qmul.eecs.ccmi.accessibility;
fiore@0:
fiore@0: import uk.ac.qmul.eecs.ccmi.activities.R;
fiore@1: import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
fiore@0: import android.content.Context;
fiore@0: import android.util.AttributeSet;
fiore@0: import android.view.MotionEvent;
fiore@0: import android.view.View;
fiore@0: import android.view.accessibility.AccessibilityEvent;
fiore@0: import android.widget.ArrayAdapter;
fiore@0: import android.widget.LinearLayout;
fiore@0: import android.widget.Spinner;
fiore@0:
fiore@0: /**
fiore@0: *
fiore@0: * A check box list that can be operated without looking at the display.
fiore@0: *
fiore@0: */
fiore@0: public class AccessibleCheckbox extends LinearLayout{
fiore@0: private NoClickSpinner spinner;
fiore@0: private AccessibilityService service;
fiore@0: private boolean[] checks;
fiore@0:
fiore@0: public AccessibleCheckbox(Context context, AttributeSet attrs) {
fiore@0: super(context, attrs);
fiore@0: init(context);
fiore@0: }
fiore@0:
fiore@0: public AccessibleCheckbox(Context context) {
fiore@0: super(context);
fiore@0: init(context);
fiore@0: }
fiore@0:
fiore@0: private void init(Context context){
fiore@0: spinner = new NoClickSpinner(context);
fiore@0: spinner.setContentDescription("selection box: ");
fiore@0: spinner.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
fiore@0: setTag("CHECKBOX");
fiore@0: addView(spinner);
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Sets the {@code accessibility} service for this class.
fiore@0: *
fiore@0: * @param service the {@code AccessibilityService} for this class
fiore@0: */
fiore@0: public void setAccessibilityService(AccessibilityService service){
fiore@0: this.service = service;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns a reference to the {@code accessibility} service for this class.
fiore@0: *
fiore@0: * @return the {@code AccessibilityService} for this class
fiore@0: */
fiore@0: public AccessibilityService getAccessibilityService(){
fiore@0: return service;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Sets the values to display to the user.
fiore@0: *
fiore@0: * @param values the values to display
fiore@0: * @param valueChecks The initial checks. If {@code valueChecks[i]} is {@code true} then {@code values[i]} will be
fiore@0: * checked when displayed to the user
fiore@0: */
fiore@0: public void setValues(String[] values, boolean[] valueChecks){
fiore@0: /* initialize the string array with the labels of the spinner, which are going to be between
fiore@0: * "<" and ">" if they are checked (according to valueChecks).
fiore@0: * checks is also initialized with valueChecks values, this will modified according
fiore@0: * to the user's selections and then returned by getValues() when the dialog is closed.
fiore@0: */
fiore@0: final String[] markedValues = new String[values.length];
fiore@0: checks = new boolean[valueChecks.length];
fiore@0: for(int i=0; i" : values[i] );
fiore@0: }
fiore@0:
fiore@0: spinner.setAdapter(new ArrayAdapter(getContext(),R.layout.list_item_1,markedValues));
fiore@0:
fiore@0: setOnClickListener(new View.OnClickListener(){
fiore@0: @Override
fiore@0: public void onClick(View view) {
fiore@0: spinner.setSelection((spinner.getSelectedItemPosition()+1) % spinner.getCount());
fiore@1: ILogger.logTap("checkbox (new value="+spinner.getSelectedItem().toString()+')');
fiore@0: if(service != null){
fiore@0: service.speak(spinner.getSelectedItem().toString()+(checks[spinner.getSelectedItemPosition()] ? " " : " un")+"checked");
fiore@0: }
fiore@0: }
fiore@0: });
fiore@0:
fiore@0: setOnLongClickListener(new View.OnLongClickListener(){
fiore@0: @Override
fiore@0: public boolean onLongClick(View view) {
fiore@0: int itemPosition = spinner.getSelectedItemPosition();
fiore@0: checks[itemPosition] = !checks[itemPosition];
fiore@0: if(checks[itemPosition]){
fiore@0: markedValues[itemPosition] = "<"+markedValues[itemPosition]+">";
fiore@0: }else{
fiore@0: markedValues[itemPosition] = markedValues[itemPosition].replaceAll("(^<)|(>$)", "");
fiore@0: }
fiore@0: if(service != null)
fiore@0: service.speak(spinner.getSelectedItem().toString()+(checks[spinner.getSelectedItemPosition()] ? "" : "un")+"checked");
fiore@1: ILogger.log("user long tap: spinner");
fiore@1: ILogger.log(spinner.getSelectedItem().toString()+' '+(checks[spinner.getSelectedItemPosition()] ? "" : "un")+"checked");
fiore@0: spinner.setAdapter(new ArrayAdapter(getContext(),R.layout.list_item_1,markedValues));
fiore@0: spinner.setSelection(itemPosition);
fiore@0: return true;
fiore@0: }
fiore@0: });
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the checks of the current values. To be called after this checkbox has been displayed
fiore@0: * to the user to collect their checks.
fiore@0: *
fiore@0: * @return the current checks
fiore@0: */
fiore@0: public boolean[] getChecks(){
fiore@0: return checks;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the currently selected value of the list.
fiore@0: *
fiore@0: * @return the currently selected value of the list
fiore@0: */
fiore@0: public String getSelectedValue(){
fiore@0: return spinner.getSelectedItem().toString();
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the position in the list of the currently selected value.
fiore@0: *
fiore@0: * @return the position in the list of the currently selected value
fiore@0: */
fiore@0: public int getSelectedValuePosition(){
fiore@0: return spinner.getSelectedItemPosition();
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * This method is empty to prevent the screen reader to speak when clicking on this text view.
fiore@0: */
fiore@0: @Override
fiore@0: public void sendAccessibilityEvent(int eventType){
fiore@0:
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * This method is empty to prevent the screen reader to speak when clicking on this text view.
fiore@0: */
fiore@0: @Override
fiore@0: public void sendAccessibilityEventUnchecked(AccessibilityEvent event){
fiore@0:
fiore@0: }
fiore@0:
fiore@0: private static class NoClickSpinner extends Spinner {
fiore@0:
fiore@0: public NoClickSpinner(Context context) {
fiore@0: super(context);
fiore@0: }
fiore@0:
fiore@0: public NoClickSpinner(Context context, AttributeSet attrs, int defStyle) {
fiore@0: super(context, attrs, defStyle);
fiore@0: }
fiore@0:
fiore@0: public NoClickSpinner(Context context, AttributeSet attrs) {
fiore@0: super(context, attrs);
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public boolean dispatchTouchEvent(MotionEvent evt){
fiore@0: return false;
fiore@0: }
fiore@0: }
fiore@0:
fiore@0: }