fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Diagram Editor for Android
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2012 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
5
|
fiore@0
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
7 it under the terms of the GNU General Public License as published by
|
fiore@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
9 (at your option) any later version.
|
fiore@0
|
10
|
fiore@0
|
11 This program is distributed in the hope that it will be useful,
|
fiore@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
14 GNU General Public License for more details.
|
fiore@0
|
15
|
fiore@0
|
16 You should have received a copy of the GNU General Public License
|
fiore@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
18 */
|
fiore@0
|
19 package uk.ac.qmul.eecs.ccmi.accessibility;
|
fiore@0
|
20
|
fiore@0
|
21 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
|
fiore@0
|
22 import uk.ac.qmul.eecs.ccmi.activities.R;
|
fiore@1
|
23 import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
|
fiore@0
|
24 import android.app.AlertDialog;
|
fiore@0
|
25 import android.app.Dialog;
|
fiore@0
|
26 import android.content.Context;
|
fiore@0
|
27 import android.content.DialogInterface;
|
fiore@0
|
28 import android.os.Bundle;
|
fiore@0
|
29 import android.support.v4.app.DialogFragment;
|
fiore@0
|
30 import android.support.v4.app.FragmentManager;
|
fiore@0
|
31 import android.view.LayoutInflater;
|
fiore@0
|
32 import android.view.MotionEvent;
|
fiore@0
|
33 import android.view.View;
|
fiore@0
|
34 import android.view.ViewGroup;
|
fiore@0
|
35 import android.widget.ArrayAdapter;
|
fiore@0
|
36 import android.widget.Button;
|
fiore@0
|
37 import android.widget.EditText;
|
fiore@0
|
38
|
fiore@0
|
39 public class AccessibleDialogBuilder {
|
fiore@0
|
40 private FragmentManager fragmentManager;
|
fiore@0
|
41 private AccessibilityService accessibilityService;
|
fiore@0
|
42
|
fiore@0
|
43 public AccessibleDialogBuilder(FragmentManager fragmentManager) {
|
fiore@0
|
44 this.fragmentManager = fragmentManager;
|
fiore@0
|
45 }
|
fiore@0
|
46
|
fiore@0
|
47 /**
|
fiore@0
|
48 * Sets the {@code AccessibilityService} for the dialogs. The call to this method must happen before
|
fiore@0
|
49 * any dialog is displayed. The dialogs will be then accessible through a {@code LayoutSonifier}.
|
fiore@0
|
50 *
|
fiore@0
|
51 * @param accessibilityService the {@code AccessibilityService} instance for this class.
|
fiore@0
|
52 */
|
fiore@0
|
53 public void setAccessibilityService(AccessibilityService accessibilityService){
|
fiore@0
|
54 this.accessibilityService = accessibilityService;
|
fiore@0
|
55 }
|
fiore@0
|
56
|
fiore@0
|
57 /**
|
fiore@0
|
58 * Returns the instance of accessibility service in use. This can be useful to the client of this class to play
|
fiore@0
|
59 * speech and sound when showing and dismissing dialogs.
|
fiore@0
|
60 *
|
fiore@0
|
61 * @return a reference to the {@code AccessibilityService} class in use
|
fiore@0
|
62 */
|
fiore@0
|
63 public AccessibilityService getAccessibilityService(){
|
fiore@0
|
64 return accessibilityService;
|
fiore@0
|
65 }
|
fiore@0
|
66
|
fiore@0
|
67 /**
|
fiore@0
|
68 * Displays an accessible dialog
|
fiore@0
|
69 *
|
fiore@0
|
70 * @param type ID for an XML layout resource to load (e.g., R.layout.main_page)
|
fiore@0
|
71 * @param tag the tag for this dialog. It's also used uttered out through the speech
|
fiore@0
|
72 * synthesizer to notify the user the dialog has been displayed
|
fiore@0
|
73 * @param buttonClickListener a listener that will be called when any of the buttons
|
fiore@0
|
74 * of the dialog will be pressed
|
fiore@0
|
75 */
|
fiore@0
|
76 public void displayDialog(int type, String tag, ButtonClickListener buttonClickListener){
|
fiore@0
|
77 AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
|
fiore@0
|
78
|
fiore@0
|
79 accessibleDialogFragment.buttonClickListener = buttonClickListener;
|
fiore@0
|
80 accessibleDialogFragment.accessibilityService = accessibilityService;
|
fiore@0
|
81
|
fiore@0
|
82 /* args to be used in onCreateDialog by the dialog fragment */
|
fiore@0
|
83 Bundle args = new Bundle();
|
fiore@0
|
84 args.putInt("dialogType", type);
|
fiore@0
|
85 args.putString("tag", tag);
|
fiore@0
|
86 accessibleDialogFragment.setArguments(args);
|
fiore@1
|
87
|
fiore@1
|
88 ILogger.logDialog(tag);
|
fiore@0
|
89 /* show the dialog */
|
fiore@0
|
90 accessibleDialogFragment.show(fragmentManager,tag);
|
fiore@0
|
91 }
|
fiore@0
|
92
|
fiore@0
|
93 /**
|
fiore@0
|
94 * Displays an accessible text dialog. The dialog has one text field for text input, and buttons
|
fiore@0
|
95 * to confirm or cancel your input.
|
fiore@0
|
96 *
|
fiore@0
|
97 * @param tag the tag for this dialog. It's also used uttered out through the speech
|
fiore@0
|
98 * synthesizer to notify the user the dialog has been displayed
|
fiore@0
|
99 * @param text optional text to set in the text field before shoing the dialog
|
fiore@0
|
100 * @param buttonClickListener a listener that will be called when any of the buttons
|
fiore@0
|
101 * of the dialog will be pressed
|
fiore@0
|
102 */
|
fiore@0
|
103 public void displayTextDialog(String tag, String text, ButtonClickListener buttonClickListener){
|
fiore@0
|
104 AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
|
fiore@0
|
105
|
fiore@0
|
106 accessibleDialogFragment.buttonClickListener = buttonClickListener;
|
fiore@0
|
107 accessibleDialogFragment.accessibilityService = accessibilityService;
|
fiore@0
|
108
|
fiore@0
|
109 /* args to be used in onCreateDialog by the dialog fragment */
|
fiore@0
|
110 Bundle args = new Bundle();
|
fiore@0
|
111 args.putInt("dialogType", R.layout.text_dialog);
|
fiore@0
|
112 args.putString("tag", tag);
|
fiore@0
|
113 if(text != null)
|
fiore@0
|
114 args.putString("text", text);
|
fiore@0
|
115 accessibleDialogFragment.setArguments(args);
|
fiore@1
|
116
|
fiore@1
|
117 ILogger.logDialog(tag);
|
fiore@0
|
118 /* show the dialog */
|
fiore@0
|
119 accessibleDialogFragment.show(fragmentManager,tag);
|
fiore@0
|
120 }
|
fiore@0
|
121
|
fiore@0
|
122 /**
|
fiore@0
|
123 * Displays an accessible selection dialog. The dialog has one selection box for selection input, and buttons
|
fiore@0
|
124 * to confirm or cancel your input.
|
fiore@0
|
125 *
|
fiore@0
|
126 * @param tag tag the tag for this dialog. It's also used uttered out through the speech
|
fiore@0
|
127 * synthesizer to notify the user the dialog has been displayed
|
fiore@0
|
128 * @param values the possible values of the selection box
|
fiore@0
|
129 * @param buttonClickListener a listener that will be called when any of the buttons
|
fiore@0
|
130 * of the dialog will be pressed
|
fiore@0
|
131 */
|
fiore@0
|
132 public void displaySelectionDialog(String tag, String[] values, ButtonClickListener buttonClickListener ){
|
fiore@0
|
133 AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
|
fiore@0
|
134
|
fiore@0
|
135 accessibleDialogFragment.buttonClickListener = buttonClickListener;
|
fiore@0
|
136 accessibleDialogFragment.accessibilityService = accessibilityService;
|
fiore@0
|
137 accessibleDialogFragment.values = values;
|
fiore@0
|
138
|
fiore@0
|
139 /* args to be used in onCreateDialog by the dialog fragment */
|
fiore@0
|
140 Bundle args = new Bundle();
|
fiore@0
|
141 args.putInt("dialogType", R.layout.selection_dialog);
|
fiore@0
|
142 args.putString("tag", tag);
|
fiore@0
|
143 accessibleDialogFragment.setArguments(args);
|
fiore@1
|
144
|
fiore@1
|
145 ILogger.logDialog(tag);
|
fiore@0
|
146 /* show the dialog */
|
fiore@0
|
147 accessibleDialogFragment.show(fragmentManager,tag);
|
fiore@0
|
148 }
|
fiore@0
|
149
|
fiore@0
|
150 /**
|
fiore@0
|
151 * Displays an accessible check box dialog. The dialog has one check box for selection input, and buttons
|
fiore@0
|
152 * to confirm or cancel your input.
|
fiore@0
|
153 *
|
fiore@0
|
154 * @param tag tag the tag for this dialog. It's also used uttered out through the speech
|
fiore@0
|
155 * synthesizer to notify the user the dialog has been displayed
|
fiore@0
|
156 * @param values the possible values that can be checked
|
fiore@0
|
157 * @param checks The initial checks. If {@code valueChecks[i]} is {@code true} then {@code values[i]} will be
|
fiore@0
|
158 * checked when displayed to the user
|
fiore@0
|
159 * @param buttonClickListener a listener that will be called when any of the buttons
|
fiore@0
|
160 * of the dialog will be pressed
|
fiore@0
|
161 */
|
fiore@0
|
162 public void displayCheckDialog(String tag, String[] values, boolean[] checks, ButtonClickListener buttonClickListener){
|
fiore@0
|
163 AccessibleDialogFragment accessibleDialogFragment = new AccessibleDialogFragment();
|
fiore@0
|
164
|
fiore@0
|
165 accessibleDialogFragment.buttonClickListener = buttonClickListener;
|
fiore@0
|
166 accessibleDialogFragment.accessibilityService = accessibilityService;
|
fiore@0
|
167 accessibleDialogFragment.values = values;
|
fiore@0
|
168 accessibleDialogFragment.checks = checks;
|
fiore@0
|
169
|
fiore@0
|
170 /* args to be used in onCreateDialog by the dialog fragment */
|
fiore@0
|
171 Bundle args = new Bundle();
|
fiore@0
|
172 args.putInt("dialogType", R.layout.checkbox_dialog);
|
fiore@0
|
173 args.putString("tag", tag);
|
fiore@0
|
174 accessibleDialogFragment.setArguments(args);
|
fiore@1
|
175
|
fiore@1
|
176 ILogger.logDialog(tag);
|
fiore@0
|
177 /* show the dialog */
|
fiore@0
|
178 accessibleDialogFragment.show(fragmentManager,tag);
|
fiore@0
|
179 }
|
fiore@0
|
180
|
fiore@0
|
181 public static class AccessibleDialogFragment extends DialogFragment {
|
fiore@0
|
182 private String[] values;
|
fiore@0
|
183 private boolean[] checks;
|
fiore@0
|
184 private ButtonClickListener buttonClickListener;
|
fiore@0
|
185 private AccessibilityService accessibilityService;
|
fiore@0
|
186
|
fiore@0
|
187 @Override
|
fiore@0
|
188 public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
fiore@0
|
189 /* Get layout inflater */
|
fiore@0
|
190 LayoutInflater inflater = getActivity().getLayoutInflater();
|
fiore@0
|
191 /* inflate the view with layout and pass it to the builder for creation */
|
fiore@0
|
192 ViewGroup layout = (ViewGroup)inflater.inflate(getArguments().getInt("dialogType"), null);
|
fiore@0
|
193
|
fiore@0
|
194 if(values != null){
|
fiore@0
|
195 if(checks == null){ //selection dialog
|
fiore@0
|
196 AccessibleSpinner spinner = (AccessibleSpinner)layout.findViewById(R.id.selectionSpinner);
|
fiore@0
|
197 spinner.setAccessibilityService(accessibilityService);
|
fiore@0
|
198 spinner.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item_1 ,values));
|
fiore@0
|
199 }else{ // check box dialog
|
fiore@0
|
200 AccessibleCheckbox checkbox = (AccessibleCheckbox)layout.findViewById(R.id.checkBox);
|
fiore@0
|
201 checkbox.setValues(values, checks);
|
fiore@0
|
202 checkbox.setAccessibilityService(accessibilityService);
|
fiore@0
|
203 }
|
fiore@0
|
204 }
|
fiore@0
|
205 if(getArguments().getString("text") != null){
|
fiore@0
|
206 EditText textField = (EditText)layout.findViewById(R.id.text_edit);
|
fiore@0
|
207 textField.setText(getArguments().getString("text"));
|
fiore@0
|
208 }
|
fiore@0
|
209
|
fiore@0
|
210 AlertDialog createdDialog = new AccessibleDialog(getActivity(),accessibilityService,layout);
|
fiore@0
|
211 createdDialog.setCancelable(false);
|
fiore@0
|
212 createdDialog.setCanceledOnTouchOutside(false);
|
fiore@0
|
213
|
fiore@0
|
214 /* go through the layout and look for any buttons to hook them up with the button listener */
|
fiore@0
|
215 for(int i=0; i< layout.getChildCount(); i++){
|
fiore@0
|
216 if(layout.getChildAt(i) instanceof Button){
|
fiore@0
|
217 Button b = (Button)layout.getChildAt(i);
|
fiore@0
|
218 b.setOnClickListener(new View.OnClickListener() {
|
fiore@0
|
219 @Override
|
fiore@0
|
220 public void onClick(View v) {
|
fiore@0
|
221 buttonClickListener.onClick(v, AccessibleDialogFragment.this, getArguments().getString("tag"));
|
fiore@0
|
222 }
|
fiore@0
|
223 });
|
fiore@0
|
224 }
|
fiore@0
|
225 }
|
fiore@0
|
226
|
fiore@0
|
227 /* when showing a dialog a background sound is played in loop to notify the user they *
|
fiore@0
|
228 * have changed mode. More over the tag ( = the title) of the dialog is uttered out */
|
fiore@0
|
229 accessibilityService.playSound(SoundEvent.V_EDITING_MODE, true);
|
fiore@0
|
230 accessibilityService.speak(getArguments().getString("tag"));
|
fiore@0
|
231 return createdDialog;
|
fiore@0
|
232 }
|
fiore@0
|
233
|
fiore@0
|
234 @Override
|
fiore@0
|
235 public void onDismiss (DialogInterface dialog){
|
fiore@0
|
236 /* when the dialog is dismissed the ambient sound is stopped to *
|
fiore@0
|
237 * notify the userhe is back in the non edit mode */
|
fiore@0
|
238 accessibilityService.stopSound();
|
fiore@0
|
239 }
|
fiore@0
|
240
|
fiore@0
|
241 }
|
fiore@0
|
242
|
fiore@0
|
243 /**
|
fiore@0
|
244 * A listener for the click of buttons in the dialogs displayed through {@code AccessibleDialogBuilder}.
|
fiore@0
|
245 */
|
fiore@0
|
246 public interface ButtonClickListener {
|
fiore@0
|
247 /**
|
fiore@0
|
248 * When a button of a displayed dialog is clicked this method is called.
|
fiore@0
|
249 *
|
fiore@0
|
250 * @param v the clicked button
|
fiore@0
|
251 * @param dialogFragment the fragment used to show the dialog
|
fiore@0
|
252 * @param tag the tag of the dialog. Passed as argument to the display methods
|
fiore@0
|
253 */
|
fiore@0
|
254 public void onClick(View v, DialogFragment dialogFragment, String tag);
|
fiore@0
|
255 }
|
fiore@0
|
256
|
fiore@0
|
257 private static class AccessibleDialog extends AlertDialog {
|
fiore@0
|
258 AccessibilityService accessibilityService;
|
fiore@0
|
259 ViewGroup layout;
|
fiore@0
|
260
|
fiore@0
|
261 private AccessibleDialog(Context context, AccessibilityService accessibilityService, ViewGroup layout) {
|
fiore@0
|
262 super(context);
|
fiore@0
|
263 this.accessibilityService = accessibilityService;
|
fiore@0
|
264 this.layout = layout;
|
fiore@0
|
265 setView(layout);
|
fiore@0
|
266 }
|
fiore@0
|
267
|
fiore@0
|
268 @Override
|
fiore@0
|
269 public boolean dispatchTouchEvent(MotionEvent evt){
|
fiore@0
|
270 LayoutSonifier.getInstance().onTouch(layout, evt, accessibilityService);
|
fiore@0
|
271 return super.dispatchTouchEvent(evt);
|
fiore@0
|
272 }
|
fiore@1
|
273
|
fiore@1
|
274 @Override
|
fiore@1
|
275 public void onBackPressed(){
|
fiore@1
|
276 super.onBackPressed();
|
fiore@1
|
277 ILogger.logTap("back (cancel)");
|
fiore@1
|
278 }
|
fiore@0
|
279 }
|
fiore@0
|
280
|
fiore@0
|
281 }
|