annotate src/uk/ac/qmul/eecs/ccmi/activities/AccessibleActivity.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.activities;
fiore@0 20
fiore@0 21 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService;
fiore@0 22 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
fiore@0 23 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleDialogBuilder;
fiore@0 24 import uk.ac.qmul.eecs.ccmi.accessibility.LayoutSonifier;
fiore@1 25 import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
fiore@0 26 import android.content.pm.PackageManager;
fiore@0 27 import android.media.AudioManager;
fiore@0 28 import android.os.Bundle;
fiore@0 29 import android.support.v4.app.FragmentActivity;
fiore@0 30 import android.view.MotionEvent;
fiore@0 31 import android.view.View;
fiore@0 32 import android.view.ViewGroup;
fiore@0 33 import android.view.ViewGroup.LayoutParams;
fiore@0 34 import android.view.WindowManager;
fiore@1 35 import android.widget.AbsListView;
fiore@0 36 import android.widget.Button;
fiore@0 37 import android.widget.LinearLayout;
fiore@0 38 import android.widget.ListAdapter;
fiore@0 39 import android.widget.ListView;
fiore@0 40 import android.widget.TextView;
fiore@0 41
fiore@0 42 /**
fiore@0 43 * An abstract accessible activity, displaying items of a list in a ListView and a text header.
fiore@0 44 */
fiore@0 45 public abstract class AccessibleActivity extends FragmentActivity {
fiore@0 46 private TextView header;
fiore@0 47 private ViewGroup mainLayout;
fiore@0 48 private Button scrollButton;
fiore@0 49 private boolean activityNameUttered = false;
fiore@0 50
fiore@0 51 /**
fiore@0 52 * the class used to generate audio and tactile cues when exploring the activity
fiore@0 53 */
fiore@0 54 protected AccessibilityService accessibilityService;
fiore@0 55 /**
fiore@0 56 * The list item list of the activity
fiore@0 57 */
fiore@0 58 protected ListView list;
fiore@0 59 /**
fiore@0 60 * used to generate dialogs when the user clicks or long-clicks on an item
fiore@0 61 */
fiore@0 62 protected AccessibleDialogBuilder dialogBuilder;
fiore@0 63
fiore@0 64 /** Called when the activity is first created. */
fiore@0 65 @Override
fiore@0 66 public void onCreate(Bundle savedInstanceState) {
fiore@0 67 super.onCreate(savedInstanceState);
fiore@0 68 // Set the hardware buttons to control the music
fiore@0 69 this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
fiore@0 70
fiore@0 71 /* makes the activity run on a full screen. */
fiore@0 72 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
fiore@0 73 WindowManager.LayoutParams.FLAG_FULLSCREEN);
fiore@0 74 mainLayout = (ViewGroup)getLayoutInflater().inflate(R.layout.main, null);
fiore@0 75 setContentView(mainLayout);
fiore@0 76
fiore@0 77 dialogBuilder = new AccessibleDialogBuilder(this.getSupportFragmentManager());
fiore@0 78
fiore@0 79 /* place the main list in the view */
fiore@0 80 LinearLayout listLayout = (LinearLayout)findViewById(R.id.listView1);
fiore@0 81 /* avoid scrolling upon touching, we rather want the user to hear the content */
fiore@0 82 list = new ListView(this){
fiore@0 83 @Override
fiore@0 84 public boolean dispatchTouchEvent(MotionEvent ev){
fiore@0 85 //returning true prevents the scrolling action on the listview
fiore@0 86 if(ev.getAction()==MotionEvent.ACTION_MOVE && ev.getPointerCount() == 1)
fiore@0 87 return true;
fiore@0 88 return super.dispatchTouchEvent(ev);
fiore@0 89 }
fiore@0 90
fiore@0 91 @Override
fiore@0 92 public void setAdapter(final ListAdapter adapter){
fiore@0 93 super.setAdapter(adapter);
fiore@0 94 if(scrollButton != null){
fiore@0 95 post(new Runnable(){ // need to be posted in order to work, as the list is not rendered yet at this point
fiore@0 96 public void run(){
fiore@0 97 boolean thereIsMore = (list.getLastVisiblePosition() < adapter.getCount()-1);
fiore@0 98 scrollButton.setEnabled(thereIsMore);
fiore@0 99 scrollButton.setContentDescription(
fiore@0 100 thereIsMore ? "scroll button" : "scroll button disabled");
fiore@0 101 }
fiore@0 102 });
fiore@0 103 }
fiore@0 104 }
fiore@0 105 };
fiore@0 106 list.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
fiore@1 107 list.setOnScrollListener(new AbsListView.OnScrollListener(){
fiore@1 108
fiore@1 109 @Override
fiore@1 110 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
fiore@1 111
fiore@1 112 @Override
fiore@1 113 public void onScrollStateChanged(AbsListView view, int scrollState) {
fiore@1 114 switch(scrollState){
fiore@1 115 case AbsListView.OnScrollListener.SCROLL_STATE_FLING :
fiore@1 116 ILogger.log("user scroll: fling");
fiore@1 117 break;
fiore@1 118 case AbsListView.OnScrollListener.SCROLL_STATE_IDLE :
fiore@1 119 ILogger.log("user scroll: "+ view.getItemAtPosition(list.getFirstVisiblePosition()));
fiore@1 120 break;
fiore@1 121 case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL :
fiore@1 122 ILogger.log("user scroll: started scrolling");
fiore@1 123 break;
fiore@1 124 }
fiore@1 125 }
fiore@1 126 });
fiore@0 127 listLayout.addView(list);
fiore@0 128
fiore@0 129 /* init header with a button to scroll down an up the list */
fiore@0 130 header = (TextView)findViewById(R.id.txtHeader);
fiore@0 131 scrollButton = (Button)findViewById(R.id.scrollButton);
fiore@0 132
fiore@0 133 /* if the device supports double finger touch screen then the user will scroll by
fiore@0 134 * swiping with two fingers. Otherwise a button at the very bottom will be created that will scroll the
fiore@0 135 * list of one item each time it's pressed and when the bottom is reached it will scroll up to the top.
fiore@0 136 */
fiore@0 137 if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)){
fiore@0 138 mainLayout.removeView(scrollButton);
fiore@0 139 scrollButton = null;
fiore@0 140 }else{
fiore@0 141 scrollButton.setOnClickListener(new View.OnClickListener() {
fiore@0 142 boolean doOnceMore = true;
fiore@0 143
fiore@0 144 @Override
fiore@0 145 public void onClick(View v) {
fiore@0 146 if(list.getLastVisiblePosition() == list.getCount()-1){
fiore@0 147 /* when the last item becomes visible it's not entirely visible. So don't go immediately *
fiore@0 148 * to the top but let the user scroll once more and make it entirely visible */
fiore@0 149 if(doOnceMore){
fiore@0 150 doOnceMore = false;
fiore@0 151 accessibilityService.playSound(SoundEvent.V_OK, false);
fiore@0 152 list.smoothScrollToPosition(list.getLastVisiblePosition());
fiore@0 153 scrollButton.setText(R.string.scrollBtnUp);
fiore@0 154 }else{
fiore@0 155 doOnceMore = true;
fiore@0 156 accessibilityService.playSound(SoundEvent.V_ENDOFLIST, false);
fiore@0 157 list.smoothScrollToPosition(0);
fiore@0 158 scrollButton.setText(R.string.scrollBtnDown);
fiore@0 159 }
fiore@0 160 }else{
fiore@0 161 accessibilityService.playSound(SoundEvent.V_OK, false);
fiore@0 162 list.smoothScrollToPosition(list.getLastVisiblePosition());
fiore@0 163 }
fiore@0 164 }
fiore@0 165 });
fiore@0 166 }
fiore@0 167 }
fiore@0 168
fiore@0 169 @Override
fiore@0 170 protected void onResume(){
fiore@0 171 super.onResume();
fiore@0 172 accessibilityService = new AccessibilityService(this);
fiore@0 173 accessibilityService.loadSounds();
fiore@0 174 dialogBuilder.setAccessibilityService(accessibilityService);
fiore@0 175
fiore@0 176 }
fiore@0 177
fiore@0 178 /**
fiore@0 179 * When the activity is resumed the header text is uttered thought the text to speech sinthesizer
fiore@0 180 */
fiore@0 181 @Override
fiore@0 182 public void onPostResume(){
fiore@0 183 super.onPostResume();
fiore@0 184 header.post(new Runnable(){
fiore@0 185 @Override
fiore@0 186 public void run() {
fiore@0 187 if(!activityNameUttered){
fiore@0 188 accessibilityService.speak(getName()+". Displaying "+getHeaderText());
fiore@0 189 activityNameUttered = true;
fiore@0 190 }else{
fiore@0 191 accessibilityService.speak("Displaying "+getHeaderText());
fiore@0 192 }
fiore@0 193 }
fiore@0 194 });
fiore@0 195 }
fiore@0 196
fiore@0 197 @Override
fiore@0 198 protected void onPause(){
fiore@0 199 super.onPause();
fiore@0 200 accessibilityService.stopSound();
fiore@0 201 accessibilityService.dispose();
fiore@0 202 dialogBuilder.setAccessibilityService(null);
fiore@0 203 }
fiore@0 204
fiore@0 205 @Override
fiore@0 206 public boolean dispatchTouchEvent(MotionEvent evt){
fiore@0 207 //returning true prevents the scrolling action on the listview
fiore@0 208 if(evt.getAction()==MotionEvent.ACTION_MOVE && evt.getPointerCount() == 1){
fiore@0 209 LayoutSonifier.getInstance().onTouch(mainLayout, evt, accessibilityService);
fiore@0 210 return true;
fiore@0 211 }
fiore@0 212
fiore@0 213 if(evt.getAction() == MotionEvent.ACTION_UP)
fiore@0 214 LayoutSonifier.getInstance().onTouch(mainLayout, evt, accessibilityService);
fiore@0 215 return super.dispatchTouchEvent(evt);
fiore@0 216 }
fiore@0 217
fiore@0 218 /**
fiore@0 219 * Set the header text. The text is uttered when the user hover over the header.
fiore@0 220 *
fiore@0 221 * @param headerText the header text
fiore@0 222 */
fiore@0 223 protected void setHeaderText(CharSequence headerText){
fiore@0 224 header.setText(headerText);
fiore@0 225 }
fiore@0 226
fiore@0 227 /**
fiore@0 228 * Returns the header text. The text is uttered when the user hover over the header.
fiore@0 229 *
fiore@0 230 * @return the header text
fiore@0 231 */
fiore@0 232 protected CharSequence getHeaderText(){
fiore@0 233 return header.getText();
fiore@0 234 }
fiore@0 235
fiore@0 236 public abstract String getName();
fiore@0 237 }