diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /mobile/android/geckoview/src/thirdparty | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'mobile/android/geckoview/src/thirdparty')
3 files changed, 606 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java new file mode 100644 index 000000000..3bdd8c450 --- /dev/null +++ b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java @@ -0,0 +1,147 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package com.googlecode.eyesfree.braille.selfbraille; + +/** + * Interface for a client to control braille output for a part of the + * accessibility node tree. + */ +public interface ISelfBrailleService extends android.os.IInterface { + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements + com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService { + private static final java.lang.String DESCRIPTOR = "com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService"; + + /** Construct the stub at attach it to the interface. */ + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + /** + * Cast an IBinder object into an + * com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService + * interface, generating a proxy if needed. + */ + public static com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService asInterface( + android.os.IBinder obj) { + if ((obj == null)) { + return null; + } + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin != null) && (iin instanceof com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService))) { + return ((com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService) iin); + } + return new com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService.Stub.Proxy( + obj); + } + + @Override + public android.os.IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, android.os.Parcel data, + android.os.Parcel reply, int flags) + throws android.os.RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + case TRANSACTION_write: { + data.enforceInterface(DESCRIPTOR); + android.os.IBinder _arg0; + _arg0 = data.readStrongBinder(); + com.googlecode.eyesfree.braille.selfbraille.WriteData _arg1; + if ((0 != data.readInt())) { + _arg1 = com.googlecode.eyesfree.braille.selfbraille.WriteData.CREATOR + .createFromParcel(data); + } else { + _arg1 = null; + } + this.write(_arg0, _arg1); + reply.writeNoException(); + return true; + } + case TRANSACTION_disconnect: { + data.enforceInterface(DESCRIPTOR); + android.os.IBinder _arg0; + _arg0 = data.readStrongBinder(); + this.disconnect(_arg0); + return true; + } + } + return super.onTransact(code, data, reply, flags); + } + + private static class Proxy implements + com.googlecode.eyesfree.braille.selfbraille.ISelfBrailleService { + private android.os.IBinder mRemote; + + Proxy(android.os.IBinder remote) { + mRemote = remote; + } + + @Override + public android.os.IBinder asBinder() { + return mRemote; + } + + public java.lang.String getInterfaceDescriptor() { + return DESCRIPTOR; + } + + @Override + public void write( + android.os.IBinder clientToken, + com.googlecode.eyesfree.braille.selfbraille.WriteData writeData) + throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeStrongBinder(clientToken); + if ((writeData != null)) { + _data.writeInt(1); + writeData.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + mRemote.transact(Stub.TRANSACTION_write, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void disconnect(android.os.IBinder clientToken) + throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeStrongBinder(clientToken); + mRemote.transact(Stub.TRANSACTION_disconnect, _data, null, + android.os.IBinder.FLAG_ONEWAY); + } finally { + _data.recycle(); + } + } + } + + static final int TRANSACTION_write = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + static final int TRANSACTION_disconnect = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); + } + + public void write(android.os.IBinder clientToken, + com.googlecode.eyesfree.braille.selfbraille.WriteData writeData) + throws android.os.RemoteException; + + public void disconnect(android.os.IBinder clientToken) + throws android.os.RemoteException; +} diff --git a/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java new file mode 100644 index 000000000..e4a363aca --- /dev/null +++ b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java @@ -0,0 +1,267 @@ +/* + * 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.selfbraille; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Client-side interface to the self brailling interface. + * + * Threading: Instances of this object should be created and shut down + * in a thread with a {@link Looper} associated with it. Other methods may + * be called on any thread. + */ +public class SelfBrailleClient { + private static final String LOG_TAG = + SelfBrailleClient.class.getSimpleName(); + private static final String ACTION_SELF_BRAILLE_SERVICE = + "com.googlecode.eyesfree.braille.service.ACTION_SELF_BRAILLE_SERVICE"; + private static final String BRAILLE_BACK_PACKAGE = + "com.googlecode.eyesfree.brailleback"; + private static final Intent mServiceIntent = + new Intent(ACTION_SELF_BRAILLE_SERVICE) + .setPackage(BRAILLE_BACK_PACKAGE); + /** + * SHA-1 hash value of the Eyes-Free release key certificate, used to sign + * BrailleBack. It was generated from the keystore with: + * $ keytool -exportcert -keystore <keystorefile> -alias android.keystore \ + * > cert + * $ keytool -printcert -file cert + */ + // The typecasts are to silence a compiler warning about loss of precision + private static final byte[] EYES_FREE_CERT_SHA1 = new byte[] { + (byte) 0x9B, (byte) 0x42, (byte) 0x4C, (byte) 0x2D, + (byte) 0x27, (byte) 0xAD, (byte) 0x51, (byte) 0xA4, + (byte) 0x2A, (byte) 0x33, (byte) 0x7E, (byte) 0x0B, + (byte) 0xB6, (byte) 0x99, (byte) 0x1C, (byte) 0x76, + (byte) 0xEC, (byte) 0xA4, (byte) 0x44, (byte) 0x61 + }; + /** + * 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 final Binder mIdentity = new Binder(); + private final Context mContext; + private final boolean mAllowDebugService; + private final SelfBrailleHandler mHandler = new SelfBrailleHandler(); + private boolean mShutdown = false; + + /** + * Written in handler thread, read in any thread calling methods on the + * object. + */ + private volatile Connection mConnection; + /** Protected by synchronizing on mHandler. */ + private int mNumFailedBinds = 0; + + /** + * Constructs an instance of this class. {@code context} is used to bind + * to the self braille service. The current thread must have a Looper + * associated with it. If {@code allowDebugService} is true, this instance + * will connect to a BrailleBack service without requiring it to be signed + * by the release key used to sign BrailleBack. + */ + public SelfBrailleClient(Context context, boolean allowDebugService) { + mContext = context; + mAllowDebugService = allowDebugService; + doBindService(); + } + + /** + * Shuts this instance down, deallocating any global resources it is using. + * This method must be called on the same thread that created this object. + */ + public void shutdown() { + mShutdown = true; + doUnbindService(); + } + + public void write(WriteData writeData) { + writeData.validate(); + ISelfBrailleService localService = getSelfBrailleService(); + if (localService != null) { + try { + localService.write(mIdentity, writeData); + } catch (RemoteException ex) { + Log.e(LOG_TAG, "Self braille write failed", ex); + } + } + } + + 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 self braille service"); + } + + private void doUnbindService() { + if (mConnection != null) { + ISelfBrailleService localService = getSelfBrailleService(); + if (localService != null) { + try { + localService.disconnect(mIdentity); + } catch (RemoteException ex) { + // Nothing to do. + } + } + mContext.unbindService(mConnection); + mConnection = null; + } + } + + private ISelfBrailleService getSelfBrailleService() { + Connection localConnection = mConnection; + if (localConnection != null) { + return localConnection.mService; + } + return null; + } + + private boolean verifyPackage() { + PackageManager pm = mContext.getPackageManager(); + PackageInfo pi; + try { + pi = pm.getPackageInfo(BRAILLE_BACK_PACKAGE, + PackageManager.GET_SIGNATURES); + } catch (PackageManager.NameNotFoundException ex) { + Log.w(LOG_TAG, "Can't verify package " + BRAILLE_BACK_PACKAGE, + ex); + return false; + } + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException ex) { + Log.e(LOG_TAG, "SHA-1 not supported", ex); + return false; + } + // Check if any of the certificates match our hash. + for (Signature signature : pi.signatures) { + digest.update(signature.toByteArray()); + if (MessageDigest.isEqual(EYES_FREE_CERT_SHA1, digest.digest())) { + return true; + } + digest.reset(); + } + if (mAllowDebugService) { + Log.w(LOG_TAG, String.format( + "*** %s connected to BrailleBack with invalid (debug?) " + + "signature ***", + mContext.getPackageName())); + return true; + } + return false; + } + private class Connection implements ServiceConnection { + // Read in application threads, written in main thread. + private volatile ISelfBrailleService mService; + + @Override + public void onServiceConnected(ComponentName className, + IBinder binder) { + if (!verifyPackage()) { + Log.w(LOG_TAG, String.format("Service certificate mismatch " + + "for %s, dropping connection", + BRAILLE_BACK_PACKAGE)); + mHandler.unbindService(); + return; + } + Log.i(LOG_TAG, "Connected to self braille service"); + mService = ISelfBrailleService.Stub.asInterface(binder); + synchronized (mHandler) { + mNumFailedBinds = 0; + } + } + + @Override + public void onServiceDisconnected(ComponentName className) { + Log.e(LOG_TAG, "Disconnected from self braille service"); + mService = null; + // Retry by rebinding. + mHandler.scheduleRebind(); + } + } + + private class SelfBrailleHandler extends Handler { + private static final int MSG_REBIND_SERVICE = 1; + private static final int MSG_UNBIND_SERVICE = 2; + + public void scheduleRebind() { + synchronized (this) { + if (mNumFailedBinds < MAX_REBIND_ATTEMPTS) { + int delay = REBIND_DELAY_MILLIS << mNumFailedBinds; + sendEmptyMessageDelayed(MSG_REBIND_SERVICE, delay); + ++mNumFailedBinds; + } + } + } + + public void unbindService() { + sendEmptyMessage(MSG_UNBIND_SERVICE); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REBIND_SERVICE: + handleRebindService(); + break; + case MSG_UNBIND_SERVICE: + handleUnbindService(); + break; + } + } + + private void handleRebindService() { + if (mShutdown) { + return; + } + if (mConnection != null) { + doUnbindService(); + } + doBindService(); + } + + private void handleUnbindService() { + doUnbindService(); + } + } +} diff --git a/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/WriteData.java b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/WriteData.java new file mode 100644 index 000000000..ef81a2990 --- /dev/null +++ b/mobile/android/geckoview/src/thirdparty/java/com/googlecode/eyesfree/braille/selfbraille/WriteData.java @@ -0,0 +1,192 @@ +/* + * 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.selfbraille; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; + +/** + * Represents what should be shown on the braille display for a + * part of the accessibility node tree. + */ +public class WriteData implements Parcelable { + + private static final String PROP_SELECTION_START = "selectionStart"; + private static final String PROP_SELECTION_END = "selectionEnd"; + + private AccessibilityNodeInfo mAccessibilityNodeInfo; + private CharSequence mText; + private Bundle mProperties = Bundle.EMPTY; + + /** + * Returns a new {@link WriteData} instance for the given {@code view}. + */ + public static WriteData forView(View view) { + AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(view); + WriteData writeData = new WriteData(); + writeData.mAccessibilityNodeInfo = node; + return writeData; + } + + public static WriteData forInfo(AccessibilityNodeInfo info){ + WriteData writeData = new WriteData(); + writeData.mAccessibilityNodeInfo = info; + return writeData; + } + + + public AccessibilityNodeInfo getAccessibilityNodeInfo() { + return mAccessibilityNodeInfo; + } + + /** + * Sets the text to be displayed when the accessibility node associated + * with this instance has focus. If this method is not called (or + * {@code text} is {@code null}), this client relinquishes control over + * this node. + */ + public WriteData setText(CharSequence text) { + mText = text; + return this; + } + + public CharSequence getText() { + return mText; + } + + /** + * Sets the start position in the text of a text selection or cursor that + * should be marked on the display. A negative value (the default) means + * no selection will be added. + */ + public WriteData setSelectionStart(int v) { + writableProperties().putInt(PROP_SELECTION_START, v); + return this; + } + + /** + * @see {@link #setSelectionStart}. + */ + public int getSelectionStart() { + return mProperties.getInt(PROP_SELECTION_START, -1); + } + + /** + * Sets the end of the text selection to be marked on the display. This + * value should only be non-negative if the selection start is + * non-negative. If this value is <= the selection start, the selection + * is a cursor. Otherwise, the selection covers the range from + * start(inclusive) to end (exclusive). + * + * @see {@link android.text.Selection}. + */ + public WriteData setSelectionEnd(int v) { + writableProperties().putInt(PROP_SELECTION_END, v); + return this; + } + + /** + * @see {@link #setSelectionEnd}. + */ + public int getSelectionEnd() { + return mProperties.getInt(PROP_SELECTION_END, -1); + } + + private Bundle writableProperties() { + if (mProperties == Bundle.EMPTY) { + mProperties = new Bundle(); + } + return mProperties; + } + + /** + * Checks constraints on the fields that must be satisfied before sending + * this instance to the self braille service. + * @throws IllegalStateException + */ + public void validate() throws IllegalStateException { + if (mAccessibilityNodeInfo == null) { + throw new IllegalStateException( + "Accessibility node info can't be null"); + } + int selectionStart = getSelectionStart(); + int selectionEnd = getSelectionEnd(); + if (mText == null) { + if (selectionStart > 0 || selectionEnd > 0) { + throw new IllegalStateException( + "Selection can't be set without text"); + } + } else { + if (selectionStart < 0 && selectionEnd >= 0) { + throw new IllegalStateException( + "Selection end without start"); + } + int textLength = mText.length(); + if (selectionStart > textLength || selectionEnd > textLength) { + throw new IllegalStateException("Selection out of bounds"); + } + } + } + + // For Parcelable support. + + public static final Parcelable.Creator<WriteData> CREATOR = + new Parcelable.Creator<WriteData>() { + @Override + public WriteData createFromParcel(Parcel in) { + return new WriteData(in); + } + + @Override + public WriteData[] newArray(int size) { + return new WriteData[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + /** + * {@inheritDoc} + * <strong>Note:</strong> The {@link AccessibilityNodeInfo} will be + * recycled by this method, don't try to use this more than once. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + mAccessibilityNodeInfo.writeToParcel(out, flags); + // The above call recycles the node, so make sure we don't use it + // anymore. + mAccessibilityNodeInfo = null; + out.writeString(mText.toString()); + out.writeBundle(mProperties); + } + + private WriteData() { + } + + private WriteData(Parcel in) { + mAccessibilityNodeInfo = + AccessibilityNodeInfo.CREATOR.createFromParcel(in); + mText = in.readString(); + mProperties = in.readBundle(); + } +} |