summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorplundblad@google.com <plundblad@google.com@584082c0-ab3a-11dd-9ddb-6f86aeb5eef6>2012-07-03 21:38:44 +0000
committerplundblad@google.com <plundblad@google.com@584082c0-ab3a-11dd-9ddb-6f86aeb5eef6>2012-07-03 21:38:44 +0000
commit344caf0bfb20161349dbf2f658a7f096a08ea769 (patch)
tree3eb1c50e0b9222f8e544f5b59e443a8c84a204d5
downloadbraille-344caf0bfb20161349dbf2f658a7f096a08ea769.tar.gz
Add BrailleBack.
git-svn-id: https://eyes-free.googlecode.com/svn/trunk/braille/client/src/com/googlecode/eyesfree/braille@781 584082c0-ab3a-11dd-9ddb-6f86aeb5eef6
-rw-r--r--display/BrailleDisplayProperties.aidl19
-rw-r--r--display/BrailleDisplayProperties.java102
-rw-r--r--display/BrailleInputEvent.aidl19
-rw-r--r--display/BrailleInputEvent.java300
-rw-r--r--display/BrailleKeyBinding.java100
-rw-r--r--display/Display.java321
-rw-r--r--display/IBrailleService.aidl43
-rw-r--r--display/IBrailleServiceCallback.aidl30
-rw-r--r--translate/BrailleTranslator.java35
-rw-r--r--translate/ITranslatorService.aidl47
-rw-r--r--translate/ITranslatorServiceCallback.aidl21
-rw-r--r--translate/TranslatorManager.java278
12 files changed, 1315 insertions, 0 deletions
diff --git a/display/BrailleDisplayProperties.aidl b/display/BrailleDisplayProperties.aidl
new file mode 100644
index 0000000..5a7f410
--- /dev/null
+++ b/display/BrailleDisplayProperties.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+parcelable BrailleDisplayProperties;
diff --git a/display/BrailleDisplayProperties.java b/display/BrailleDisplayProperties.java
new file mode 100644
index 0000000..f61bad0
--- /dev/null
+++ b/display/BrailleDisplayProperties.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Properties of a braille display such as dimensions and keyboard
+ * configuration.
+ */
+public class BrailleDisplayProperties implements Parcelable {
+ private final int mNumTextCells;
+ private final int mNumStatusCells;
+ private final BrailleKeyBinding[] mKeyBindings;
+
+ public BrailleDisplayProperties(int numTextCells, int numStatusCells,
+ BrailleKeyBinding[] keyBindings) {
+ mNumTextCells = numTextCells;
+ mNumStatusCells = numStatusCells;
+ mKeyBindings = keyBindings;
+ }
+
+ /**
+ * Returns the number of cells on the main display intended for display of
+ * text or other content.
+ */
+ public int getNumTextCells() {
+ return mNumTextCells;
+ }
+
+ /**
+ * Returns the number of status cells that are separated from the main
+ * display. This value will be {@code 0} for displays without any separate
+ * status cells.
+ */
+ public int getNumStatusCells() {
+ return mNumStatusCells;
+ }
+
+ /**
+ * Returns the list of key bindings for this display.
+ */
+ public BrailleKeyBinding[] getKeyBindings() {
+ return mKeyBindings;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "BrailleDisplayProperties [numTextCells: %d, numStatusCells: %d, "
+ + "keyBindings: %d]",
+ mNumTextCells, mNumStatusCells, mKeyBindings.length);
+ }
+
+ // For Parcelable support.
+
+ public static final Parcelable.Creator<BrailleDisplayProperties> CREATOR =
+ new Parcelable.Creator<BrailleDisplayProperties>() {
+ @Override
+ public BrailleDisplayProperties createFromParcel(Parcel in) {
+ return new BrailleDisplayProperties(in);
+ }
+
+ @Override
+ public BrailleDisplayProperties[] newArray(int size) {
+ return new BrailleDisplayProperties[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mNumTextCells);
+ out.writeInt(mNumStatusCells);
+ out.writeTypedArray(mKeyBindings, flags);
+ }
+
+ private BrailleDisplayProperties(Parcel in) {
+ mNumTextCells = in.readInt();
+ mNumStatusCells = in.readInt();
+ mKeyBindings = in.createTypedArray(BrailleKeyBinding.CREATOR);
+ }
+}
diff --git a/display/BrailleInputEvent.aidl b/display/BrailleInputEvent.aidl
new file mode 100644
index 0000000..f64c080
--- /dev/null
+++ b/display/BrailleInputEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+parcelable BrailleInputEvent;
diff --git a/display/BrailleInputEvent.java b/display/BrailleInputEvent.java
new file mode 100644
index 0000000..1c2ffb4
--- /dev/null
+++ b/display/BrailleInputEvent.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import java.util.HashMap;
+
+/**
+ * An input event, originating from a braille display.
+ *
+ * An event contains a command that is a high-level representation of the
+ * key or key combination that was pressed on the display such as a
+ * navigation key or braille keyboard combination. For some commands, there is
+ * also an integer argument that contains additional information.
+ */
+public class BrailleInputEvent implements Parcelable {
+
+ // Movement commands.
+
+ /** Keyboard command: Used when there is no actual command. */
+ public static final int CMD_NONE = -1;
+
+ /** Keyboard command: Navigate upwards. */
+ public static final int CMD_NAV_LINE_PREVIOUS = 1;
+ /** Keyboard command: Navigate downwards. */
+ public static final int CMD_NAV_LINE_NEXT = 2;
+ /** Keyboard command: Navigate left one item. */
+ public static final int CMD_NAV_ITEM_PREVIOUS = 3;
+ /** Keyboard command: Navigate right one item. */
+ public static final int CMD_NAV_ITEM_NEXT = 4;
+ /** Keyboard command: Navigate one display window to the left. */
+ public static final int CMD_NAV_PAN_LEFT = 5;
+ /** Keyboard command: Navigate one display window to the right. */
+ public static final int CMD_NAV_PAN_RIGHT = 6;
+ /** Keyboard command: Navigate to the top or beginning. */
+ public static final int CMD_NAV_TOP = 7;
+ /** Keyboard command: Navigate to the bottom or end. */
+ public static final int CMD_NAV_BOTTOM = 8;
+
+ // Activation commands.
+
+ /** Keyboard command: Activate the currently selected/focused item. */
+ public static final int CMD_ACTIVATE_CURRENT = 20;
+
+ // Scrolling.
+
+ /** Keyboard command: Scroll backward. */
+ public static final int CMD_SCROLL_BACKWARD = 30;
+ /** Keyboard command: Scroll forward. */
+ public static final int CMD_SCROLL_FORWARD = 31;
+
+ // Selection commands.
+
+ /** Keyboard command: Set the start ot the selection. */
+ public static final int CMD_SELECTION_START = 40;
+ /** Keyboard command: Set the end of the selection. */
+ public static final int CMD_SELECTION_END = 41;
+ /** Keyboard command: Select all content of the current field. */
+ public static final int CMD_SELECTION_SELECT_ALL = 42;
+ /** Keyboard command: Cut the content of the selection. */
+ public static final int CMD_SELECTION_CUT = 43;
+ /** Keyboard command: Copy the current selection. */
+ public static final int CMD_SELECTION_COPY = 44;
+ /**
+ * Keyboard command: Paste the content of the clipboard at the current
+ * insertion point.
+ */
+ public static final int CMD_SELECTION_PASTE = 45;
+
+ /**
+ * Keyboard command: Primary routing key pressed, typically
+ * used to move the insertion point or click/tap on the item
+ * under the key.
+ * The argument is the zero-based position, relative to the first cell
+ * on the display, of the cell that is closed to the key that
+ * was pressed.
+ */
+ public static final int CMD_ROUTE = 50;
+
+ // Braille keyboard input.
+
+ /**
+ * Keyboard command: A key combination was pressed on the braille
+ * keyboard.
+ * The argument contains the dots that were pressed as a bitmask.
+ */
+ public static final int CMD_BRAILLE_KEY = 60;
+
+ // Editing keys.
+
+ /** Keyboard command: Enter key. */
+ public static final int CMD_KEY_ENTER = 70;
+ /** Keyboard command: Delete backward. */
+ public static final int CMD_KEY_DEL = 71;
+ /** Keyboard command: Delete forward. */
+ public static final int CMD_KEY_FORWARD_DEL = 72;
+
+ // Glboal navigation keys.
+
+ /** Keyboard command: Back button. */
+ public static final int CMD_GLOBAL_BACK = 90;
+ /** Keyboard command: Home button. */
+ public static final int CMD_GLOBAL_HOME = 91;
+ /** Keyboard command: Recent apps button. */
+ public static final int CMD_GLOBAL_RECENTS = 92;
+ /** Keyboard command: Show notificaitons. */
+ public static final int CMD_GLOBAL_NOTIFICATIONS = 93;
+
+ // Miscelanous commands.
+
+ /** Keyboard command: Invoke keyboard help. */
+ public static final int CMD_HELP = 100;
+
+ // Meanings of the argument to a command.
+
+ /** This command doesn't have an argument. */
+ public static final int ARGUMENT_NONE = 0;
+ /**
+ * The lower order bits of the arguemnt to this command represent braille
+ * dots. Dot 1 is represented by the rightmost bit and so on until dot 8,
+ * which is represented by bit 7, counted from the right.
+ */
+ public static final int ARGUMENT_DOTS = 1;
+ /**
+ * The argument represents a 0-based position on the display counted from
+ * the leftmost cell.
+ */
+ public static final int ARGUMENT_POSITION = 2;
+
+ private static final SparseArray<String> CMD_NAMES =
+ new SparseArray<String>();
+ private static final HashMap<String, Integer> NAMES_TO_CMDS
+ = new HashMap<String, Integer>();
+ static {
+ CMD_NAMES.append(CMD_NAV_LINE_PREVIOUS, "CMD_NAV_LINE_PREVIOUS");
+ CMD_NAMES.append(CMD_NAV_LINE_NEXT, "CMD_NAV_LINE_NEXT");
+ CMD_NAMES.append(CMD_NAV_ITEM_PREVIOUS, "CMD_NAV_ITEM_PREVIOUS");
+ CMD_NAMES.append(CMD_NAV_ITEM_NEXT, "CMD_NAV_ITEM_NEXT");
+ CMD_NAMES.append(CMD_NAV_PAN_LEFT, "CMD_NAV_PAN_LEFT");
+ CMD_NAMES.append(CMD_NAV_PAN_RIGHT, "CMD_NAV_PAN_RIGHT");
+ CMD_NAMES.append(CMD_NAV_TOP, "CMD_NAV_TOP");
+ CMD_NAMES.append(CMD_NAV_BOTTOM, "CMD_NAV_BOTTOM");
+ CMD_NAMES.append(CMD_ACTIVATE_CURRENT, "CMD_ACTIVATE_CURRENT");
+ CMD_NAMES.append(CMD_SCROLL_BACKWARD, "CMD_SCROLL_BACKWARD");
+ CMD_NAMES.append(CMD_SCROLL_FORWARD, "CMD_SCROLL_FORWARD");
+ CMD_NAMES.append(CMD_SELECTION_START, "CMD_SELECTION_START");
+ CMD_NAMES.append(CMD_SELECTION_END, "CMD_SELECTION_END");
+ CMD_NAMES.append(CMD_SELECTION_SELECT_ALL, "CMD_SELECTION_SELECT_ALL");
+ CMD_NAMES.append(CMD_SELECTION_CUT, "CMD_SELECTION_CUT");
+ CMD_NAMES.append(CMD_SELECTION_COPY, "CMD_SELECTION_COPY");
+ CMD_NAMES.append(CMD_SELECTION_PASTE, "CMD_SELECTION_PASTE");
+ CMD_NAMES.append(CMD_ROUTE, "CMD_ROUTE");
+ CMD_NAMES.append(CMD_BRAILLE_KEY, "CMD_BRAILLE_KEY");
+ CMD_NAMES.append(CMD_KEY_ENTER, "CMD_KEY_ENTER");
+ CMD_NAMES.append(CMD_KEY_DEL, "CMD_KEY_DEL");
+ CMD_NAMES.append(CMD_KEY_FORWARD_DEL, "CMD_KEY_FORWARD_DEL");
+ CMD_NAMES.append(CMD_GLOBAL_BACK, "CMD_GLOBAL_BACK");
+ CMD_NAMES.append(CMD_GLOBAL_HOME, "CMD_GLOBAL_HOME");
+ CMD_NAMES.append(CMD_GLOBAL_RECENTS, "CMD_GLOBAL_RECENTS");
+ CMD_NAMES.append(CMD_GLOBAL_NOTIFICATIONS, "CMD_GLOBAL_NOTIFICATIONS");
+ CMD_NAMES.append(CMD_HELP, "CMD_HELP");
+ for (int i = 0; i < CMD_NAMES.size(); ++i) {
+ NAMES_TO_CMDS.put(CMD_NAMES.valueAt(i),
+ CMD_NAMES.keyAt(i));
+ }
+ }
+
+ private final int mCommand;
+ private final int mArgument;
+ private final long mEventTime;
+
+ public BrailleInputEvent(int command, int argument, long eventTime) {
+ mCommand = command;
+ mArgument = argument;
+ mEventTime = eventTime;
+ }
+
+ /**
+ * Returns the keyboard command that this event represents.
+ */
+ public int getCommand() {
+ return mCommand;
+ }
+
+ /**
+ * Returns the command-specific argument of the event, or zero if the
+ * command doesn't have an argument. See the individual command constants
+ * for more details.
+ */
+ public int getArgument() {
+ return mArgument;
+ }
+
+ /**
+ * Returns the approximate time when this event happened as
+ * returned by {@link android.os.SystemClock#uptimeMillis}.
+ */
+ public long getEventTime() {
+ return mEventTime;
+ }
+
+ /**
+ * Returns a string representation of {@code command}, or the string
+ * {@code (unknown)} if the command is unknown.
+ */
+ public static String commandToString(int command) {
+ String ret = CMD_NAMES.get(command);
+ return ret != null ? ret : "(unknown)";
+ }
+
+ /**
+ * Returns the command corresponding to {@code commandName}, or
+ * {@link #CMD_NONE} if the name doesn't match any existing command.
+ */
+ public static int stringToCommand(String commandName) {
+ Integer command = NAMES_TO_CMDS.get(commandName);
+ if (command == null) {
+ return CMD_NONE;
+ }
+ return command;
+ }
+
+ /**
+ * Returns the type of argument for the given {@code command}.
+ */
+ public static int argumentType(int command) {
+ switch (command) {
+ case CMD_SELECTION_START:
+ case CMD_SELECTION_END:
+ case CMD_ROUTE:
+ return ARGUMENT_POSITION;
+ case CMD_BRAILLE_KEY:
+ return ARGUMENT_DOTS;
+ default:
+ return ARGUMENT_NONE;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BrailleInputEvent {");
+ sb.append("amd=");
+ sb.append(commandToString(mCommand));
+ sb.append(", arg=");
+ sb.append(mArgument);
+ sb.append("}");
+ return sb.toString();
+ }
+
+ // For Parcelable support.
+
+ public static final Parcelable.Creator<BrailleInputEvent> CREATOR =
+ new Parcelable.Creator<BrailleInputEvent>() {
+ @Override
+ public BrailleInputEvent createFromParcel(Parcel in) {
+ return new BrailleInputEvent(in);
+ }
+
+ @Override
+ public BrailleInputEvent[] newArray(int size) {
+ return new BrailleInputEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mCommand);
+ out.writeInt(mArgument);
+ out.writeLong(mEventTime);
+ }
+
+ private BrailleInputEvent(Parcel in) {
+ mCommand = in.readInt();
+ mArgument = in.readInt();
+ mEventTime = in.readLong();
+ }
+}
diff --git a/display/BrailleKeyBinding.java b/display/BrailleKeyBinding.java
new file mode 100644
index 0000000..92b58d0
--- /dev/null
+++ b/display/BrailleKeyBinding.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a binding between a combination of braille device keys and a
+ * command as declared in {@link BrailleInputEvent}.
+ */
+public class BrailleKeyBinding implements Parcelable {
+ private int mCommand;
+ private String[] mKeyNames;
+
+ public BrailleKeyBinding() {
+ }
+
+ public BrailleKeyBinding(int command, String[] keyNames) {
+ mCommand = command;
+ mKeyNames = keyNames;
+ }
+
+ /**
+ * Sets the command for this binding.
+ */
+ public BrailleKeyBinding setCommand(int command) {
+ mCommand = command;
+ return this;
+ }
+
+ /**
+ * Sets the key names for this binding.
+ */
+ public BrailleKeyBinding setKeyNames(String[] keyNames) {
+ mKeyNames = keyNames;
+ return this;
+ }
+
+ /**
+ * Returns the command for this key binding.
+ * @see {@link BrailleInputEvent}.
+ */
+ public int getCommand() {
+ return mCommand;
+ }
+
+ /**
+ * Returns the list of device-specific keys that, when pressed
+ * at the same time, will yield the command of this key binding.
+ */
+ public String[] getKeyNames() {
+ return mKeyNames;
+ }
+
+ // For Parcelable support.
+
+ public static final Parcelable.Creator<BrailleKeyBinding> CREATOR =
+ new Parcelable.Creator<BrailleKeyBinding>() {
+ @Override
+ public BrailleKeyBinding createFromParcel(Parcel in) {
+ return new BrailleKeyBinding(in);
+ }
+
+ @Override
+ public BrailleKeyBinding[] newArray(int size) {
+ return new BrailleKeyBinding[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mCommand);
+ out.writeStringArray(mKeyNames);
+ }
+
+ private BrailleKeyBinding(Parcel in) {
+ mCommand = in.readInt();
+ mKeyNames = in.createStringArray();
+ }
+}
diff --git a/display/Display.java b/display/Display.java
new file mode 100644
index 0000000..54a57a2
--- /dev/null
+++ b/display/Display.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import android.os.Message;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A client for the braille display service.
+ */
+public class Display {
+ private static final String LOG_TAG = Display.class.getSimpleName();
+ /** Service name used for connecting to the service. */
+ public static final String ACTION_DISPLAY_SERVICE =
+ "com.googlecode.eyesfree.braille.service.ACTION_DISPLAY_SERVICE";
+
+ /** Initial value, which is never reported to the listener. */
+ private static final int STATE_UNKNOWN = -2;
+ public static final int STATE_ERROR = -1;
+ public static final int STATE_NOT_CONNECTED = 0;
+ public static final int STATE_CONNECTED = 1;
+
+ private final OnConnectionStateChangeListener
+ mConnectionStateChangeListener;
+ private final Context mContext;
+ private final DisplayHandler mHandler;
+ private volatile OnInputEventListener mInputEventListener;
+ private static final Intent mServiceIntent =
+ new Intent(ACTION_DISPLAY_SERVICE);
+ private Connection mConnection;
+ private int currentConnectionState = STATE_UNKNOWN;
+ private BrailleDisplayProperties mDisplayProperties;
+ private ServiceCallback mServiceCallback = new ServiceCallback();
+ /**
+ * Delay before the first rebind attempt on bind error or service
+ * disconnect.
+ */
+ private static final int REBIND_DELAY_MILLIS = 500;
+ private static final int MAX_REBIND_ATTEMPTS = 5;
+ private int mNumFailedBinds = 0;
+
+ /**
+ * A callback interface to get informed about connection state changes.
+ */
+ public interface OnConnectionStateChangeListener {
+ void onConnectionStateChanged(int state);
+ }
+
+ /**
+ * A callback interface for input from the braille display.
+ */
+ public interface OnInputEventListener {
+ void onInputEvent(BrailleInputEvent inputEvent);
+ }
+
+ /**
+ * Constructs an instance and connects to the braille display service.
+ * The current thread must have an {@link android.os.Looper} associated
+ * with it. Callbacks from this object will all be executed on the
+ * current thread. Connection state will be reported to {@code listener).
+ */
+ public Display(Context context, OnConnectionStateChangeListener listener) {
+ this(context, listener, null);
+ }
+
+ /**
+ * Constructs an instance and connects to the braille display service.
+ * Callbacks from this object will all be executed on the thread
+ * associated with {@code handler}. If {@code handler} is {@code null},
+ * the current thread must have an {@link android.os.Looper} associated
+ * with it, which will then be used to execute callbacks. Connection
+ * state will be reported to {@code listener).
+ */
+ public Display(Context context, OnConnectionStateChangeListener listener,
+ Handler handler) {
+ mContext = context;
+ mConnectionStateChangeListener = listener;
+ if (handler == null) {
+ mHandler = new DisplayHandler();
+ } else {
+ mHandler = new DisplayHandler(handler);
+ }
+
+ doBindService();
+ }
+
+ /**
+ * Sets a {@code listener} for input events. {@code listener} can be
+ * {@code null} to remove a previously set listener.
+ */
+ public void setOnInputEventListener(OnInputEventListener listener) {
+ mInputEventListener = listener;
+ }
+
+ /**
+ * Returns the display properties, or {@code null} if not connected
+ * to a display.
+ */
+ public BrailleDisplayProperties getDisplayProperties() {
+ return mDisplayProperties;
+ }
+
+ /**
+ * Displays a given dots configuration on the braille display.
+ * @param patterns Dots configuration to be displayed.
+ */
+ public void displayDots(byte[] patterns) {
+ IBrailleService localService = getBrailleService();
+ if (localService != null) {
+ try {
+ localService.displayDots(patterns);
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Error in displayDots", ex);
+ }
+ } else {
+ Log.v(LOG_TAG, "Error in displayDots: service not connected");
+ }
+ }
+
+ /**
+ * Unbinds from the braille display service and deallocates any
+ * resources. This method should be called when the braille display
+ * is no longer in use by this client.
+ */
+ public void shutdown() {
+ doUnbindService();
+ }
+
+ // NOTE: The methods in this class will be executed in the main
+ // application thread.
+ private class Connection implements ServiceConnection {
+ private volatile IBrailleService mService;
+
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder binder) {
+ Log.i(LOG_TAG, "Connected to braille service");
+ IBrailleService localService =
+ IBrailleService.Stub.asInterface(binder);
+ try {
+ localService.registerCallback(mServiceCallback);
+ mService = localService;
+ synchronized (mHandler) {
+ mNumFailedBinds = 0;
+ }
+ } catch (RemoteException e) {
+ // In this case the service has crashed before we could even do
+ // anything with it.
+ Log.e(LOG_TAG, "Failed to register callback on service", e);
+ // We should get a disconnected call and the rebind
+ // and failure reporting happens in that handler.
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mService = null;
+ Log.e(LOG_TAG, "Disconnected from braille service");
+ // Report display disconnected for now, this will turn into a
+ // connected state or error state depending on how the retrying
+ // goes.
+ mHandler.reportConnectionState(STATE_NOT_CONNECTED, null);
+ mHandler.scheduleRebind();
+ }
+ }
+
+ // NOTE: The methods of this class will be executed in the IPC
+ // thread pool and not on the main application thread.
+ private class ServiceCallback extends IBrailleServiceCallback.Stub {
+ @Override
+ public void onDisplayConnected(
+ BrailleDisplayProperties displayProperties) {
+ mHandler.reportConnectionState(STATE_CONNECTED, displayProperties);
+ }
+
+ @Override
+ public void onDisplayDisconnected() {
+ mHandler.reportConnectionState(STATE_NOT_CONNECTED, null);
+ }
+
+ @Override
+ public void onInput(BrailleInputEvent inputEvent) {
+ mHandler.reportInputEvent(inputEvent);
+ }
+ }
+
+ private void doBindService() {
+ Connection localConnection = new Connection();
+ if (!mContext.bindService(mServiceIntent, localConnection,
+ Context.BIND_AUTO_CREATE)) {
+ Log.e(LOG_TAG, "Failed to bind Service");
+ mHandler.scheduleRebind();
+ return;
+ }
+ mConnection = localConnection;
+ Log.i(LOG_TAG, "Bound to braille service");
+ }
+
+ private void doUnbindService() {
+ IBrailleService localService = getBrailleService();
+ if (localService != null) {
+ try {
+ localService.unregisterCallback(mServiceCallback);
+ } catch (RemoteException e) {
+ // Nothing to do if the service can't be reached.
+ }
+ }
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+ }
+
+ private IBrailleService getBrailleService() {
+ Connection localConnection = mConnection;
+ if (localConnection != null) {
+ return localConnection.mService;
+ }
+ return null;
+ }
+
+ private class DisplayHandler extends Handler {
+ private static final int MSG_REPORT_CONNECTION_STATE = 1;
+ private static final int MSG_REPORT_INPUT_EVENT = 2;
+ private static final int MSG_REBIND_SERVICE = 3;
+
+ public DisplayHandler() {
+ }
+
+ public DisplayHandler(Handler handler) {
+ super(handler.getLooper());
+ }
+
+ public void reportConnectionState(final int newState,
+ final BrailleDisplayProperties displayProperties) {
+ obtainMessage(MSG_REPORT_CONNECTION_STATE, newState, 0,
+ displayProperties)
+ .sendToTarget();
+ }
+
+ public void reportInputEvent(BrailleInputEvent event) {
+ obtainMessage(MSG_REPORT_INPUT_EVENT, event).sendToTarget();
+ }
+
+ public void scheduleRebind() {
+ synchronized (this) {
+ if (mNumFailedBinds < MAX_REBIND_ATTEMPTS) {
+ int delay = REBIND_DELAY_MILLIS << mNumFailedBinds;
+ sendEmptyMessageDelayed(MSG_REBIND_SERVICE, delay);
+ ++mNumFailedBinds;
+ Log.w(LOG_TAG, String.format(
+ "Will rebind to braille service in %d ms.", delay));
+ } else {
+ reportConnectionState(STATE_ERROR, null);
+ }
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REPORT_CONNECTION_STATE:
+ handleReportConnectionState(msg.arg1,
+ (BrailleDisplayProperties) msg.obj);
+ break;
+ case MSG_REPORT_INPUT_EVENT:
+ handleReportInputEvent((BrailleInputEvent) msg.obj);
+ break;
+ case MSG_REBIND_SERVICE:
+ handleRebindService();
+ break;
+ }
+ }
+
+ private void handleReportConnectionState(int newState,
+ BrailleDisplayProperties displayProperties) {
+ mDisplayProperties = displayProperties;
+ if (newState != currentConnectionState
+ && mConnectionStateChangeListener != null) {
+ mConnectionStateChangeListener.onConnectionStateChanged(
+ newState);
+ }
+ currentConnectionState = newState;
+ }
+
+ private void handleReportInputEvent(BrailleInputEvent event) {
+ OnInputEventListener localListener = mInputEventListener;
+ if (localListener != null) {
+ localListener.onInputEvent(event);
+ }
+ }
+
+ private void handleRebindService() {
+ if (mConnection != null) {
+ doUnbindService();
+ }
+ doBindService();
+ }
+ }
+}
diff --git a/display/IBrailleService.aidl b/display/IBrailleService.aidl
new file mode 100644
index 0000000..2b478bb
--- /dev/null
+++ b/display/IBrailleService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import com.googlecode.eyesfree.braille.display.IBrailleServiceCallback;
+
+/**
+ * Interface for clients to talk to the braille display service.
+ */
+interface IBrailleService {
+ /**
+ * Register a callback for the {@code callingApp} which will receive
+ * certain braille display related events.
+ */
+ boolean registerCallback(in IBrailleServiceCallback callback);
+
+ /**
+ * Unregister a previously registered callback for the {@code callingApp}.
+ */
+ oneway void unregisterCallback(in IBrailleServiceCallback callback);
+
+ /**
+ * Updates the main cells of the connected braille display
+ * with a given dot {@code pattern}.
+ *
+ * @return {@code true} on success and {@code false} otherwise.
+ */
+ void displayDots(in byte[] patterns);
+}
diff --git a/display/IBrailleServiceCallback.aidl b/display/IBrailleServiceCallback.aidl
new file mode 100644
index 0000000..545d1ad
--- /dev/null
+++ b/display/IBrailleServiceCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.display;
+
+import com.googlecode.eyesfree.braille.display.BrailleDisplayProperties;
+import com.googlecode.eyesfree.braille.display.BrailleInputEvent;
+
+/**
+ * Callback interface that a braille display client can expose to
+ * get information about various braille display events.
+ */
+interface IBrailleServiceCallback {
+ void onDisplayConnected(in BrailleDisplayProperties displayProperties);
+ void onDisplayDisconnected();
+ void onInput(in BrailleInputEvent inputEvent);
+}
diff --git a/translate/BrailleTranslator.java b/translate/BrailleTranslator.java
new file mode 100644
index 0000000..e7ee9cb
--- /dev/null
+++ b/translate/BrailleTranslator.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.translate;
+
+/**
+ * Translates from text to braille and the other way according to a
+ * particular translation table.
+ */
+public interface BrailleTranslator {
+ /**
+ * Translates a string into the corresponding dot patterns and returns the
+ * resulting byte array. Returns {@code null} on error.
+ */
+ byte[] translate(String text);
+
+ /**
+ * Translates the braille {@code cells} into the corresponding text, which
+ * is returned. Returns {@code null} on error.
+ */
+ String backTranslate(byte[] cells);
+}
diff --git a/translate/ITranslatorService.aidl b/translate/ITranslatorService.aidl
new file mode 100644
index 0000000..1ccab87
--- /dev/null
+++ b/translate/ITranslatorService.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.translate;
+
+import com.googlecode.eyesfree.braille.translate.ITranslatorServiceCallback;
+
+interface ITranslatorService {
+ /**
+ * Sets a callback to be called when the service is ready to translate.
+ * Using any of the other methods in this interface before the
+ * callback is called with a successful status will return
+ * failure.
+ */
+ void setCallback(ITranslatorServiceCallback callback);
+
+ /**
+ * Makes sure that the given table string is valid and that the
+ * table compiles.
+ */
+ boolean checkTable(String tableName);
+
+ /**
+ * Translates text into braille according to the give tableName.
+ * Returns null on fatal translation errors.
+ */
+ byte[] translate(String text, String tableName);
+
+ /**
+ * Translates braille cells into text according to the given table
+ * name. Returns null on fatal translation errors.
+ */
+ String backTranslate(in byte[] cells, String tableName);
+}
diff --git a/translate/ITranslatorServiceCallback.aidl b/translate/ITranslatorServiceCallback.aidl
new file mode 100644
index 0000000..91c74cb
--- /dev/null
+++ b/translate/ITranslatorServiceCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.translate;
+
+oneway interface ITranslatorServiceCallback {
+ void onInit(int status);
+}
diff --git a/translate/TranslatorManager.java b/translate/TranslatorManager.java
new file mode 100644
index 0000000..841a041
--- /dev/null
+++ b/translate/TranslatorManager.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.googlecode.eyesfree.braille.translate;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Client-side interface to the central braille translator service.
+ *
+ * This class can be used to retrieve {@link BrailleTranslator} instances for
+ * performing translation between text and braille cells.
+ *
+ * Typically, an instance of this class is created at application
+ * initialization time and destroyed using the {@link destroy()} method when
+ * the application is about to be destroyed. It is recommended that the
+ * instance is destroyed and recreated if braille translation is not going to
+ * be need for a long period of time.
+ *
+ * Threading:<br>
+ * The object must be destroyed on the same thread it was created.
+ * Other methods may be called from any thread.
+ */
+public class TranslatorManager {
+ private static final String LOG_TAG =
+ TranslatorManager.class.getSimpleName();
+ private static final String ACTION_TRANSLATOR_SERVICE =
+ "com.googlecode.eyesfree.braille.service.ACTION_TRANSLATOR_SERVICE";
+ private static final Intent mServiceIntent =
+ new Intent(ACTION_TRANSLATOR_SERVICE);
+ /**
+ * Delay before the first rebind attempt on bind error or service
+ * disconnect.
+ */
+ private static final int REBIND_DELAY_MILLIS = 500;
+ private static final int MAX_REBIND_ATTEMPTS = 5;
+ public static final int ERROR = -1;
+ public static final int SUCCESS = 0;
+
+ /**
+ * A callback interface to get notified when the translation
+ * manager is ready to be used, or an error occurred during
+ * initialization.
+ */
+ public interface OnInitListener {
+ /**
+ * Called exactly once when it has been determined that the
+ * translation service is either ready to be used ({@code SUCCESS})
+ * or the service is not available {@code ERROR}.
+ */
+ public void onInit(int status);
+ }
+
+ private final Context mContext;
+ private final TranslatorManagerHandler mHandler =
+ new TranslatorManagerHandler();
+ private final ServiceCallback mServiceCallback = new ServiceCallback();
+
+ private OnInitListener mOnInitListener;
+ private Connection mConnection;
+ private int mNumFailedBinds = 0;
+
+ /**
+ * Constructs an instance. {@code context} is used to bind to the
+ * translator service. The other methods of this class should not be
+ * called (they will fail) until {@code onInitListener.onInit()}
+ * is called.
+ */
+ public TranslatorManager(Context context, OnInitListener onInitListener) {
+ mContext = context;
+ mOnInitListener = onInitListener;
+ doBindService();
+ }
+
+ /**
+ * Destroys this instance, deallocating any global resources it is using.
+ * Any {@link BrailleTranslator} objects that were created using this
+ * object are invalid after this call.
+ */
+ public void destroy() {
+ doUnbindService();
+ mHandler.destroy();
+ }
+
+ /**
+ * Returns a new {@link BrailleTranslator} for the translation
+ * table specified by {@code tableName}.
+ */
+ // TODO: Document how to discover valid table names.
+ public BrailleTranslator getTranslator(String tableName) {
+ ITranslatorService localService = getTranslatorService();
+ if (localService != null) {
+ try {
+ if (localService.checkTable(tableName)) {
+ return new BrailleTranslatorImpl(tableName);
+ }
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Error in getTranslator", ex);
+ }
+ }
+ return null;
+ }
+
+ private void doBindService() {
+ Connection localConnection = new Connection();
+ if (!mContext.bindService(mServiceIntent, localConnection,
+ Context.BIND_AUTO_CREATE)) {
+ Log.e(LOG_TAG, "Failed to bind to service");
+ mHandler.scheduleRebind();
+ return;
+ }
+ mConnection = localConnection;
+ Log.i(LOG_TAG, "Bound to translator service");
+ }
+
+ private void doUnbindService() {
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+ }
+
+ private ITranslatorService getTranslatorService() {
+ Connection localConnection = mConnection;
+ if (localConnection != null) {
+ return localConnection.mService;
+ }
+ return null;
+ }
+
+ private class Connection implements ServiceConnection {
+ // Read in application threads, written in main thread.
+ private volatile ITranslatorService mService;
+
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder binder) {
+ Log.i(LOG_TAG, "Connected to translation service");
+ ITranslatorService localService =
+ ITranslatorService.Stub.asInterface(binder);
+ try {
+ localService.setCallback(mServiceCallback);
+ mService = localService;
+ synchronized (mHandler) {
+ mNumFailedBinds = 0;
+ }
+ } catch (RemoteException ex) {
+ // Service went away, rely on disconnect handler to
+ // schedule a rebind.
+ Log.e(LOG_TAG, "Error when setting callback", ex);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ Log.e(LOG_TAG, "Disconnected from translator service");
+ mService = null;
+ // Retry by rebinding, and finally call the onInit if aplicable.
+ mHandler.scheduleRebind();
+ }
+ }
+
+ private class BrailleTranslatorImpl implements BrailleTranslator {
+ private final String mTable;
+
+ public BrailleTranslatorImpl(String table) {
+ mTable = table;
+ }
+
+ @Override
+ public byte[] translate(String text) {
+ ITranslatorService localService = getTranslatorService();
+ if (localService != null) {
+ try {
+ return localService.translate(text, mTable);
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Error in translate", ex);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String backTranslate(byte[] cells) {
+ ITranslatorService localService = getTranslatorService();
+ if (localService != null) {
+ try {
+ return localService.backTranslate(cells, mTable);
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Error in backTranslate", ex);
+ }
+ }
+ return null;
+ }
+ }
+
+ private class ServiceCallback extends ITranslatorServiceCallback.Stub {
+ @Override
+ public void onInit(int status) {
+ mHandler.onInit(status);
+ }
+ }
+
+ private class TranslatorManagerHandler extends Handler {
+ private static final int MSG_ON_INIT = 1;
+ private static final int MSG_REBIND_SERVICE = 2;
+
+ public void onInit(int status) {
+ obtainMessage(MSG_ON_INIT, status, 0).sendToTarget();
+ }
+
+ public void destroy() {
+ mOnInitListener = null;
+ // Cacnel outstanding messages, most importantly
+ // scheduled rebinds.
+ removeCallbacksAndMessages(null);
+ }
+
+ public void scheduleRebind() {
+ synchronized (this) {
+ if (mNumFailedBinds < MAX_REBIND_ATTEMPTS) {
+ int delay = REBIND_DELAY_MILLIS << mNumFailedBinds;
+ sendEmptyMessageDelayed(MSG_REBIND_SERVICE, delay);
+ ++mNumFailedBinds;
+ } else {
+ onInit(ERROR);
+ }
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_INIT:
+ handleOnInit(msg.arg1);
+ break;
+ case MSG_REBIND_SERVICE:
+ handleRebindService();
+ break;
+ }
+ }
+
+ private void handleOnInit(int status) {
+ if (mOnInitListener != null) {
+ mOnInitListener.onInit(status);
+ mOnInitListener = null;
+ }
+ }
+
+ private void handleRebindService() {
+ if (mConnection != null) {
+ doUnbindService();
+ }
+ doBindService();
+ }
+ }
+}