aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCasey Burkhardt <caseyburkhardt@google.com>2010-08-08 20:08:39 -0700
committerCasey Burkhardt <caseyburkhardt@google.com>2010-08-08 20:08:39 -0700
commit79c6f8b2df9023bf46d6b2829ecf69bc4672566a (patch)
tree81cbc881845031a192f6b7f0de2177db0066a041 /src
parentbb25b9e5b33c9ed7ce04e4dceb1c0f1f8b3e4036 (diff)
downloadconnectbot-79c6f8b2df9023bf46d6b2829ecf69bc4672566a.tar.gz
connectbot-79c6f8b2df9023bf46d6b2829ecf69bc4672566a.tar.bz2
connectbot-79c6f8b2df9023bf46d6b2829ecf69bc4672566a.zip
Improves accessibility by causing AccessibilityEvents to be fired after console changes occur.
Diffstat (limited to 'src')
-rwxr-xr-x[-rw-r--r--]src/org/connectbot/TerminalView.java108
-rw-r--r--src/org/connectbot/service/Relay.java4
-rw-r--r--src/org/connectbot/service/TerminalBridge.java10
3 files changed, 118 insertions, 4 deletions
diff --git a/src/org/connectbot/TerminalView.java b/src/org/connectbot/TerminalView.java
index 35a3c56..057399f 100644..100755
--- a/src/org/connectbot/TerminalView.java
+++ b/src/org/connectbot/TerminalView.java
@@ -17,21 +17,29 @@
package org.connectbot;
+import java.util.List;
+
import org.connectbot.bean.SelectionArea;
import org.connectbot.service.FontSizeChangedListener;
import org.connectbot.service.TerminalBridge;
import org.connectbot.service.TerminalKeyListener;
import android.app.Activity;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelXorXfermode;
import android.graphics.RectF;
+import android.net.Uri;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -63,6 +71,14 @@ public class TerminalView extends View implements FontSizeChangedListener {
private String lastNotification = null;
private volatile boolean notifications = true;
+ // Related to Accessibility Features
+ private boolean accessibilityActive = false;
+ private StringBuffer accessibilityBuffer = null;
+ private AccessibilityEventSender eventSender = null;
+ private int ACCESSIBILITY_EVENT_THRESHOLD = 1000;
+ private static final String SCREENREADER_INTENT_ACTION = "android.accessibilityservice.AccessibilityService";
+ private static final String SCREENREADER_INTENT_CATEGORY = "android.accessibilityservice.category.FEEDBACK_SPOKEN";
+
public TerminalView(Context context, TerminalBridge bridge) {
super(context);
@@ -112,6 +128,9 @@ public class TerminalView extends View implements FontSizeChangedListener {
// connect our view up to the bridge
setOnKeyListener(bridge.getKeyHandler());
+
+ // Enable accessibility features if a screen reader is active.
+ accessibilityActive = isScreenReaderActive();
}
public void destroy() {
@@ -268,4 +287,93 @@ public class TerminalView extends View implements FontSizeChangedListener {
outAttrs.inputType = EditorInfo.TYPE_NULL;
return new BaseInputConnection(this, false);
}
+
+ private boolean isScreenReaderActive() {
+ // Restrict the set of intents to only accessibility services that have
+ // the category FEEDBACK_SPOKEN (aka, screen readers).
+ Intent screenReaderIntent = new Intent(SCREENREADER_INTENT_ACTION);
+ screenReaderIntent.addCategory(SCREENREADER_INTENT_CATEGORY);
+ List<ResolveInfo> screenReaders = context.getPackageManager().queryIntentServices(
+ screenReaderIntent, 0);
+ ContentResolver cr = context.getContentResolver();
+ Cursor cursor = null;
+ int status = 0;
+ for (ResolveInfo screenReader : screenReaders) {
+ // All screen readers are expected to implement a content provider that responds to
+ // content://<nameofpackage>.providers.StatusProvider
+ cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
+ + ".providers.StatusProvider"), null, null, null, null);
+ if (cursor != null) {
+ cursor.moveToFirst();
+ // These content providers use a special cursor that only has one element,
+ // an integer that is 1 if the screen reader is running.
+ status = cursor.getInt(0);
+ cursor.close();
+ if (status == 1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ public StringBuffer getAccessibilityBuffer() {
+ return accessibilityBuffer;
+ }
+
+ public void propagateConsoleText(char[] rawText, int length) {
+ if (accessibilityActive) {
+ if (accessibilityBuffer == null) {
+ accessibilityBuffer = new StringBuffer();
+ }
+
+ for (int i = 0; i < length; ++i) {
+ accessibilityBuffer.append(rawText[i]);
+ }
+
+ if (eventSender != null) {
+ removeCallbacks(eventSender);
+ } else {
+ eventSender = new AccessibilityEventSender();
+ }
+ postDelayed(eventSender, ACCESSIBILITY_EVENT_THRESHOLD);
+ }
+ }
+
+ private class AccessibilityEventSender implements Runnable {
+ public void run() {
+ synchronized (accessibilityBuffer) {
+ // Strip Console Codes
+ String regex = "" + ((char) 27) + (char) 92 + ((char) 91) + "[^m]+[m|:]";
+ accessibilityBuffer =
+ new StringBuffer(accessibilityBuffer.toString().replaceAll(regex, " "));
+
+ // Apply Backspaces
+ String backspaceCode = "" + ((char) 8) + ((char) 27) + ((char) 91) + ((char) 75);
+ int i = accessibilityBuffer.indexOf(backspaceCode);
+ while (i != -1) {
+ if (i == 0) {
+ accessibilityBuffer =
+ accessibilityBuffer.replace(i, i + backspaceCode.length(), "");
+ } else {
+ accessibilityBuffer =
+ accessibilityBuffer.replace(i - 1, i + backspaceCode.length(), "");
+ }
+ i = accessibilityBuffer.indexOf(backspaceCode);
+ }
+
+ if (accessibilityBuffer.length() > 0) {
+ AccessibilityEvent event =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+ event.setFromIndex(0);
+ event.setAddedCount(accessibilityBuffer.length());
+ event.getText().add(accessibilityBuffer);
+
+ sendAccessibilityEventUnchecked(event);
+ accessibilityBuffer.setLength(0);
+ }
+ }
+ }
+ }
}
diff --git a/src/org/connectbot/service/Relay.java b/src/org/connectbot/service/Relay.java
index 18bf896..f14ff53 100644
--- a/src/org/connectbot/service/Relay.java
+++ b/src/org/connectbot/service/Relay.java
@@ -17,8 +17,6 @@
package org.connectbot.service;
-import org.apache.harmony.niochar.charset.additional.IBM437;
-
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@@ -27,6 +25,7 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
+import org.apache.harmony.niochar.charset.additional.IBM437;
import org.connectbot.transport.AbsTransport;
import org.connectbot.util.EastAsianWidth;
@@ -154,6 +153,7 @@ public class Relay implements Runnable {
wideAttribute, isLegacyEastAsian);
}
buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
+ bridge.propagateConsoleText(charArray, charBuffer.position());
charBuffer.clear();
bridge.redraw();
}
diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java
index e9e69ca..9b4b96c 100644
--- a/src/org/connectbot/service/TerminalBridge.java
+++ b/src/org/connectbot/service/TerminalBridge.java
@@ -35,12 +35,12 @@ import org.connectbot.util.HostDatabase;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.graphics.Bitmap.Config;
import android.graphics.Paint.FontMetrics;
+import android.graphics.Typeface;
import android.text.ClipboardManager;
import android.util.Log;
import de.mud.terminal.VDUBuffer;
@@ -644,6 +644,12 @@ public class TerminalBridge implements VDUDisplay {
return buffer;
}
+ public void propagateConsoleText(char[] rawText, int length) {
+ if (parent != null) {
+ parent.propagateConsoleText(rawText, length);
+ }
+ }
+
public void onDraw() {
int fg, bg;
synchronized (buffer) {