summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java68
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl64
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java66
-rw-r--r--core/java/android/hardware/Camera.java56
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java38
-rw-r--r--core/java/android/nfc/ErrorCodes.java5
-rw-r--r--core/java/android/nfc/tech/BasicTagTechnology.java4
-rw-r--r--core/java/android/os/FileUtils.java37
-rw-r--r--core/java/android/provider/Calendar.java832
-rw-r--r--core/java/android/util/FinitePool.java5
-rw-r--r--core/java/android/util/Poolable.java2
-rw-r--r--core/java/android/view/Gravity.java28
-rw-r--r--core/java/android/view/VelocityTracker.java15
-rw-r--r--core/java/android/view/View.java146
-rw-r--r--core/java/android/view/ViewAncestor.java530
-rw-r--r--core/java/android/view/ViewGroup.java23
-rw-r--r--core/java/android/view/WindowManager.java4
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java188
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java103
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.aidl19
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java947
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java146
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl41
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl36
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl12
-rw-r--r--core/java/android/webkit/WebView.java18
-rw-r--r--core/java/android/widget/FrameLayout.java4
-rw-r--r--core/java/android/widget/LinearLayout.java16
-rw-r--r--core/java/android/widget/RelativeLayout.java28
-rw-r--r--core/java/android/widget/TextView.java29
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/jni/android/graphics/Canvas.cpp26
-rw-r--r--core/jni/android/graphics/TextLayout.cpp18
-rw-r--r--core/jni/android_util_Process.cpp13
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp18
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/drawable-hdpi/pointer_arrow.pngbin0 -> 1336 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_arrow_icon.xml5
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_anchor.pngbin0 -> 6817 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml5
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_hover.pngbin0 -> 9669 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml5
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_touch.pngbin0 -> 2880 bytes
-rw-r--r--core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml5
-rw-r--r--core/res/res/values-af/strings.xml4
-rw-r--r--core/res/res/values-am/strings.xml4
-rw-r--r--core/res/res/values-ar/strings.xml4
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml4
-rw-r--r--core/res/res/values-cs/strings.xml4
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rGB/strings.xml4
-rw-r--r--core/res/res/values-es-rUS/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml4
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml6
-rw-r--r--core/res/res/values-hr/strings.xml4
-rw-r--r--core/res/res/values-hu/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml4
-rw-r--r--core/res/res/values-it/strings.xml4
-rw-r--r--core/res/res/values-iw/strings.xml4
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml4
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-lv/strings.xml4
-rw-r--r--core/res/res/values-ms/strings.xml4
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-nl/strings.xml4
-rw-r--r--core/res/res/values-pl/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-rm/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-sk/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml4
-rw-r--r--core/res/res/values-sw/strings.xml4
-rw-r--r--core/res/res/values-th/strings.xml4
-rw-r--r--core/res/res/values-tl/strings.xml4
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml4
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values-zu/strings.xml4
-rwxr-xr-xcore/res/res/values/config.xml1
-rwxr-xr-xcore/res/res/values/strings.xml7
-rw-r--r--core/tests/coretests/AndroidManifest.xml10
-rw-r--r--core/tests/coretests/res/layout/interrogation_activity.xml101
-rw-r--r--core/tests/coretests/res/values/strings.xml12
-rw-r--r--core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java47
-rw-r--r--core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java464
-rw-r--r--core/tests/coretests/src/android/view/GravityTest.java8
98 files changed, 3995 insertions, 458 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 28fc21a..8bb305d 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -25,6 +25,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
/**
* An accessibility service runs in the background and receives callbacks by the system
@@ -51,7 +52,11 @@ import android.view.accessibility.AccessibilityEvent;
* enabling or disabling it in the device settings. After the system binds to a service it
* calls {@link AccessibilityService#onServiceConnected()}. This method can be
* overriden by clients that want to perform post binding setup.
+ * </p>
* <p>
+ * An accessibility service can be configured to receive specific types of accessibility events,
+ * listen only to specific packages, get events from each type only once in a given time frame,
+ * retrieve window content, specify a settings activity, etc.
* </p>
* There are two approaches for configuring an accessibility service:
* <ul>
@@ -59,20 +64,23 @@ import android.view.accessibility.AccessibilityEvent;
* Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
* the service. A service declaration with a meta-data tag is presented below:
* <p>
- * <code>
- * &lt;service android:name=".MyAccessibilityService"&gt;<br>
- * &nbsp;&nbsp;&lt;intent-filter&gt;<br>
- * &nbsp;&nbsp;&nbsp;&nbsp;&lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;<br>
- * &nbsp;&nbsp;&lt;/intent-filter&gt;<br>
- * &nbsp;&nbsp;&lt;meta-data android:name="android.accessibilityservice.as" android:resource="@xml/accessibilityservice" /&gt;<br>
- * &lt;/service&gt;<br>
- * </code>
+ * <code>
+ * &lt;service android:name=".MyAccessibilityService"&gt;<br>
+ * &nbsp;&nbsp;&lt;intent-filter&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/intent-filter&gt;<br>
+ * &nbsp;&nbsp;&lt;meta-data android:name="android.accessibilityservice.as" android:resource="@xml/accessibilityservice" /&gt;<br>
+ * &lt;/service&gt;<br>
+ * </code>
* </p>
* <p>
* <strong>
* This approach enables setting all accessibility service properties.
* </strong>
* </p>
+ * <p>
+ * For more details refer to {@link #SERVICE_META_DATA}.
+ * </p>
* </li>
* <li>
* Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
@@ -88,6 +96,9 @@ import android.view.accessibility.AccessibilityEvent;
* {@link AccessibilityServiceInfo#packageNames}
* </strong>
* </p>
+ * <p>
+ * For more details refer to {@link AccessibilityServiceInfo}.
+ * </p>
* </li>
* </ul>
* <p>
@@ -151,16 +162,49 @@ public abstract class AccessibilityService extends Service {
* <code>
* &lt;?xml version="1.0" encoding="utf-8"?&gt;<br>
* &lt;accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"<br>
- * &nbsp;&nbsp;android:eventTypes="typeViewClicked|typeViewFocused"<br>
+ * &nbsp;&nbsp;android:accessibilityEventTypes="typeViewClicked|typeViewFocused"<br>
* &nbsp;&nbsp;android:packageNames="foo.bar, foo.baz"<br>
- * &nbsp;&nbsp;android:feedbackType="feedbackSpoken"<br>
+ * &nbsp;&nbsp;android:accessibilityFeedbackType="feedbackSpoken"<br>
* &nbsp;&nbsp;android:notificationTimeout="100"<br>
- * &nbsp;&nbsp;android:flags="flagDefault"<br>
+ * &nbsp;&nbsp;android:accessibilityFlags="flagDefault"<br>
* &nbsp;&nbsp;android:settingsActivity="foo.bar.TestBackActivity"<br>
* &nbsp;&nbsp;. . .<br>
* /&gt;
* </code>
* </p>
+ * <p>
+ * <strong>Note:</strong> A service can retrieve only the content of the active window.
+ * An active window is the source of the most recent event of type
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START},
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END},
+ * {@link AccessibilityEvent#TYPE_VIEW_CLICKED},
+ * {@link AccessibilityEvent#TYPE_VIEW_FOCUSED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
+ * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED},
+ * {@link AccessibilityEvent#TYPE_VIEW_SELECTED},
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED},
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}.
+ * Therefore the service should:
+ * <ul>
+ * <li>
+ * Register for all event types with no notification timeout and keep track
+ * for the active window by calling
+ * {@link AccessibilityEvent#getAccessibilityWindowId()} of the last received
+ * event and compare this with the
+ * {@link AccessibilityNodeInfo#getAccessibilityWindowId()} before calling
+ * retrieval methods on the latter.
+ * </li>
+ * <li>
+ * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail
+ * since the active window has changed and the service did not get the
+ * accessibility event. Note that it is possible to have a retrieval method
+ * failing event adopting the strategy specified in the previous bullet
+ * because the accessibility event dispatch is asynchronous and crosses
+ * process boundaries.
+ * </li>
+ * <ul>
+ * </p>
*/
public static final String SERVICE_META_DATA = "android.accessibilityservice";
@@ -224,7 +268,7 @@ public abstract class AccessibilityService extends Service {
/**
* Implement to return the implementation of the internal accessibility
- * service interface. Subclasses should not override.
+ * service interface.
*/
@Override
public final IBinder onBind(Intent intent) {
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 7157def..19f0bf0 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -17,14 +17,72 @@
package android.accessibilityservice;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.view.accessibility.AccessibilityNodeInfo;
/**
- * Interface AccessibilityManagerService#Service implements, and passes to an
- * AccessibilityService so it can dynamically configure how the system handles it.
+ * Interface given to an AccessibilitySerivce to talk to the AccessibilityManagerService.
*
* @hide
*/
-oneway interface IAccessibilityServiceConnection {
+interface IAccessibilityServiceConnection {
void setServiceInfo(in AccessibilityServiceInfo info);
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ *
+ * @param accessibilityWindowId A unique window id.
+ * @param accessibilityViewId A unique View accessibility id.
+ * @return The node info.
+ */
+ AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
+ int accessibilityViewId);
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+ * insensitive containment.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received infos by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ *
+ * @param text The searched text.
+ * @return A list of node info.
+ */
+ List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text);
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ *
+ * @param id The id of the node.
+ * @return The node info.
+ */
+ AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId);
+
+ /**
+ * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+ *
+ * @param accessibilityWindowId The id of the window.
+ * @param accessibilityViewId The of a view in the .
+ * @return Whether the action was performed.
+ */
+ boolean performAccessibilityAction(int accessibilityWindowId, int accessibilityViewId,
+ int action);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 26707c9..a8c31f9 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -873,10 +873,10 @@ public final class BluetoothAdapter {
/**
* Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
- * <p>The link key will be unauthenticated i.e the communication is
+ * <p>The link key is not required to be authenticated, i.e the communication may be
* vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
- * the link key will be encrypted, as encryption is mandartory.
- * For legacy devices (pre Bluetooth 2.1 devices) the link key will not
+ * the link will be encrypted, as encryption is mandartory.
+ * For legacy devices (pre Bluetooth 2.1 devices) the link will not
* be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
* encrypted and authenticated communication channel is desired.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
@@ -902,6 +902,44 @@ public final class BluetoothAdapter {
return createNewRfcommSocketAndRecord(name, uuid, false, false);
}
+ /**
+ * Create a listening, encrypted,
+ * RFCOMM Bluetooth socket with Service Record.
+ * <p>The link will be encrypted, but the link key is not required to be authenticated
+ * i.e the communication is vulnerable to Man In the Middle attacks. Use
+ * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
+ * <p> Use this socket if authentication of link key is not possible.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not have
+ * an input and output capability or just has the ability to display a numeric key,
+ * a secure socket connection is not possible and this socket can be used.
+ * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
+ * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
+ * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections from a listening {@link BluetoothServerSocket}.
+ * <p>The system will assign an unused RFCOMM channel to listen on.
+ * <p>The system will also register a Service Discovery
+ * Protocol (SDP) record with the local SDP server containing the specified
+ * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
+ * can use the same UUID to query our SDP server and discover which channel
+ * to connect to. This SDP record will be removed when this socket is
+ * closed, or if this application closes unexpectedly.
+ * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
+ * connect to this socket from another device using the same {@link UUID}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ * @param name service name for SDP record
+ * @param uuid uuid for SDP record
+ * @return a listening RFCOMM BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
+ String name, UUID uuid) throws IOException {
+ return createNewRfcommSocketAndRecord(name, uuid, false, true);
+ }
+
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
@@ -973,6 +1011,28 @@ public final class BluetoothAdapter {
return socket;
}
+ /**
+ * Construct an encrypted, RFCOMM server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return An RFCOMM BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
+ throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, false, true, port);
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
+ try {
+ socket.close();
+ } catch (IOException e) {}
+ socket.mSocket.throwErrnoNative(errno);
+ }
+ return socket;
+ }
+
/**
* Construct a SCO server socket.
* Call #accept to retrieve connections to this socket.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index d5c4ace..dea5133 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -16,22 +16,22 @@
package android.hardware;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.io.IOException;
-
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringTokenizer;
/**
* The Camera class is used to set image capture settings, start/stop preview,
@@ -834,8 +834,6 @@ public class Camera {
* @param raw the callback for raw (uncompressed) image data, or null
* @param postview callback with postview image data, may be null
* @param jpeg the callback for JPEG image data, or null
- *
- * @see #addRawImageCallbackBuffer(byte[])
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
@@ -1084,10 +1082,14 @@ public class Camera {
};
/**
- * Area class for focus.
- *
- * @see #setFocusAreas(List)
- * @see #getFocusAreas()
+ * Area class for focus and metering.
+ *
+ * @see Parameters#setFocusAreas(List)
+ * @see Parameters#getFocusAreas()
+ * @see Parameters#getMaxNumFocusAreas()
+ * @see Parameters#setMeteringAreas(List)
+ * @see Parameters#getMeteringAreas()
+ * @see Parameters#getMaxNumMeteringAreas()
*/
public static class Area {
/**
@@ -1121,12 +1123,22 @@ public class Camera {
return weight == a.weight;
}
- /** rectangle of the area */
+ /**
+ * Rectangle of the area.
+ *
+ * @see Parameters#getFocusAreas()
+ * @see Parameters#getMeteringAreas()
+ */
public Rect rect;
- /** weight of the area */
+ /**
+ * Weight of the area.
+ *
+ * @see Parameters#getFocusAreas()
+ * @see Parameters#getMeteringAreas()
+ */
public int weight;
- };
+ }
/**
* Camera service settings.
@@ -2775,7 +2787,7 @@ public class Camera {
* The direction is not affected by the rotation or mirroring of
* {@link #setDisplayOrientation(int)}. Coordinates of the rectangle
* range from -1000 to 1000. (-1000, -1000) is the upper left point.
- * (1000, 1000) is the lower right point. The length and width of focus
+ * (1000, 1000) is the lower right point. The width and height of focus
* areas cannot be 0 or negative.
*
* The weight must range from 1 to 1000. The weight should be
@@ -2842,7 +2854,7 @@ public class Camera {
* sensor sees. The direction is not affected by the rotation or
* mirroring of {@link #setDisplayOrientation(int)}. Coordinates of the
* rectangle range from -1000 to 1000. (-1000, -1000) is the upper left
- * point. (1000, 1000) is the lower right point. The length and width of
+ * point. (1000, 1000) is the lower right point. The width and height of
* metering areas cannot be 0 or negative.
*
* The weight must range from 1 to 1000, and represents a weight for
@@ -3033,7 +3045,7 @@ public class Camera {
if (result.size() == 0) return null;
if (result.size() == 1) {
- Area area = (Area) result.get(0);
+ Area area = result.get(0);
Rect rect = area.rect;
if (rect.left == 0 && rect.top == 0 && rect.right == 0
&& rect.bottom == 0 && area.weight == 0) {
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 3bf64b2..8e50cd5 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -28,6 +28,7 @@ import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
@@ -86,6 +87,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
private SSLSocketFactory mInsecureFactory = null;
private SSLSocketFactory mSecureFactory = null;
+ private TrustManager[] mTrustManagers = null;
+ private KeyManager[] mKeyManagers = null;
private final int mHandshakeTimeoutMillis;
private final SSLClientSessionCache mSessionCache;
@@ -197,10 +200,11 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
}
- private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
+ private SSLSocketFactory makeSocketFactory(
+ KeyManager[] keyManagers, TrustManager[] trustManagers) {
try {
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
- sslContext.engineInit(null, trustManagers, null);
+ sslContext.engineInit(keyManagers, trustManagers, null);
sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
return sslContext.engineGetSocketFactory();
} catch (KeyManagementException e) {
@@ -223,18 +227,44 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
} else {
Log.w(TAG, "Bypassing SSL security checks at caller's request");
}
- mInsecureFactory = makeSocketFactory(INSECURE_TRUST_MANAGER);
+ mInsecureFactory = makeSocketFactory(mKeyManagers, INSECURE_TRUST_MANAGER);
}
return mInsecureFactory;
} else {
if (mSecureFactory == null) {
- mSecureFactory = makeSocketFactory(null);
+ mSecureFactory = makeSocketFactory(mKeyManagers, mTrustManagers);
}
return mSecureFactory;
}
}
/**
+ * Sets the {@link TrustManager}s to be used for connections made by this factory.
+ * @hide
+ */
+ public void setTrustManagers(TrustManager[] trustManager) {
+ mTrustManagers = trustManager;
+
+ // Clear out all cached secure factories since configurations have changed.
+ mSecureFactory = null;
+ // Note - insecure factories only ever use the INSECURE_TRUST_MANAGER so they need not
+ // be cleared out here.
+ }
+
+ /**
+ * Sets the {@link KeyManager}s to be used for connections made by this factory.
+ * @hide
+ */
+ public void setKeyManagers(KeyManager[] keyManagers) {
+ mKeyManagers = keyManagers;
+
+ // Clear out any existing cached factories since configurations have changed.
+ mSecureFactory = null;
+ mInsecureFactory = null;
+ }
+
+
+ /**
* {@inheritDoc}
*
* <p>This method verifies the peer's certificate hostname after connecting
diff --git a/core/java/android/nfc/ErrorCodes.java b/core/java/android/nfc/ErrorCodes.java
index 69329df..3adcdc3 100644
--- a/core/java/android/nfc/ErrorCodes.java
+++ b/core/java/android/nfc/ErrorCodes.java
@@ -57,6 +57,7 @@ public class ErrorCodes {
case ERROR_SE_ALREADY_SELECTED: return "SE_ALREADY_SELECTED";
case ERROR_SE_CONNECTED: return "SE_CONNECTED";
case ERROR_NO_SE_CONNECTED: return "NO_SE_CONNECTED";
+ case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
default: return "UNKNOWN ERROR";
}
}
@@ -105,4 +106,6 @@ public class ErrorCodes {
public static final int ERROR_NO_SE_CONNECTED = -20;
-} \ No newline at end of file
+ public static final int ERROR_NOT_SUPPORTED = -21;
+
+}
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java
index 7ec807a..6557ee0 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -77,6 +77,10 @@ import java.io.IOException;
// Store this in the tag object
mTag.setConnectedTechnology(mSelectedTechnology);
mIsConnected = true;
+ } else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) {
+ throw new UnsupportedOperationException("Connecting to " +
+ "this technology is not supported by the NFC " +
+ "adapter.");
} else {
throw new IOException();
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index eb0cf37..215e836 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -19,20 +19,21 @@ package android.os;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.util.regex.Pattern;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
/**
* Tools for managing files. Not for public consumption.
* @hide
*/
-public class FileUtils
-{
+public class FileUtils {
public static final int S_IRWXU = 00700;
public static final int S_IRUSR = 00400;
public static final int S_IWUSR = 00200;
@@ -95,7 +96,7 @@ public class FileUtils
/** returns the FAT file system volume ID for the volume mounted
* at the given mount point, or -1 for failure
- * @param mount point for FAT volume
+ * @param mountPoint point for FAT volume
* @return volume ID or -1
*/
public static native int getFatVolumeId(String mountPoint);
@@ -243,4 +244,32 @@ public class FileUtils
out.close();
}
}
+
+ /**
+ * Computes the checksum of a file using the CRC32 checksum routine.
+ * The value of the checksum is returned.
+ *
+ * @param file the file to checksum, must not be null
+ * @return the checksum value or an exception is thrown.
+ */
+ public static long checksumCrc32(File file) throws FileNotFoundException, IOException {
+ CRC32 checkSummer = new CRC32();
+ CheckedInputStream cis = null;
+
+ try {
+ cis = new CheckedInputStream( new FileInputStream(file), checkSummer);
+ byte[] buf = new byte[128];
+ while(cis.read(buf) >= 0) {
+ // Just read for checksum to get calculated.
+ }
+ return checkSummer.getValue();
+ } finally {
+ if (cis != null) {
+ try {
+ cis.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 0ef38bf..2df2688 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -16,6 +16,7 @@
package android.provider;
+
import android.accounts.Account;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -32,7 +33,6 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
-import android.pim.ICalendar;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
@@ -44,24 +44,30 @@ import android.util.Log;
* @hide
*/
public final class Calendar {
-
- public static final String TAG = "Calendar";
+ private static final String TAG = "Calendar";
/**
- * Broadcast Action: An event reminder.
+ * Broadcast Action: This is the intent that gets fired when an alarm
+ * notification needs to be posted for a reminder.
*/
public static final String EVENT_REMINDER_ACTION = "android.intent.action.EVENT_REMINDER";
/**
- * These are the symbolic names for the keys used in the extra data
- * passed in the intent for event reminders.
+ * Intent Extras key: The start time of an event or an instance of a
+ * recurring event. (milliseconds since epoch)
*/
public static final String EVENT_BEGIN_TIME = "beginTime";
+
+ /**
+ * Intent Extras key: The end time of an event or an instance of a recurring
+ * event. (milliseconds since epoch)
+ */
public static final String EVENT_END_TIME = "endTime";
/**
- * This must not be changed or horrible, unspeakable things could happen.
- * For instance, the Calendar app might break. Also, the db might not work.
+ * This authority is used for writing to or querying from the calendar
+ * provider. Note: This is set at first run and cannot be changed without
+ * breaking apps that access the provider.
*/
public static final String AUTHORITY = "com.android.calendar";
@@ -73,20 +79,37 @@ public final class Calendar {
/**
* An optional insert, update or delete URI parameter that allows the caller
- * to specify that it is a sync adapter. The default value is false. If true
- * the dirty flag is not automatically set and the "syncToNetwork" parameter
- * is set to false when calling
- * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+ * to specify that it is a sync adapter. The default value is false. If set
+ * to true, the modified row is not marked as "dirty" (needs to be synced)
+ * and when the provider calls
+ * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
+ * , the third parameter "syncToNetwork" is set to false. Furthermore, if
+ * set to true, the caller must also include
+ * {@link SyncColumns#ACCOUNT_NAME} and {@link SyncColumns#ACCOUNT_TYPE} as
+ * query parameters.
+ *
+ * @See Uri.Builder#appendQueryParameter(java.lang.String, java.lang.String)
*/
public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
+ /**
+ * A special account type for calendars not associated with any account.
+ * Normally calendars that do not match an account on the device will be
+ * removed. Setting the account_type on a calendar to this will prevent it
+ * from being wiped if it does not match an existing account.
+ *
+ * @see SyncColumns#ACCOUNT_TYPE
+ */
+ public static final String ACCOUNT_TYPE_LOCAL = "LOCAL";
/**
- * Generic columns for use by sync adapters. The specific functions of
- * these columns are private to the sync adapter. Other clients of the API
- * should not attempt to either read or write this column.
+ * Generic columns for use by sync adapters. The specific functions of these
+ * columns are private to the sync adapter. Other clients of the API should
+ * not attempt to either read or write this column. These columns are
+ * editable as part of the Calendars Uri, but can only be read if accessed
+ * through any other Uri.
*/
- protected interface BaseSyncColumns {
+ protected interface CalendarSyncColumns {
/** Generic column for use by sync adapters. */
public static final String CAL_SYNC1 = "cal_sync1";
@@ -103,29 +126,41 @@ public final class Calendar {
}
/**
- * Columns for Sync information used by Calendars and Events tables.
+ * Columns for Sync information used by Calendars and Events tables. These
+ * have specific uses which are expected to be consistent by the app and
+ * sync adapter.
+ *
+ * @hide
*/
- public interface SyncColumns extends BaseSyncColumns {
+ public interface SyncColumns extends CalendarSyncColumns {
/**
- * The account that was used to sync the entry to the device.
+ * The account that was used to sync the entry to the device. If the
+ * account_type is not {@link #ACCOUNT_TYPE_LOCAL} then the name and
+ * type must match an account on the device or the calendar will be
+ * deleted.
* <P>Type: TEXT</P>
*/
public static final String ACCOUNT_NAME = "account_name";
/**
- * The type of the account that was used to sync the entry to the device.
+ * The type of the account that was used to sync the entry to the
+ * device. A type of {@link #ACCOUNT_TYPE_LOCAL} will keep this event
+ * form being deleted if there are no matching accounts on the device.
* <P>Type: TEXT</P>
*/
public static final String ACCOUNT_TYPE = "account_type";
/**
- * The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
+ * The unique ID for a row assigned by the sync source. NULL if the row
+ * has never been synced. This is used as a reference id for exceptions
+ * along with {@link BaseColumns#_ID}.
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ID = "_sync_id";
/**
- * The last time, from the sync source's point of view, that this row has been synchronized.
+ * The last time, from the sync source's point of view, that this row
+ * has been synchronized.
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_TIME = "_sync_time";
@@ -151,9 +186,9 @@ public final class Calendar {
}
/**
- * Columns from the Calendars table that other tables join into themselves.
+ * Columns specific to the Calendars Uri that other Uris can query.
*/
- public interface CalendarsColumns {
+ private interface CalendarsColumns {
/**
* The color of the calendar
* <P>Type: INTEGER (color value)</P>
@@ -172,10 +207,17 @@ public final class Calendar {
public static final int FREEBUSY_ACCESS = 100;
/** Can read all event details */
public static final int READ_ACCESS = 200;
+ /** Can reply yes/no/maybe to an event */
public static final int RESPOND_ACCESS = 300;
+ /** not used */
public static final int OVERRIDE_ACCESS = 400;
- /** Full access to modify the calendar, but not the access control settings */
+ /** Full access to modify the calendar, but not the access control
+ * settings
+ */
public static final int CONTRIBUTOR_ACCESS = 500;
+ /** Full access to modify the calendar, but not the access control
+ * settings
+ */
public static final int EDITOR_ACCESS = 600;
/** Full access to the calendar */
public static final int OWNER_ACCESS = 700;
@@ -184,31 +226,35 @@ public final class Calendar {
/**
* Is the calendar selected to be displayed?
+ * 0 - do not show events associated with this calendar.
+ * 1 - show events associated with this calendar
* <P>Type: INTEGER (boolean)</P>
*/
public static final String VISIBLE = "visible";
/**
- * The timezone the calendar's events occurs in
+ * The time zone the calendar is associated with.
* <P>Type: TEXT</P>
*/
public static final String CALENDAR_TIMEZONE = "calendar_timezone";
/**
- * If this calendar is in the list of calendars that are selected for
- * syncing then "sync_events" is 1, otherwise 0.
+ * Is this calendar synced and are its events stored on the device?
+ * 0 - Do not sync this calendar or store events for this calendar.
+ * 1 - Sync down events for this calendar.
* <p>Type: INTEGER (boolean)</p>
*/
public static final String SYNC_EVENTS = "sync_events";
/**
- * Sync state data.
+ * Sync state data. Usable by the sync adapter.
* <p>Type: String (blob)</p>
*/
public static final String SYNC_STATE = "sync_state";
/**
- * Whether the row has been deleted. A deleted row should be ignored.
+ * Whether the row has been deleted but not synced to the server. A
+ * deleted row should be ignored.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String DELETED = "deleted";
@@ -216,35 +262,32 @@ public final class Calendar {
/**
* Class that represents a Calendar Entity. There is one entry per calendar.
+ * This is a helper class to make batch operations easier.
*/
public static class CalendarsEntity implements BaseColumns, SyncColumns, CalendarsColumns {
+ /**
+ * The default Uri used when creating a new calendar EntityIterator.
+ */
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
"/calendar_entities");
- public static EntityIterator newEntityIterator(Cursor cursor, ContentResolver resolver) {
- return new EntityIteratorImpl(cursor, resolver);
- }
-
- public static EntityIterator newEntityIterator(Cursor cursor,
- ContentProviderClient provider) {
- return new EntityIteratorImpl(cursor, provider);
+ /**
+ * Creates an entity iterator for the given cursor. It assumes the
+ * cursor contains a calendars query.
+ *
+ * @param cursor query on {@link #CONTENT_URI}
+ * @return an EntityIterator of calendars
+ */
+ public static EntityIterator newEntityIterator(Cursor cursor) {
+ return new EntityIteratorImpl(cursor);
}
private static class EntityIteratorImpl extends CursorEntityIterator {
- private final ContentResolver mResolver;
- private final ContentProviderClient mProvider;
- public EntityIteratorImpl(Cursor cursor, ContentResolver resolver) {
+ public EntityIteratorImpl(Cursor cursor) {
super(cursor);
- mResolver = resolver;
- mProvider = null;
- }
-
- public EntityIteratorImpl(Cursor cursor, ContentProviderClient provider) {
- super(cursor);
- mResolver = null;
- mProvider = provider;
}
@Override
@@ -305,27 +348,40 @@ public final class Calendar {
}
/**
- * Contains a list of available calendars.
+ * Fields and helpers for interacting with Calendars.
*/
- public static class Calendars implements BaseColumns, SyncColumns,
- CalendarsColumns
- {
+ public static class Calendars implements BaseColumns, SyncColumns, CalendarsColumns {
private static final String WHERE_DELETE_FOR_ACCOUNT = Calendars.ACCOUNT_NAME + "=?"
+ " AND "
+ Calendars.ACCOUNT_TYPE + "=?";
- public static final Cursor query(ContentResolver cr, String[] projection,
- String where, String orderBy)
- {
- return cr.query(CONTENT_URI, projection, where,
- null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+ /**
+ * Helper function for generating a calendars query. This is blocking
+ * and should not be used on the UI thread. See
+ * {@link ContentResolver#query(Uri, String[], String, String[], String)}
+ * for more details about using the parameters.
+ *
+ * @param cr The ContentResolver to query with
+ * @param projection A list of columns to return
+ * @param selection A formatted selection string
+ * @param selectionArgs arguments to the selection string
+ * @param orderBy How to order the returned rows
+ * @return
+ */
+ public static final Cursor query(ContentResolver cr, String[] projection, String selection,
+ String[] selectionArgs, String orderBy) {
+ return cr.query(CONTENT_URI, projection, selection, selectionArgs,
+ orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
/**
- * Convenience method perform a delete on the Calendar provider
+ * Convenience method perform a delete on the Calendar provider. This is
+ * a blocking call and should not be used on the UI thread.
*
* @param cr the ContentResolver
- * @param selection the rows to delete
+ * @param selection A filter to apply to rows before deleting, formatted
+ * as an SQL WHERE clause (excluding the WHERE itself).
+ * @param selectionArgs Fill in the '?'s in the selection
* @return the count of rows that were deleted
*/
public static int delete(ContentResolver cr, String selection, String[] selectionArgs)
@@ -335,10 +391,12 @@ public final class Calendar {
/**
* Convenience method to delete all calendars that match the account.
+ * This is a blocking call and should not be used on the UI thread.
*
* @param cr the ContentResolver
- * @param account the account whose rows should be deleted
- * @return the count of rows that were deleted
+ * @param account the account whose calendars and events should be
+ * deleted
+ * @return the count of calendar rows that were deleted
*/
public static int deleteCalendarsForAccount(ContentResolver cr, Account account) {
// delete all calendars that match this account
@@ -348,8 +406,9 @@ public final class Calendar {
}
/**
- * The content:// style URL for this table
+ * The content:// style URL for accessing Calendars
*/
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/calendars");
/**
@@ -358,43 +417,43 @@ public final class Calendar {
public static final String DEFAULT_SORT_ORDER = "displayName";
/**
- * The URL to the calendar
+ * The URL to the calendar. Column name.
* <P>Type: TEXT (URL)</P>
*/
public static final String URL = "url";
/**
- * The URL for the calendar itself
+ * The URL for the calendar itself. Column name.
* <P>Type: TEXT (URL)</P>
*/
public static final String SELF_URL = "selfUrl";
/**
- * The URL for the calendar to be edited
+ * The URL for the calendar to be edited. Column name.
* <P>Type: TEXT (URL)</P>
*/
public static final String EDIT_URL = "editUrl";
/**
- * The URL for the calendar events
+ * The URL for the calendar events. Column name.
* <P>Type: TEXT (URL)</P>
*/
public static final String EVENTS_URL = "eventsUrl";
/**
- * The name of the calendar
+ * The name of the calendar. Column name.
* <P>Type: TEXT</P>
*/
public static final String NAME = "name";
/**
- * The display name of the calendar
+ * The display name of the calendar. Column name.
* <P>Type: TEXT</P>
*/
public static final String DISPLAY_NAME = "displayName";
/**
- * The location the of the events in the calendar
+ * The default location for the calendar. Column name.
* <P>Type: TEXT</P>
*/
public static final String CALENDAR_LOCATION = "calendar_location";
@@ -402,41 +461,45 @@ public final class Calendar {
/**
* The owner account for this calendar, based on the calendar feed.
* This will be different from the _SYNC_ACCOUNT for delegated calendars.
+ * Column name.
* <P>Type: String</P>
*/
public static final String OWNER_ACCOUNT = "ownerAccount";
/**
* Can the organizer respond to the event? If no, the status of the
- * organizer should not be shown by the UI. Defaults to 1
+ * organizer should not be shown by the UI. Defaults to 1. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String CAN_ORGANIZER_RESPOND = "canOrganizerRespond";
/**
- * Can the organizer modify the time zone of the event?
+ * Can the organizer modify the time zone of the event? Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone";
/**
- * The maximum number of reminders allowed for an event.
+ * The maximum number of reminders allowed for an event. Column name.
* <P>Type: INTEGER</P>
*/
public static final String MAX_REMINDERS = "maxReminders";
/**
- * The maximum number of reminders allowed for an event.
- * <P>
- * Type: INTEGER
- * </P>
+ * A comma separated list of reminder methods supported for this
+ * calendar in the format "#,#,#". Valid types are
+ * {@link Reminders#METHOD_DEFAULT}, {@link Reminders#METHOD_ALERT},
+ * {@link Reminders#METHOD_EMAIL}, {@link Reminders#METHOD_SMS}. Column
+ * name.
+ * <P>Type: TEXT</P>
*/
public static final String ALLOWED_REMINDERS = "allowedReminders";
/**
* These fields are only writable by a sync adapter. To modify them the
- * caller must include CALLER_IS_SYNCADAPTER, _SYNC_ACCOUNT, and
- * _SYNC_ACCOUNT_TYPE in the query parameters.
+ * caller must include {@link #CALLER_IS_SYNCADAPTER},
+ * {@link #ACCOUNT_NAME}, and {@link #ACCOUNT_TYPE} in the query
+ * parameters.
*/
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
@@ -457,7 +520,8 @@ public final class Calendar {
CAL_SYNC2,
CAL_SYNC3,
CAL_SYNC4,
- CAL_SYNC5, CAL_SYNC6,
+ CAL_SYNC5,
+ CAL_SYNC6,
SYNC_STATE,
};
}
@@ -465,29 +529,29 @@ public final class Calendar {
/**
* Columns from the Attendees table that other tables join into themselves.
*/
- public interface AttendeesColumns {
+ private interface AttendeesColumns {
/**
- * The id of the event.
+ * The id of the event. Column name.
* <P>Type: INTEGER</P>
*/
public static final String EVENT_ID = "event_id";
/**
- * The name of the attendee.
+ * The name of the attendee. Column name.
* <P>Type: STRING</P>
*/
public static final String ATTENDEE_NAME = "attendeeName";
/**
- * The email address of the attendee.
+ * The email address of the attendee. Column name.
* <P>Type: STRING</P>
*/
public static final String ATTENDEE_EMAIL = "attendeeEmail";
/**
- * The relationship of the attendee to the user.
- * <P>Type: INTEGER (one of {@link #RELATIONSHIP_ATTENDEE}, ...}.
+ * The relationship of the attendee to the user. Column name.
+ * <P>Type: INTEGER (one of {@link #RELATIONSHIP_ATTENDEE}, ...}.</P>
*/
public static final String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
@@ -498,8 +562,8 @@ public final class Calendar {
public static final int RELATIONSHIP_SPEAKER = 4;
/**
- * The type of attendee.
- * <P>Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL})
+ * The type of attendee. Column name.
+ * <P>Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL})</P>
*/
public static final String ATTENDEE_TYPE = "attendeeType";
@@ -508,8 +572,8 @@ public final class Calendar {
public static final int TYPE_OPTIONAL = 2;
/**
- * The attendance status of the attendee.
- * <P>Type: Integer (one of {@link #ATTENDEE_STATUS_ACCEPTED}, ...}.
+ * The attendance status of the attendee. Column name.
+ * <P>Type: Integer (one of {@link #ATTENDEE_STATUS_ACCEPTED}, ...).</P>
*/
public static final String ATTENDEE_STATUS = "attendeeStatus";
@@ -520,59 +584,84 @@ public final class Calendar {
public static final int ATTENDEE_STATUS_TENTATIVE = 4;
}
+ /**
+ * Fields and helpers for interacting with Attendees.
+ */
public static final class Attendees implements BaseColumns, AttendeesColumns, EventsColumns {
+
+ /**
+ * The content:// style URL for accessing Attendees data
+ */
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/attendees");
+ /**
+ * the projection used by the attendees query
+ */
+ public static final String[] PROJECTION = new String[] {
+ _ID, ATTENDEE_NAME, ATTENDEE_EMAIL, ATTENDEE_RELATIONSHIP, ATTENDEE_STATUS,};
+ private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
- // TODO: fill out this class when we actually start utilizing attendees
- // in the calendar application.
+ /**
+ * Queries all attendees associated with the given event. This is a
+ * blocking call and should not be done on the UI thread.
+ *
+ * @param cr The content resolver to use for the query
+ * @param eventId The id of the event to retrieve attendees for
+ * @return A Cursor containing all attendees for the event
+ */
+ public static final Cursor query(ContentResolver cr, long eventId) {
+ String[] attArgs = {Long.toString(eventId)};
+ return cr.query(CONTENT_URI, PROJECTION, ATTENDEES_WHERE, attArgs /* selection args */,
+ null /* sort order */);
+ }
}
/**
* Columns from the Events table that other tables join into themselves.
*/
- public interface EventsColumns {
+ private interface EventsColumns {
/**
- * For use by sync adapter at its discretion; not modified by CalendarProvider
- * Note that this column was formerly named _SYNC_LOCAL_ID. We are using it to avoid a
- * schema change.
- * TODO Replace this with something more general in the future.
+ * For use by sync adapter at its discretion. Column name.
+ * TODO change to sync_data2
* <P>Type: INTEGER (long)</P>
*/
public static final String _SYNC_DATA = "_sync_local_id";
/**
- * The calendar the event belongs to
- * <P>Type: INTEGER (foreign key to the Calendars table)</P>
+ * The {@link Calendars#_ID} of the calendar the event belongs to.
+ * Column name.
+ * <P>Type: INTEGER</P>
*/
public static final String CALENDAR_ID = "calendar_id";
/**
- * The URI for an HTML version of this event.
+ * The URI for an HTML version of this event. Column name.
+ * TODO change to sync_data3
* <P>Type: TEXT</P>
*/
public static final String HTML_URI = "htmlUri";
/**
- * The title of the event
+ * The title of the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
- * The description of the event
+ * The description of the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String DESCRIPTION = "description";
/**
- * Where the event takes place.
+ * Where the event takes place. Column name.
* <P>Type: TEXT</P>
*/
public static final String EVENT_LOCATION = "eventLocation";
/**
- * The event status
- * <P>Type: INTEGER (int)</P>
+ * The event status. Column name.
+ * <P>Type: INTEGER (one of {@link #STATUS_TENTATIVE}...)</P>
*/
public static final String STATUS = "eventStatus";
@@ -584,64 +673,65 @@ public final class Calendar {
* This is a copy of the attendee status for the owner of this event.
* This field is copied here so that we can efficiently filter out
* events that are declined without having to look in the Attendees
- * table.
+ * table. Column name.
*
* <P>Type: INTEGER (int)</P>
*/
public static final String SELF_ATTENDEE_STATUS = "selfAttendeeStatus";
/**
- * This column is available for use by sync adapters
+ * This column is available for use by sync adapters. Column name.
* <P>Type: TEXT</P>
*/
public static final String SYNC_DATA1 = "sync_data1";
/**
- * The comments feed uri.
+ * The comments feed uri. Column name.
+ * TODO change to sync_data6
* <P>Type: TEXT</P>
*/
public static final String COMMENTS_URI = "commentsUri";
/**
- * The time the event starts
+ * The time the event starts in UTC millis since epoch. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String DTSTART = "dtstart";
/**
- * The time the event ends
+ * The time the event ends in UTC millis since epoch. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String DTEND = "dtend";
/**
- * The duration of the event
+ * The duration of the event in RFC2445 format. Column name.
* <P>Type: TEXT (duration in RFC2445 format)</P>
*/
public static final String DURATION = "duration";
/**
- * The timezone for the event.
- * <P>Type: TEXT
+ * The timezone for the event. Column name.
+ * <P>Type: TEXT</P>
*/
public static final String EVENT_TIMEZONE = "eventTimezone";
/**
- * The timezone for the event, allDay events will have a local tz instead of UTC
- * <P>Type: TEXT
+ * The timezone for the end time of the event. Column name.
+ * <P>Type: TEXT</P>
*/
public static final String EVENT_END_TIMEZONE = "eventEndTimezone";
/**
- * Whether the event lasts all day or not
+ * Is the event all day (time zone independent). Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String ALL_DAY = "allDay";
/**
* Defines how the event shows up for others when the calendar is
- * shared.
- * <P>Type: INTEGER</P>
+ * shared. Column name.
+ * <P>Type: INTEGER (One of {@link #ACCESS_DEFAULT}, ...)</P>
*/
public static final String ACCESS_LEVEL = "accessLevel";
@@ -655,20 +745,20 @@ public final class Calendar {
*/
public static final int ACCESS_CONFIDENTIAL = 1;
/**
- * Private assumes the event appears as a free/busy slot with no
- * details.
+ * Private shares the event as a free/busy slot with no details.
*/
public static final int ACCESS_PRIVATE = 2;
/**
- * Public assumes the contents are visible to anyone with access to the
+ * Public makes the contents visible to anyone with access to the
* calendar.
*/
public static final int ACCESS_PUBLIC = 3;
/**
* If this event counts as busy time or is still free time that can be
- * scheduled over.
- * <P>Type: INTEGER</P>
+ * scheduled over. Column name.
+ * <P>Type: INTEGER (One of {@link #AVAILABILITY_BUSY},
+ * {@link #AVAILABILITY_FREE})</P>
*/
public static final String AVAILABILITY = "availability";
@@ -684,45 +774,44 @@ public final class Calendar {
public static final int AVAILABILITY_FREE = 1;
/**
- * Whether the event has an alarm or not
+ * Whether the event has an alarm or not. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HAS_ALARM = "hasAlarm";
/**
- * Whether the event has extended properties or not
+ * Whether the event has extended properties or not. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HAS_EXTENDED_PROPERTIES = "hasExtendedProperties";
/**
- * The recurrence rule for the event.
- * than one.
+ * The recurrence rule for the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String RRULE = "rrule";
/**
- * The recurrence dates for the event.
+ * The recurrence dates for the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String RDATE = "rdate";
/**
- * The recurrence exception rule for the event.
+ * The recurrence exception rule for the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String EXRULE = "exrule";
/**
- * The recurrence exception dates for the event.
+ * The recurrence exception dates for the event. Column name.
* <P>Type: TEXT</P>
*/
public static final String EXDATE = "exdate";
/**
- * The _id of the original recurring event for which this event is an
- * exception.
+ * The {@link Events#_ID} of the original recurring event for which this
+ * event is an exception. Column name.
* <P>Type: TEXT</P>
*/
public static final String ORIGINAL_ID = "original_id";
@@ -730,27 +819,28 @@ public final class Calendar {
/**
* The _sync_id of the original recurring event for which this event is
* an exception. The provider should keep the original_id in sync when
- * this is updated.
+ * this is updated. Column name.
* <P>Type: TEXT</P>
*/
public static final String ORIGINAL_SYNC_ID = "original_sync_id";
/**
* The original instance time of the recurring event for which this
- * event is an exception.
+ * event is an exception. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String ORIGINAL_INSTANCE_TIME = "originalInstanceTime";
/**
* The allDay status (true or false) of the original recurring event
- * for which this event is an exception.
+ * for which this event is an exception. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String ORIGINAL_ALL_DAY = "originalAllDay";
/**
- * The last date this event repeats on, or NULL if it never ends
+ * The last date this event repeats on, or NULL if it never ends. Column
+ * name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String LAST_DATE = "lastDate";
@@ -758,61 +848,66 @@ public final class Calendar {
/**
* Whether the event has attendee information. True if the event
* has full attendee data, false if the event has information about
- * self only.
+ * self only. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HAS_ATTENDEE_DATA = "hasAttendeeData";
/**
- * Whether guests can modify the event.
+ * Whether guests can modify the event. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String GUESTS_CAN_MODIFY = "guestsCanModify";
/**
- * Whether guests can invite other guests.
+ * Whether guests can invite other guests. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
/**
- * Whether guests can see the list of attendees.
+ * Whether guests can see the list of attendees. Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
/**
- * Email of the organizer (owner) of the event.
+ * Email of the organizer (owner) of the event. Column name.
* <P>Type: STRING</P>
*/
public static final String ORGANIZER = "organizer";
/**
- * Whether the user can invite others to the event.
- * The GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary guest,
- * while CAN_INVITE_OTHERS indicates if the user can invite others (either through
- * GUESTS_CAN_INVITE_OTHERS or because the user has modify access to the event).
+ * Whether the user can invite others to the event. The
+ * GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary
+ * guest, while CAN_INVITE_OTHERS indicates if the user can invite
+ * others (either through GUESTS_CAN_INVITE_OTHERS or because the user
+ * has modify access to the event). Column name.
* <P>Type: INTEGER (boolean, readonly)</P>
*/
public static final String CAN_INVITE_OTHERS = "canInviteOthers";
/**
* The owner account for this calendar, based on the calendar (foreign
- * key into the calendars table).
+ * key into the calendars table). Column name.
* <P>Type: String</P>
*/
public static final String OWNER_ACCOUNT = "ownerAccount";
/**
- * Whether the row has been deleted. A deleted row should be ignored.
+ * Whether the row has been deleted. A deleted row should be ignored.
+ * Column name.
* <P>Type: INTEGER (boolean)</P>
*/
public static final String DELETED = "deleted";
}
/**
- * Contains one entry per calendar event. Recurring events show up as a
- * single entry.
+ * Class that represents an Event Entity. There is one entry per event.
+ * Recurring events show up as a single entry. This is a helper class to
+ * make batch operations easier. A {@link ContentResolver} or
+ * {@link ContentProviderClient} is required as the helper does additional
+ * queries to add reminders and attendees to each entry.
*/
public static final class EventsEntity implements BaseColumns, SyncColumns, EventsColumns {
/**
@@ -821,10 +916,26 @@ public final class Calendar {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
"/event_entities");
+ /**
+ * Creates a new iterator for events
+ *
+ * @param cursor An event query
+ * @param resolver For performing additional queries
+ * @return an EntityIterator containing one entity per event in the
+ * cursor
+ */
public static EntityIterator newEntityIterator(Cursor cursor, ContentResolver resolver) {
return new EntityIteratorImpl(cursor, resolver);
}
+ /**
+ * Creates a new iterator for events
+ *
+ * @param cursor An event query
+ * @param provider For performing additional queries
+ * @return an EntityIterator containing one entity per event in the
+ * cursor
+ */
public static EntityIterator newEntityIterator(Cursor cursor,
ContentProviderClient provider) {
return new EntityIteratorImpl(cursor, provider);
@@ -921,7 +1032,7 @@ public final class Calendar {
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_DATA);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, _SYNC_VERSION);
- DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, EventsColumns.DELETED);
+ DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC1);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC2);
DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, CAL_SYNC3);
@@ -1018,53 +1129,54 @@ public final class Calendar {
}
/**
- * Contains one entry per calendar event. Recurring events show up as a single entry.
+ * Fields and helpers for interacting with Events.
*/
public static final class Events implements BaseColumns, SyncColumns, EventsColumns {
- private static final String[] FETCH_ENTRY_COLUMNS =
- new String[] { Events.ACCOUNT_NAME, Events._SYNC_ID };
-
- private static final String[] ATTENDEES_COLUMNS =
- new String[] { AttendeesColumns.ATTENDEE_NAME,
- AttendeesColumns.ATTENDEE_EMAIL,
- AttendeesColumns.ATTENDEE_RELATIONSHIP,
- AttendeesColumns.ATTENDEE_TYPE,
- AttendeesColumns.ATTENDEE_STATUS };
-
+ /**
+ * Queries all events with the given projection. This is a blocking call
+ * and should not be done on the UI thread.
+ *
+ * @param cr The content resolver to use for the query
+ * @param projection The columns to return
+ * @return A Cursor containing all events in the db
+ */
public static final Cursor query(ContentResolver cr, String[] projection) {
return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
}
- public static final Cursor query(ContentResolver cr, String[] projection,
- String where, String orderBy) {
- return cr.query(CONTENT_URI, projection, where,
- null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
- private static String extractValue(ICalendar.Component component,
- String propertyName) {
- ICalendar.Property property =
- component.getFirstProperty(propertyName);
- if (property != null) {
- return property.getValue();
- }
- return null;
+ /**
+ * Queries events using the given projection, selection filter, and
+ * ordering. This is a blocking call and should not be done on the UI
+ * thread. For selection and selectionArgs usage see
+ * {@link ContentResolver#query(Uri, String[], String, String[], String)}
+ *
+ * @param cr The content resolver to use for the query
+ * @param projection The columns to return
+ * @param selection Filter on the query as an SQL WHERE statement
+ * @param selectionArgs Args to replace any '?'s in the selection
+ * @param orderBy How to order the rows as an SQL ORDER BY statement
+ * @return A Cursor containing the matching events
+ */
+ public static final Cursor query(ContentResolver cr, String[] projection, String selection,
+ String[] selectionArgs, String orderBy) {
+ return cr.query(CONTENT_URI, projection, selection, null,
+ orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
/**
- * The content:// style URL for this table
+ * The content:// style URL for interacting with events. Appending an
+ * event id using {@link ContentUris#withAppendedId(Uri, long)} will
+ * specify a single event.
*/
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/events");
- public static final Uri DELETED_CONTENT_URI =
- Uri.parse("content://" + AUTHORITY + "/deleted_events");
-
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "";
+ private static final String DEFAULT_SORT_ORDER = "";
/**
* These are columns that should only ever be updated by the provider,
@@ -1073,7 +1185,13 @@ public final class Calendar {
*/
public static String[] PROVIDER_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
- ACCOUNT_TYPE
+ ACCOUNT_TYPE,
+ CAL_SYNC1,
+ CAL_SYNC2,
+ CAL_SYNC3,
+ CAL_SYNC4,
+ CAL_SYNC5,
+ CAL_SYNC6
};
/**
@@ -1091,13 +1209,29 @@ public final class Calendar {
}
/**
- * Contains one entry per calendar event instance. Recurring events show up every time
- * they occur.
+ * Fields and helpers for interacting with Instances. An instance is a
+ * single occurrence of an event including time zone specific start and end
+ * days and minutes.
*/
public static final class Instances implements BaseColumns, EventsColumns, CalendarsColumns {
private static final String WHERE_CALENDARS_SELECTED = Calendars.VISIBLE + "=1";
+ /**
+ * Performs a query to return all visible instances in the given range.
+ * This is a blocking function and should not be done on the UI thread.
+ * This will cause an expansion of recurring events to fill this time
+ * range if they are not already expanded and will slow down for larger
+ * time ranges with many recurring events.
+ *
+ * @param cr The ContentResolver to use for the query
+ * @param projection The columns to return
+ * @param begin The start of the time range to query in UTC millis since
+ * epoch
+ * @param end The end of the time range to query in UTC millis since
+ * epoch
+ * @return A Cursor containing all instances in the given range
+ */
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end) {
Uri.Builder builder = CONTENT_URI.buildUpon();
@@ -1107,111 +1241,184 @@ public final class Calendar {
null, DEFAULT_SORT_ORDER);
}
+ /**
+ * Performs a query to return all visible instances in the given range
+ * that match the given query. This is a blocking function and should
+ * not be done on the UI thread. This will cause an expansion of
+ * recurring events to fill this time range if they are not already
+ * expanded and will slow down for larger time ranges with many
+ * recurring events.
+ *
+ * @param cr The ContentResolver to use for the query
+ * @param projection The columns to return
+ * @param begin The start of the time range to query in UTC millis since
+ * epoch
+ * @param end The end of the time range to query in UTC millis since
+ * epoch
+ * @param searchQuery A string of space separated search terms. Segments
+ * enclosed by double quotes will be treated as a single
+ * term.
+ * @return A Cursor of instances matching the search terms in the given
+ * time range
+ */
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end, String searchQuery) {
Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
- return cr.query(builder.build(), projection, WHERE_CALENDARS_SELECTED,
- new String[] { searchQuery }, DEFAULT_SORT_ORDER);
+ builder = builder.appendPath(searchQuery);
+ return cr.query(builder.build(), projection, WHERE_CALENDARS_SELECTED, null,
+ DEFAULT_SORT_ORDER);
}
- public static final Cursor query(ContentResolver cr, String[] projection,
- long begin, long end, String where, String orderBy) {
+ /**
+ * Performs a query to return all visible instances in the given range
+ * that match the given selection. This is a blocking function and
+ * should not be done on the UI thread. This will cause an expansion of
+ * recurring events to fill this time range if they are not already
+ * expanded and will slow down for larger time ranges with many
+ * recurring events.
+ *
+ * @param cr The ContentResolver to use for the query
+ * @param projection The columns to return
+ * @param begin The start of the time range to query in UTC millis since
+ * epoch
+ * @param end The end of the time range to query in UTC millis since
+ * epoch
+ * @param selection Filter on the query as an SQL WHERE statement
+ * @param selectionArgs Args to replace any '?'s in the selection
+ * @param orderBy How to order the rows as an SQL ORDER BY statement
+ * @return A Cursor of instances matching the selection
+ */
+ public static final Cursor query(ContentResolver cr, String[] projection, long begin,
+ long end, String selection, String[] selectionArgs, String orderBy) {
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
- if (TextUtils.isEmpty(where)) {
- where = WHERE_CALENDARS_SELECTED;
+ if (TextUtils.isEmpty(selection)) {
+ selection = WHERE_CALENDARS_SELECTED;
} else {
- where = "(" + where + ") AND " + WHERE_CALENDARS_SELECTED;
+ selection = "(" + selection + ") AND " + WHERE_CALENDARS_SELECTED;
}
- return cr.query(builder.build(), projection, where,
- null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+ return cr.query(builder.build(), projection, selection, selectionArgs,
+ orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
+ /**
+ * Performs a query to return all visible instances in the given range
+ * that match the given selection. This is a blocking function and
+ * should not be done on the UI thread. This will cause an expansion of
+ * recurring events to fill this time range if they are not already
+ * expanded and will slow down for larger time ranges with many
+ * recurring events.
+ *
+ * @param cr The ContentResolver to use for the query
+ * @param projection The columns to return
+ * @param begin The start of the time range to query in UTC millis since
+ * epoch
+ * @param end The end of the time range to query in UTC millis since
+ * epoch
+ * @param searchQuery A string of space separated search terms. Segments
+ * enclosed by double quotes will be treated as a single
+ * term.
+ * @param selection Filter on the query as an SQL WHERE statement
+ * @param selectionArgs Args to replace any '?'s in the selection
+ * @param orderBy How to order the rows as an SQL ORDER BY statement
+ * @return A Cursor of instances matching the selection
+ */
public static final Cursor query(ContentResolver cr, String[] projection, long begin,
- long end, String searchQuery, String where, String orderBy) {
+ long end, String searchQuery, String selection, String[] selectionArgs,
+ String orderBy) {
Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
builder = builder.appendPath(searchQuery);
- if (TextUtils.isEmpty(where)) {
- where = WHERE_CALENDARS_SELECTED;
+ if (TextUtils.isEmpty(selection)) {
+ selection = WHERE_CALENDARS_SELECTED;
} else {
- where = "(" + where + ") AND " + WHERE_CALENDARS_SELECTED;
+ selection = "(" + selection + ") AND " + WHERE_CALENDARS_SELECTED;
}
- return cr.query(builder.build(), projection, where, null,
+ return cr.query(builder.build(), projection, selection, selectionArgs,
orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
/**
- * The content:// style URL for this table
+ * The content:// style URL for querying an instance range. The begin
+ * and end of the range to query should be added as path segments if
+ * this is used directly.
*/
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
"/instances/when");
+ /**
+ * The content:// style URL for querying an instance range by Julian
+ * Day. The start and end day should be added as path segments if this
+ * is used directly.
+ */
public static final Uri CONTENT_BY_DAY_URI =
Uri.parse("content://" + AUTHORITY + "/instances/whenbyday");
+ /**
+ * The content:// style URL for querying an instance range with a search
+ * term. The begin, end, and search string should be appended as path
+ * segments if this is used directly.
+ */
public static final Uri CONTENT_SEARCH_URI = Uri.parse("content://" + AUTHORITY +
"/instances/search");
+ /**
+ * The content:// style URL for querying an instance range with a search
+ * term. The start day, end day, and search string should be appended as
+ * path segments if this is used directly.
+ */
public static final Uri CONTENT_SEARCH_BY_DAY_URI =
Uri.parse("content://" + AUTHORITY + "/instances/searchbyday");
/**
* The default sort order for this table.
*/
- public static final String DEFAULT_SORT_ORDER = "begin ASC";
+ private static final String DEFAULT_SORT_ORDER = "begin ASC";
/**
- * The sort order is: events with an earlier start time occur
- * first and if the start times are the same, then events with
- * a later end time occur first. The later end time is ordered
- * first so that long-running events in the calendar views appear
- * first. If the start and end times of two events are
- * the same then we sort alphabetically on the title. This isn't
- * required for correctness, it just adds a nice touch.
- */
- public static final String SORT_CALENDAR_VIEW = "begin ASC, end DESC, title ASC";
- /**
- * The beginning time of the instance, in UTC milliseconds
+ * The beginning time of the instance, in UTC milliseconds. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String BEGIN = "begin";
/**
- * The ending time of the instance, in UTC milliseconds
+ * The ending time of the instance, in UTC milliseconds. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String END = "end";
/**
- * The event for this instance
+ * The _id of the event for this instance. Column name.
* <P>Type: INTEGER (long, foreign key to the Events table)</P>
*/
public static final String EVENT_ID = "event_id";
/**
- * The Julian start day of the instance, relative to the local timezone
+ * The Julian start day of the instance, relative to the local time
+ * zone. Column name.
* <P>Type: INTEGER (int)</P>
*/
public static final String START_DAY = "startDay";
/**
- * The Julian end day of the instance, relative to the local timezone
+ * The Julian end day of the instance, relative to the local time
+ * zone. Column name.
* <P>Type: INTEGER (int)</P>
*/
public static final String END_DAY = "endDay";
/**
* The start minute of the instance measured from midnight in the
- * local timezone.
+ * local time zone. Column name.
* <P>Type: INTEGER (int)</P>
*/
public static final String START_MINUTE = "startMinute";
/**
* The end minute of the instance measured from midnight in the
- * local timezone.
+ * local time zone. Column name.
* <P>Type: INTEGER (int)</P>
*/
public static final String END_MINUTE = "endMinute";
@@ -1219,14 +1426,12 @@ public final class Calendar {
/**
* CalendarCache stores some settings for calendar including the current
- * time zone for the app. These settings are stored using a key/value
+ * time zone for the instaces. These settings are stored using a key/value
* scheme.
*/
- public interface CalendarCacheColumns {
+ private interface CalendarCacheColumns {
/**
- * The key for the setting. Keys are defined in CalendarChache in the
- * Calendar provider.
- * TODO Add keys to this file
+ * The key for the setting. Keys are defined in {@link CalendarCache}.
*/
public static final String KEY = "key";
@@ -1296,7 +1501,7 @@ public final class Calendar {
* the Instances table and these are all stored in the first (and only)
* row of the CalendarMetaData table.
*/
- public interface CalendarMetaDataColumns {
+ private interface CalendarMetaDataColumns {
/**
* The local timezone that was used for precomputing the fields
* in the Instances table.
@@ -1330,34 +1535,51 @@ public final class Calendar {
public static final String MAX_EVENTDAYS = "maxEventDays";
}
+ /**
+ * @hide
+ */
public static final class CalendarMetaData implements CalendarMetaDataColumns, BaseColumns {
}
- public interface EventDaysColumns {
+ private interface EventDaysColumns {
/**
- * The Julian starting day number.
+ * The Julian starting day number. Column name.
* <P>Type: INTEGER (int)</P>
*/
public static final String STARTDAY = "startDay";
+ /**
+ * The Julian ending day number. Column name.
+ * <P>Type: INTEGER (int)</P>
+ */
public static final String ENDDAY = "endDay";
}
+ /**
+ * Fields and helpers for querying for a list of days that contain events.
+ */
public static final class EventDays implements EventDaysColumns {
- public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
- "/instances/groupbyday");
+ private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ + "/instances/groupbyday");
+ /**
+ * The projection used by the EventDays query.
+ */
public static final String[] PROJECTION = { STARTDAY, ENDDAY };
- public static final String SELECTION = "selected=1";
+ private static final String SELECTION = "selected=1";
/**
- * Retrieves the days with events for the Julian days starting at "startDay"
- * for "numDays".
+ * Retrieves the days with events for the Julian days starting at
+ * "startDay" for "numDays". It returns a cursor containing startday and
+ * endday representing the max range of days for all events beginning on
+ * each startday.This is a blocking function and should not be done on
+ * the UI thread.
*
* @param cr the ContentResolver
* @param startDay the first Julian day in the range
* @param numDays the number of days to load (must be at least 1)
- * @return a database cursor
+ * @return a database cursor containing a list of start and end days for
+ * events
*/
public static final Cursor query(ContentResolver cr, int startDay, int numDays) {
if (numDays < 1) {
@@ -1372,9 +1594,9 @@ public final class Calendar {
}
}
- public interface RemindersColumns {
+ private interface RemindersColumns {
/**
- * The event the reminder belongs to
+ * The event the reminder belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
*/
public static final String EVENT_ID = "event_id";
@@ -1382,17 +1604,24 @@ public final class Calendar {
/**
* The minutes prior to the event that the alarm should ring. -1
* specifies that we should use the default value for the system.
+ * Column name.
* <P>Type: INTEGER</P>
*/
public static final String MINUTES = "minutes";
+ /**
+ * Passing this as a minutes value will use the default reminder
+ * minutes.
+ */
public static final int MINUTES_DEFAULT = -1;
/**
- * The alarm method, as set on the server. DEFAULT, ALERT, EMAIL, and
- * SMS are possible values; the device will only process DEFAULT and
- * ALERT reminders (the other types are simply stored so we can send the
- * same reminder info back to the server when we make changes).
+ * The alarm method, as set on the server. {@link #METHOD_DEFAULT},
+ * {@link #METHOD_ALERT}, {@link #METHOD_EMAIL}, and {@link #METHOD_SMS}
+ * are possible values; the device will only process
+ * {@link #METHOD_DEFAULT} and {@link #METHOD_ALERT} reminders (the
+ * other types are simply stored so we can send the same reminder info
+ * back to the server when we make changes).
*/
public static final String METHOD = "method";
@@ -1402,61 +1631,85 @@ public final class Calendar {
public static final int METHOD_SMS = 3;
}
+ /**
+ * Fields and helpers for accessing reminders for an event.
+ */
public static final class Reminders implements BaseColumns, RemindersColumns, EventsColumns {
- public static final String TABLE_NAME = "Reminders";
+ private static final String REMINDERS_WHERE = Calendar.Reminders.EVENT_ID + "=?";
+ /**
+ * The projection used by the reminders query.
+ */
+ public static final String[] PROJECTION = new String[] {
+ _ID, MINUTES, METHOD,};
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/reminders");
+
+ /**
+ * Queries all reminders associated with the given event. This is a
+ * blocking call and should not be done on the UI thread.
+ *
+ * @param cr The content resolver to use for the query
+ * @param eventId The id of the event to retrieve reminders for
+ * @return A Cursor containing all reminders for the event
+ */
+ public static final Cursor query(ContentResolver cr, long eventId) {
+ String[] remArgs = {Long.toString(eventId)};
+ return cr.query(CONTENT_URI, PROJECTION, REMINDERS_WHERE, remArgs /* selection args */,
+ null /* sort order */);
+ }
}
- public interface CalendarAlertsColumns {
+ private interface CalendarAlertsColumns {
/**
- * The event that the alert belongs to
+ * The event that the alert belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
*/
public static final String EVENT_ID = "event_id";
/**
- * The start time of the event, in UTC
+ * The start time of the event, in UTC. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String BEGIN = "begin";
/**
- * The end time of the event, in UTC
+ * The end time of the event, in UTC. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String END = "end";
/**
- * The alarm time of the event, in UTC
+ * The alarm time of the event, in UTC. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String ALARM_TIME = "alarmTime";
/**
* The creation time of this database entry, in UTC.
- * (Useful for debugging missed reminders.)
+ * Useful for debugging missed reminders. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String CREATION_TIME = "creationTime";
/**
* The time that the alarm broadcast was received by the Calendar app,
- * in UTC. (Useful for debugging missed reminders.)
+ * in UTC. Useful for debugging missed reminders. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String RECEIVED_TIME = "receivedTime";
/**
* The time that the notification was created by the Calendar app,
- * in UTC. (Useful for debugging missed reminders.)
+ * in UTC. Useful for debugging missed reminders. Column name.
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String NOTIFY_TIME = "notifyTime";
/**
- * The state of this alert. It starts out as SCHEDULED, then when
- * the alarm goes off, it changes to FIRED, and then when the user
- * dismisses the alarm it changes to DISMISSED.
+ * The state of this alert. It starts out as {@link SCHEDULED}, then
+ * when the alarm goes off, it changes to {@link FIRED}, and then when
+ * the user dismisses the alarm it changes to {@link DISMISSED}. Column
+ * name.
* <P>Type: INTEGER</P>
*/
public static final String STATE = "state";
@@ -1466,21 +1719,33 @@ public final class Calendar {
public static final int DISMISSED = 2;
/**
- * The number of minutes that this alarm precedes the start time
- * <P>Type: INTEGER </P>
+ * The number of minutes that this alarm precedes the start time. Column
+ * name.
+ * <P>Type: INTEGER</P>
*/
public static final String MINUTES = "minutes";
/**
- * The default sort order for this table
+ * The default sort order for this alerts queries
*/
public static final String DEFAULT_SORT_ORDER = "begin ASC,title ASC";
}
+ /**
+ * Fields and helpers for accessing calendar alerts information. These
+ * fields are for tracking which alerts have been fired.
+ */
public static final class CalendarAlerts implements BaseColumns,
CalendarAlertsColumns, EventsColumns, CalendarsColumns {
+ /**
+ * @hide
+ */
public static final String TABLE_NAME = "CalendarAlerts";
+ /**
+ * The Uri for querying calendar alert information
+ */
+ @SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +
"/calendar_alerts");
@@ -1507,6 +1772,11 @@ public final class Calendar {
private static final boolean DEBUG = true;
+ /**
+ * Helper for inserting an alarm time associated with an event
+ *
+ * @hide
+ */
public static final Uri insert(ContentResolver cr, long eventId,
long begin, long end, long alarmTime, int minutes) {
ContentValues values = new ContentValues();
@@ -1523,6 +1793,19 @@ public final class Calendar {
return cr.insert(CONTENT_URI, values);
}
+ /**
+ * Queries alerts info using the given projection, selection filter, and
+ * ordering. This is a blocking call and should not be done on the UI
+ * thread. For selection and selectionArgs usage see
+ * {@link ContentResolver#query(Uri, String[], String, String[], String)}
+ *
+ * @param cr The content resolver to use for the query
+ * @param projection The columns to return
+ * @param selection Filter on the query as an SQL WHERE statement
+ * @param selectionArgs Args to replace any '?'s in the selection
+ * @param sortOrder How to order the rows as an SQL ORDER BY statement
+ * @return A Cursor containing the matching alerts
+ */
public static final Cursor query(ContentResolver cr, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
return cr.query(CONTENT_URI, projection, selection, selectionArgs,
@@ -1531,12 +1814,13 @@ public final class Calendar {
/**
* Finds the next alarm after (or equal to) the given time and returns
- * the time of that alarm or -1 if no such alarm exists.
+ * the time of that alarm or -1 if no such alarm exists. This is a
+ * blocking call and should not be done on the UI thread.
*
* @param cr the ContentResolver
* @param millis the time in UTC milliseconds
* @return the next alarm time greater than or equal to "millis", or -1
- * if no such alarm exists.
+ * if no such alarm exists.
*/
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
String selection = ALARM_TIME + ">=" + millis;
@@ -1619,6 +1903,17 @@ public final class Calendar {
}
}
+ /**
+ * Schedules an alarm intent with the system AlarmManager that will
+ * cause the Calendar provider to recheck alarms. This is used to wake
+ * the Calendar alarm handler when an alarm is expected or to do a
+ * periodic refresh of alarm data.
+ *
+ * @param context A context for referencing system resources
+ * @param manager The AlarmManager to use or null
+ * @param alarmTime The time to fire the intent in UTC millis since
+ * epoch
+ */
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
if (DEBUG) {
Time time = new Time();
@@ -1678,27 +1973,32 @@ public final class Calendar {
}
}
- public interface ExtendedPropertiesColumns {
+ private interface ExtendedPropertiesColumns {
/**
- * The event the extended property belongs to
+ * The event the extended property belongs to. Column name.
* <P>Type: INTEGER (foreign key to the Events table)</P>
*/
public static final String EVENT_ID = "event_id";
/**
* The name of the extended property. This is a uri of the form
- * {scheme}#{local-name} convention.
+ * {scheme}#{local-name} convention. Column name.
* <P>Type: TEXT</P>
*/
public static final String NAME = "name";
/**
- * The value of the extended property.
+ * The value of the extended property. Column name.
* <P>Type: TEXT</P>
*/
public static final String VALUE = "value";
}
+ /**
+ * Fields for accessing the Extended Properties. This is a generic set of
+ * name/value pairs for use by sync adapters or apps to add extra
+ * information to events.
+ */
public static final class ExtendedProperties implements BaseColumns,
ExtendedPropertiesColumns, EventsColumns {
public static final Uri CONTENT_URI =
@@ -1719,7 +2019,7 @@ public final class Calendar {
*/
private SyncState() {}
- public static final String CONTENT_DIRECTORY =
+ private static final String CONTENT_DIRECTORY =
SyncStateContract.Constants.CONTENT_DIRECTORY;
/**
@@ -1732,39 +2032,43 @@ public final class Calendar {
/**
* Columns from the EventsRawTimes table
*/
- public interface EventsRawTimesColumns {
+ private interface EventsRawTimesColumns {
/**
- * The corresponding event id
+ * The corresponding event id. Column name.
* <P>Type: INTEGER (long)</P>
*/
public static final String EVENT_ID = "event_id";
/**
- * The RFC2445 compliant time the event starts
+ * The RFC2445 compliant time the event starts. Column name.
* <P>Type: TEXT</P>
*/
public static final String DTSTART_2445 = "dtstart2445";
/**
- * The RFC2445 compliant time the event ends
+ * The RFC2445 compliant time the event ends. Column name.
* <P>Type: TEXT</P>
*/
public static final String DTEND_2445 = "dtend2445";
/**
- * The RFC2445 compliant original instance time of the recurring event for which this
- * event is an exception.
+ * The RFC2445 compliant original instance time of the recurring event
+ * for which this event is an exception. Column name.
* <P>Type: TEXT</P>
*/
public static final String ORIGINAL_INSTANCE_TIME_2445 = "originalInstanceTime2445";
/**
- * The RFC2445 compliant last date this event repeats on, or NULL if it never ends
+ * The RFC2445 compliant last date this event repeats on, or NULL if it
+ * never ends. Column name.
* <P>Type: TEXT</P>
*/
public static final String LAST_DATE_2445 = "lastDate2445";
}
+ /**
+ * @hide
+ */
public static final class EventsRawTimes implements BaseColumns, EventsRawTimesColumns {
}
}
diff --git a/core/java/android/util/FinitePool.java b/core/java/android/util/FinitePool.java
index 3ef8293..4ae21ad 100644
--- a/core/java/android/util/FinitePool.java
+++ b/core/java/android/util/FinitePool.java
@@ -69,6 +69,7 @@ class FinitePool<T extends Poolable<T>> implements Pool<T> {
if (element != null) {
element.setNextPoolable(null);
+ element.setPooled(false);
mManager.onAcquired(element);
}
@@ -76,9 +77,13 @@ class FinitePool<T extends Poolable<T>> implements Pool<T> {
}
public void release(T element) {
+ if (element.isPooled()) {
+ throw new IllegalArgumentException("Element already in the pool.");
+ }
if (mInfinite || mPoolCount < mLimit) {
mPoolCount++;
element.setNextPoolable(mRoot);
+ element.setPooled(true);
mRoot = element;
}
mManager.onReleased(element);
diff --git a/core/java/android/util/Poolable.java b/core/java/android/util/Poolable.java
index fd9bd9b..87e0529 100644
--- a/core/java/android/util/Poolable.java
+++ b/core/java/android/util/Poolable.java
@@ -22,4 +22,6 @@ package android.util;
public interface Poolable<T> {
void setNextPoolable(T element);
T getNextPoolable();
+ boolean isPooled();
+ void setPooled(boolean isPooled);
}
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index b2a35d3..ba06795 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -109,16 +109,16 @@ public class Gravity
*/
public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000;
- /** Push object to x-axis position before its container, not changing its size. */
- public static final int BEFORE = RELATIVE_HORIZONTAL_DIRECTION | LEFT;
+ /** Push object to x-axis position at the start of its container, not changing its size. */
+ public static final int START = RELATIVE_HORIZONTAL_DIRECTION | LEFT;
- /** Push object to x-axis position after its container, not changing its size. */
- public static final int AFTER = RELATIVE_HORIZONTAL_DIRECTION | RIGHT;
+ /** Push object to x-axis position at the end of its container, not changing its size. */
+ public static final int END = RELATIVE_HORIZONTAL_DIRECTION | RIGHT;
/**
* Binary mask for the horizontal gravity and script specific direction bit.
*/
- public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = BEFORE | AFTER;
+ public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
/**
* Apply a gravity constant to an object. This suppose that the layout direction is LTR.
@@ -342,8 +342,8 @@ public class Gravity
/**
* <p>Convert script specific gravity to absolute horizontal value.</p>
*
- * if horizontal direction is LTR, then BEFORE will set LEFT and AFTER will set RIGHT.
- * if horizontal direction is RTL, then BEFORE will set RIGHT and AFTER will set LEFT.
+ * if horizontal direction is LTR, then START will set LEFT and END will set RIGHT.
+ * if horizontal direction is RTL, then START will set RIGHT and END will set LEFT.
*
* @param gravity The gravity to convert to absolute (horizontal) values.
* @param isRtl Whether the layout is right-to-left.
@@ -351,11 +351,11 @@ public class Gravity
*/
public static int getAbsoluteGravity(int gravity, boolean isRtl) {
int result = gravity;
- // If layout is script specific and gravity is horizontal relative (BEFORE or AFTER)
+ // If layout is script specific and gravity is horizontal relative (START or END)
if ((result & RELATIVE_HORIZONTAL_DIRECTION) > 0) {
- if ((result & Gravity.BEFORE) == Gravity.BEFORE) {
- // Remove the BEFORE bit
- result &= ~BEFORE;
+ if ((result & Gravity.START) == Gravity.START) {
+ // Remove the START bit
+ result &= ~START;
if (isRtl) {
// Set the RIGHT bit
result |= RIGHT;
@@ -363,9 +363,9 @@ public class Gravity
// Set the LEFT bit
result |= LEFT;
}
- } else if ((result & Gravity.AFTER) == Gravity.AFTER) {
- // Remove the AFTER bit
- result &= ~AFTER;
+ } else if ((result & Gravity.END) == Gravity.END) {
+ // Remove the END bit
+ result &= ~END;
if (isRtl) {
// Set the LEFT bit
result |= LEFT;
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index fccef2b..5a91d31 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -50,6 +50,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
private int mPtr;
private VelocityTracker mNext;
+ private boolean mIsPooled;
private static native int nativeInitialize();
private static native void nativeDispose(int ptr);
@@ -93,6 +94,20 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
return mNext;
}
+ /**
+ * @hide
+ */
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ /**
+ * @hide
+ */
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
+
private VelocityTracker() {
mPtr = nativeInitialize();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 014f19f..51eb13b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -61,6 +61,7 @@ import android.view.ContextMenu.ContextMenuInfo;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
@@ -1492,6 +1493,11 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
private static final Object sTagsLock = new Object();
/**
+ * The next available accessiiblity id.
+ */
+ private static int sNextAccessibilityViewId;
+
+ /**
* The animation currently associated with this view.
* @hide
*/
@@ -1533,6 +1539,11 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
int mID = NO_ID;
/**
+ * The stable ID of this view for accessibility porposes.
+ */
+ int mAccessibilityViewId = NO_ID;
+
+ /**
* The view's tag.
* {@hide}
*
@@ -3649,6 +3660,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
*/
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ event.setSource(this);
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
event.setEnabled(isEnabled());
@@ -3664,6 +3676,112 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
}
/**
+ * Returns an {@link AccessibilityNodeInfo} representing this view from the
+ * point of view of an {@link android.accessibilityservice.AccessibilityService}.
+ * This method is responsible for obtaining an accessibility node info from a
+ * pool of reusable instances and calling
+ * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to
+ * initialize the former.
+ * <p>
+ * Note: The client is responsible for recycling the obtained instance by calling
+ * {@link AccessibilityNodeInfo#recycle()} to minimize object creation.
+ * </p>
+ * @return A populated {@link AccessibilityNodeInfo}.
+ *
+ * @see AccessibilityNodeInfo
+ */
+ public AccessibilityNodeInfo createAccessibilityNodeInfo() {
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this);
+ onInitializeAccessibilityNodeInfo(info);
+ return info;
+ }
+
+ /**
+ * Initializes an {@link AccessibilityNodeInfo} with information about this view.
+ * The base implementation sets:
+ * <ul>
+ * <li>{@link AccessibilityNodeInfo#setParent(View)},</li>
+ * <li>{@link AccessibilityNodeInfo#setBounds(Rect)},</li>
+ * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li>
+ * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li>
+ * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li>
+ * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li>
+ * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li>
+ * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li>
+ * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li>
+ * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li>
+ * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li>
+ * </ul>
+ * <p>
+ * Subclasses should override this method, call the super implementation,
+ * and set additional attributes.
+ * </p>
+ * @param info The instance to initialize.
+ */
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ Rect bounds = mAttachInfo.mTmpInvalRect;
+ getDrawingRect(bounds);
+ info.setBounds(bounds);
+
+ ViewParent parent = getParent();
+ if (parent instanceof View) {
+ View parentView = (View) parent;
+ info.setParent(parentView);
+ }
+
+ info.setPackageName(mContext.getPackageName());
+ info.setClassName(getClass().getName());
+ info.setContentDescription(getContentDescription());
+
+ info.setEnabled(isEnabled());
+ info.setClickable(isClickable());
+ info.setFocusable(isFocusable());
+ info.setFocused(isFocused());
+ info.setSelected(isSelected());
+ info.setLongClickable(isLongClickable());
+
+ // TODO: These make sense only if we are in an AdapterView but all
+ // views can be selected. Maybe from accessiiblity perspective
+ // we should report as selectable view in an AdapterView.
+ info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+ info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
+
+ if (isFocusable()) {
+ if (isFocused()) {
+ info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
+ } else {
+ info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
+ }
+ }
+ }
+
+ /**
+ * Gets the unique identifier of this view on the screen for accessibility purposes.
+ * If this {@link View} is not attached to any window, {@value #NO_ID} is returned.
+ *
+ * @return The view accessibility id.
+ *
+ * @hide
+ */
+ public int getAccessibilityViewId() {
+ if (mAccessibilityViewId == NO_ID) {
+ mAccessibilityViewId = sNextAccessibilityViewId++;
+ }
+ return mAccessibilityViewId;
+ }
+
+ /**
+ * Gets the unique identifier of the window in which this View reseides.
+ *
+ * @return The window accessibility id.
+ *
+ * @hide
+ */
+ public int getAccessibilityWindowId() {
+ return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId : NO_ID;
+ }
+
+ /**
* Gets the {@link View} description. It briefly describes the view and is
* primarily used for accessibility support. Set this property to enable
* better accessibility support for your application. This is especially
@@ -4571,6 +4689,16 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
}
/**
+ * Finds the Views that contain given text. The containment is case insensitive.
+ * As View's text is considered any text content that View renders.
+ *
+ * @param outViews The output list of matching Views.
+ * @param text The text to match against.
+ */
+ public void findViewsWithText(ArrayList<View> outViews, CharSequence text) {
+ }
+
+ /**
* Find and return all touchable views that are descendants of this view,
* possibly including this view if it is touchable itself.
*
@@ -4677,8 +4805,8 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
// need to be focusable in touch mode if in touch mode
if (isInTouchMode() &&
- (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
- return false;
+ (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
+ return false;
}
// need to not have any parents blocking us
@@ -12719,6 +12847,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
);
private InvalidateInfo mNext;
+ private boolean mIsPooled;
View target;
@@ -12742,6 +12871,14 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
void release() {
sPool.release(this);
}
+
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
}
final IWindowSession mSession;
@@ -12952,6 +13089,11 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
/**
+ * The id of the window for accessibility purposes.
+ */
+ int mAccessibilityWindowId = View.NO_ID;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 1e72529..9ab4c82 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -50,18 +50,28 @@ import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pool;
+import android.util.Poolable;
+import android.util.PoolableManager;
+import android.util.Pools;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
+import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
+
import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.Predicate;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
@@ -71,6 +81,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.List;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -248,6 +259,12 @@ public final class ViewAncestor extends Handler implements ViewParent,
*/
AudioManager mAudioManager;
+ final AccessibilityManager mAccessibilityManager;
+
+ AccessibilityInteractionController mAccessibilityInteractionContrtoller;
+
+ AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
+
private final int mDensity;
/**
@@ -285,7 +302,7 @@ public final class ViewAncestor extends Handler implements ViewParent,
// done here instead of in the static block because Zygote does not
// allow the spawning of threads.
getWindowSession(context.getMainLooper());
-
+
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
@@ -302,6 +319,11 @@ public final class ViewAncestor extends Handler implements ViewParent,
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
+ mAccessibilityInteractionConnectionManager =
+ new AccessibilityInteractionConnectionManager();
+ mAccessibilityManager.addAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager);
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
@@ -490,10 +512,14 @@ public final class ViewAncestor extends Handler implements ViewParent,
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
}
-
+
view.assignParent(this);
mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
+
+ if (mAccessibilityManager.isEnabled()) {
+ mAccessibilityInteractionConnectionManager.ensureConnection();
+ }
}
}
}
@@ -2004,6 +2030,10 @@ public final class ViewAncestor extends Handler implements ViewParent,
mView.dispatchDetachedFromWindow();
}
+ mAccessibilityInteractionConnectionManager.ensureNoConnection();
+ mAccessibilityManager.removeAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager);
+
mView = null;
mAttachInfo.mRootView = null;
mAttachInfo.mSurface = null;
@@ -2020,7 +2050,6 @@ public final class ViewAncestor extends Handler implements ViewParent,
InputQueue.unregisterInputChannel(mInputChannel);
}
}
-
try {
sWindowSession.remove(mWindow);
} catch (RemoteException e) {
@@ -2098,6 +2127,10 @@ public final class ViewAncestor extends Handler implements ViewParent,
public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
public final static int DISPATCH_GENERIC_MOTION = 1018;
+ public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1019;
+ public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1020;
+ public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1021;
+ public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1022;
@Override
public void handleMessage(Message msg) {
@@ -2298,9 +2331,25 @@ public final class ViewAncestor extends Handler implements ViewParent,
case DISPATCH_SYSTEM_UI_VISIBILITY: {
handleDispatchSystemUiVisibilityChanged(msg.arg1);
} break;
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
+ } break;
+ case DO_PERFORM_ACCESSIBILITY_ACTION: {
+ getAccessibilityInteractionController()
+ .perfromAccessibilityActionUiThread(msg);
+ } break;
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByViewIdUiThread(msg);
+ } break;
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT: {
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfosByViewTextUiThread(msg);
+ } break;
}
}
-
+
private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
if (mFinishedCallback != null) {
Slog.w(TAG, "Received a new input event from the input queue but there is "
@@ -3220,6 +3269,17 @@ public final class ViewAncestor extends Handler implements ViewParent,
return mAudioManager;
}
+ public AccessibilityInteractionController getAccessibilityInteractionController() {
+ if (mView == null) {
+ throw new IllegalStateException("getAccessibilityInteractionController"
+ + " called when there is no mView");
+ }
+ if (mAccessibilityInteractionContrtoller == null) {
+ mAccessibilityInteractionContrtoller = new AccessibilityInteractionController();
+ }
+ return mAccessibilityInteractionContrtoller;
+ }
+
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
@@ -3517,7 +3577,7 @@ public final class ViewAncestor extends Handler implements ViewParent,
* send an {@link AccessibilityEvent} to announce that.
*/
private void sendAccessibilityEvents() {
- if (!AccessibilityManager.getInstance(mView.getContext()).isEnabled()) {
+ if (!mAccessibilityManager.isEnabled()) {
return;
}
mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -3545,7 +3605,7 @@ public final class ViewAncestor extends Handler implements ViewParent,
if (mView == null) {
return false;
}
- AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event);
+ mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
@@ -3608,18 +3668,18 @@ public final class ViewAncestor extends Handler implements ViewParent,
static class InputMethodCallback extends IInputMethodCallback.Stub {
private WeakReference<ViewAncestor> mViewAncestor;
- public InputMethodCallback(ViewAncestor viewRoot) {
- mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
+ public InputMethodCallback(ViewAncestor viewAncestor) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
}
public void finishedEvent(int seq, boolean handled) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchFinishedEvent(seq, handled);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchFinishedEvent(seq, handled);
}
}
- public void sessionCreated(IInputMethodSession session) throws RemoteException {
+ public void sessionCreated(IInputMethodSession session) {
// Stub -- not for use in the client.
}
}
@@ -3627,36 +3687,37 @@ public final class ViewAncestor extends Handler implements ViewParent,
static class W extends IWindow.Stub {
private final WeakReference<ViewAncestor> mViewAncestor;
- W(ViewAncestor viewRoot) {
- mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
+ W(ViewAncestor viewAncestor) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
}
public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
boolean reportDraw, Configuration newConfig) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw,
+ newConfig);
}
}
public void dispatchAppVisibility(boolean visible) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchAppVisibility(visible);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchAppVisibility(visible);
}
}
public void dispatchGetNewSurface() {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchGetNewSurface();
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchGetNewSurface();
}
}
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.windowFocusChanged(hasFocus, inTouchMode);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
}
}
@@ -3674,9 +3735,9 @@ public final class ViewAncestor extends Handler implements ViewParent,
}
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- final View view = viewRoot.mView;
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ final View view = viewAncestor.mView;
if (view != null) {
if (checkCallingPermission(Manifest.permission.DUMP) !=
PackageManager.PERMISSION_GRANTED) {
@@ -3705,9 +3766,9 @@ public final class ViewAncestor extends Handler implements ViewParent,
}
public void closeSystemDialogs(String reason) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchCloseSystemDialogs(reason);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchCloseSystemDialogs(reason);
}
}
@@ -3720,7 +3781,7 @@ public final class ViewAncestor extends Handler implements ViewParent,
}
}
}
-
+
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
@@ -3733,17 +3794,16 @@ public final class ViewAncestor extends Handler implements ViewParent,
/* Drag/drop */
public void dispatchDragEvent(DragEvent event) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchDragEvent(event);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchDragEvent(event);
}
}
- @Override
public void dispatchSystemUiVisibilityChanged(int visibility) {
- final ViewAncestor viewRoot = mViewAncestor.get();
- if (viewRoot != null) {
- viewRoot.dispatchSystemUiVisibilityChanged(visibility);
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchSystemUiVisibilityChanged(visibility);
}
}
}
@@ -4053,5 +4113,395 @@ public final class ViewAncestor extends Handler implements ViewParent,
}
}
+ /**
+ * Class for managing the accessibility interaction connection
+ * based on the global accessibility state.
+ */
+ final class AccessibilityInteractionConnectionManager
+ implements AccessibilityStateChangeListener {
+ public void onAccessibilityStateChanged(boolean enabled) {
+ if (enabled) {
+ ensureConnection();
+ } else {
+ ensureNoConnection();
+ }
+ }
+
+ public void ensureConnection() {
+ final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
+ if (!registered) {
+ mAttachInfo.mAccessibilityWindowId =
+ mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+ new AccessibilityInteractionConnection(ViewAncestor.this));
+ }
+ }
+
+ public void ensureNoConnection() {
+ final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
+ if (registered) {
+ mAttachInfo.mAccessibilityWindowId = View.NO_ID;
+ mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
+ }
+ }
+ }
+
+ /**
+ * This class is an interface this ViewAncestor provides to the
+ * AccessibilityManagerService to the latter can interact with
+ * the view hierarchy in this ViewAncestor.
+ */
+ final class AccessibilityInteractionConnection
+ extends IAccessibilityInteractionConnection.Stub {
+ private final WeakReference<ViewAncestor> mViewAncestor;
+
+ AccessibilityInteractionConnection(ViewAncestor viewAncestor) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+ }
+
+ public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor == null) {
+ return;
+ }
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityId,
+ interactionId, callback);
+ }
+
+ public void performAccessibilityAction(int accessibilityId, int action,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor == null) {
+ return;
+ }
+ getAccessibilityInteractionController()
+ .performAccessibilityActionClientThread(accessibilityId, action, interactionId,
+ callback);
+ }
+
+ public void findAccessibilityNodeInfoByViewId(int viewId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor == null) {
+ return;
+ }
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback);
+ }
+
+ public void findAccessibilityNodeInfosByViewText(String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback) {
+ final ViewAncestor viewAncestor = mViewAncestor.get();
+ if (viewAncestor == null) {
+ return;
+ }
+ getAccessibilityInteractionController()
+ .findAccessibilityNodeInfosByViewTextClientThread(text, interactionId, callback);
+ }
+ }
+
+ /**
+ * Class for managing accessibility interactions initiated from the system
+ * and targeting the view hierarchy. A *ClientThread method is to be
+ * called from the interaction connection this ViewAncestor gives the
+ * system to talk to it and a corresponding *UiThread method that is executed
+ * on the UI thread.
+ */
+ final class AccessibilityInteractionController {
+ private static final int POOL_SIZE = 5;
+
+ private FindByAccessibilitytIdPredicate mFindByAccessibilityIdPredicate =
+ new FindByAccessibilitytIdPredicate();
+
+ private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
+ new ArrayList<AccessibilityNodeInfo>();
+
+ // Reusable poolable arguments for interacting with the view hierarchy
+ // to fit more arguments than Message and to avoid sharing objects between
+ // two messages since several threads can send messages concurrently.
+ private final Pool<SomeArgs> mPool = Pools.synchronizedPool(Pools.finitePool(
+ new PoolableManager<SomeArgs>() {
+ public SomeArgs newInstance() {
+ return new SomeArgs();
+ }
+
+ public void onAcquired(SomeArgs info) {
+ /* do nothing */
+ }
+
+ public void onReleased(SomeArgs info) {
+ info.clear();
+ }
+ }, POOL_SIZE)
+ );
+
+ public class SomeArgs implements Poolable<SomeArgs> {
+ private SomeArgs mNext;
+ private boolean mIsPooled;
+
+ public Object arg1;
+ public Object arg2;
+ public int argi1;
+ public int argi2;
+ public int argi3;
+
+ public SomeArgs getNextPoolable() {
+ return mNext;
+ }
+
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ public void setNextPoolable(SomeArgs args) {
+ mNext = args;
+ }
+
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
+
+ private void clear() {
+ arg1 = null;
+ arg2 = null;
+ argi1 = 0;
+ argi2 = 0;
+ argi3 = 0;
+ }
+ }
+
+ public void findAccessibilityNodeInfoByAccessibilityIdClientThread(int accessibilityId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
+ Message message = Message.obtain();
+ message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+ message.arg1 = accessibilityId;
+ message.arg2 = interactionId;
+ message.obj = callback;
+ sendMessage(message);
+ }
+
+ public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
+ final int accessibilityId = message.arg1;
+ final int interactionId = message.arg2;
+ final IAccessibilityInteractionConnectionCallback callback =
+ (IAccessibilityInteractionConnectionCallback) message.obj;
+
+ View root = ViewAncestor.this.mView;
+ if (root == null) {
+ return;
+ }
+
+ FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
+ predicate.init(accessibilityId);
+
+ View target = root.findViewByPredicate(predicate);
+ if (target != null) {
+ AccessibilityNodeInfo info = target.createAccessibilityNodeInfo();
+ try {
+ callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+ }
+
+ public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback) {
+ Message message = Message.obtain();
+ message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
+ message.arg1 = viewId;
+ message.arg2 = interactionId;
+ message.obj = callback;
+ sendMessage(message);
+ }
+
+ public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
+ final int viewId = message.arg1;
+ final int interactionId = message.arg2;
+ final IAccessibilityInteractionConnectionCallback callback =
+ (IAccessibilityInteractionConnectionCallback) message.obj;
+
+ View root = ViewAncestor.this.mView;
+ if (root == null) {
+ return;
+ }
+ View target = root.findViewById(viewId);
+ if (target != null) {
+ AccessibilityNodeInfo info = target.createAccessibilityNodeInfo();
+ try {
+ callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+ }
+
+ public void findAccessibilityNodeInfosByViewTextClientThread(String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback) {
+ Message message = Message.obtain();
+ message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT;
+ SomeArgs args = mPool.acquire();
+ args.arg1 = text;
+ args.argi1 = interactionId;
+ args.arg2 = callback;
+ message.obj = args;
+ sendMessage(message);
+ }
+
+ public void findAccessibilityNodeInfosByViewTextUiThread(Message message) {
+ SomeArgs args = (SomeArgs) message.obj;
+ final String text = (String) args.arg1;
+ final int interactionId = args.argi1;
+ final IAccessibilityInteractionConnectionCallback callback =
+ (IAccessibilityInteractionConnectionCallback) args.arg2;
+ mPool.release(args);
+
+ View root = ViewAncestor.this.mView;
+ if (root == null) {
+ return;
+ }
+
+ ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
+ foundViews.clear();
+
+ root.findViewsWithText(foundViews, text);
+ if (foundViews.isEmpty()) {
+ return;
+ }
+
+ List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
+
+ final int viewCount = foundViews.size();
+ for (int i = 0; i < viewCount; i++) {
+ View foundView = foundViews.get(i);
+ infos.add(foundView.createAccessibilityNodeInfo());
+ }
+
+ try {
+ callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+
+ public void performAccessibilityActionClientThread(int accessibilityId, int action,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback) {
+ Message message = Message.obtain();
+ message.what = DO_PERFORM_ACCESSIBILITY_ACTION;
+ SomeArgs args = mPool.acquire();
+ args.argi1 = accessibilityId;
+ args.argi2 = action;
+ args.argi3 = interactionId;
+ args.arg1 = callback;
+ message.obj = args;
+ sendMessage(message);
+ }
+
+ public void perfromAccessibilityActionUiThread(Message message) {
+ SomeArgs args = (SomeArgs) message.obj;
+ final int accessibilityId = args.argi1;
+ final int action = args.argi2;
+ final int interactionId = args.argi3;
+ final IAccessibilityInteractionConnectionCallback callback =
+ (IAccessibilityInteractionConnectionCallback) args.arg1;
+ mPool.release(args);
+
+ if (ViewAncestor.this.mView == null) {
+ return;
+ }
+
+ boolean succeeded = false;
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_FOCUS: {
+ succeeded = performActionFocus(accessibilityId);
+ } break;
+ case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
+ succeeded = performActionClearFocus(accessibilityId);
+ } break;
+ case AccessibilityNodeInfo.ACTION_SELECT: {
+ succeeded = performActionSelect(accessibilityId);
+ } break;
+ case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
+ succeeded = performActionClearSelection(accessibilityId);
+ } break;
+ }
+
+ try {
+ callback.setPerformAccessibilityActionResult(succeeded, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+
+ private boolean performActionFocus(int accessibilityId) {
+ View target = findViewByAccessibilityId(accessibilityId);
+ if (target == null) {
+ return false;
+ }
+ // Get out of touch mode since accessibility wants to move focus around.
+ ensureTouchMode(false);
+ return target.requestFocus();
+ }
+
+ private boolean performActionClearFocus(int accessibilityId) {
+ View target = findViewByAccessibilityId(accessibilityId);
+ if (target == null) {
+ return false;
+ }
+ if (!target.isFocused()) {
+ return false;
+ }
+ target.clearFocus();
+ return !target.isFocused();
+ }
+
+ private boolean performActionSelect(int accessibilityId) {
+ View target = findViewByAccessibilityId(accessibilityId);
+ if (target == null) {
+ return false;
+ }
+ if (target.isSelected()) {
+ return false;
+ }
+ target.setSelected(true);
+ return target.isSelected();
+ }
+
+ private boolean performActionClearSelection(int accessibilityId) {
+ View target = findViewByAccessibilityId(accessibilityId);
+ if (target == null) {
+ return false;
+ }
+ if (!target.isSelected()) {
+ return false;
+ }
+ target.setSelected(false);
+ return !target.isSelected();
+ }
+
+ private View findViewByAccessibilityId(int accessibilityId) {
+ View root = ViewAncestor.this.mView;
+ if (root == null) {
+ return null;
+ }
+ mFindByAccessibilityIdPredicate.init(accessibilityId);
+ return root.findViewByPredicate(mFindByAccessibilityIdPredicate);
+ }
+
+ private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
+ public int mSerchedId;
+
+ public void init(int searchedId) {
+ mSerchedId = searchedId;
+ }
+
+ public boolean apply(View view) {
+ return (view.getAccessibilityViewId() == mSerchedId);
+ }
+ }
+ }
+
private static native void nativeShowFPS(Canvas canvas, int durationMillis);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f504b90..57ee8a0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -35,6 +35,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -772,6 +773,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ @Override
+ public void findViewsWithText(ArrayList<View> outViews, CharSequence text) {
+ final int childrenCount = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < childrenCount; i++) {
+ View child = children[i];
+ if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+ child.findViewsWithText(outViews, text);
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
@@ -2007,6 +2020,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return false;
}
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+
+ for (int i = 0, count = mChildrenCount; i < count; i++) {
+ View child = mChildren[i];
+ info.addChild(child);
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a1ddd08..b0181bb 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -77,8 +77,8 @@ public interface WindowManager extends ViewManager {
implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
- * When using {@link Gravity#LEFT} or {@link Gravity#BEFORE} or {@link Gravity#RIGHT} or
- * {@link Gravity#AFTER} it provides an offset from the given edge.
+ * When using {@link Gravity#LEFT} or {@link Gravity#START} or {@link Gravity#RIGHT} or
+ * {@link Gravity#END} it provides an offset from the given edge.
*/
@ViewDebug.ExportedProperty
public int x;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 7b80797..32bfa2f 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -16,9 +16,12 @@
package android.view.accessibility;
+import android.accessibilityservice.IAccessibilityServiceConnection;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
import android.text.TextUtils;
+import android.view.View;
import java.util.ArrayList;
@@ -159,6 +162,7 @@ import java.util.ArrayList;
* @see android.accessibilityservice.AccessibilityService
*/
public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
+ private static final boolean DEBUG = false;
/**
* Invalid selection/focus position.
@@ -256,21 +260,38 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
private static final Object sPoolLock = new Object();
private static AccessibilityEvent sPool;
private static int sPoolSize;
-
private AccessibilityEvent mNext;
private boolean mIsInPool;
private int mEventType;
+ private int mSourceAccessibilityViewId;
+ private int mSourceAccessibilityWindowId;
private CharSequence mPackageName;
private long mEventTime;
private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
+ private IAccessibilityServiceConnection mConnection;
+
/*
* Hide constructor from clients.
*/
private AccessibilityEvent() {
+ }
+ /**
+ * Initialize an event from another one.
+ *
+ * @param event The event to initialize from.
+ */
+ void init(AccessibilityEvent event) {
+ super.init(event);
+ mEventType = event.mEventType;
+ mEventTime = event.mEventTime;
+ mSourceAccessibilityWindowId = event.mSourceAccessibilityWindowId;
+ mSourceAccessibilityViewId = event.mSourceAccessibilityViewId;
+ mPackageName = event.mPackageName;
+ mConnection = event.mConnection;
}
/**
@@ -286,8 +307,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Appends an {@link AccessibilityRecord} to the end of event records.
*
* @param record The record to append.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void appendRecord(AccessibilityRecord record) {
+ enforceNotSealed();
mRecords.add(record);
}
@@ -311,11 +335,89 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
+ * Sets the event source.
+ *
+ * @param source The source.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setSource(View source) {
+ enforceNotSealed();
+ if (source != null) {
+ mSourceAccessibilityWindowId = source.getAccessibilityWindowId();
+ mSourceAccessibilityViewId = source.getAccessibilityViewId();
+ } else {
+ mSourceAccessibilityWindowId = View.NO_ID;
+ mSourceAccessibilityViewId = View.NO_ID;
+ }
+ }
+
+ /**
+ * Gets the {@link AccessibilityNodeInfo} of the event source.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ * @return The info.
+ */
+ public AccessibilityNodeInfo getSource() {
+ enforceSealed();
+ if (mSourceAccessibilityWindowId == View.NO_ID
+ || mSourceAccessibilityViewId == View.NO_ID) {
+ return null;
+ }
+ try {
+ return mConnection.findAccessibilityNodeInfoByAccessibilityId(
+ mSourceAccessibilityWindowId, mSourceAccessibilityViewId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the id of the window from which the event comes from.
+ *
+ * @return The window id.
+ */
+ public int getAccessibilityWindowId() {
+ return mSourceAccessibilityWindowId;
+ }
+
+ /**
+ * Sets the client token for the accessibility service that
+ * provided this node info.
+ *
+ * @param connection The connection.
+ *
+ * @hide
+ */
+ public final void setConnection(IAccessibilityServiceConnection connection) {
+ mConnection = connection;
+ }
+
+ /**
+ * Gets the accessibility window id of the source window.
+ *
+ * @return The id.
+ *
+ * @hide
+ */
+ public int getSourceAccessibilityWindowId() {
+ return mSourceAccessibilityWindowId;
+ }
+
+ /**
* Sets the event type.
*
* @param eventType The event type.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setEventType(int eventType) {
+ enforceNotSealed();
mEventType = eventType;
}
@@ -332,8 +434,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Sets the time in which this event was sent.
*
* @param eventTime The event time.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setEventTime(long eventTime) {
+ enforceNotSealed();
mEventTime = eventTime;
}
@@ -350,8 +455,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Sets the package name of the source.
*
* @param packageName The package name.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setPackageName(CharSequence packageName) {
+ enforceNotSealed();
mPackageName = packageName;
}
@@ -370,6 +478,27 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
/**
* Returns a cached instance if such is available or a new one is
+ * instantiated with type property set.
+ *
+ * @param event The other event.
+ * @return An instance.
+ */
+ public static AccessibilityEvent obtain(AccessibilityEvent event) {
+ AccessibilityEvent eventClone = AccessibilityEvent.obtain();
+ eventClone.init(event);
+
+ final int recordCount = event.mRecords.size();
+ for (int i = 0; i < recordCount; i++) {
+ AccessibilityRecord record = event.mRecords.get(i);
+ AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
+ eventClone.mRecords.add(recordClone);
+ }
+
+ return eventClone;
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
* instantiated.
*
* @return An instance.
@@ -413,11 +542,16 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
/**
* Clears the state of this instance.
+ *
+ * @hide
*/
@Override
protected void clear() {
super.clear();
+ mConnection = null;
mEventType = 0;
+ mSourceAccessibilityViewId = View.NO_ID;
+ mSourceAccessibilityWindowId = View.NO_ID;
mPackageName = null;
mEventTime = 0;
while (!mRecords.isEmpty()) {
@@ -432,7 +566,14 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* @param parcel A parcel containing the state of a {@link AccessibilityEvent}.
*/
public void initFromParcel(Parcel parcel) {
+ if (parcel.readInt() == 1) {
+ mConnection = IAccessibilityServiceConnection.Stub.asInterface(
+ parcel.readStrongBinder());
+ }
+ setSealed(parcel.readInt() == 1);
mEventType = parcel.readInt();
+ mSourceAccessibilityWindowId = parcel.readInt();
+ mSourceAccessibilityViewId = parcel.readInt();
mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
mEventTime = parcel.readLong();
readAccessibilityRecordFromParcel(this, parcel);
@@ -471,7 +612,16 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* {@inheritDoc}
*/
public void writeToParcel(Parcel parcel, int flags) {
+ if (mConnection == null) {
+ parcel.writeInt(0);
+ } else {
+ parcel.writeInt(1);
+ parcel.writeStrongBinder(mConnection.asBinder());
+ }
+ parcel.writeInt(isSealed() ? 1 : 0);
parcel.writeInt(mEventType);
+ parcel.writeInt(mSourceAccessibilityWindowId);
+ parcel.writeInt(mSourceAccessibilityViewId);
TextUtils.writeToParcel(mPackageName, parcel, 0);
parcel.writeLong(mEventTime);
writeAccessibilityRecordToParcel(this, parcel, flags);
@@ -519,18 +669,36 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
builder.append("; EventType: ").append(eventTypeToString(mEventType));
builder.append("; EventTime: ").append(mEventTime);
builder.append("; PackageName: ").append(mPackageName);
- builder.append(" \n{\n");
builder.append(super.toString());
- builder.append("\n");
- for (int i = 0; i < mRecords.size(); i++) {
- AccessibilityRecord record = mRecords.get(i);
- builder.append(" Record ");
- builder.append(i);
- builder.append(":");
- builder.append(record.toString());
+ if (DEBUG) {
builder.append("\n");
+ builder.append("; sourceAccessibilityWindowId: ").append(mSourceAccessibilityWindowId);
+ builder.append("; sourceAccessibilityViewId: ").append(mSourceAccessibilityViewId);
+ for (int i = 0; i < mRecords.size(); i++) {
+ AccessibilityRecord record = mRecords.get(i);
+ builder.append(" Record ");
+ builder.append(i);
+ builder.append(":");
+ builder.append(" [ ClassName: " + record.mClassName);
+ builder.append("; Text: " + record.mText);
+ builder.append("; ContentDescription: " + record.mContentDescription);
+ builder.append("; ItemCount: " + record.mItemCount);
+ builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex);
+ builder.append("; IsEnabled: " + record.isEnabled());
+ builder.append("; IsPassword: " + record.isPassword());
+ builder.append("; IsChecked: " + record.isChecked());
+ builder.append("; IsFullScreen: " + record.isFullScreen());
+ builder.append("; BeforeText: " + record.mBeforeText);
+ builder.append("; FromIndex: " + record.mFromIndex);
+ builder.append("; AddedCount: " + record.mAddedCount);
+ builder.append("; RemovedCount: " + record.mRemovedCount);
+ builder.append("; ParcelableData: " + record.mParcelableData);
+ builder.append(" ]");
+ builder.append("\n");
+ }
+ } else {
+ builder.append("; recordCount: ").append(getAddedCount());
}
- builder.append("}\n");
return builder.toString();
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 88f8878..eece64a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -28,10 +28,13 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
+import android.view.IWindow;
+import android.view.View;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* System level service that serves as an event dispatch for {@link AccessibilityEvent}s.
@@ -62,6 +65,21 @@ public final class AccessibilityManager {
boolean mIsEnabled;
+ final CopyOnWriteArrayList<AccessibilityStateChangeListener> mAccessibilityStateChangeListeners =
+ new CopyOnWriteArrayList<AccessibilityStateChangeListener>();
+
+ /**
+ * Listener for the accessibility state.
+ */
+ public interface AccessibilityStateChangeListener {
+ /**
+ * Called back on change in the accessibility state.
+ *
+ * @param enabled
+ */
+ public void onAccessibilityStateChanged(boolean enabled);
+ }
+
final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
public void setEnabled(boolean enabled) {
mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
@@ -78,9 +96,8 @@ public final class AccessibilityManager {
public void handleMessage(Message message) {
switch (message.what) {
case DO_SET_ENABLED :
- synchronized (mHandler) {
- mIsEnabled = (message.arg1 == 1);
- }
+ final boolean isEnabled = (message.arg1 == 1);
+ setAccessibilityState(isEnabled);
return;
default :
Log.w(LOG_TAG, "Unknown message type: " + message.what);
@@ -117,7 +134,8 @@ public final class AccessibilityManager {
mService = service;
try {
- mIsEnabled = mService.addClient(mClient);
+ final boolean isEnabled = mService.addClient(mClient);
+ setAccessibilityState(isEnabled);
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
}
@@ -253,4 +271,81 @@ public final class AccessibilityManager {
}
return Collections.unmodifiableList(services);
}
+
+ /**
+ * Registers an {@link AccessibilityStateChangeListener}.
+ *
+ * @param listener The listener.
+ * @return True if successfully registered.
+ */
+ public boolean addAccessibilityStateChangeListener(
+ AccessibilityStateChangeListener listener) {
+ return mAccessibilityStateChangeListeners.add(listener);
+ }
+
+ /**
+ * Unregisters an {@link AccessibilityStateChangeListener}.
+ *
+ * @param listener The listener.
+ * @return True if successfully unregistered.
+ */
+ public boolean removeAccessibilityStateChangeListener(
+ AccessibilityStateChangeListener listener) {
+ return mAccessibilityStateChangeListeners.remove(listener);
+ }
+
+ /**
+ * Sets the enabled state.
+ *
+ * @param isEnabled The accessibility state.
+ */
+ private void setAccessibilityState(boolean isEnabled) {
+ synchronized (mHandler) {
+ if (isEnabled != mIsEnabled) {
+ mIsEnabled = isEnabled;
+ notifyAccessibilityStateChanged();
+ }
+ }
+ }
+
+ /**
+ * Notifies the registered {@link AccessibilityStateChangeListener}s.
+ */
+ private void notifyAccessibilityStateChanged() {
+ final int listenerCount = mAccessibilityStateChangeListeners.size();
+ for (int i = 0; i < listenerCount; i++) {
+ mAccessibilityStateChangeListeners.get(i).onAccessibilityStateChanged(mIsEnabled);
+ }
+ }
+
+ /**
+ * Adds an accessibility interaction connection interface for a given window.
+ * @param windowToken The window token to which a connection is added.
+ * @param connection The connection.
+ *
+ * @hide
+ */
+ public int addAccessibilityInteractionConnection(IWindow windowToken,
+ IAccessibilityInteractionConnection connection) {
+ try {
+ return mService.addAccessibilityInteractionConnection(windowToken, connection);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
+ }
+ return View.NO_ID;
+ }
+
+ /**
+ * Removed an accessibility interaction connection interface for a given window.
+ * @param windowToken The window token to which a connection is removed.
+ *
+ * @hide
+ */
+ public void removeAccessibilityInteractionConnection(IWindow windowToken) {
+ try {
+ mService.removeAccessibilityInteractionConnection(windowToken);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re);
+ }
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.aidl b/core/java/android/view/accessibility/AccessibilityNodeInfo.aidl
new file mode 100644
index 0000000..59175ce
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.view.accessibility;
+
+parcelable AccessibilityNodeInfo;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
new file mode 100644
index 0000000..752f864
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -0,0 +1,947 @@
+/*
+ * 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 android.view.accessibility;
+
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.View;
+
+/**
+ * This class represents a node of the screen content. From the point of
+ * view of an accessibility service the screen content is presented as tree
+ * of accessibility nodes.
+ *
+ * TODO(svertoslavganov): Update the documentation, add sample, and describe
+ * the security policy.
+ */
+public class AccessibilityNodeInfo implements Parcelable {
+
+ private static final boolean DEBUG = false;
+
+ // Actions.
+
+ /**
+ * Action that focuses the node.
+ */
+ public static final int ACTION_FOCUS = 0x00000001;
+
+ /**
+ * Action that unfocuses the node.
+ */
+ public static final int ACTION_CLEAR_FOCUS = 0x00000002;
+
+ /**
+ * Action that selects the node.
+ */
+ public static final int ACTION_SELECT = 0x00000004;
+
+ /**
+ * Action that unselects the node.
+ */
+ public static final int ACTION_CLEAR_SELECTION = 0x00000008;
+
+ // Boolean attributes.
+
+ private static final int PROPERTY_CHECKABLE = 0x00000001;
+
+ private static final int PROPERTY_CHECKED = 0x00000002;
+
+ private static final int PROPERTY_FOCUSABLE = 0x00000004;
+
+ private static final int PROPERTY_FOCUSED = 0x00000008;
+
+ private static final int PROPERTY_SELECTED = 0x00000010;
+
+ private static final int PROPERTY_CLICKABLE = 0x00000020;
+
+ private static final int PROPERTY_LONG_CLICKABLE = 0x00000040;
+
+ private static final int PROPERTY_ENABLED = 0x00000080;
+
+ private static final int PROPERTY_PASSWORD = 0x00000100;
+
+ // Readable representations - lazily initialized.
+ private static SparseArray<String> sActionSymbolicNames;
+
+ // Housekeeping.
+ private static final int MAX_POOL_SIZE = 50;
+ private static final Object sPoolLock = new Object();
+ private static AccessibilityNodeInfo sPool;
+ private static int sPoolSize;
+ private AccessibilityNodeInfo mNext;
+ private boolean mIsInPool;
+ private boolean mSealed;
+
+ // Data.
+ private int mAccessibilityViewId;
+ private int mAccessibilityWindowId;
+ private int mParentAccessibilityViewId;
+ private int mBooleanProperties;
+ private final Rect mBounds = new Rect();
+
+ private CharSequence mPackageName;
+ private CharSequence mClassName;
+ private CharSequence mText;
+ private CharSequence mContentDescription;
+
+ private final SparseIntArray mChildAccessibilityIds = new SparseIntArray();
+ private int mActions;
+
+ private IAccessibilityServiceConnection mConnection;
+
+ /**
+ * Hide constructor from clients.
+ */
+ private AccessibilityNodeInfo() {
+ /* do nothing */
+ }
+
+ /**
+ * Sets the source.
+ *
+ * @param source The info source.
+ */
+ public void setSource(View source) {
+ enforceNotSealed();
+ mAccessibilityViewId = source.getAccessibilityViewId();
+ mAccessibilityWindowId = source.getAccessibilityWindowId();
+ }
+
+ /**
+ * Gets the id of the window from which the info comes from.
+ *
+ * @return The window id.
+ */
+ public int getAccessibilityWindowId() {
+ return mAccessibilityWindowId;
+ }
+
+ /**
+ * Gets the number of children.
+ *
+ * @return The child count.
+ */
+ public int getChildCount() {
+ return mChildAccessibilityIds.size();
+ }
+
+ /**
+ * Get the child at given index.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ * @param index The child index.
+ * @return The child node.
+ *
+ * @throws IllegalStateException If called outside of an AccessibilityService.
+ *
+ */
+ public AccessibilityNodeInfo getChild(int index) {
+ enforceSealed();
+ final int childAccessibilityViewId = mChildAccessibilityIds.get(index);
+ try {
+ return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
+ childAccessibilityViewId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Adds a child.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param child The child.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void addChild(View child) {
+ enforceNotSealed();
+ final int childAccessibilityViewId = child.getAccessibilityViewId();
+ final int index = mChildAccessibilityIds.size();
+ mChildAccessibilityIds.put(index, childAccessibilityViewId);
+ }
+
+ /**
+ * Gets the actions that can be performed on the node.
+ *
+ * @return The bit mask of with actions.
+ *
+ * @see AccessibilityNodeInfo#ACTION_FOCUS
+ * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
+ * @see AccessibilityNodeInfo#ACTION_SELECT
+ * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
+ */
+ public int getActions() {
+ return mActions;
+ }
+
+ /**
+ * Adds an action that can be performed on the node.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param action The action.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void addAction(int action) {
+ enforceNotSealed();
+ mActions |= action;
+ }
+
+ /**
+ * Performs an action on the node.
+ * <p>
+ * Note: An action can be performed only if the request is made
+ * from an {@link android.accessibilityservice.AccessibilityService}.
+ * </p>
+ * @param action The action to perform.
+ * @return True if the action was performed.
+ *
+ * @throws IllegalStateException If called outside of an AccessibilityService.
+ */
+ public boolean performAction(int action) {
+ enforceSealed();
+ try {
+ return mConnection.performAccessibilityAction(mAccessibilityWindowId,
+ mAccessibilityViewId, action);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Gets the unique id identifying this node's parent.
+ * <p>
+ * <strong>
+ * It is a client responsibility to recycle the received info by
+ * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+ * of multiple instances.
+ * </strong>
+ * </p>
+ * @return The node's patent id.
+ */
+ public AccessibilityNodeInfo getParent() {
+ enforceSealed();
+ try {
+ return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
+ mParentAccessibilityViewId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the parent.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param parent The parent.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setParent(View parent) {
+ enforceNotSealed();
+ mParentAccessibilityViewId = parent.getAccessibilityViewId();
+ }
+
+ /**
+ * Gets the node bounds in parent coordinates.
+ *
+ * @param outBounds The output node bounds.
+ */
+ public void getBounds(Rect outBounds) {
+ outBounds.set(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
+ }
+
+ /**
+ * Sets the node bounds in parent coordinates.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param bounds The node bounds.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setBounds(Rect bounds) {
+ enforceNotSealed();
+ mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ }
+
+ /**
+ * Gets whether this node is checkable.
+ *
+ * @return True if the node is checkable.
+ */
+ public boolean isCheckable() {
+ return getBooleanProperty(PROPERTY_CHECKABLE);
+ }
+
+ /**
+ * Sets whether this node is checkable.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param checkable True if the node is checkable.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setCheckable(boolean checkable) {
+ setBooleanProperty(PROPERTY_CHECKABLE, checkable);
+ }
+
+ /**
+ * Gets whether this node is checked.
+ *
+ * @return True if the node is checked.
+ */
+ public boolean isChecked() {
+ return getBooleanProperty(PROPERTY_CHECKED);
+ }
+
+ /**
+ * Sets whether this node is checked.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param checked True if the node is checked.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setChecked(boolean checked) {
+ setBooleanProperty(PROPERTY_CHECKED, checked);
+ }
+
+ /**
+ * Gets whether this node is focusable.
+ *
+ * @return True if the node is focusable.
+ */
+ public boolean isFocusable() {
+ return getBooleanProperty(PROPERTY_FOCUSABLE);
+ }
+
+ /**
+ * Sets whether this node is focusable.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param focusable True if the node is focusable.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setFocusable(boolean focusable) {
+ setBooleanProperty(PROPERTY_FOCUSABLE, focusable);
+ }
+
+ /**
+ * Gets whether this node is focused.
+ *
+ * @return True if the node is focused.
+ */
+ public boolean isFocused() {
+ return getBooleanProperty(PROPERTY_FOCUSED);
+ }
+
+ /**
+ * Sets whether this node is focused.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param focused True if the node is focused.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setFocused(boolean focused) {
+ setBooleanProperty(PROPERTY_FOCUSED, focused);
+ }
+
+ /**
+ * Gets whether this node is selected.
+ *
+ * @return True if the node is selected.
+ */
+ public boolean isSelected() {
+ return getBooleanProperty(PROPERTY_SELECTED);
+ }
+
+ /**
+ * Sets whether this node is selected.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param selected True if the node is selected.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setSelected(boolean selected) {
+ setBooleanProperty(PROPERTY_SELECTED, selected);
+ }
+
+ /**
+ * Gets whether this node is clickable.
+ *
+ * @return True if the node is clickable.
+ */
+ public boolean isClickable() {
+ return getBooleanProperty(PROPERTY_CLICKABLE);
+ }
+
+ /**
+ * Sets whether this node is clickable.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param clickable True if the node is clickable.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setClickable(boolean clickable) {
+ setBooleanProperty(PROPERTY_CLICKABLE, clickable);
+ }
+
+ /**
+ * Gets whether this node is long clickable.
+ *
+ * @return True if the node is long clickable.
+ */
+ public boolean isLongClickable() {
+ return getBooleanProperty(PROPERTY_LONG_CLICKABLE);
+ }
+
+ /**
+ * Sets whether this node is long clickable.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param longClickable True if the node is long clickable.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setLongClickable(boolean longClickable) {
+ setBooleanProperty(PROPERTY_LONG_CLICKABLE, longClickable);
+ }
+
+ /**
+ * Gets whether this node is enabled.
+ *
+ * @return True if the node is enabled.
+ */
+ public boolean isEnabled() {
+ return getBooleanProperty(PROPERTY_ENABLED);
+ }
+
+ /**
+ * Sets whether this node is enabled.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param enabled True if the node is enabled.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setEnabled(boolean enabled) {
+ setBooleanProperty(PROPERTY_ENABLED, enabled);
+ }
+
+ /**
+ * Gets whether this node is a password.
+ *
+ * @return True if the node is a password.
+ */
+ public boolean isPassword() {
+ return getBooleanProperty(PROPERTY_PASSWORD);
+ }
+
+ /**
+ * Sets whether this node is a password.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param password True if the node is a password.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setPassword(boolean password) {
+ setBooleanProperty(PROPERTY_PASSWORD, password);
+ }
+
+ /**
+ * Gets the package this node comes from.
+ *
+ * @return The package name.
+ */
+ public CharSequence getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Sets the package this node comes from.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param packageName The package name.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setPackageName(CharSequence packageName) {
+ enforceNotSealed();
+ mPackageName = packageName;
+ }
+
+ /**
+ * Gets the class this node comes from.
+ *
+ * @return The class name.
+ */
+ public CharSequence getClassName() {
+ return mClassName;
+ }
+
+ /**
+ * Sets the class this node comes from.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param className The class name.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setClassName(CharSequence className) {
+ enforceNotSealed();
+ mClassName = className;
+ }
+
+ /**
+ * Gets the text of this node.
+ *
+ * @return The text.
+ */
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /**
+ * Sets the text of this node.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param text The text.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setText(CharSequence text) {
+ enforceNotSealed();
+ mText = text;
+ }
+
+ /**
+ * Gets the content description of this node.
+ *
+ * @return The content description.
+ */
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Sets the content description of this node.
+ * <p>
+ * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ * @param contentDescription The content description.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setContentDescription(CharSequence contentDescription) {
+ enforceNotSealed();
+ mContentDescription = contentDescription;
+ }
+
+ /**
+ * Gets the value of a boolean property.
+ *
+ * @param property The property.
+ * @return The value.
+ */
+ private boolean getBooleanProperty(int property) {
+ return (mBooleanProperties & property) != 0;
+ }
+
+ /**
+ * Sets a boolean property.
+ *
+ * @param property The property.
+ * @param value The value.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ private void setBooleanProperty(int property, boolean value) {
+ enforceNotSealed();
+ if (value) {
+ mBooleanProperties |= property;
+ } else {
+ mBooleanProperties &= ~property;
+ }
+ }
+
+ /**
+ * Sets the connection for interacting with the system.
+ *
+ * @param connection The client token.
+ *
+ * @hide
+ */
+ public final void setConnection(IAccessibilityServiceConnection connection) {
+ mConnection = connection;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Sets if this instance is sealed.
+ *
+ * @param sealed Whether is sealed.
+ *
+ * @hide
+ */
+ public void setSealed(boolean sealed) {
+ mSealed = sealed;
+ }
+
+ /**
+ * Gets if this instance is sealed.
+ *
+ * @return Whether is sealed.
+ *
+ * @hide
+ */
+ public boolean isSealed() {
+ return mSealed;
+ }
+
+ /**
+ * Enforces that this instance is sealed.
+ *
+ * @throws IllegalStateException If this instance is not sealed.
+ *
+ * @hide
+ */
+ protected void enforceSealed() {
+ if (!isSealed()) {
+ throw new IllegalStateException("Cannot perform this "
+ + "action on a not sealed instance.");
+ }
+ }
+
+ /**
+ * Enforces that this instance is not sealed.
+ *
+ * @throws IllegalStateException If this instance is sealed.
+ *
+ * @hide
+ */
+ protected void enforceNotSealed() {
+ if (isSealed()) {
+ throw new IllegalStateException("Cannot perform this "
+ + "action on an sealed instance.");
+ }
+ }
+
+ /**
+ * Returns a cached instance if such is available otherwise a new one
+ * and sets the source.
+ *
+ * @return An instance.
+ *
+ * @see #setSource(View)
+ */
+ public static AccessibilityNodeInfo obtain(View source) {
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ info.setSource(source);
+ return info;
+ }
+
+ /**
+ * Returns a cached instance if such is available otherwise a new one.
+ *
+ * @return An instance.
+ */
+ public static AccessibilityNodeInfo obtain() {
+ synchronized (sPoolLock) {
+ if (sPool != null) {
+ AccessibilityNodeInfo info = sPool;
+ sPool = sPool.mNext;
+ sPoolSize--;
+ info.mNext = null;
+ info.mIsInPool = false;
+ }
+ return new AccessibilityNodeInfo();
+ }
+ }
+
+ /**
+ * Return an instance back to be reused.
+ * <p>
+ * <b>Note: You must not touch the object after calling this function.</b>
+ *
+ * @throws IllegalStateException If the info is already recycled.
+ */
+ public void recycle() {
+ if (mIsInPool) {
+ throw new IllegalStateException("Info already recycled!");
+ }
+ clear();
+ synchronized (sPoolLock) {
+ if (sPoolSize <= MAX_POOL_SIZE) {
+ mNext = sPool;
+ sPool = this;
+ mIsInPool = true;
+ sPoolSize++;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * <b>Note: After the instance is written to a parcel it is recycled.
+ * You must not touch the object after calling this function.</b>
+ * </p>
+ */
+ public void writeToParcel(Parcel parcel, int flags) {
+ if (mConnection == null) {
+ parcel.writeInt(0);
+ } else {
+ parcel.writeInt(1);
+ parcel.writeStrongBinder(mConnection.asBinder());
+ }
+ parcel.writeInt(isSealed() ? 1 : 0);
+ parcel.writeInt(mAccessibilityViewId);
+ parcel.writeInt(mAccessibilityWindowId);
+ parcel.writeInt(mParentAccessibilityViewId);
+
+ SparseIntArray childIds = mChildAccessibilityIds;
+ final int childIdsSize = childIds.size();
+ parcel.writeInt(childIdsSize);
+ for (int i = 0; i < childIdsSize; i++) {
+ parcel.writeInt(childIds.valueAt(i));
+ }
+
+ parcel.writeInt(mBounds.top);
+ parcel.writeInt(mBounds.bottom);
+ parcel.writeInt(mBounds.left);
+ parcel.writeInt(mBounds.right);
+
+ parcel.writeInt(mActions);
+
+ parcel.writeInt(mBooleanProperties);
+
+ TextUtils.writeToParcel(mPackageName, parcel, flags);
+ TextUtils.writeToParcel(mClassName, parcel, flags);
+ TextUtils.writeToParcel(mText, parcel, flags);
+ TextUtils.writeToParcel(mContentDescription, parcel, flags);
+
+ // Since instances of this class are fetched via synchronous i.e. blocking
+ // calls in IPCs and we always recycle as soon as the instance is marshaled.
+ recycle();
+ }
+
+ /**
+ * Creates a new instance from a {@link Parcel}.
+ *
+ * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
+ */
+ private void initFromParcel(Parcel parcel) {
+ if (parcel.readInt() == 1) {
+ mConnection = IAccessibilityServiceConnection.Stub.asInterface(
+ parcel.readStrongBinder());
+ }
+ mSealed = (parcel.readInt() == 1);
+ mAccessibilityViewId = parcel.readInt();
+ mAccessibilityWindowId = parcel.readInt();
+ mParentAccessibilityViewId = parcel.readInt();
+
+ SparseIntArray childIds = mChildAccessibilityIds;
+ final int childrenSize = parcel.readInt();
+ for (int i = 0; i < childrenSize; i++) {
+ final int childId = parcel.readInt();
+ childIds.put(i, childId);
+ }
+
+ mBounds.top = parcel.readInt();
+ mBounds.bottom = parcel.readInt();
+ mBounds.left = parcel.readInt();
+ mBounds.right = parcel.readInt();
+
+ mActions = parcel.readInt();
+
+ mBooleanProperties = parcel.readInt();
+
+ mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ }
+
+ /**
+ * Clears the state of this instance.
+ */
+ private void clear() {
+ mSealed = false;
+ mConnection = null;
+ mAccessibilityViewId = View.NO_ID;
+ mParentAccessibilityViewId = View.NO_ID;
+ mChildAccessibilityIds.clear();
+ mBounds.set(0, 0, 0, 0);
+ mBooleanProperties = 0;
+ mPackageName = null;
+ mClassName = null;
+ mText = null;
+ mContentDescription = null;
+ mActions = 0;
+ }
+
+ /**
+ * Gets the human readable action symbolic name.
+ *
+ * @param action The action.
+ * @return The symbolic name.
+ */
+ private static String getActionSymbolicName(int action) {
+ SparseArray<String> actionSymbolicNames = sActionSymbolicNames;
+ if (actionSymbolicNames == null) {
+ actionSymbolicNames = sActionSymbolicNames = new SparseArray<String>();
+ actionSymbolicNames.put(ACTION_FOCUS, "ACTION_FOCUS");
+ actionSymbolicNames.put(ACTION_CLEAR_FOCUS, "ACTION_UNFOCUS");
+ actionSymbolicNames.put(ACTION_SELECT, "ACTION_SELECT");
+ actionSymbolicNames.put(ACTION_CLEAR_SELECTION, "ACTION_UNSELECT");
+ }
+ return actionSymbolicNames.get(action);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mAccessibilityViewId;
+ result = prime * result + mAccessibilityWindowId;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(super.toString());
+
+ if (DEBUG) {
+ builder.append("; accessibilityId: " + mAccessibilityViewId);
+ builder.append("; parentAccessibilityId: " + mParentAccessibilityViewId);
+ SparseIntArray childIds = mChildAccessibilityIds;
+ builder.append("; childAccessibilityIds: [");
+ for (int i = 0, count = childIds.size(); i < count; i++) {
+ builder.append(childIds.valueAt(i));
+ if (i < count - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append("]");
+ }
+
+ builder.append("; bounds: " + mBounds);
+
+ builder.append("; packageName: ").append(mPackageName);
+ builder.append("; className: ").append(mClassName);
+ builder.append("; text: ").append(mText);
+ builder.append("; contentDescription: ").append(mContentDescription);
+
+ builder.append("; checkable: ").append(isCheckable());
+ builder.append("; checked: ").append(isChecked());
+ builder.append("; focusable: ").append(isFocusable());
+ builder.append("; focused: ").append(isFocused());
+ builder.append("; selected: ").append(isSelected());
+ builder.append("; clickable: ").append(isClickable());
+ builder.append("; longClickable: ").append(isLongClickable());
+ builder.append("; enabled: ").append(isEnabled());
+ builder.append("; password: ").append(isPassword());
+
+ builder.append("; [");
+
+ for (int actionBits = mActions; actionBits != 0;) {
+ final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
+ actionBits &= ~action;
+ builder.append(getActionSymbolicName(action));
+ if (actionBits != 0) {
+ builder.append(", ");
+ }
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+ /**
+ * @see Parcelable.Creator
+ */
+ public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
+ new Parcelable.Creator<AccessibilityNodeInfo>() {
+ public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ info.initFromParcel(parcel);
+ return info;
+ }
+
+ public AccessibilityNodeInfo[] newArray(int size) {
+ return new AccessibilityNodeInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 7819b17..4bf03a7 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -38,13 +38,14 @@ public class AccessibilityRecord {
private static final int PROPERTY_PASSWORD = 0x00000004;
private static final int PROPERTY_FULL_SCREEN = 0x00000080;
+ // Housekeeping
private static final int MAX_POOL_SIZE = 10;
private static final Object sPoolLock = new Object();
private static AccessibilityRecord sPool;
private static int sPoolSize;
-
private AccessibilityRecord mNext;
private boolean mIsInPool;
+ private boolean mSealed;
protected int mBooleanProperties;
protected int mCurrentItemIndex;
@@ -68,6 +69,26 @@ public class AccessibilityRecord {
}
/**
+ * Initialize this record from another one.
+ *
+ * @param record The to initialize from.
+ */
+ void init(AccessibilityRecord record) {
+ mSealed = record.isSealed();
+ mBooleanProperties = record.mBooleanProperties;
+ mCurrentItemIndex = record.mCurrentItemIndex;
+ mItemCount = record.mItemCount;
+ mFromIndex = record.mFromIndex;
+ mAddedCount = record.mAddedCount;
+ mRemovedCount = record.mRemovedCount;
+ mClassName = record.mClassName;
+ mContentDescription = record.mContentDescription;
+ mBeforeText = record.mBeforeText;
+ mParcelableData = record.mParcelableData;
+ mText.addAll(record.mText);
+ }
+
+ /**
* Gets if the source is checked.
*
* @return True if the view is checked, false otherwise.
@@ -80,8 +101,11 @@ public class AccessibilityRecord {
* Sets if the source is checked.
*
* @param isChecked True if the view is checked, false otherwise.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setChecked(boolean isChecked) {
+ enforceNotSealed();
setBooleanProperty(PROPERTY_CHECKED, isChecked);
}
@@ -98,8 +122,11 @@ public class AccessibilityRecord {
* Sets if the source is enabled.
*
* @param isEnabled True if the view is enabled, false otherwise.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setEnabled(boolean isEnabled) {
+ enforceNotSealed();
setBooleanProperty(PROPERTY_ENABLED, isEnabled);
}
@@ -116,27 +143,33 @@ public class AccessibilityRecord {
* Sets if the source is a password field.
*
* @param isPassword True if the view is a password field, false otherwise.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setPassword(boolean isPassword) {
+ enforceNotSealed();
setBooleanProperty(PROPERTY_PASSWORD, isPassword);
}
/**
- * Sets if the source is taking the entire screen.
+ * Gets if the source is taking the entire screen.
*
- * @param isFullScreen True if the source is full screen, false otherwise.
+ * @return True if the source is full screen, false otherwise.
*/
- public void setFullScreen(boolean isFullScreen) {
- setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
+ public boolean isFullScreen() {
+ return getBooleanProperty(PROPERTY_FULL_SCREEN);
}
/**
- * Gets if the source is taking the entire screen.
+ * Sets if the source is taking the entire screen.
*
- * @return True if the source is full screen, false otherwise.
+ * @param isFullScreen True if the source is full screen, false otherwise.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
- public boolean isFullScreen() {
- return getBooleanProperty(PROPERTY_FULL_SCREEN);
+ public void setFullScreen(boolean isFullScreen) {
+ enforceNotSealed();
+ setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
}
/**
@@ -152,8 +185,11 @@ public class AccessibilityRecord {
* Sets the number of items that can be visited.
*
* @param itemCount The number of items.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setItemCount(int itemCount) {
+ enforceNotSealed();
mItemCount = itemCount;
}
@@ -170,8 +206,11 @@ public class AccessibilityRecord {
* Sets the index of the source in the list of items that can be visited.
*
* @param currentItemIndex The current item index.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setCurrentItemIndex(int currentItemIndex) {
+ enforceNotSealed();
mCurrentItemIndex = currentItemIndex;
}
@@ -188,8 +227,11 @@ public class AccessibilityRecord {
* Sets the index of the first character of the changed sequence.
*
* @param fromIndex The index of the first character.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setFromIndex(int fromIndex) {
+ enforceNotSealed();
mFromIndex = fromIndex;
}
@@ -206,8 +248,11 @@ public class AccessibilityRecord {
* Sets the number of added characters.
*
* @param addedCount The number of added characters.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setAddedCount(int addedCount) {
+ enforceNotSealed();
mAddedCount = addedCount;
}
@@ -224,8 +269,11 @@ public class AccessibilityRecord {
* Sets the number of removed characters.
*
* @param removedCount The number of removed characters.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setRemovedCount(int removedCount) {
+ enforceNotSealed();
mRemovedCount = removedCount;
}
@@ -242,8 +290,11 @@ public class AccessibilityRecord {
* Sets the class name of the source.
*
* @param className The lass name.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setClassName(CharSequence className) {
+ enforceNotSealed();
mClassName = className;
}
@@ -270,8 +321,11 @@ public class AccessibilityRecord {
* Sets the text before a change.
*
* @param beforeText The text before the change.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setBeforeText(CharSequence beforeText) {
+ enforceNotSealed();
mBeforeText = beforeText;
}
@@ -288,8 +342,11 @@ public class AccessibilityRecord {
* Sets the description of the source.
*
* @param contentDescription The description.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setContentDescription(CharSequence contentDescription) {
+ enforceNotSealed();
mContentDescription = contentDescription;
}
@@ -306,18 +363,71 @@ public class AccessibilityRecord {
* Sets the {@link Parcelable} data of the event.
*
* @param parcelableData The parcelable data.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
*/
public void setParcelableData(Parcelable parcelableData) {
+ enforceNotSealed();
mParcelableData = parcelableData;
}
/**
+ * Sets if this instance is sealed.
+ *
+ * @param sealed Whether is sealed.
+ *
+ * @hide
+ */
+ public void setSealed(boolean sealed) {
+ mSealed = sealed;
+ }
+
+ /**
+ * Gets if this instance is sealed.
+ *
+ * @return Whether is sealed.
+ *
+ * @hide
+ */
+ public boolean isSealed() {
+ return mSealed;
+ }
+
+ /**
+ * Enforces that this instance is sealed.
+ *
+ * @throws IllegalStateException If this instance is not sealed.
+ *
+ * @hide
+ */
+ protected void enforceSealed() {
+ if (!isSealed()) {
+ throw new IllegalStateException("Cannot perform this "
+ + "action on a not sealed instance.");
+ }
+ }
+
+ /**
+ * Enforces that this instance is not sealed.
+ *
+ * @throws IllegalStateException If this instance is sealed.
+ *
+ * @hide
+ */
+ protected void enforceNotSealed() {
+ if (isSealed()) {
+ throw new IllegalStateException("Cannot perform this "
+ + "action on an sealed instance.");
+ }
+ }
+
+ /**
* Gets the value of a boolean property.
*
* @param property The property.
* @return The value.
*/
- public boolean getBooleanProperty(int property) {
+ private boolean getBooleanProperty(int property) {
return (mBooleanProperties & property) == property;
}
@@ -337,6 +447,19 @@ public class AccessibilityRecord {
/**
* Returns a cached instance if such is available or a new one is
+ * instantiated. The instance is initialized with data from the
+ * given record.
+ *
+ * @return An instance.
+ */
+ public static AccessibilityRecord obtain(AccessibilityRecord record) {
+ AccessibilityRecord clone = AccessibilityRecord.obtain();
+ clone.init(record);
+ return clone;
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
* instantiated.
*
* @return An instance.
@@ -379,8 +502,11 @@ public class AccessibilityRecord {
/**
* Clears the state of this instance.
+ *
+ * @hide
*/
protected void clear() {
+ mSealed = false;
mBooleanProperties = 0;
mCurrentItemIndex = INVALID_POSITION;
mItemCount = 0;
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
new file mode 100644
index 0000000..77dcd07
--- /dev/null
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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 android.view.accessibility;
+
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+
+/**
+ * Interface for interaction between the AccessibilityManagerService
+ * and the ViewRoot in a given window.
+ *
+ * @hide
+ */
+oneway interface IAccessibilityInteractionConnection {
+
+ void findAccessibilityNodeInfoByAccessibilityId(int accessibilityViewId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback);
+
+ void findAccessibilityNodeInfoByViewId(int id, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback);
+
+ void findAccessibilityNodeInfosByViewText(String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback);
+
+ void performAccessibilityAction(int accessibilityId, int action, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback);
+}
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
new file mode 100644
index 0000000..9c5e8dc
--- /dev/null
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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 android.view.accessibility;
+
+import android.view.accessibility.AccessibilityNodeInfo;
+import java.util.List;
+
+/**
+ * Callback for specifying the result for an asynchronous request made
+ * via calling a method on IAccessibilityInteractionConnectionCallback.
+ *
+ * @hide
+ */
+oneway interface IAccessibilityInteractionConnectionCallback {
+
+ void setFindAccessibilityNodeInfoResult(in AccessibilityNodeInfo info, int interactionId);
+
+ void setFindAccessibilityNodeInfosResult(in List<AccessibilityNodeInfo> infos,
+ int interactionId);
+
+ void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
+}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 6b2aae2..b14f02a 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -18,8 +18,13 @@
package android.view.accessibility;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.accessibilityservice.IEventListener;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityManagerClient;
+import android.view.IWindow;
/**
* Interface implemented by the AccessibilityManagerService called by
@@ -38,4 +43,11 @@ interface IAccessibilityManager {
List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType);
void interrupt();
+
+ int addAccessibilityInteractionConnection(IWindow windowToken,
+ in IAccessibilityInteractionConnection connection);
+
+ void removeAccessibilityInteractionConnection(IWindow windowToken);
+
+ IAccessibilityServiceConnection registerEventListener(IEventListener client);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9e61ecf..a68ca60 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6503,6 +6503,8 @@ public class WebView extends AbsoluteLayout
// arrow key events, not trackball events, from one child to the next
private boolean mMapTrackballToArrowKeys = true;
+ private DrawData mDelaySetPicture;
+
public void setMapTrackballToArrowKeys(boolean setMap) {
checkThread();
mMapTrackballToArrowKeys = setMap;
@@ -7912,7 +7914,8 @@ public class WebView extends AbsoluteLayout
// after WebView's destroy() is called, skip handling messages.
return;
}
- if (mBlockWebkitViewMessages) {
+ if (mBlockWebkitViewMessages
+ && msg.what != WEBCORE_INITIALIZED_MSG_ID) {
// Blocking messages from webkit
return;
}
@@ -8060,6 +8063,10 @@ public class WebView extends AbsoluteLayout
BrowserFrame.DRAWABLEDIR, mContext);
AssetManager am = mContext.getAssets();
nativeCreate(msg.arg1, drawableDir, am);
+ if (mDelaySetPicture != null) {
+ setNewPicture(mDelaySetPicture);
+ mDelaySetPicture = null;
+ }
break;
case UPDATE_TEXTFIELD_TEXT_MSG_ID:
// Make sure that the textfield is currently focused
@@ -8371,6 +8378,15 @@ public class WebView extends AbsoluteLayout
}
void setNewPicture(final WebViewCore.DrawData draw) {
+ if (mNativeClass == 0) {
+ if (mDelaySetPicture != null) {
+ throw new IllegalStateException(
+ "Tried to setNewPicture with a delay picture already set! (memory leak)");
+ }
+ // Not initialized yet, delay set
+ mDelaySetPicture = draw;
+ return;
+ }
WebViewCore.ViewState viewState = draw.mViewState;
boolean isPictureAfterFirstLayout = viewState != null;
setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 4ee16e7..6b498fe 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -115,7 +115,7 @@ public class FrameLayout extends ViewGroup {
}
/**
- * Describes how the foreground is positioned. Defaults to BEFORE and TOP.
+ * Describes how the foreground is positioned. Defaults to START and TOP.
*
* @param foregroundGravity See {@link android.view.Gravity}
*
@@ -125,7 +125,7 @@ public class FrameLayout extends ViewGroup {
public void setForegroundGravity(int foregroundGravity) {
if (mForegroundGravity != foregroundGravity) {
if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- foregroundGravity |= Gravity.BEFORE;
+ foregroundGravity |= Gravity.START;
}
if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index f843574..3876735 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -116,10 +116,10 @@ public class LinearLayout extends ViewGroup {
equals = Gravity.LEFT, name = "LEFT"),
@ViewDebug.FlagToString(mask = Gravity.RIGHT,
equals = Gravity.RIGHT, name = "RIGHT"),
- @ViewDebug.FlagToString(mask = Gravity.BEFORE,
- equals = Gravity.BEFORE, name = "BEFORE"),
- @ViewDebug.FlagToString(mask = Gravity.AFTER,
- equals = Gravity.AFTER, name = "AFTER"),
+ @ViewDebug.FlagToString(mask = Gravity.START,
+ equals = Gravity.START, name = "START"),
+ @ViewDebug.FlagToString(mask = Gravity.END,
+ equals = Gravity.END, name = "END"),
@ViewDebug.FlagToString(mask = Gravity.CENTER_VERTICAL,
equals = Gravity.CENTER_VERTICAL, name = "CENTER_VERTICAL"),
@ViewDebug.FlagToString(mask = Gravity.FILL_VERTICAL,
@@ -135,7 +135,7 @@ public class LinearLayout extends ViewGroup {
@ViewDebug.FlagToString(mask = Gravity.RELATIVE_HORIZONTAL_DIRECTION,
equals = Gravity.RELATIVE_HORIZONTAL_DIRECTION, name = "RELATIVE")
})
- private int mGravity = Gravity.BEFORE | Gravity.TOP;
+ private int mGravity = Gravity.START | Gravity.TOP;
@ViewDebug.ExportedProperty(category = "measurement")
private int mTotalLength;
@@ -1649,7 +1649,7 @@ public class LinearLayout extends ViewGroup {
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- gravity |= Gravity.BEFORE;
+ gravity |= Gravity.START;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
@@ -1742,8 +1742,8 @@ public class LinearLayout extends ViewGroup {
@ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
@ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
@ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
- @ViewDebug.IntToString(from = Gravity.BEFORE, to = "BEFORE"),
- @ViewDebug.IntToString(from = Gravity.AFTER, to = "AFTER"),
+ @ViewDebug.IntToString(from = Gravity.START, to = "START"),
+ @ViewDebug.IntToString(from = Gravity.END, to = "END"),
@ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index acd8539..a4771d5 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -16,6 +16,15 @@
package android.widget;
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -32,14 +41,6 @@ import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.SortedSet;
-import java.util.TreeSet;
import static android.util.Log.d;
@@ -222,7 +223,7 @@ public class RelativeLayout extends ViewGroup {
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- gravity |= Gravity.BEFORE;
+ gravity |= Gravity.START;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
@@ -1440,6 +1441,7 @@ public class RelativeLayout extends ViewGroup {
);
private Node mNext;
+ private boolean mIsPooled;
public void setNextPoolable(Node element) {
mNext = element;
@@ -1449,6 +1451,14 @@ public class RelativeLayout extends ViewGroup {
return mNext;
}
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
+
static Node acquire(View view) {
final Node node = sPool.acquire();
node.view = view;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 35e78fb..eba9d37 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -113,6 +113,7 @@ import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
@@ -2094,7 +2095,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public void setGravity(int gravity) {
if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- gravity |= Gravity.BEFORE;
+ gravity |= Gravity.START;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.TOP;
@@ -7647,7 +7648,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
protected int computeVerticalScrollExtent() {
return getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
}
-
+
+ @Override
+ public void findViewsWithText(ArrayList<View> outViews, CharSequence text) {
+ CharSequence thisText = getText();
+ if (TextUtils.isEmpty(thisText)) {
+ return;
+ }
+ if (thisText.toString().toLowerCase().contains(text)) {
+ outViews.add(this);
+ }
+ }
+
public enum BufferType {
NORMAL, SPANNABLE, EDITABLE,
}
@@ -7899,6 +7911,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
event.setPassword(isPassword);
}
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+
+ final boolean isPassword = hasPasswordTransformationMethod();
+ if (!isPassword) {
+ info.setText(getText());
+ }
+ info.setPassword(isPassword);
+ }
+
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
int fromIndex, int removedCount, int addedCount) {
AccessibilityEvent event =
@@ -10005,7 +10028,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mSelectAllOnFocus = false;
- private int mGravity = Gravity.TOP | Gravity.BEFORE;
+ private int mGravity = Gravity.TOP | Gravity.START;
private boolean mHorizontallyScrolling;
private int mAutoLinkMask;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index c41b2cb..b9948fe 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -16,8 +16,6 @@
package com.android.internal.view;
-import android.content.ClipData;
-import android.content.ClipDescription;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
@@ -26,8 +24,6 @@ import android.os.RemoteException;
import android.view.DragEvent;
import android.view.IWindow;
import android.view.IWindowSession;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
public class BaseIWindow extends IWindow.Stub {
private IWindowSession mSession;
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 4a09232..942aa8a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -755,32 +755,46 @@ public:
jfloat x, jfloat y, int flags, SkPaint* paint) {
jint count = end - start;
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, textArray, start, count, end, flags);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = gTextLayoutCache.getValue(paint, textArray, start, count, end, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
+#else
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, textArray, start, count, end, flags);
+#endif
+
#if DEBUG_GLYPHS
logGlyphs(value);
#endif
- doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
- x, y, flags, paint);
+
+ doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
+ x, y, flags, paint);
}
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
int start, int count, int contextCount,
jfloat x, jfloat y, int flags, SkPaint* paint) {
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, textArray, start, count, contextCount, flags);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = gTextLayoutCache.getValue(paint, textArray, start, count, contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
+#else
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, textArray, start, count, contextCount, flags);
+#endif
+
#if DEBUG_GLYPHS
logGlyphs(value);
#endif
+
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
x, y, flags, paint);
}
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 46e6c2b..7e89a37 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -254,21 +254,21 @@ void TextLayout::drawTextRun(SkPaint* paint, const jchar* chars,
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+ sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
// Return advances from the cache. Compute them if needed
- sp<TextLayoutCacheValue> layout = gTextLayoutCache.getValue(
+ value = gTextLayoutCache.getValue(
paint, chars, start, count, contextCount, dirFlags);
- if (layout != NULL) {
+#else
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, chars, start, count, contextCount, dirFlags);
+#endif
+ if (value != NULL) {
if (resultAdvances != NULL) {
- memcpy(resultAdvances, layout->getAdvances(), layout->getAdvancesCount() * sizeof(jfloat));
+ memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
}
- resultTotalAdvance = layout->getTotalAdvance();
+ resultTotalAdvance = value->getTotalAdvance();
}
-#else
- // Compute advances and return them
- TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, start, count, contextCount,
- dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL );
-#endif
}
void TextLayout::getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint start,
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index e5c2848..0960b25 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -38,18 +38,7 @@
#include <grp.h>
#include <pwd.h>
#include <signal.h>
-
-/* desktop Linux needs a little help with gettid() */
-#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
-#define __KERNEL__
-# include <linux/unistd.h>
-#ifdef _syscall0
-_syscall0(pid_t,gettid)
-#else
-pid_t gettid() { return syscall(__NR_gettid);}
-#endif
-#undef __KERNEL__
-#endif
+#include <unistd.h>
#define POLICY_DEBUG 0
#define GUARD_THREAD_PRIORITY 0
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 31988f7..57a97bd 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -438,12 +438,17 @@ static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
#if RTL_USE_HARFBUZZ
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, text, 0, count, count, flags);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = gTextLayoutCache.getValue(paint, text, 0, count, count, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
+#else
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, text, 0, count, count, flags);
+#endif
#if DEBUG_GLYPHS
logGlyphs(value);
#endif
@@ -466,12 +471,17 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
#if RTL_USE_HARFBUZZ
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, text, start, count, contextCount, flags);
+ sp<TextLayoutCacheValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = gTextLayoutCache.getValue(paint, text, start, count, contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
+#else
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, text, start, count, contextCount, flags);
+#endif
#if DEBUG_GLYPHS
logGlyphs(value);
#endif
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 110268e..3efb83c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -677,6 +677,14 @@
android:label="@string/permlab_dump"
android:description="@string/permdesc_dump" />
+ <!-- Allows an application to retrieve the content of the active window
+ An active window is the window that has fired an accessibility event. -->
+ <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_retrieve_window_content"
+ android:description="@string/permdesc_retrieve_window_content" />
+
<!-- Allows an application to open windows using the type
{@link android.view.WindowManager.LayoutParams#TYPE_SYSTEM_ALERT},
shown on top of all other applications. Very few applications
diff --git a/core/res/res/drawable-hdpi/pointer_arrow.png b/core/res/res/drawable-hdpi/pointer_arrow.png
new file mode 100644
index 0000000..fbd187c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_arrow_icon.xml b/core/res/res/drawable-hdpi/pointer_arrow_icon.xml
new file mode 100644
index 0000000..2f5676f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_arrow_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+ android:bitmap="@drawable/pointer_arrow"
+ android:hotSpotX="6"
+ android:hotSpotY="6" />
diff --git a/core/res/res/drawable-hdpi/pointer_spot_anchor.png b/core/res/res/drawable-hdpi/pointer_spot_anchor.png
new file mode 100644
index 0000000..d7aca36
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_anchor.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml b/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml
new file mode 100644
index 0000000..2222b8e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_anchor_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+ android:bitmap="@drawable/pointer_spot_anchor"
+ android:hotSpotX="33"
+ android:hotSpotY="33" />
diff --git a/core/res/res/drawable-hdpi/pointer_spot_hover.png b/core/res/res/drawable-hdpi/pointer_spot_hover.png
new file mode 100644
index 0000000..5041aa3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_hover.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml b/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml
new file mode 100644
index 0000000..dc62a69
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_hover_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+ android:bitmap="@drawable/pointer_spot_hover"
+ android:hotSpotX="33"
+ android:hotSpotY="33" />
diff --git a/core/res/res/drawable-hdpi/pointer_spot_touch.png b/core/res/res/drawable-hdpi/pointer_spot_touch.png
new file mode 100644
index 0000000..64a42a1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_touch.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml b/core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml
new file mode 100644
index 0000000..4bffee6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pointer_spot_touch_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+ android:bitmap="@drawable/pointer_spot_touch"
+ android:hotSpotX="24"
+ android:hotSpotY="24" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 38b62d4..cab43ac 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -412,6 +412,10 @@
<!-- no translation found for permlab_setOrientation (3365947717163866844) -->
<skip />
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Laat \'n program toe om die skerm te enige tyd te draai. Behoort vir gewone programme nooit nodig te wees nie."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<!-- no translation found for permlab_signalPersistentProcesses (4255467255488653854) -->
<skip />
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Laat program toe om te versoek dat die voorsiende materiaal aan alle aanhoudende prosesse gestuur word."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9c22f0e..b97bc7a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -396,6 +396,10 @@
<!-- no translation found for permlab_setOrientation (3365947717163866844) -->
<skip />
<string name="permdesc_setOrientation" msgid="6335814461615851863">"ትግበራው በማንኛውም ሰዓት የማያንማሽከርከሪያለመለወጥ ይፈቅዳል።ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<!-- no translation found for permlab_signalPersistentProcesses (4255467255488653854) -->
<skip />
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"ትግበራዎች ለሁሉም ተከታታይ ሂደቶች ልከው የሚያቀርቧቸው ሲግናሎችን ለመጠየቅ ይፈቅዳል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c9454d3..8d5ecb8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"للسماح لتطبيق ما بتغيير تدوير الشاشة في أي وقت. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"إرسال إشارات Linux للتطبيقات"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"للسماح للتطبيق بطلب إرسال الإشارة المزوّدة لجميع العمليات المستمرة."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"تشغيل التطبيق دائمًا"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 70eb79a..b43b50f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Разрешава на приложението да променя ориентацията на екрана по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"изпращане на сигнали от Linux до приложенията"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Разрешава на приложението да подаде заявка предоставеният сигнал да се изпрати до всички постоянни процеси."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"задаване на постоянно изпълнение на приложението"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 45201c1..2947b93 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet al titular enviar intencions a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet a una aplicació canviar el gir de la pantalla en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar senyals Linux a les aplicacions"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet a l\'aplicació sol·licitar que el senyal subministrat s\'enviï a tots els processos persistents."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"fer que l\'aplicació s\'executi sempre"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f88e381..92deaca 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění nikdy neměly požadovat."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odeslání signálů Linux aplikacím"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spuštění aplikace"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index c6946d4..a3149a2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillader brugeren at sende hensigter til en enhedsadministrator. Bør aldrig være nødvendigt for almindelige programmer."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillader, at et program ændrer rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux-signaler til programmer"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillader, at programmet kan anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"lad altid programmet køre"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ffef226..b6b6be5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Anwendungen benötigt werden."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index bf1d432..a5e13f1 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Επιτρέπει σε μια εφαρμογή την αλλαγή της περιστροφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"αποστολή σημάτων Linux σε εφαρμογές"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Επιτρέπει σε μια εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"η εφαρμογή να εκτελείται συνεχώς"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b0e77ba..d5ef98b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Allows the holder to send intents to a device administrator. Should never be needed for normal applications."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux signals to applications"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Allows application to request that the supplied signal be sent to all persistent processes."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"make application always run"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index fb97c4a..3cb61e4 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que el propietario envíe sus intentos a un administrador de dispositivos. No se necesita para las aplicaciones normales."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales de Linux a las aplicaciones"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que siempre se ejecute la aplicación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index a1e3a54..9db80ca 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite enviar intentos a un administrador de dispositivos. Este permiso nunca debería ser necesario para las aplicaciones normales."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales Linux a aplicaciones"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que la aplicación se ejecute siempre"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 00d173d..3fcb21d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"به نگهدارنده اجازه می دهد مفاد را به یک سرپرست دستگاه ارسال کند. هرگز برای برنامه های معمولی مورد نیاز نیست."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"به یک برنامه کاربردی اجازه می دهد چرخش صفحه را در هر زمانی تغییر دهد. هرگز برای برنامه های معمولی مورد نیاز نیست."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"ارسال سیگنال های Linux برای برنامه ها"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"به برنامه کاربردی اجازه می دهد درخواست کند که سیگنال ارائه شده را به تمام فرایندهای ثابت ارسال کند."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"برنامه همیشه اجرا شود"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 2d3bf48..70e5ff7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Antaa sovelluksen lähettää kyselyitä laitteen järjestelmänvalvojalle. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Antaa sovelluksen vaihtaa näytön suuntaa milloin tahansa. Ei tavallisten sovelluksien käyttöön."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"lähettää sovelluksiin Linux-signaaleja"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Antaa sovelluksen pyytää, että signaali lähetetään kaikille kiinteille prosesseille."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"aseta sovellus olemaan jatkuvasti käynnissä"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3f3eb93..c618edf 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"Exécution de l\'application en continu"</string>
@@ -449,7 +453,7 @@
<string name="permlab_nfc" msgid="4423351274757876953">"contrôler la communication en champ proche"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permet à une application de communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
<string name="permlab_vpn" msgid="8345800584532175312">"intercepter et modifier l\'ensemble du trafic réseau"</string>
- <string name="permdesc_vpn" msgid="5617893078989944219">"Permet à une application d\'intercepter et d\'inspecter l\'ensemble du trafic réseau, par exemple pour établir une connexion VPN. Des applications malveillantes sont susceptibles de surveiller, rediriger ou modifier les paquets réseau à votre insu."</string>
+ <string name="permdesc_vpn" msgid="5617893078989944219">"Permet à une application d\'intercepter et de contrôler l\'ensemble du trafic réseau, par exemple pour établir une connexion VPN. Des applications malveillantes sont susceptibles de surveiller, rediriger ou modifier les paquets réseau à votre insu."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 773a8f3..f17a272 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Nositelju omogućuje slanje namjera administratoru uređaja. Nikad ne bi trebalo koristiti za uobičajene aplikacije."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Aplikaciji omogućuje promjenu rotacije zaslona u svakom trenutku. Nikad ne bi trebalo koristiti za uobičajene aplikacije."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"slanje Linux signala u aplikaciju"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Aplikacijama omogućuje traženje zahtjeva da se dobiveni signal pošalje na sve trajne postupke."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"uvijek pokrenuta aplikacija"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 09dd648..0c2aef3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Lehetővé teszi a használó számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Lehetővé teszi egy alkalmazás számára a képernyő elforgatásának módosítását. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux jelek küldése alkalmazásoknak"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lehetővé teszi az alkalmazás számára, hogy a megadott jelet elküldje az összes állandó folyamatnak."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"alkalmazások folyamatos futtatása"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b2f3af8..00e2dd4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak diperlukan untuk aplikasi normal."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Mengizinkan aplikasi mengubah rotasi layar kapan saja. Tidak diperlukan untuk aplikasi normal."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"kirim sinyal Linux ke aplikasi"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Mengizinkan aplikasi meminta sinyal yang diberikan untuk dikirimkan ke semua proses yang ada."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"jadikan aplikasi selalu berjalan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 19d317e..0d78861 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non deve mai essere necessaria per le normali applicazioni."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"invio segnali Linuz alle applicazioni"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"esecuzione permanente delle applicazioni"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 4aba678..6b50982 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"מאפשר למשתמש לשלוח כוונות למנהל התקן. לא אמור להידרש לעולם ביישומים רגילים."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"מאפשר ליישום לשנות את סיבוב המסך בכל עת. לא אמור להידרש לעולם ביישומים רגילים."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"שלח אותות Linux ליישומים"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"מאפשר ליישום לבקש שהאות המסופק יישלח לכל התהליכים המתמשכים."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"הגדר את היישום לפעול תמיד"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e078274..bdad7b6 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリケーションでは不要です。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linuxのシグナルをアプリケーションに送信"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"受信した電波を継続プロセスに送信することをアプリケーションに許可します。"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"アプリケーションを常に実行する"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4d1778e..5a3584a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"보유자가 기기 관리자에게 인텐트를 보낼 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"애플리케이션이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"애플리케이션에 Linux 시그널 보내기"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"애플리케이션이 제공된 시그널을 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"애플리케이션이 항상 실행되도록 설정"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 5b7ef8c..eab92c6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Leidžia savininkui siųsti tikslus įrenginio administratoriui. Neturėtų reikėti įprastose programose."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Leidžia programai bet kuriuo metu keisti ekrano sukimą. Neturėtų reikėti įprastoms programoms."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"programoms siųsti „Linux“ signalus"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Leidžia programai pateikti užklausą, kad teikiamas signalas būtų siunčiamas visiems nuolatiniams procesams."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"nustatyti, kad programa būtų visada paleista"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 2aa49ca..5c5525c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Ļauj īpašniekam sūtīt nolūkus ierīces administratoram. Nekad nav nepieciešams parastajām lietojumprogrammām."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Ļauj lietojumprogrammai jebkurā brīdī mainīt ekrāna pagriešanas iestatījumu. Parastajām lietojumprogrammām nekad nav nepieciešama."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sūtīt Linux signālus uz lietojumprogrammām"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ļauj lietojumprogrammai pieprasīt, lai piegādātais signāls tiktu sūtīts uz visiem pastāvīgajiem procesiem."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"likt lietojumprogrammai vienmēr darboties"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e82fc10..6b0e18e 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -297,6 +297,10 @@
<skip />
<string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Membolehkan aplikasi untuk menukar putaran skrin pada bila-bila masa. Tidak seharusnya diperlukan untuk aplikasi biasa."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"hantar isyarat Linux kepada aplikasi"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Membenarkan aplikasi meminta isyarat yang dibekalkan dihantar kepada semua proses gigih."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"buatkan aplikasi sentiasa berjalan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 02a414c..2413685 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillater innehaveren å sende hensikter til enhetsadministrator. Bør aldri være nødvendig for normale programmer."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sende Linux-signaler til applikasjoner"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"forbli kjørende"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ad214bf..dbb7e98 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Staat de houder toe intenties te verzenden naar een apparaatbeheerder. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een app op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale apps."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"app altijd laten uitvoeren"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ed877bb..36d3cdd 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Zezwala posiadaczowi na wysyłanie informacji o zamiarach do administratora urządzenia. Opcja nie powinna być nigdy potrzebna w przypadku zwykłych aplikacji."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 7ba9ad0..9cec4b6 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite ao titular enviar intenções para um administrador do dispositivo. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais Linux para aplicações"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"fazer com que a aplicação seja sempre executada"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 750a751..57737c9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que o detentor envie tentativas ao administrador de um dispositivo. Não é necessário para aplicativos normais."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais de Linux para os aplicativos"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"executar sempre o aplicativo"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index ff2eecb..60f6049 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -275,6 +275,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permetta al possessur da trametter intenziuns a l\'administratur dal apparat periferic. Betg previs per applicaziuns normalas."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"midar l\'orientaziun dal visur"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permetta a l\'applicaziun da midar da tut temp la orientaziun dal visur. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"trametter signals Linux a las applicaziuns"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permetta a l\'applicaziun da pretender ch\'il signal furnì vegnia tramess a tut ils process persistents."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"exequir permanentamain applicaziuns"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7fb4f7318..1961903 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite unei aplicaţii să modifice rotaţia ecranului în orice moment. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"trimitere semnale Linux către aplicaţii"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite aplicaţiei să solicite trimiterea semnalului furnizat către toate procesele persistente."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"rulare întotdeauna a aplicaţiei"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fe5815f..83dc30f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Позволяет владельцу отправлять целевые значения администратору устройства. Никогда не используется обычными приложениями."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"изменять ориентацию экрана"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Позволяет приложению изменять ориентацию экрана в любое время. Не требуется для обычных приложений."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"отправлять приложениям сигналы Linux"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Позволяет приложению направлять запрос на передачу предоставленного сигнала всем постоянным процессам."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"запускать постоянную работу приложения"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d7d9725..3439f59 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto oprávnenie nemali nikdy požadovať."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikácii kedykoľvek zmeniť orientáciu obrazovky. Bežné aplikácie by toto nastavenie nemali vôbec využívať."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odoslanie signálov systému Linux aplikáciám"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikácii vyžiadať zaslanie poskytnutého signálu všetkým trvalým procesom."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spustenie aplikácie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cbb097b..cd4cd07 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Dovoljuje lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Dovoljuje, da program kadar koli spremeni smer sukanja zaslona. Tega nikoli ni treba uporabiti za navadne programe."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"pošiljanje signalov Linuxa programom"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Dovoljuje, da program zahteva, da je posredovan signal poslan vsem trajnim procesom."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"neprekinjeno izvajanje programov"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 93faf2f..59329b4 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Омогућава власнику да шаље своје намере администратору уређаја. Обичне апликације никада не би требало да је користе."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Омогућава да апликација у сваком тренутку промени ротацију екрана. Обичне апликације никада не би требало да је користе."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"слање Linux сигнала апликацијама"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Омогућава да апликација захтева да испоручени сигнал буде послат свим трајним процесима."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"омогућавање непрекидне активности апликације"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index c3561d7..a3350e5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga program behöver aldrig göra detta."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till appar"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"se till att programmet alltid körs"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 453f74e..ff1907a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -396,6 +396,10 @@
<!-- no translation found for permlab_setOrientation (3365947717163866844) -->
<skip />
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Huruhusu programu kubadilisha uzungukaji wa skrini wakati wowote. Haipaswi kuhitajika kwa programu za kawaida za kompyuta."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<!-- no translation found for permlab_signalPersistentProcesses (4255467255488653854) -->
<skip />
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Huruhusu programu kuomba kwamba mawimbi yaliyotolewa yatumwe kwa michakato yote isiyokoma."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 54b33f4..be958dc 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"อนุญาตให้ผู้ถือส่งเนื้อหาไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"อนุญาตให้แอปพลิเคชันเปลี่ยนการหมุนหน้าจอได้ตลอดเวลา ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"ส่งสัญญาณ Linux ไปยังแอปพลิเคชัน"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"อนุญาตให้แอปพลิเคชันร้องขอให้ส่งสัญญาณแจ้งไปยังกระบวนการที่ยังทำงานอยู่ทั้งหมด"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"ทำให้แอปพลิเคชันทำงานตลอดเวลา"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9eeac34..b6942a4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Pinapayagan ang holder na magpadala ng mga intensyon sa administrator ng device. Hindi kailanman dapat kailanganin para sa mga normal na application."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Pinapayagan ang isang application na baguhin ang pag-rotate ng screen anumang oras. Hindi kailanman dapat kailanganin para sa mga normal na application."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"magpadala ng mga Linux signal sa mga application"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pinapayagan ang application na hilinging ipadala ang na-supply na signal sa lahat ng mga paulit-ulit na proseso."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"palaging patakbuhin ang mga application"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7f1d3c3..e97d834 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"uygulamalara Linux sinyalleri gönder"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"uygulamayı her zaman çalıştır"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 00e6333..07b11f7 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Дозволяє власнику надсилати цілі адміністратору пристрою. Ніколи не потрібний для звичайних програм."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Дозволяє програмі будь-коли змінювати обертання екрана. Ніколи не потрібний для звичайних програм."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"надсилати сигнали Linux програмам"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Дозволяє програмі подавати запит щодо надсилання наданого сигналу всім постійним процесам."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"збер. програму завжди запущ."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 45c3ad8..cfb53ac 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Cho phép chủ nhân gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Cho phép ứng dụng thay đổi việc xoay màn hình bất kỳ khi nào. Không cần thiết cho các ứng dụng thông thường."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"gửi tín hiệu Linux đến ứng dụng"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Cho phép ứng dụng yêu cầu tín hiệu đã cung cấp được gửi đến tất cả các quá trình liên tục."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"đặt ứng dụng luôn chạy"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f5ee751..b45b346 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"允许持有对象将意向发送到设备管理器。普通的应用程序一律无需此权限。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"允许应用程序随时更改屏幕的旋转方向。普通应用程序从不需要使用此权限。"</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"向应用程序发送 Linux 信号"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允许应用程序请求将所提供的信号发送给所有持久进程。"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"让应用程序始终运行"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1779baf..399a5b0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -265,6 +265,10 @@
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"允許應用程式將調用請求 (intent) 傳送至裝置管理員;一般應用程式不需使用此選項。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"允許應用程式可隨時變更螢幕旋轉方向。一般應用不應使用這項功能。"</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"傳送 Linux 訊號到應用程式"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允許應用程式要求將支援的訊號傳送到所有持續的程序。"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"設定應用程式持續執行"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ad143a7..6f147e7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -396,6 +396,10 @@
<!-- no translation found for permlab_setOrientation (3365947717163866844) -->
<skip />
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Ivumela uhlelo lokusebenza ukushintsha ukujikeleleza kwesikrini nganoma isiphi isikhathi. Ayisoze yadingeka izinhlelo zokusebenza ezivamile."</string>
+ <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
+ <skip />
+ <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) -->
+ <skip />
<!-- no translation found for permlab_signalPersistentProcesses (4255467255488653854) -->
<skip />
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ivumela uhlelo lokusebenza ukucela ukuthi isiginali enikeziwe ithunyelwe kuzo zonke izinqubo eziphikelelayo"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fc14a2a..f9fa51c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -156,6 +156,7 @@
<!-- Regex array of allowable upstream ifaces for tethering - for example if you want
tethering on a new interface called "foo2" add <item>"foo\\d"</item> to the array -->
+ <!-- Interfaces will be prioritized according to the order listed -->
<string-array translatable="false" name="config_tether_upstream_regexs">
</string-array>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8a4b74b..29c23a6 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -562,6 +562,13 @@
never normally need.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_retrieve_window_content">retrieve screen content</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_retrieve_window_content">Allows application to retrieve
+ the content of the active window. Malicious applications may retrieve
+ the entire window content and examine all its text except passwords.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_shutdown">partial shutdown</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_shutdown">Puts the activity manager into a shutdown
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 6084dd2..8e2d925 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -98,6 +98,9 @@
<uses-permission android:name="android.permission.ASEC_RENAME" />
<uses-permission android:name="android.permission.SHUTDOWN" />
+ <!-- accessibility test permissions -->
+ <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
+
<application android:theme="@style/Theme">
<uses-library android:name="android.test.runner" />
<activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
@@ -1225,6 +1228,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.accessibilityservice.InterrogationActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/core/tests/coretests/res/layout/interrogation_activity.xml b/core/tests/coretests/res/layout/interrogation_activity.xml
new file mode 100644
index 0000000..28d965b
--- /dev/null
+++ b/core/tests/coretests/res/layout/interrogation_activity.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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:id="@+id/root"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ >
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button1"
+ />
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button2"
+ />
+ <Button
+ android:id="@+id/button3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button3"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <Button
+ android:id="@+id/button4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button4"
+ />
+ <Button
+ android:id="@+id/button5"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button5"
+ />
+ <Button
+ android:id="@+id/button6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button6"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <Button
+ android:id="@+id/button7"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button7"
+ />
+ <Button
+ android:id="@+id/button8"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button8"
+ />
+ <Button
+ android:id="@+id/button9"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button9"
+ />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 807386a..f51b08e 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -117,4 +117,16 @@
<string name="searchable_label">SearchManager Test</string>
<string name="searchable_hint">A search hint</string>
+
+ <!-- InterrogationActivity -->
+ <string name="button1">Button1</string>
+ <string name="button2">Button2</string>
+ <string name="button3">Button3</string>
+ <string name="button4">Button4</string>
+ <string name="button5">Button5</string>
+ <string name="button6">Button6</string>
+ <string name="button7">Button7</string>
+ <string name="button8">Button8</string>
+ <string name="button9">Button9</string>
+
</resources>
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
new file mode 100644
index 0000000..b4a0581
--- /dev/null
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
@@ -0,0 +1,47 @@
+/**
+ * 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 android.accessibilityservice;
+
+import com.android.frameworks.coretests.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * Activity for testing the accessibility APIs for "interrogation" of
+ * the screen content. These APIs allow exploring the screen and
+ * requesting an action to be performed on a given view from an
+ * AccessiiblityService.
+ */
+public class InterrogationActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.interrogation_activity);
+
+ findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ /* do nothing */
+ }
+ });
+ findViewById(R.id.button5).setOnLongClickListener(new View.OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ return true;
+ }
+ });
+ }
+}
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
new file mode 100644
index 0000000..a20cc1f
--- /dev/null
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -0,0 +1,464 @@
+/**
+ * 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 android.accessibilityservice;
+
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
+
+import com.android.frameworks.coretests.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityManager;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * Activity for testing the accessibility APIs for "interrogation" of
+ * the screen content. These APIs allow exploring the screen and
+ * requesting an action to be performed on a given view from an
+ * AccessiiblityService.
+ */
+public class InterrogationActivityTest
+ extends ActivityInstrumentationTestCase2<InterrogationActivity> {
+
+ // Timeout before give up wait for the system to process an accessibility setting change.
+ private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
+
+ // Helpers to figure out the first and last test methods
+ // This is a workaround for the lack of such support in JUnit3
+ private static int sTestMethodCount;
+ private static int sExecutedTestMethodCount;
+
+ // Handle to a connection to the AccessibilityManagerService
+ private static IAccessibilityServiceConnection sConnection;
+
+ // The last received accessibility event
+ private static volatile AccessibilityEvent sLastAccessibilityEvent;
+
+ public InterrogationActivityTest() {
+ super(InterrogationActivity.class);
+ sTestMethodCount = getTestMethodCount();
+ }
+
+ @LargeTest
+ public void testFindAccessibilityNodeInfoByViewId() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertNotNull(button);
+ assertEquals(0, button.getChildCount());
+
+ // bounds
+ Rect bounds = new Rect();
+ button.getBounds(bounds);
+ assertEquals(0, bounds.left);
+ assertEquals(0, bounds.top);
+ assertEquals(73, bounds.right);
+ assertEquals(48, bounds.bottom);
+
+ // char sequence attributes
+ assertEquals("com.android.frameworks.coretests", button.getPackageName());
+ assertEquals("android.widget.Button", button.getClassName());
+ assertEquals("Button5", button.getText());
+ assertNull(button.getContentDescription());
+
+ // boolean attributes
+ assertTrue(button.isFocusable());
+ assertTrue(button.isClickable());
+ assertTrue(button.isEnabled());
+ assertFalse(button.isFocused());
+ assertTrue(button.isClickable());
+ assertFalse(button.isPassword());
+ assertFalse(button.isSelected());
+ assertFalse(button.isCheckable());
+ assertFalse(button.isChecked());
+
+ // actions
+ assertEquals(ACTION_FOCUS | ACTION_SELECT | ACTION_CLEAR_SELECTION,
+ button.getActions());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testFindAccessibilityNodeInfoByViewText() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view by text
+ List<AccessibilityNodeInfo> buttons =
+ getConnection().findAccessibilityNodeInfosByViewText("butto");
+ assertEquals(9, buttons.size());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testTraverseAllViews() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // make list of expected nodes
+ List<String> classNameAndTextList = new ArrayList<String>();
+ classNameAndTextList.add("android.widget.LinearLayout");
+ classNameAndTextList.add("android.widget.LinearLayout");
+ classNameAndTextList.add("android.widget.LinearLayout");
+ classNameAndTextList.add("android.widget.LinearLayout");
+ classNameAndTextList.add("android.widget.ButtonButton1");
+ classNameAndTextList.add("android.widget.ButtonButton2");
+ classNameAndTextList.add("android.widget.ButtonButton3");
+ classNameAndTextList.add("android.widget.ButtonButton4");
+ classNameAndTextList.add("android.widget.ButtonButton5");
+ classNameAndTextList.add("android.widget.ButtonButton6");
+ classNameAndTextList.add("android.widget.ButtonButton7");
+ classNameAndTextList.add("android.widget.ButtonButton8");
+ classNameAndTextList.add("android.widget.ButtonButton9");
+
+ AccessibilityNodeInfo root = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.root);
+ assertNotNull("We must find the existing root.", root);
+
+ Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
+ fringe.add(root);
+
+ // do a BFS traversal and check nodes
+ while (!fringe.isEmpty()) {
+ AccessibilityNodeInfo current = fringe.poll();
+
+ CharSequence className = current.getClassName();
+ CharSequence text = current.getText();
+ String receivedClassNameAndText = className.toString()
+ + ((text != null) ? text.toString() : "");
+ String expectedClassNameAndText = classNameAndTextList.remove(0);
+
+ assertEquals("Did not get the expected node info",
+ expectedClassNameAndText, receivedClassNameAndText);
+
+ final int childCount = current.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ AccessibilityNodeInfo child = current.getChild(i);
+ fringe.add(child);
+ }
+ }
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testPerformAccessibilityActionFocus() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not focused
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertFalse(button.isFocused());
+
+ // focus the view
+ assertTrue(button.performAction(ACTION_FOCUS));
+
+ // find the view again and make sure it is focused
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertTrue(button.isFocused());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testPerformAccessibilityActionClearFocus() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not focused
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertFalse(button.isFocused());
+
+ // focus the view
+ assertTrue(button.performAction(ACTION_FOCUS));
+
+ // find the view again and make sure it is focused
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertTrue(button.isFocused());
+
+ // unfocus the view
+ assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
+
+ // find the view again and make sure it is not focused
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertFalse(button.isFocused());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testPerformAccessibilityActionSelect() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not selected
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertFalse(button.isSelected());
+
+ // select the view
+ assertTrue(button.performAction(ACTION_SELECT));
+
+ // find the view again and make sure it is selected
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertTrue(button.isSelected());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testPerformAccessibilityActionClearSelection() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not selected
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertFalse(button.isSelected());
+
+ // select the view
+ assertTrue(button.performAction(ACTION_SELECT));
+
+ // find the view again and make sure it is selected
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertTrue(button.isSelected());
+
+ // unselect the view
+ assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
+
+ // find the view again and make sure it is not selected
+ button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+ assertFalse(button.isSelected());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @LargeTest
+ public void testAccessibilityEventGetSource() throws Exception {
+ beforeClassIfNeeded();
+ try {
+ // bring up the activity
+ getActivity();
+
+ // find a view and make sure it is not focused
+ AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
+ R.id.button5);
+ assertFalse(button.isSelected());
+
+ // focus the view
+ assertTrue(button.performAction(ACTION_FOCUS));
+ SystemClock.sleep(200);
+
+ // check that last event source
+ AccessibilityNodeInfo source = sLastAccessibilityEvent.getSource();
+ assertNotNull(source);
+
+ // bounds
+ Rect buttonBounds = new Rect();
+ button.getBounds(buttonBounds);
+ Rect sourceBounds = new Rect();
+ source.getBounds(sourceBounds);
+
+ assertEquals(buttonBounds.left, sourceBounds.left);
+ assertEquals(buttonBounds.right, sourceBounds.right);
+ assertEquals(buttonBounds.top, sourceBounds.top);
+ assertEquals(buttonBounds.bottom, sourceBounds.bottom);
+
+ // char sequence attributes
+ assertEquals(button.getPackageName(), source.getPackageName());
+ assertEquals(button.getClassName(), source.getClassName());
+ assertEquals(button.getText(), source.getText());
+ assertSame(button.getContentDescription(), source.getContentDescription());
+
+ // boolean attributes
+ assertSame(button.isFocusable(), source.isFocusable());
+ assertSame(button.isClickable(), source.isClickable());
+ assertSame(button.isEnabled(), source.isEnabled());
+ assertNotSame(button.isFocused(), source.isFocused());
+ assertSame(button.isLongClickable(), source.isLongClickable());
+ assertSame(button.isPassword(), source.isPassword());
+ assertSame(button.isSelected(), source.isSelected());
+ assertSame(button.isCheckable(), source.isCheckable());
+ assertSame(button.isChecked(), source.isChecked());
+ } finally {
+ afterClassIfNeeded();
+ }
+ }
+
+ @Override
+ protected void scrubClass(Class<?> testCaseClass) {
+ /* intentionally do not scrub */
+ }
+
+ /**
+ * Sets accessibility in a given state by writing the state to the
+ * settings and waiting until the accessibility manager service picks
+ * it up for max {@link #TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING}.
+ *
+ * @param state The accessibility state.
+ * @throws Exception If any error occurs.
+ */
+ private void ensureAccessibilityState(boolean state) throws Exception {
+ Context context = getInstrumentation().getContext();
+ // If the local manager ready => nothing to do.
+ AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
+ if (accessibilityManager.isEnabled() == state) {
+ return;
+ }
+ synchronized (this) {
+ // Check if the system already knows about the desired state.
+ final boolean currentState = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED) == 1;
+ if (currentState != state) {
+ // Make sure we wake ourselves as the desired state is propagated.
+ accessibilityManager.addAccessibilityStateChangeListener(
+ new AccessibilityManager.AccessibilityStateChangeListener() {
+ public void onAccessibilityStateChanged(boolean enabled) {
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ });
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, state ? 1 : 0);
+ }
+ // No while one attempt and that is it.
+ try {
+ wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ if (accessibilityManager.isEnabled() != state) {
+ throw new IllegalStateException("Could not set accessibility state to: " + state);
+ }
+ }
+
+ /**
+ * Execute some set up code before any test method.
+ *
+ * NOTE: I miss Junit4's @BeforeClass
+ *
+ * @throws Exception If an error occurs.
+ */
+ private void beforeClassIfNeeded() throws Exception {
+ sExecutedTestMethodCount++;
+ if (sExecutedTestMethodCount == 1) {
+ ensureAccessibilityState(true);
+ }
+ }
+
+ /**
+ * Execute some clean up code after all test methods.
+ *
+ * NOTE: I miss Junit4's @AfterClass
+ *
+ * @throws Exception If an error occurs.
+ */
+ public void afterClassIfNeeded() throws Exception {
+ if (sExecutedTestMethodCount == sTestMethodCount) {
+ sExecutedTestMethodCount = 0;
+ ensureAccessibilityState(false);
+ }
+ }
+
+ private static IAccessibilityServiceConnection getConnection() throws Exception {
+ if (sConnection == null) {
+ IEventListener listener = new IEventListener.Stub() {
+ public void setConnection(IAccessibilityServiceConnection connection)
+ throws RemoteException {
+ AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+ info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
+ info.notificationTimeout = 0;
+ info.flags = AccessibilityServiceInfo.DEFAULT;
+ connection.setServiceInfo(info);
+ }
+
+ public void onInterrupt() {}
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ sLastAccessibilityEvent= AccessibilityEvent.obtain(event);
+ }
+ };
+ IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+ sConnection = manager.registerEventListener(listener);
+ }
+ return sConnection;
+ }
+
+ /**
+ * @return The number of test methods.
+ */
+ private int getTestMethodCount() {
+ int testMethodCount = 0;
+ for (Method method : getClass().getMethods()) {
+ final int modifiers = method.getModifiers();
+ if (method.getName().startsWith("test")
+ && (modifiers & Modifier.PUBLIC) != 0
+ && (modifiers & Modifier.STATIC) == 0) {
+ testMethodCount++;
+ }
+ }
+ return testMethodCount;
+ }
+}
diff --git a/core/tests/coretests/src/android/view/GravityTest.java b/core/tests/coretests/src/android/view/GravityTest.java
index 180a390..2a7a64f 100644
--- a/core/tests/coretests/src/android/view/GravityTest.java
+++ b/core/tests/coretests/src/android/view/GravityTest.java
@@ -59,11 +59,11 @@ public class GravityTest extends AndroidTestCase {
assertOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, false);
assertOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, true);
- assertOneGravity(Gravity.LEFT, Gravity.BEFORE, false);
- assertOneGravity(Gravity.RIGHT, Gravity.BEFORE, true);
+ assertOneGravity(Gravity.LEFT, Gravity.START, false);
+ assertOneGravity(Gravity.RIGHT, Gravity.START, true);
- assertOneGravity(Gravity.RIGHT, Gravity.AFTER, false);
- assertOneGravity(Gravity.LEFT, Gravity.AFTER, true);
+ assertOneGravity(Gravity.RIGHT, Gravity.END, false);
+ assertOneGravity(Gravity.LEFT, Gravity.END, true);
}
private void assertOneGravity(int expected, int initial, boolean isRtl) {