am 96c0210e: Adding ICS Accessibility Features to ApiDemos app.

* commit '96c0210eb57e60f03c23a8e504782a8ba4b9edfe':
  Adding ICS Accessibility Features to ApiDemos app.
This commit is contained in:
Alexander Lucas
2011-10-28 17:26:20 +00:00
committed by Android Git Automerger
10 changed files with 457 additions and 4 deletions

View File

@@ -36,7 +36,7 @@
<!-- For android.media.audiofx.Visualizer -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="13" />
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14" />
<!-- We will request access to the camera, saying we require a camera
of some sort but not one with autofocus capability. -->
@@ -242,7 +242,7 @@
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- Fragment Samples -->
<activity android:name=".app.FragmentAlertDialog"
@@ -541,6 +541,25 @@
</intent-filter>
</activity>
<activity android:name=".accessibility.TaskListActivity"
android:label="@string/accessibility_taskapp_name"
android:enabled="@bool/atLeastIceCreamSandwich">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<service android:name=".accessibility.TaskBackService"
android:label="@string/accessibility_service_label"
android:enabled="@bool/atLeastIceCreamSandwich">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice" android:resource="@xml/taskbackconfig" />
</service>
<!-- Instrumentation Samples -->
<activity android:name=".app.LocalSample" android:label="@string/activity_local_sample">
@@ -2237,7 +2256,7 @@
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".graphics.TriangleActivity"
android:label="Graphics/OpenGL ES/Textured Triangle"
android:theme="@android:style/Theme.Holo.Dialog"

View File

@@ -36,6 +36,9 @@ fragment animations</a></li>
<li><a href="src/com/example/android/apis/graphics/TouchPaint.html">Stylus and hover
support</a></li>
<li><a href="src/com/example/android/apis/view/Switches.html">Switch widget</a></li>
<li><a
href="src/com/example/android/apis/accessibility/TaskBackService.html">Window
Querying Accessibility Service</a></li>
</ul>
</div>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.android.apis.accessibility.TaskListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout
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">
<TextView android:id="@+id/tasklist_label"
android:textSize="20dp"
android:textStyle="bold"
android:layout_height="48dp"
android:layout_width="300dip"
/>
<CheckBox android:id="@+id/tasklist_finished"
android:checked="false" android:layout_height="48dp"
android:layout_weight=".25"
android:layout_width="wrap_content" />
</LinearLayout>

View File

@@ -1286,4 +1286,18 @@
<string name="dismiss">Dismiss</string>
<string name="share">Share</string>
</resources>
<!-- ============================ -->
<!-- Accessibility examples strings -->
<!-- ============================ -->
<string name="accessibility_taskapp_name">Accessibility/Accessibility Node Querying</string>
<string name="accessibility_service_description">Task App Accessibility Service</string>
<string name="accessibility_service_label">TaskBack</string>
<string name="task_name">Task</string>
<string name="task_complete_template">Task %1$s %2$s</string>
<string name="task_complete">is complete</string>
<string name="task_not_complete">is not complete</string>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
android:packageNames="com.example.android.apis"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description" />

View File

@@ -0,0 +1,160 @@
/*
* 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 com.example.android.apis.R;
import android.accessibilityservice.AccessibilityService;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityRecord;
import android.speech.tts.TextToSpeech;
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.
*/
public class TaskBackService extends AccessibilityService implements OnInitListener {
private final String LOG_TAG = "TaskBackService/onAccessibilityEvent";
private boolean mTextToSpeechInitialized = false;
private TextToSpeech mTts = null;
private static final String SEPARATOR = ", ";
/** Initializes the Text-To-Speech engine as soon as the service is connected. */
@Override
public void onServiceConnected() {
mTts = new TextToSpeech(getApplicationContext(), this);
}
/** 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) {
if (!mTextToSpeechInitialized) {
Log.e(LOG_TAG, "Text-To-Speech engine not ready. Bailing out.");
return;
}
int eventType = event.getEventType();
if (eventType != AccessibilityEvent.TYPE_VIEW_CLICKED) {
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();
if (rowNode == null) {
return;
}
/* 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;
}
/* 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.
*/
// Quick check to make sure we're not in the ApiDemos nav.
if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) {
return;
}
CharSequence taskLabel = labelNode.getText();
boolean isComplete = completeNode.isChecked();
String completeStr = null;;
if (isComplete) {
completeStr = getString(R.string.task_complete);
} else {
completeStr = getString(R.string.task_not_complete);
}
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();
for (int i = 0; i < records; i++) {
AccessibilityRecord record = event.getRecord(i);
CharSequence contentDescription = record.getContentDescription();
if (contentDescription != null) {
forSpeech.append(SEPARATOR).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());
}
@Override
public void onInterrupt() {
/* do nothing */
}
/** Sets a flag so that the TaskBackService knows that the Text-To-Speech engine has been
* initialized, and can now handle speaking requests.
*/
@Override
public void onInit (int status) {
if (status == TextToSpeech.SUCCESS) {
mTts.setLanguage(Locale.US);
mTextToSpeechInitialized = true;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mTextToSpeechInitialized) {
mTts.shutdown();
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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 com.example.android.apis.R;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
/** Starts up the task list that will interact with the AccessibilityService sample. */
public class TaskListActivity extends ListActivity {
/** 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.
boolean[] checkboxes = {true, true, false, true, false, false, false};
String[] labels = {"Take out Trash", "Do Laundry",
"Conquer World", "Nap", "Do Taxes",
"Abolish IRS", "Tea with Aunt Sharon" };
TaskAdapter myAdapter = new TaskAdapter(this, labels, checkboxes);
this.setListAdapter(myAdapter);
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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 com.example.android.apis.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
/** Acts as a go-between for all AccessibilityEvents sent from items in the ListView, providing the
* option of sending more context to an AccessibilityService by adding more AccessiblityRecords to
* an event.
*/
public class TaskListView extends ListView {
public TaskListView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
/**
* This method will fire whenever a child event wants to send an AccessibilityEvent. As a
* result, it's a great place to add more AccessibilityRecords, if you want. In this case,
* the code is grabbing the position of the item in the list, and assuming that to be the
* priority for the task.
*/
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Add a record for ourselves as well.
AccessibilityEvent record = AccessibilityEvent.obtain();
super.onInitializeAccessibilityEvent(record);
int priority = (Integer) child.getTag();
String priorityStr = "Priority: " + priority;
record.setContentDescription(priorityStr);
event.appendRecord(record);
return true;
}
}
/** Adds Accessibility information to individual child views of rows in the list. */
final class TaskAdapter extends BaseAdapter{
private String[] mLabels = null;
private boolean[] mCheckboxes = null;
private Context mContext = null;
public TaskAdapter(Context context, String[] labels, boolean[] checkboxes) {
super();
mContext = context;
mLabels = labels;
mCheckboxes = checkboxes;
}
@Override
public int getCount() {
return mLabels.length;
}
/** Expands the views for individual list entries, and sets content descriptions for use by the
* TaskBackAccessibilityService.
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(R.layout.tasklist_row, parent, false);
}
CheckBox checkbox = (CheckBox) convertView.findViewById(R.id.tasklist_finished);
checkbox.setChecked(mCheckboxes[position]);
TextView label = (TextView)(convertView.findViewById(R.id.tasklist_label));
label.setText(mLabels[position]);
String contentDescription = new StringBuilder()
.append(mContext.getString(R.string.task_name))
.append(' ')
.append(mLabels[position]).toString();
label.setContentDescription(contentDescription);
convertView.setTag(position);
return convertView;
}
@Override
public Object getItem(int position) {
return mLabels[position];
}
@Override
public long getItemId(int position) {
return position;
}
}

View File

@@ -0,0 +1,9 @@
<dl>
<dt><a href="TaskBackService.html">Window Querying Accessibility Service</a></dt>
<dd>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.
</dd>
</dl>