From 101f061d3566023ac65b7bcdc548b5875b58a2e7 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Fri, 28 Oct 2011 19:08:02 -0700 Subject: [PATCH] Folding Accessibility Service sample into ApiDemos. 1. Moving Accerssibility Service sample into ApiDemos since we are putting all accessibility samples there. 2. Fixed regressions (mainly due to adding new event types) in the Accessibility Service sample. 3. Updated the Query Window Content sample to have some instructions and to work with touch exploration. Change-Id: I226ac4130f7f8cae47bb52cbdeab9f104cfaba40 --- build/sdk.atree | 1 - samples/AccessibilityService/Android.mk | 12 -- .../AccessibilityService/AndroidManifest.xml | 40 ---- samples/AccessibilityService/_index.html | 120 ------------ .../res/values/strings.xml | 50 ----- samples/ApiDemos/AndroidManifest.xml | 40 +++- .../res/layout/accessibility_service.xml | 36 ++++ samples/ApiDemos/res/layout/tasklist_main.xml | 19 ++ samples/ApiDemos/res/layout/tasklist_row.xml | 6 +- .../res/raw/sound_ringer_normal.ogg | Bin .../res/raw/sound_ringer_silent.ogg | Bin .../res/raw/sound_ringer_vibrate.ogg | Bin .../res/raw/sound_screen_off.ogg | Bin .../res/raw/sound_screen_on.ogg | Bin .../res/raw/sound_view_clicked.ogg | Bin .../raw/sound_view_focused_or_selected.ogg | Bin .../res/raw/sound_view_hover_enter.ogg | Bin 0 -> 13311 bytes .../res/raw/sound_window_state_changed.ogg | Bin samples/ApiDemos/res/values/strings.xml | 30 ++- samples/ApiDemos/res/xml/taskbackconfig.xml | 15 +- .../apis/accessibility/ClockBackActivity.java | 55 ++++++ .../apis/accessibility}/ClockBackService.java | 180 +++--------------- .../apis/accessibility/TaskBackService.java | 149 +++++++++------ .../apis/accessibility/TaskListActivity.java | 21 +- .../android/apis/accessibility/_index.html | 26 ++- ...tionBarSettingsActionProviderActivity.java | 9 - 26 files changed, 335 insertions(+), 474 deletions(-) delete mode 100644 samples/AccessibilityService/Android.mk delete mode 100644 samples/AccessibilityService/AndroidManifest.xml delete mode 100644 samples/AccessibilityService/_index.html delete mode 100644 samples/AccessibilityService/res/values/strings.xml create mode 100644 samples/ApiDemos/res/layout/accessibility_service.xml rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_ringer_normal.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_ringer_silent.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_ringer_vibrate.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_screen_off.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_screen_on.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_view_clicked.ogg (100%) rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_view_focused_or_selected.ogg (100%) create mode 100644 samples/ApiDemos/res/raw/sound_view_hover_enter.ogg rename samples/{AccessibilityService => ApiDemos}/res/raw/sound_window_state_changed.ogg (100%) create mode 100644 samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackActivity.java rename samples/{AccessibilityService/src/com/example/android/clockback => ApiDemos/src/com/example/android/apis/accessibility}/ClockBackService.java (75%) diff --git a/build/sdk.atree b/build/sdk.atree index 5996c9ccb..0d436c6a4 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -152,7 +152,6 @@ development/samples/source.properties samples/${PLATFORM_NAME}/source.pro # # PLEASE KEEP THE SAMPLES IN ALPHABETICAL ORDER. # -development/samples/AccessibilityService samples/${PLATFORM_NAME}/AccessibilityService development/samples/AccelerometerPlay samples/${PLATFORM_NAME}/AccelerometerPlay development/samples/ActionBarCompat samples/${PLATFORM_NAME}/ActionBarCompat development/samples/AndroidBeamDemo samples/${PLATFORM_NAME}/AndroidBeamDemo diff --git a/samples/AccessibilityService/Android.mk b/samples/AccessibilityService/Android.mk deleted file mode 100644 index e47b6f605..000000000 --- a/samples/AccessibilityService/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := samples - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_PACKAGE_NAME := AccessibilityService - -LOCAL_SDK_VERSION := current - -include $(BUILD_PACKAGE) diff --git a/samples/AccessibilityService/AndroidManifest.xml b/samples/AccessibilityService/AndroidManifest.xml deleted file mode 100644 index 1b5f7944a..000000000 --- a/samples/AccessibilityService/AndroidManifest.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/AccessibilityService/_index.html b/samples/AccessibilityService/_index.html deleted file mode 100644 index d6adbf2c7..000000000 --- a/samples/AccessibilityService/_index.html +++ /dev/null @@ -1,120 +0,0 @@ -

- This is an example of an accessibility service that provides custom feedback for the Clock application which comes by default with Android devices. It demonstrates the following key features of the Android accessibility APIs: -

-
    -
  1. - Simple demonstration of how to use the accessibility APIs. -
  2. -
  3. - Hands-on example of various ways to utilize the accessibility API for providing alternative and complementary feedback. -
  4. -
  5. - Providing application specific feedback — the service handles only accessibility events from the Clock application. -
  6. -
  7. - Providing dynamic, context-dependent feedback — feedback type changes depending on the ringer mode. -
  8. -
  9. - Application specific UI enhancement — application domain knowledge is utilized to enhance the provided feedback. -
  10. -
-

- - Note: This code sample will work only on devices shipped with the default Clock application. If you are - running Android 1.6 of Android 2.0 you should enable first ClockBack and then TalkBack since in these - releases accessibility services are notified in the order of registration. - -

-

- Steps to exercise the ClockBack example: -

-
    -
  1. -
      -
    • - Action: Enable accessibility and all default accessibility services:
      - Settings → Accessibility → select the Accessibility, TalkBack, KickBack, and SoundBack checkboxes -
    • -
    • - Result: The system provides spoken, audible, and haptic feedback. -
    • -
    -
  2. -
  3. -
      -
    • - Action: Explore the feedback provided by the system:
      - Poke around with the trackball. -
    • -
    • - Result: You are somehow familiar with the type of the provided feedback. -
    • -
    -
  4. -
  5. -
      -
    • - Action: Go to the Clock application and try to change the time of an alarm:
      - All applications → Clock → Alarms (left corner) → Select an alarm → Time — explore the plus, minus buttons, hour and minute edit boxes. -
    • -
    • - Result: The hour and minute edit boxes are announced without any clue which is the hour and which is the minute one (you can guess from the arrangement). -
    • -
    -
  6. -
  7. -
      -
    • - Action: Enable ClockBack:
      - Settings → Accessibility → ClockBack — select the checkbox (assuming you have installed the APK). -
    • -
    • - Result: We have active accessibility service for providing application specific feedback for the Clock application. -
    • -
    -
  8. -
  9. -
      -
    • - Action: Go to the Clock application and try to change the time of an alarm:
      - All applications → Clock → Alarms (left corner) → Select an alarm → Time — explore the hour and minute edit boxes. -
    • -
    • - Result: The hour and minute edit boxes are now spoken. This is an example of application specific feedback that utilizes domain information to enhance the user experience. -
    • -
    -
  10. -
  11. -
      -
    • - Action: Set the ringer to vibration mode and explore the provided feedback:
      - Use the device button for reducing the ringer volume until it is in vibration mode. Move around the Clock application and outside of that application. -
    • -
    • - Result: The Clock application provides custom audible and default haptic feedback. The rest of the system provides the default feedback. -
    • -
    -
  12. -
  13. -
      -
    • - Action: Set the ringer to muted mode and explore the provided feedback:
      - Use the device button for reducing the ringer volume until it is in muted mode. Move around the Clock application and outside of that application. -
    • -
    • - Result: The Clock application provides only custom haptic feedback. The rest of the system provides the default feedback. Now we are providing custom context dependent feedback based on the device state (ringer mode). -
    • -
    -
  14. -
  15. -
      -
    • - Action: Write an accessibility service:
      - The Eyes-Free open source project has more accessibility-related resources. To contribute, visit the project page or post to the mailing list. -
    • -
    • - Result: One more cool application has been written. -
    • -
    -
  16. -
diff --git a/samples/AccessibilityService/res/values/strings.xml b/samples/AccessibilityService/res/values/strings.xml deleted file mode 100644 index a9913c240..000000000 --- a/samples/AccessibilityService/res/values/strings.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - ClockBack - - - Increase hours - - - Increase minutes - - - Decrease hours - - - Decrease minutes - - - hour - - - hours - - - minute - - - minutes - - - Ringer audible - - - Ringer vibrate - - - Ringer silent - - - - - Screen on. Volume %1$s percent. - - - Screen off. Volume %1$s percent. - - diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index 064d05887..d897adc1a 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -541,8 +541,27 @@ + + + + + + + + + + + + + + + + + @@ -550,15 +569,16 @@ - - - - - - - + + + + + + diff --git a/samples/ApiDemos/res/layout/accessibility_service.xml b/samples/ApiDemos/res/layout/accessibility_service.xml new file mode 100644 index 000000000..169379bde --- /dev/null +++ b/samples/ApiDemos/res/layout/accessibility_service.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/samples/ApiDemos/res/layout/tasklist_main.xml b/samples/ApiDemos/res/layout/tasklist_main.xml index 61a17e3ef..3226344ad 100644 --- a/samples/ApiDemos/res/layout/tasklist_main.xml +++ b/samples/ApiDemos/res/layout/tasklist_main.xml @@ -19,10 +19,29 @@ android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> + + + + + + diff --git a/samples/ApiDemos/res/layout/tasklist_row.xml b/samples/ApiDemos/res/layout/tasklist_row.xml index 51bb31eea..029eb0465 100644 --- a/samples/ApiDemos/res/layout/tasklist_row.xml +++ b/samples/ApiDemos/res/layout/tasklist_row.xml @@ -19,7 +19,10 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="match_parent" android:weightSum="1" android:baselineAligned="false"> + android:layout_height="match_parent" + android:weightSum="1" + android:baselineAligned="false"> + + diff --git a/samples/AccessibilityService/res/raw/sound_ringer_normal.ogg b/samples/ApiDemos/res/raw/sound_ringer_normal.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_ringer_normal.ogg rename to samples/ApiDemos/res/raw/sound_ringer_normal.ogg diff --git a/samples/AccessibilityService/res/raw/sound_ringer_silent.ogg b/samples/ApiDemos/res/raw/sound_ringer_silent.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_ringer_silent.ogg rename to samples/ApiDemos/res/raw/sound_ringer_silent.ogg diff --git a/samples/AccessibilityService/res/raw/sound_ringer_vibrate.ogg b/samples/ApiDemos/res/raw/sound_ringer_vibrate.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_ringer_vibrate.ogg rename to samples/ApiDemos/res/raw/sound_ringer_vibrate.ogg diff --git a/samples/AccessibilityService/res/raw/sound_screen_off.ogg b/samples/ApiDemos/res/raw/sound_screen_off.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_screen_off.ogg rename to samples/ApiDemos/res/raw/sound_screen_off.ogg diff --git a/samples/AccessibilityService/res/raw/sound_screen_on.ogg b/samples/ApiDemos/res/raw/sound_screen_on.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_screen_on.ogg rename to samples/ApiDemos/res/raw/sound_screen_on.ogg diff --git a/samples/AccessibilityService/res/raw/sound_view_clicked.ogg b/samples/ApiDemos/res/raw/sound_view_clicked.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_view_clicked.ogg rename to samples/ApiDemos/res/raw/sound_view_clicked.ogg diff --git a/samples/AccessibilityService/res/raw/sound_view_focused_or_selected.ogg b/samples/ApiDemos/res/raw/sound_view_focused_or_selected.ogg similarity index 100% rename from samples/AccessibilityService/res/raw/sound_view_focused_or_selected.ogg rename to samples/ApiDemos/res/raw/sound_view_focused_or_selected.ogg diff --git a/samples/ApiDemos/res/raw/sound_view_hover_enter.ogg b/samples/ApiDemos/res/raw/sound_view_hover_enter.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bf3632e7bf6c2e38ab3cfc88ff0b3448ac649c2c GIT binary patch literal 13311 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 M;l~ + Accessibility/Accessibility Service + ClockBack + + 1. Enable TalkBack (Settings -> Accessibility -> TalkBack). + \n\n2. Enable Explore-byTouch (Settings -> Accessibility -> Explore by Touch). + \n\n3. Touch explore the Clock application and the home screen. + \n\n4. Go to the Clock application and change the time of an alarm. + \n\n5. Enable ClockBack (Settings -> Accessibility -> ClockBack). + \n\n6. Go to the Clock application and change an alarm. + \n\n7. Set the ringer to vibration mode and change an alarm. + \n\n8. Set the ringer to muted mode and change an alarm. + - Accessibility/Accessibility Node Querying - Task App Accessibility Service - TaskBack + Ringer audible + Ringer vibrate + Ringer silent + Screen on. Volume %1$s percent. + Screen off. Volume %1$s percent. + + Accessibility/Accessibility Node Querying + QueryBack + Task App Accessibility Service + + 1. Enable QueryBack (Settings -> Accessibility -> QueryBack). + \n\n2. Enable Explore-byTouch (Settings -> Accessibility -> Explore by Touch). + \n\n3. Touch explore the list. + Task Task %1$s %2$s is complete is not complete + diff --git a/samples/ApiDemos/res/xml/taskbackconfig.xml b/samples/ApiDemos/res/xml/taskbackconfig.xml index 02ff11c70..5dc0cf5c7 100644 --- a/samples/ApiDemos/res/xml/taskbackconfig.xml +++ b/samples/ApiDemos/res/xml/taskbackconfig.xml @@ -15,11 +15,10 @@ limitations under the License. --> - + diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackActivity.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackActivity.java new file mode 100644 index 000000000..75fb1ff3d --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackActivity.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.apis.accessibility; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; +import android.view.View; +import android.widget.ImageButton; + +import com.example.android.apis.R; + +/** + * This is the entry activity for a sample that demonstrates how to implement an + * {@link android.accessibilityservice.AccessibilityService}. + */ +public class ClockBackActivity extends Activity { + + /** An intent for launching the system settings. */ + private static final Intent sSettingsIntent = + new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + + /** + * {@inheritDoc} + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.accessibility_service); + + // Add a shortcut to the accessibility settings. + ImageButton button = (ImageButton) findViewById(R.id.button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(sSettingsIntent); + } + }); + } +} diff --git a/samples/AccessibilityService/src/com/example/android/clockback/ClockBackService.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackService.java similarity index 75% rename from samples/AccessibilityService/src/com/example/android/clockback/ClockBackService.java rename to samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackService.java index 5746716e1..d5cd2a3cb 100644 --- a/samples/AccessibilityService/src/com/example/android/clockback/ClockBackService.java +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/ClockBackService.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.example.android.clockback; +package com.example.android.apis.accessibility; + +import com.example.android.apis.R; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; @@ -54,19 +56,7 @@ import java.util.List; * Providing dynamic, context-dependent feedback — feedback type changes * depending on the ringer state. * - *
  • - * Application specific UI enhancement - application domain knowledge is - * utilized to enhance the provided feedback. - *
  • * - *

    - * - * Note: This code sample will work only on devices shipped with the default Clock - * application. If you are running Android 1.6 of Android 2.0 you should enable first - * ClockBack and then TalkBack since in these releases accessibility services are - * notified in the order of registration. - * - *

    */ public class ClockBackService extends AccessibilityService { @@ -147,56 +137,6 @@ public class ClockBackService extends AccessibilityService { /** The space string constant. */ private static final String SPACE = " "; - /** - * The class name of the number picker buttons with no text we want to - * announce in the Clock application. - */ - private static final String CLASS_NAME_NUMBER_PICKER_BUTTON_CLOCK = "android.widget.NumberPickerButton"; - - /** - * The class name of the number picker buttons with no text we want to - * announce in the AlarmClock application. - */ - private static final String CLASS_NAME_NUMBER_PICKER_BUTTON_ALARM_CLOCK = "com.android.internal.widget.NumberPickerButton"; - - /** - * The class name of the edit text box for hours and minutes we want to - * better announce. - */ - private static final String CLASS_NAME_EDIT_TEXT = "android.widget.EditText"; - - /** - * Mapping from integer to string resource id where the keys are generated - * from the {@link AccessibilityEvent#getText()}, - * {@link AccessibilityEvent#getItemCount()} and - * {@link AccessibilityEvent#getCurrentItemIndex()} properties. - *

    - * Note: In general, computing these mappings includes the widget position on - * the screen. This is fragile and should be used as a last resort since - * changing the layout could potentially change the widget position. This is - * a workaround since the widgets of interest are image buttons that do not - * have contentDescription attribute set (plus/minus buttons) or no other - * information in the accessibility event is available to distinguish them - * aside of their positions on the screen (hour/minute inputs).
    - * If you are owner of the target application (Clock in this case) you - * should add contentDescription attribute to all image buttons such that a - * screen reader knows how to speak them. For input fields (while not - * applicable for the hour and minute inputs since they are not empty) a - * hint text should be set to enable better announcement. - *

    - */ - private static final SparseArray sEventDataMappedStringResourceIds = new SparseArray(); - static { - sEventDataMappedStringResourceIds.put(110, R.string.value_increase_hours); - sEventDataMappedStringResourceIds.put(1140, R.string.value_increase_minutes); - sEventDataMappedStringResourceIds.put(1120, R.string.value_decrease_hours); - sEventDataMappedStringResourceIds.put(1160, R.string.value_decrease_minutes); - sEventDataMappedStringResourceIds.put(1111, R.string.value_hour); - sEventDataMappedStringResourceIds.put(1110, R.string.value_hours); - sEventDataMappedStringResourceIds.put(1151, R.string.value_minute); - sEventDataMappedStringResourceIds.put(1150, R.string.value_minutes); - } - /** Mapping from integers to vibration patterns for haptic feedback. */ private static final SparseArray sVibrationPatterns = new SparseArray(); static { @@ -215,6 +155,9 @@ public class ClockBackService extends AccessibilityService { sVibrationPatterns.put(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, new long[] { 0L, 25L, 50L, 25L, 50L, 25L }); + sVibrationPatterns.put(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, new long[] { + 0L, 15L, 10L, 15L, 15L, 10L + }); sVibrationPatterns.put(INDEX_SCREEN_ON, new long[] { 0L, 10L, 10L, 20L, 20L, 30L }); @@ -226,11 +169,18 @@ public class ClockBackService extends AccessibilityService { /** Mapping from integers to raw sound resource ids. */ private static SparseArray sSoundsResourceIds = new SparseArray(); static { - sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_CLICKED, R.raw.sound_view_clicked); - sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, R.raw.sound_view_clicked); - sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_SELECTED, R.raw.sound_view_focused_or_selected); - sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_FOCUSED, R.raw.sound_view_focused_or_selected); - sSoundsResourceIds.put(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, R.raw.sound_window_state_changed); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_CLICKED, + R.raw.sound_view_clicked); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, + R.raw.sound_view_clicked); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_SELECTED, + R.raw.sound_view_focused_or_selected); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_FOCUSED, + R.raw.sound_view_focused_or_selected); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, + R.raw.sound_window_state_changed); + sSoundsResourceIds.put(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + R.raw.sound_view_hover_enter); sSoundsResourceIds.put(INDEX_SCREEN_ON, R.raw.sound_screen_on); sSoundsResourceIds.put(INDEX_SCREEN_OFF, R.raw.sound_screen_off); sSoundsResourceIds.put(INDEX_RINGER_SILENT, R.raw.sound_ringer_silent); @@ -304,7 +254,9 @@ public class ClockBackService extends AccessibilityService { case MESSAGE_VIBRATE: int key = message.arg1; long[] pattern = sVibrationPatterns.get(key); - mVibrator.vibrate(pattern, -1); + if (pattern != null) { + mVibrator.vibrate(pattern, -1); + } return; case MESSAGE_STOP_VIBRATE: mVibrator.cancel(); @@ -473,12 +425,6 @@ public class ClockBackService extends AccessibilityService { * Let some other services provide audible feedback (SounBack) and haptic * feedback (KickBack). *

    - * Note: In the above description an assumption is made that all default feedback - * services are enabled. Such services are TalkBack, SoundBack, and KickBack. - * Also the feature of defining a service as the default for a given feedback - * type will be available in Android 2.2 and above. For previous releases the package - * specific accessibility service must be registered first i.e. checked in the - * settings. * * @param ringerMode The device ringer mode. */ @@ -593,19 +539,6 @@ public class ClockBackService extends AccessibilityService { utterance.append(SPACE); } - // Here we do a bit of enhancement of the UI presentation by using the semantic - // of the event source in the context of the Clock application. - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED - && CLASS_NAME_EDIT_TEXT.equals(event.getClassName())) { - // If the source is an edit text box and we have a mapping based on - // its position in the items of the container parent of the event source - // we append that value as well. We say "XX hours" and "XX minutes". - String resourceValue = getEventDataMappedStringResource(event); - if (resourceValue != null) { - utterance.append(resourceValue); - } - } - return utterance.toString(); } @@ -617,70 +550,9 @@ public class ClockBackService extends AccessibilityService { return utterance.toString(); } - // No text and content description for the plus and minus buttons, so we lookup - // custom values based on the event's itemCount and currentItemIndex properties. - CharSequence className = event.getClassName(); - - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED - && (CLASS_NAME_NUMBER_PICKER_BUTTON_ALARM_CLOCK.equals(className) - || CLASS_NAME_NUMBER_PICKER_BUTTON_CLOCK.equals(className))) { - String resourceValue = getEventDataMappedStringResource(event); - utterance.append(resourceValue); - } - return utterance.toString(); } - /** - * Returns a string resource mapped based on the accessibility event - * data, specifically the - * {@link AccessibilityEvent#getText()}, - * {@link AccessibilityEvent#getItemCount()}, and - * {@link AccessibilityEvent#getCurrentItemIndex()} properties. - * - * @param event The {@link AccessibilityEvent} to process. - * @return The mapped string if such exists, null otherwise. - */ - private String getEventDataMappedStringResource(AccessibilityEvent event) { - int lookupIndex = computeLookupIndex(event); - int resourceId = sEventDataMappedStringResourceIds.get(lookupIndex); - return getString(resourceId); - } - - /** - * Computes an index for looking up the custom text for views which either - * do not have text/content description or the position information - * is the only oracle for deciding from which widget was an accessibility - * event generated. The index is computed based on - * {@link AccessibilityEvent#getText()}, - * {@link AccessibilityEvent#getItemCount()}, and - * {@link AccessibilityEvent#getCurrentItemIndex()} properties. - * - * @param event The event from which to compute the index. - * @return The lookup index. - */ - private int computeLookupIndex(AccessibilityEvent event) { - int lookupIndex = event.getItemCount(); - int divided = event.getCurrentItemIndex(); - - while (divided > 0) { - lookupIndex *= 10; - divided /= 10; - } - - lookupIndex += event.getCurrentItemIndex(); - lookupIndex *= 10; - - // This is primarily for handling the zero hour/zero minutes cases - if (!event.getText().isEmpty() - && ("1".equals(event.getText().get(0).toString()) || "01".equals(event.getText() - .get(0).toString()))) { - lookupIndex++; - } - - return lookupIndex; - } - /** * Plays an earcon given its id. * @@ -690,10 +562,12 @@ public class ClockBackService extends AccessibilityService { String earconName = mEarconNames.get(earconId); if (earconName == null) { // We do not know the sound id, hence we need to load the sound. - int resourceId = sSoundsResourceIds.get(earconId); - earconName = "[" + earconId + "]"; - mTts.addEarcon(earconName, getPackageName(), resourceId); - mEarconNames.put(earconId, earconName); + Integer resourceId = sSoundsResourceIds.get(earconId); + if (resourceId != null) { + earconName = "[" + earconId + "]"; + mTts.addEarcon(earconName, getPackageName(), resourceId); + mEarconNames.put(earconId, earconName); + } } mTts.playEarcon(earconName, QUEUING_MODE_INTERRUPT, null); diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskBackService.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskBackService.java index dbbfe3a1b..c7088be98 100644 --- a/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskBackService.java +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskBackService.java @@ -19,6 +19,7 @@ package com.example.android.apis.accessibility; import com.example.android.apis.R; import android.accessibilityservice.AccessibilityService; +import android.text.TextUtils; import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -28,26 +29,40 @@ import android.speech.tts.TextToSpeech.OnInitListener; import java.util.Locale; -/** The TaskBackService listens for AccessibilityEvents, and turns them into information it can - * communicate to the user with speech. +/** + * This class demonstrates how an accessibility service can query + * window content to improve the feedback given to the user. */ public class TaskBackService extends AccessibilityService implements OnInitListener { - private final String LOG_TAG = "TaskBackService/onAccessibilityEvent"; - private boolean mTextToSpeechInitialized = false; - private TextToSpeech mTts = null; + /** Tag for logging. */ + private static final String LOG_TAG = "TaskBackService/onAccessibilityEvent"; + + /** Comma separator. */ private static final String SEPARATOR = ", "; + /** The class name of TaskListView - for simplicity we speak only its items. */ + private static final String TASK_LIST_VIEW_CLASS_NAME = + "com.example.android.apis.accessibility.TaskListView"; + /** Flag whether Text-To-Speech is initialized. */ + private boolean mTextToSpeechInitialized; - /** Initializes the Text-To-Speech engine as soon as the service is connected. */ + /** Handle to the Text-To-Speech engine. */ + private TextToSpeech mTts; + + /** + * {@inheritDoc} + */ @Override public void onServiceConnected() { + // Initializes the Text-To-Speech engine as soon as the service is connected. mTts = new TextToSpeech(getApplicationContext(), this); } - /** Processes an AccessibilityEvent, by traversing the View's tree and putting together a - * message to speak to the user. + /** + * Processes an AccessibilityEvent, by traversing the View's tree and + * putting together a message to speak to the user. */ @Override public void onAccessibilityEvent(AccessibilityEvent event) { @@ -56,55 +71,49 @@ public class TaskBackService extends AccessibilityService implements OnInitListe return; } - int eventType = event.getEventType(); - if (eventType != AccessibilityEvent.TYPE_VIEW_CLICKED) { + // This AccessibilityNodeInfo represents the view that fired the + // AccessibilityEvent. The following code will use it to traverse the + // view hierarchy, using this node as a starting point. + // + // NOTE: Every method that returns an AccessibilityNodeInfo may return null, + // because the explored window is in another process and the + // corresponding View might be gone by the time your request reaches the + // view hierarchy. + AccessibilityNodeInfo source = event.getSource(); + if (source == null) { return; } - /* This AccessibilityNodeInfo represents the view that fired the - * AccessibilityEvent. The following code will use it to traverse - * the view hierarchy, using this node as a starting point. - */ - AccessibilityNodeInfo entryNode = event.getSource(); - - /* Every method that returns an AccessibilityNodeInfo may return null, - * because the explored window is in another process and the corresponding - * View might be gone by the time your request reaches the view hierarchy." - */ - if (entryNode == null) { - return; - } // Grab the parent of the view that fired the event. - AccessibilityNodeInfo rowNode = entryNode.getParent(); - + AccessibilityNodeInfo rowNode = getListItemNodeInfo(source); if (rowNode == null) { - return; + return; } - /* Using this parent, get references to both child nodes, - * the label and the checkbox. - */ + // Using this parent, get references to both child nodes, the label and the checkbox. AccessibilityNodeInfo labelNode = rowNode.getChild(0); - AccessibilityNodeInfo completeNode = rowNode.getChild(1); - - if (labelNode == null || completeNode == null) { - return; + if (labelNode == null) { + rowNode.recycle(); + return; } - /* Using these to determine what the task is and whether or not - * it's complete, based on the text inside the label, and the state - * of the checkbox. - */ + AccessibilityNodeInfo completeNode = rowNode.getChild(1); + if (completeNode == null) { + rowNode.recycle(); + return; + } - // Quick check to make sure we're not in the ApiDemos nav. + // Determine what the task is and whether or not it's complete, based on + // the text inside the label, and the state of the check-box. if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) { + rowNode.recycle(); return; } CharSequence taskLabel = labelNode.getText(); - boolean isComplete = completeNode.isChecked(); + final boolean isComplete = completeNode.isChecked(); - String completeStr = null;; + String completeStr = null; if (isComplete) { completeStr = getString(R.string.task_complete); } else { @@ -112,44 +121,66 @@ public class TaskBackService extends AccessibilityService implements OnInitListe } String taskStr = getString(R.string.task_complete_template, taskLabel, completeStr); - StringBuilder forSpeech = new StringBuilder(taskStr); - - /* The custom listview added extra context to the event by adding - * an AccessibilityRecord to it. Extract that from the event and read it. - */ - int records = event.getRecordCount(); + StringBuilder utterance = new StringBuilder(taskStr); + // The custom ListView added extra context to the event by adding an + // AccessibilityRecord to it. Extract that from the event and read it. + final int records = event.getRecordCount(); for (int i = 0; i < records; i++) { AccessibilityRecord record = event.getRecord(i); CharSequence contentDescription = record.getContentDescription(); - if (contentDescription != null) { - forSpeech.append(SEPARATOR).append(contentDescription); + if (!TextUtils.isEmpty(contentDescription )) { + utterance.append(SEPARATOR); + utterance.append(contentDescription); } } - /* Speak the forSpeech string to the user. QUEUE_ADD adds the string to the end of the - * queue, QUEUE_FLUSH would interrupt whatever was currently being said. - */ - mTts.speak(forSpeech.toString() , TextToSpeech.QUEUE_ADD, null); - Log.d(LOG_TAG, forSpeech.toString()); + // Announce the utterance. + mTts.speak(utterance.toString(), TextToSpeech.QUEUE_FLUSH, null); + Log.d(LOG_TAG, utterance.toString()); } - @Override - public void onInterrupt() { - /* do nothing */ + private AccessibilityNodeInfo getListItemNodeInfo(AccessibilityNodeInfo source) { + AccessibilityNodeInfo current = source; + while (true) { + AccessibilityNodeInfo parent = current.getParent(); + if (parent == null) { + return null; + } + if (TASK_LIST_VIEW_CLASS_NAME.equals(parent.getClassName())) { + return current; + } + // NOTE: Recycle the infos. + AccessibilityNodeInfo oldCurrent = current; + current = parent; + oldCurrent.recycle(); + } } - /** Sets a flag so that the TaskBackService knows that the Text-To-Speech engine has been - * initialized, and can now handle speaking requests. + /** + * {@inheritDoc} */ @Override - public void onInit (int status) { + public void onInterrupt() { + /* do nothing */ + } + + /** + * {@inheritDoc} + */ + @Override + public void onInit(int status) { + // Set a flag so that the TaskBackService knows that the Text-To-Speech + // engine has been initialized, and can now handle speaking requests. if (status == TextToSpeech.SUCCESS) { mTts.setLanguage(Locale.US); mTextToSpeechInitialized = true; } } + /** + * {@inheritDoc} + */ @Override public void onDestroy() { super.onDestroy(); diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskListActivity.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskListActivity.java index bbc1403b8..4f7f38484 100644 --- a/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskListActivity.java +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskListActivity.java @@ -19,18 +19,26 @@ package com.example.android.apis.accessibility; import com.example.android.apis.R; import android.app.ListActivity; +import android.content.Intent; import android.os.Bundle; -import android.widget.ArrayAdapter; +import android.provider.Settings; +import android.view.View; +import android.widget.ImageButton; /** Starts up the task list that will interact with the AccessibilityService sample. */ public class TaskListActivity extends ListActivity { + + /** An intent for launching the system settings. */ + private static final Intent sSettingsIntent = + new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tasklist_main); - // Hardcoded hand-waving here. + // Hard-coded hand-waving here. boolean[] checkboxes = {true, true, false, true, false, false, false}; String[] labels = {"Take out Trash", "Do Laundry", "Conquer World", "Nap", "Do Taxes", @@ -38,5 +46,14 @@ public class TaskListActivity extends ListActivity { TaskAdapter myAdapter = new TaskAdapter(this, labels, checkboxes); this.setListAdapter(myAdapter); + + // Add a shortcut to the accessibility settings. + ImageButton button = (ImageButton) findViewById(R.id.button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(sSettingsIntent); + } + }); } } diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html index eacefa10a..7506cb391 100644 --- a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html @@ -1,9 +1,23 @@ +
    +
    Accessibility Service
    +
    + This is an example of an accessibility service that provides custom feedback for the Clock + application which comes by default with Android devices. It is a hands-on example of various + ways to utilize the accessibility API for providing alternative and complementary feedback. + The sample demonstrates how to provide application specific feedback — the service + handles only accessibility events from the Clock application. Further, the sample demonstrates + how to provide dynamic, context-dependent feedback — feedback type changes depending on + the ringer mode. +
    +
    +
    Window Querying Accessibility Service
    -
    Demonstrates several new accessibility features in Ice Cream Sandwich, - including the ability for an AccessibilityService to traverse the view - hierarchy using AccessibilityNodeInfo objects, service configuration via - xml files, and adding additional information to AccessibilityEvents using - AccessibilityRecords. -
    +
    + Demonstrates several new accessibility features in Ice Cream Sandwich, + including the ability for an AccessibilityService to traverse the view + hierarchy using AccessibilityNodeInfo objects, service configuration via + xml files, and adding additional information to AccessibilityEvents using + AccessibilityRecords. +
    diff --git a/samples/ApiDemos/src/com/example/android/apis/app/ActionBarSettingsActionProviderActivity.java b/samples/ApiDemos/src/com/example/android/apis/app/ActionBarSettingsActionProviderActivity.java index 2bf7c3785..474876289 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/ActionBarSettingsActionProviderActivity.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/ActionBarSettingsActionProviderActivity.java @@ -19,7 +19,6 @@ package com.example.android.apis.app; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.provider.Settings; import android.view.ActionProvider; import android.view.LayoutInflater; @@ -39,14 +38,6 @@ import com.example.android.apis.R; */ public class ActionBarSettingsActionProviderActivity extends Activity { - /** - * {@inheritDoc} - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - /** * {@inheritDoc} */