annotate src/uk/ac/qmul/eecs/ccmi/accessibility/AccessibilityService.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
rev   line source
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 java.util.EnumMap;
fiore@0 22 import java.util.Locale;
fiore@0 23
fiore@0 24 import uk.ac.qmul.eecs.ccmi.activities.R;
fiore@0 25
fiore@0 26 import android.content.Context;
fiore@0 27 import android.media.AudioManager;
fiore@0 28 import android.media.SoundPool;
fiore@0 29 import android.os.Vibrator;
fiore@0 30 import android.speech.tts.TextToSpeech;
fiore@0 31 import android.util.Log;
fiore@0 32
fiore@0 33 /**
fiore@0 34 * Encloses all the services needed to implement a custom accessibility system. Text-to-speech synthesis, sound and
fiore@0 35 * device vibration.
fiore@0 36 *
fiore@0 37 */
fiore@0 38 public class AccessibilityService {
fiore@0 39 private static final long VIBRATE_TIME = 200;
fiore@0 40 private static final float SPEECH_RATE = 2.0f;
fiore@0 41 private TextToSpeech tts;
fiore@0 42 private SoundPool soundPool;
fiore@0 43 private AudioManager audioManager;
fiore@0 44 private Vibrator vibrator;
fiore@0 45 private Context context;
fiore@0 46 private EnumMap<SoundEvent,Integer> soundIDs;
fiore@0 47 private boolean soundLoaded;
fiore@0 48 /**
fiore@0 49 *
fiore@0 50 * A list of events that have a sound associated. The sounds are built in and cannot be modified.
fiore@0 51 *
fiore@0 52 *
fiore@0 53 */
fiore@0 54 public enum SoundEvent {
fiore@0 55 V_CANCEL,
fiore@0 56 V_COLLAPSE,
fiore@0 57 V_DRAG,
fiore@0 58 V_EDITING_MODE,
fiore@0 59 V_ENDOFLIST,
fiore@0 60 V_ERROR,
fiore@0 61 V_EXPAND,
fiore@0 62 V_HOOK_OFF,
fiore@0 63 V_HOOK_ON,
fiore@0 64 V_JUMP,
fiore@0 65 V_MAGNET_OFF,
fiore@0 66 V_MAGNET_ON,
fiore@0 67 V_OK
fiore@0 68 }
fiore@0 69
fiore@0 70 private static AccessibilityService singleton;
fiore@0 71
fiore@0 72 /**
fiore@0 73 * Creates an instance of {@code AccessibilityService}. It implements the singleton pattern, therefore
fiore@0 74 * successive calls to this method will always return the same object.
fiore@0 75 *
fiore@0 76 * @param context The context to use. Usually your {@code Application} or {@code Activity} object.
fiore@0 77 *
fiore@0 78 * @return a singleton instance of {@code AccessibilityService}
fiore@0 79 */
fiore@0 80 public static AccessibilityService getInstance(Context context){
fiore@0 81 if(singleton == null){
fiore@0 82 singleton = new AccessibilityService(context);
fiore@0 83 }
fiore@0 84 return singleton;
fiore@0 85 }
fiore@0 86
fiore@0 87 /**
fiore@0 88 * Constructs a new {@code AccessibilityService}.
fiore@0 89 *
fiore@0 90 * @param context The current context
fiore@0 91 */
fiore@0 92 public AccessibilityService(Context context){
fiore@0 93 soundPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
fiore@0 94 this.context = context;
fiore@0 95 audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
fiore@0 96 soundIDs = new EnumMap<SoundEvent,Integer>(SoundEvent.class);
fiore@0 97 tts = new TextToSpeech(context, new TextToSpeech.OnInitListener(){
fiore@0 98 @Override
fiore@0 99 public void onInit(int status) {
fiore@0 100 if (status == TextToSpeech.SUCCESS) {
fiore@0 101 int result = tts.setLanguage(Locale.UK);
fiore@0 102 if (result == TextToSpeech.LANG_MISSING_DATA
fiore@0 103 || result == TextToSpeech.LANG_NOT_SUPPORTED) {
fiore@0 104 Log.w("TEXT TO SPEECH", "Text to Speech UK language not supported");
fiore@0 105 }
fiore@0 106 }
fiore@0 107 }
fiore@0 108 });
fiore@0 109 tts.setSpeechRate(SPEECH_RATE);
fiore@0 110 vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
fiore@0 111 }
fiore@0 112
fiore@0 113 /**
fiore@0 114 * Loads the built in sound library. This method must be called before any call to
fiore@0 115 * {@code playSound} or {@code stopSound}.
fiore@0 116 */
fiore@0 117 public void loadSounds(){
fiore@0 118 if(soundLoaded)
fiore@0 119 return;
fiore@0 120 soundIDs.put(SoundEvent.V_CANCEL,soundPool.load(context, R.raw.cancel, 1));
fiore@0 121 soundIDs.put(SoundEvent.V_COLLAPSE,soundPool.load(context, R.raw.collapse, 1));
fiore@0 122 soundIDs.put(SoundEvent.V_EXPAND,soundPool.load(context, R.raw.expand, 1));
fiore@0 123 soundIDs.put(SoundEvent.V_ENDOFLIST,soundPool.load(context, R.raw.endoflist, 1));
fiore@0 124 soundIDs.put(SoundEvent.V_OK,soundPool.load(context, R.raw.ok, 1));
fiore@0 125 soundIDs.put(SoundEvent.V_DRAG,soundPool.load(context, R.raw.drag, 1));
fiore@0 126 soundIDs.put(SoundEvent.V_EDITING_MODE,soundPool.load(context, R.raw.editingmode, 1));
fiore@0 127 soundIDs.put(SoundEvent.V_ERROR,soundPool.load(context, R.raw.error, 1));
fiore@0 128 soundIDs.put(SoundEvent.V_HOOK_OFF,soundPool.load(context, R.raw.hookoff, 1));
fiore@0 129 soundIDs.put(SoundEvent.V_HOOK_ON,soundPool.load(context, R.raw.hookon, 1));
fiore@0 130 soundIDs.put(SoundEvent.V_JUMP,soundPool.load(context, R.raw.jump, 1));
fiore@0 131 soundIDs.put(SoundEvent.V_MAGNET_OFF,soundPool.load(context, R.raw.magnetoff, 1));
fiore@0 132 soundLoaded = true;
fiore@0 133 }
fiore@0 134
fiore@0 135 /**
fiore@0 136 * Plays the sound associated to a {@code SoundEvent}.
fiore@0 137 *
fiore@0 138 * @param event the event to play the sound of
fiore@0 139 * @param loop whether to play the sound in a continuous loop or not
fiore@0 140 */
fiore@0 141 public void playSound(SoundEvent event, boolean loop){
fiore@0 142 if(!soundLoaded)
fiore@0 143 throw new IllegalStateException("loadSounds() must be called before any call to playSound");
fiore@0 144 float streamVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
fiore@0 145 streamVolume = streamVolume / audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
fiore@0 146 soundPool.play(soundIDs.get(event), streamVolume, streamVolume, 1, loop ? -1 : 0, 1f);
fiore@0 147 }
fiore@0 148
fiore@0 149 /**
fiore@0 150 * Plays the sound associated to a {@code SoundEvent} once. This call is equivalent to
fiore@0 151 * {@code playSound(event,false)}.
fiore@0 152 *
fiore@0 153 * @param event the event to play the sound of
fiore@0 154 */
fiore@0 155 public void playSound(SoundEvent event){
fiore@0 156 playSound(event,false);
fiore@0 157 }
fiore@0 158
fiore@0 159 /**
fiore@0 160 * Stop all the sounds being played at the moment of the call. Useful to stop a sound that is looping
fiore@0 161 * after a call to {@code playSound(event,true)}.
fiore@0 162 */
fiore@0 163 public void stopSound(){
fiore@0 164 if(!soundLoaded)
fiore@0 165 throw new IllegalStateException("loadSounds() must be called before any call to pauseSound");
fiore@0 166 soundPool.autoPause();
fiore@0 167 }
fiore@0 168
fiore@0 169 /**
fiore@0 170 * Utters a text via android text to speech synthesizer
fiore@0 171 *
fiore@0 172 * @param text the string to be uttered
fiore@0 173 **/
fiore@0 174 public void speak(String text){
fiore@0 175 tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
fiore@0 176 }
fiore@0 177
fiore@0 178
fiore@0 179 /**
fiore@0 180 * Make the device vibrate
fiore@0 181 */
fiore@0 182 public void vibrate(){
fiore@0 183 vibrator.vibrate(VIBRATE_TIME);
fiore@0 184 }
fiore@0 185
fiore@0 186 /**
fiore@0 187 * Dispose the resources allocated during initialization. To be called when the class
fiore@0 188 * is no longer needed by client classes.
fiore@0 189 */
fiore@0 190 public void dispose(){
fiore@0 191 /* dispose sound */
fiore@0 192 for(SoundEvent evt : soundIDs.keySet()){
fiore@0 193 soundPool.unload(soundIDs.get(evt));
fiore@0 194 }
fiore@0 195 /* dispose tts */
fiore@0 196 if(tts != null){
fiore@0 197 tts.stop();
fiore@0 198 tts.shutdown();
fiore@0 199 }
fiore@0 200 }
fiore@0 201
fiore@0 202 }