view src/uk/ac/qmul/eecs/ccmi/accessibility/AccessibleDialogBuilder.java @ 1:66b3a838feca logging tip

Added logging of user interaction
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Tue, 12 Feb 2013 15:31:48 +0000
parents e0ee6ac3a45f
children
line wrap: on
line source
/*  
 CCmI Diagram Editor for Android 
  
 Copyright (C) 2012  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.ccmi.accessibility;

import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
import uk.ac.qmul.eecs.ccmi.activities.R;
import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;

public class AccessibleDialogBuilder  {
	private FragmentManager fragmentManager;
	private AccessibilityService accessibilityService;
	
	public AccessibleDialogBuilder(FragmentManager fragmentManager) {
		this.fragmentManager = fragmentManager;
	}
	
	/**
	 * Sets the {@code AccessibilityService} for the dialogs. The call to this method must happen before  
	 * any dialog is displayed. The dialogs will be then accessible through a {@code LayoutSonifier}. 
	 * 
	 * @param accessibilityService the {@code AccessibilityService} instance for this class. 
	 */
	public void setAccessibilityService(AccessibilityService accessibilityService){
		this.accessibilityService = accessibilityService;		
	}

	/**
	 * Returns the instance of accessibility service in use. This can be useful to the client of this class to play 
	 * speech and sound when showing and dismissing dialogs.
	 * 
	 * @return a reference to the {@code AccessibilityService} class in use
	 */
	public AccessibilityService getAccessibilityService(){
		return accessibilityService;
	}
	
	/**
	 * Displays an accessible dialog 
	 * 
	 * @param type ID for an XML layout resource to load (e.g., R.layout.main_page)
	 * @param tag the tag for this dialog. It's also used uttered out through the speech 
	 *       synthesizer to notify the user the dialog has been displayed  
	 * @param buttonClickListener a listener that will be called when any of the buttons 
	 *      of the dialog will be pressed
	 */
	public void displayDialog(int type, String tag, ButtonClickListener buttonClickListener){
		AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
		
		accessibleDialogFragment.buttonClickListener = buttonClickListener;
		accessibleDialogFragment.accessibilityService = accessibilityService; 
		
		/* args to be used in onCreateDialog by the dialog fragment */
		Bundle args = new Bundle();
        args.putInt("dialogType", type);
        args.putString("tag", tag);
		accessibleDialogFragment.setArguments(args);
		
		ILogger.logDialog(tag);
		/* show the dialog */
		accessibleDialogFragment.show(fragmentManager,tag);
	}
	
	/**
	 * Displays an accessible text dialog. The dialog has one text field for text input, and buttons
	 * to confirm or cancel your input.  
	 *  
	 * @param tag the tag for this dialog. It's also used uttered out through the speech 
	 *       synthesizer to notify the user the dialog has been displayed  
	 * @param text optional text to set in the text field before shoing the dialog 
	 * @param buttonClickListener  a listener that will be called when any of the buttons 
	 *      of the dialog will be pressed
	 */
	public void displayTextDialog(String tag, String text, ButtonClickListener buttonClickListener){
		AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
		
		accessibleDialogFragment.buttonClickListener = buttonClickListener;
		accessibleDialogFragment.accessibilityService = accessibilityService; 
		
		/* args to be used in onCreateDialog by the dialog fragment */
		Bundle args = new Bundle();
        args.putInt("dialogType", R.layout.text_dialog);
        args.putString("tag", tag);
        if(text != null)
        	args.putString("text", text);
		accessibleDialogFragment.setArguments(args);
		
		ILogger.logDialog(tag);
		/* show the dialog */
		accessibleDialogFragment.show(fragmentManager,tag);
	}
	
	/**
	 * Displays an accessible selection dialog. The dialog has one selection box for selection input, and buttons
	 * to confirm or cancel your input.  
	 * 
	 * @param tag tag the tag for this dialog. It's also used uttered out through the speech 
	 *       synthesizer to notify the user the dialog has been displayed  
	 * @param values the possible values of the selection box
	 * @param buttonClickListener  a listener that will be called when any of the buttons 
	 *      of the dialog will be pressed
	 */
	public void displaySelectionDialog(String tag, String[] values, ButtonClickListener buttonClickListener ){
		AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
		
		accessibleDialogFragment.buttonClickListener = buttonClickListener;
		accessibleDialogFragment.accessibilityService = accessibilityService; 
		accessibleDialogFragment.values = values;
		
		/* args to be used in onCreateDialog by the dialog fragment */
		Bundle args = new Bundle();
        args.putInt("dialogType", R.layout.selection_dialog);
        args.putString("tag", tag);
		accessibleDialogFragment.setArguments(args);
		
		ILogger.logDialog(tag);
		/* show the dialog */
		accessibleDialogFragment.show(fragmentManager,tag);
	}
	
	/**
	 * Displays an accessible check box dialog. The dialog has one check box for selection input, and buttons
	 * to confirm or cancel your input.  
	 * 
	 * @param tag tag the tag for this dialog. It's also used uttered out through the speech 
	 *       synthesizer to notify the user the dialog has been displayed  
	 * @param values the possible values that can be checked 
	 * @param checks The initial checks. If {@code valueChecks[i]} is {@code true} then {@code values[i]} will be 
	 * checked when displayed to the user
	 * @param buttonClickListener  a listener that will be called when any of the buttons 
	 *      of the dialog will be pressed
	 */
	public void displayCheckDialog(String tag, String[] values, boolean[] checks, ButtonClickListener buttonClickListener){
		AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
		
		accessibleDialogFragment.buttonClickListener = buttonClickListener;
		accessibleDialogFragment.accessibilityService = accessibilityService; 
		accessibleDialogFragment.values = values;
		accessibleDialogFragment.checks = checks;
		
		/* args to be used in onCreateDialog by the dialog fragment */
		Bundle args = new Bundle();
        args.putInt("dialogType", R.layout.checkbox_dialog);
        args.putString("tag", tag);
		accessibleDialogFragment.setArguments(args);
		
		ILogger.logDialog(tag);
		/* show the dialog */
		accessibleDialogFragment.show(fragmentManager,tag);
	}
	
	public static class AccessibleDialogFragment extends DialogFragment {
		private String[] values;
		private boolean[] checks;
		private ButtonClickListener buttonClickListener;
		private AccessibilityService accessibilityService;
		
		@Override
	    public Dialog onCreateDialog(final Bundle savedInstanceState) {
			/* Get layout inflater */
			LayoutInflater inflater = getActivity().getLayoutInflater();
			/* inflate the view with layout and pass it to the builder for creation */
			ViewGroup layout = (ViewGroup)inflater.inflate(getArguments().getInt("dialogType"), null);
			
			if(values != null){
				if(checks == null){ //selection dialog 
					AccessibleSpinner spinner = (AccessibleSpinner)layout.findViewById(R.id.selectionSpinner);
					spinner.setAccessibilityService(accessibilityService);
					spinner.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item_1 ,values));
				}else{ // check box dialog
					AccessibleCheckbox checkbox = (AccessibleCheckbox)layout.findViewById(R.id.checkBox);
					checkbox.setValues(values, checks);
					checkbox.setAccessibilityService(accessibilityService);
				}	
			}
			if(getArguments().getString("text") != null){
				EditText textField = (EditText)layout.findViewById(R.id.text_edit);
				textField.setText(getArguments().getString("text"));
			}
			
			AlertDialog createdDialog = new AccessibleDialog(getActivity(),accessibilityService,layout); 
			createdDialog.setCancelable(false);
			createdDialog.setCanceledOnTouchOutside(false);
			
			/* go through the layout and look for any buttons to hook them up with the button listener */
			for(int i=0; i< layout.getChildCount(); i++){
				if(layout.getChildAt(i) instanceof Button){
					Button b = (Button)layout.getChildAt(i);
					b.setOnClickListener(new View.OnClickListener() {
						@Override
						public void onClick(View v) {
							buttonClickListener.onClick(v, AccessibleDialogFragment.this, getArguments().getString("tag"));
						}
					});
				}
			}
			
			/* when showing a dialog a background sound is played in loop to notify the user they *
			 * have changed mode. More over the tag ( = the title) of the dialog is uttered out   */
			accessibilityService.playSound(SoundEvent.V_EDITING_MODE, true);
			accessibilityService.speak(getArguments().getString("tag"));
			return createdDialog;
		}	
		
		@Override
		public void onDismiss (DialogInterface dialog){
			/* when the dialog is dismissed the ambient sound is stopped to * 
			 * notify the userhe is back in the non edit  mode              */
			accessibilityService.stopSound();
		}
		
	}
	
	/**
	 * A listener for the click of buttons in the dialogs displayed through {@code AccessibleDialogBuilder}.  
	 */
	public interface ButtonClickListener {
		/**
		 * When a button of a displayed dialog is clicked this method is called.
		 * 
		 * @param v the clicked button
		 * @param dialogFragment the fragment used to show the dialog 
		 * @param tag the tag of the dialog. Passed as argument to the display methods 
		 */
		public void onClick(View v, DialogFragment dialogFragment, String tag);			
	}
	
	private static class AccessibleDialog extends AlertDialog {		
		AccessibilityService accessibilityService;
		ViewGroup layout;
		
		private AccessibleDialog(Context context, AccessibilityService accessibilityService, ViewGroup layout) {
			super(context);
			this.accessibilityService = accessibilityService;
			this.layout = layout;
			setView(layout);
		}
		
		@Override
		public boolean dispatchTouchEvent(MotionEvent evt){
			LayoutSonifier.getInstance().onTouch(layout, evt, accessibilityService);
			return super.dispatchTouchEvent(evt);
		}
		
		@Override
		public void	onBackPressed(){
			super.onBackPressed();
			ILogger.logTap("back (cancel)");
		}
	}
	
}