Merge "Add comment for deprecation of Intent.ACTION_UMS_CONNECTED and ACTION_UMS_DISCONNECTED"
diff --git a/Android.mk b/Android.mk
index e987f91..90ffcd3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -127,11 +127,13 @@
core/java/android/os/INetworkManagementService.aidl \
core/java/android/os/IPermissionController.aidl \
core/java/android/os/IPowerManager.aidl \
- core/java/android/os/IRemoteCallback.aidl \
+ core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/IVibratorService.aidl \
- core/java/android/service/wallpaper/IWallpaperConnection.aidl \
- core/java/android/service/wallpaper/IWallpaperEngine.aidl \
- core/java/android/service/wallpaper/IWallpaperService.aidl \
+ core/java/android/service/wallpaper/IWallpaperConnection.aidl \
+ core/java/android/service/wallpaper/IWallpaperEngine.aidl \
+ core/java/android/service/wallpaper/IWallpaperService.aidl \
+ core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
+ core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
core/java/android/view/accessibility/IAccessibilityManager.aidl \
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
core/java/android/view/IApplicationToken.aidl \
diff --git a/api/14.txt b/api/14.txt
index 58d49d9..ac93afb 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -22250,10 +22250,8 @@
public class AccessibilityRecord {
ctor protected AccessibilityRecord();
- method protected void clear();
method public int getAddedCount();
method public java.lang.CharSequence getBeforeText();
- method public boolean getBooleanProperty(int);
method public java.lang.CharSequence getClassName();
method public java.lang.CharSequence getContentDescription();
method public int getCurrentItemIndex();
diff --git a/api/current.txt b/api/current.txt
index 8aabbd8..1f27774 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -90,6 +90,7 @@
field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -16438,6 +16439,7 @@
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
method public void syncAll(int);
field public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8
+ field public static final int USAGE_GRAPHICS_RENDER_TARGET = 16; // 0x10
field public static final int USAGE_GRAPHICS_TEXTURE = 2; // 0x2
field public static final int USAGE_GRAPHICS_VERTEX = 4; // 0x4
field public static final int USAGE_SCRIPT = 1; // 0x1
@@ -20435,14 +20437,12 @@
method public static int getAbsoluteGravity(int, boolean);
method public static boolean isHorizontal(int);
method public static boolean isVertical(int);
- field public static final int AFTER = 8388613; // 0x800005
field public static final int AXIS_CLIP = 8; // 0x8
field public static final int AXIS_PULL_AFTER = 4; // 0x4
field public static final int AXIS_PULL_BEFORE = 2; // 0x2
field public static final int AXIS_SPECIFIED = 1; // 0x1
field public static final int AXIS_X_SHIFT = 0; // 0x0
field public static final int AXIS_Y_SHIFT = 4; // 0x4
- field public static final int BEFORE = 8388611; // 0x800003
field public static final int BOTTOM = 80; // 0x50
field public static final int CENTER = 17; // 0x11
field public static final int CENTER_HORIZONTAL = 1; // 0x1
@@ -20451,6 +20451,7 @@
field public static final int CLIP_VERTICAL = 128; // 0x80
field public static final int DISPLAY_CLIP_HORIZONTAL = 16777216; // 0x1000000
field public static final int DISPLAY_CLIP_VERTICAL = 268435456; // 0x10000000
+ field public static final int END = 8388613; // 0x800005
field public static final int FILL = 119; // 0x77
field public static final int FILL_HORIZONTAL = 7; // 0x7
field public static final int FILL_VERTICAL = 112; // 0x70
@@ -20460,6 +20461,7 @@
field public static final int RELATIVE_HORIZONTAL_DIRECTION = 8388608; // 0x800000
field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
field public static final int RIGHT = 5; // 0x5
+ field public static final int START = 8388611; // 0x800003
field public static final int TOP = 48; // 0x30
field public static final int VERTICAL_GRAVITY_MASK = 112; // 0x70
}
@@ -21477,6 +21479,7 @@
method protected int computeVerticalScrollExtent();
method protected int computeVerticalScrollOffset();
method protected int computeVerticalScrollRange();
+ method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
method public void dispatchConfigurationChanged(android.content.res.Configuration);
@@ -21505,6 +21508,7 @@
method public android.view.View findFocus();
method public final android.view.View findViewById(int);
method public final android.view.View findViewWithTag(java.lang.Object);
+ method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence);
method protected boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
method public void forceLayout();
@@ -21673,6 +21677,7 @@
method public boolean onGenericMotionEvent(android.view.MotionEvent);
method public boolean onHoverEvent(android.view.MotionEvent);
method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
@@ -22566,17 +22571,21 @@
method public void appendRecord(android.view.accessibility.AccessibilityRecord);
method public int describeContents();
method public static java.lang.String eventTypeToString(int);
+ method public int getAccessibilityWindowId();
method public long getEventTime();
method public int getEventType();
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityRecord getRecord(int);
method public int getRecordCount();
+ method public android.view.accessibility.AccessibilityNodeInfo getSource();
method public void initFromParcel(android.os.Parcel);
method public static android.view.accessibility.AccessibilityEvent obtain(int);
+ method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
method public static android.view.accessibility.AccessibilityEvent obtain();
method public void setEventTime(long);
method public void setEventType(int);
method public void setPackageName(java.lang.CharSequence);
+ method public void setSource(android.view.View);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int INVALID_POSITION = -1; // 0xffffffff
@@ -22601,20 +22610,75 @@
}
public final class AccessibilityManager {
+ method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
method public void interrupt();
method public boolean isEnabled();
+ method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
+ public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
+ method public abstract void onAccessibilityStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfo implements android.os.Parcelable {
+ method public void addAction(int);
+ method public void addChild(android.view.View);
+ method public int describeContents();
+ method public int getAccessibilityWindowId();
+ method public int getActions();
+ method public void getBounds(android.graphics.Rect);
+ method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
+ method public int getChildCount();
+ method public java.lang.CharSequence getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public java.lang.CharSequence getPackageName();
+ method public android.view.accessibility.AccessibilityNodeInfo getParent();
+ method public java.lang.CharSequence getText();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isPassword();
+ method public boolean isSelected();
+ method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
+ method public static android.view.accessibility.AccessibilityNodeInfo obtain();
+ method public boolean performAction(int);
+ method public void recycle();
+ method public void setBounds(android.graphics.Rect);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(java.lang.CharSequence);
+ method public void setClickable(boolean);
+ method public void setContentDescription(java.lang.CharSequence);
+ method public void setEnabled(boolean);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setLongClickable(boolean);
+ method public void setPackageName(java.lang.CharSequence);
+ method public void setParent(android.view.View);
+ method public void setPassword(boolean);
+ method public void setSelected(boolean);
+ method public void setSource(android.view.View);
+ method public void setText(java.lang.CharSequence);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public class AccessibilityRecord {
ctor protected AccessibilityRecord();
- method protected void clear();
method public int getAddedCount();
method public java.lang.CharSequence getBeforeText();
- method public boolean getBooleanProperty(int);
method public java.lang.CharSequence getClassName();
method public java.lang.CharSequence getContentDescription();
method public int getCurrentItemIndex();
@@ -22627,6 +22691,7 @@
method public boolean isEnabled();
method public boolean isFullScreen();
method public boolean isPassword();
+ method public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
method public static android.view.accessibility.AccessibilityRecord obtain();
method public void recycle();
method public void setAddedCount(int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 38cacdd..424b70a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -98,6 +98,8 @@
runStart();
} else if (op.equals("startservice")) {
runStartService();
+ } else if (op.equals("force-stop")) {
+ runForceStop();
} else if (op.equals("instrument")) {
runInstrument();
} else if (op.equals("broadcast")) {
@@ -365,6 +367,10 @@
}
}
+ private void runForceStop() throws Exception {
+ mAm.forceStopPackage(nextArgRequired());
+ }
+
private void sendBroadcast() throws Exception {
Intent intent = makeIntent();
IntentReceiver receiver = new IntentReceiver();
@@ -851,7 +857,7 @@
wm.clearForcedDisplaySize();
}
} catch (RemoteException e) {
- }
+ }
}
private class IntentReceiver extends IIntentReceiver.Stub {
@@ -1013,6 +1019,8 @@
"\n" +
" start a Service: am startservice <INTENT>\n" +
"\n" +
+ " force stop everything associated with a package: force-stop <package>\n" +
+ "\n" +
" send a broadcast Intent: am broadcast <INTENT>\n" +
"\n" +
" start an Instrumentation: am instrument [flags] <COMPONENT>\n" +
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.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 @@
* 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 @@
* 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>
- * <service android:name=".MyAccessibilityService"><br>
- * <intent-filter><br>
- * <action android:name="android.accessibilityservice.AccessibilityService" /><br>
- * </intent-filter><br>
- * <meta-data android:name="android.accessibilityservice.as" android:resource="@xml/accessibilityservice" /><br>
- * </service><br>
- * </code>
+ * <code>
+ * <service android:name=".MyAccessibilityService"><br>
+ * <intent-filter><br>
+ * <action android:name="android.accessibilityservice.AccessibilityService" /><br>
+ * </intent-filter><br>
+ * <meta-data android:name="android.accessibilityservice.as" android:resource="@xml/accessibilityservice" /><br>
+ * </service><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 @@
* {@link AccessibilityServiceInfo#packageNames}
* </strong>
* </p>
+ * <p>
+ * For more details refer to {@link AccessibilityServiceInfo}.
+ * </p>
* </li>
* </ul>
* <p>
@@ -151,16 +162,49 @@
* <code>
* <?xml version="1.0" encoding="utf-8"?><br>
* <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"<br>
- * android:eventTypes="typeViewClicked|typeViewFocused"<br>
+ * android:accessibilityEventTypes="typeViewClicked|typeViewFocused"<br>
* android:packageNames="foo.bar, foo.baz"<br>
- * android:feedbackType="feedbackSpoken"<br>
+ * android:accessibilityFeedbackType="feedbackSpoken"<br>
* android:notificationTimeout="100"<br>
- * android:flags="flagDefault"<br>
+ * android:accessibilityFlags="flagDefault"<br>
* android:settingsActivity="foo.bar.TestBackActivity"<br>
* . . .<br>
* />
* </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 @@
/**
* 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 @@
/**
* 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 @@
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 @@
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 @@
* @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 @@
};
/**
- * Area class for focus.
+ * Area class for focus and metering.
*
- * @see #setFocusAreas(List)
- * @see #getFocusAreas()
+ * @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 @@
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 @@
* 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 @@
* 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 @@
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 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 @@
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 @@
}
}
- 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 @@
} 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 @@
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 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 @@
// 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 @@
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 @@
/** 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 @@
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.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 @@
* @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 @@
/**
* 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 @@
}
/**
- * 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 @@
}
/**
- * 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 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 @@
/**
* 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 @@
/**
* 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 @@
}
/**
- * 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 @@
/**
* 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 @@
}
/**
- * 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 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 @@
/**
* 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 @@
CAL_SYNC2,
CAL_SYNC3,
CAL_SYNC4,
- CAL_SYNC5, CAL_SYNC6,
+ CAL_SYNC5,
+ CAL_SYNC6,
SYNC_STATE,
};
}
@@ -465,29 +529,29 @@
/**
* 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 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 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 static final int ATTENDEE_STATUS_TENTATIVE = 4;
}
+ /**
+ * Fields and helpers for interacting with Attendees.
+ */
public static final class Attendees implements BaseColumns, AttendeesColumns, EventsColumns {
- public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/attendees");
- // TODO: fill out this class when we actually start utilizing attendees
- // in the calendar application.
+ /**
+ * 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 + "=?";
+
+ /**
+ * 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 @@
* 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 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 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 @@
/**
* 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 @@
/**
* 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 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 @@
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 @@
}
/**
- * 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 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 @@
}
/**
- * 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 @@
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);
- }
-
- public static final Cursor query(ContentResolver cr, String[] projection, long begin,
- long end, String searchQuery, String where, 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;
- } else {
- where = "(" + where + ") 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
+ * 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 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(selection)) {
+ selection = WHERE_CALENDARS_SELECTED;
+ } else {
+ selection = "(" + selection + ") AND " + WHERE_CALENDARS_SELECTED;
+ }
+ return cr.query(builder.build(), projection, selection, selectionArgs,
+ orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+ }
+
+ /**
+ * 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 @@
/**
* 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 @@
* 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 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");
-
- public static final String[] PROJECTION = { STARTDAY, ENDDAY };
- public static final String SELECTION = "selected=1";
+ private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ + "/instances/groupbyday");
/**
- * Retrieves the days with events for the Julian days starting at "startDay"
- * for "numDays".
+ * The projection used by the EventDays query.
+ */
+ public static final String[] PROJECTION = { STARTDAY, ENDDAY };
+ private static final String SELECTION = "selected=1";
+
+ /**
+ * 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 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 @@
/**
* 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 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 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 @@
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 @@
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 @@
/**
* 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 @@
}
}
+ /**
+ * 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 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 @@
*/
private SyncState() {}
- public static final String CONTENT_DIRECTORY =
+ private static final String CONTENT_DIRECTORY =
SyncStateContract.Constants.CONTENT_DIRECTORY;
/**
@@ -1732,39 +2032,43 @@
/**
* 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 @@
if (element != null) {
element.setNextPoolable(null);
+ element.setPooled(false);
mManager.onAcquired(element);
}
@@ -76,9 +77,13 @@
}
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 @@
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 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 @@
/**
* <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 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 @@
// 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 @@
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 @@
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.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 @@
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 @@
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 @@
* @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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
// 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 @@
);
private InvalidateInfo mNext;
+ private boolean mIsPooled;
View target;
@@ -12742,6 +12871,14 @@
void release() {
sPool.release(this);
}
+
+ public boolean isPooled() {
+ return mIsPooled;
+ }
+
+ public void setPooled(boolean isPooled) {
+ mIsPooled = isPooled;
+ }
}
final IWindowSession mSession;
@@ -12952,6 +13089,11 @@
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.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.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 @@
*/
AudioManager mAudioManager;
+ final AccessibilityManager mAccessibilityManager;
+
+ AccessibilityInteractionController mAccessibilityInteractionContrtoller;
+
+ AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
+
private final int mDensity;
/**
@@ -285,7 +302,7 @@
// 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 @@
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 @@
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 @@
mView.dispatchDetachedFromWindow();
}
+ mAccessibilityInteractionConnectionManager.ensureNoConnection();
+ mAccessibilityManager.removeAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager);
+
mView = null;
mAttachInfo.mRootView = null;
mAttachInfo.mSurface = null;
@@ -2020,7 +2050,6 @@
InputQueue.unregisterInputChannel(mInputChannel);
}
}
-
try {
sWindowSession.remove(mWindow);
} catch (RemoteException e) {
@@ -2098,6 +2127,10 @@
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 @@
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 @@
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 @@
* 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 @@
if (mView == null) {
return false;
}
- AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event);
+ mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
@@ -3608,18 +3668,18 @@
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 @@
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 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 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 void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
@@ -3733,17 +3794,16 @@
/* 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 @@
}
}
+ /**
+ * 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.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 @@
}
}
+ @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 @@
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 @@
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 7b80797b..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 @@
* @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 @@
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 @@
* 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 @@
}
/**
+ * 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 @@
* 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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
* @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 @@
* {@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 @@
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 88f88783..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.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 @@
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 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 @@
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 @@
}
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 @@
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 @@
}
/**
+ * 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 @@
* 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 @@
* 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,21 +143,15 @@
* 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.
- *
- * @param isFullScreen True if the source is full screen, false otherwise.
- */
- public void setFullScreen(boolean isFullScreen) {
- setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
- }
-
- /**
* Gets if the source is taking the entire screen.
*
* @return True if the source is full screen, false otherwise.
@@ -140,6 +161,18 @@
}
/**
+ * Sets if the source is taking the entire screen.
+ *
+ * @param isFullScreen True if the source is full screen, false otherwise.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setFullScreen(boolean isFullScreen) {
+ enforceNotSealed();
+ setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
+ }
+
+ /**
* Gets the number of items that can be visited.
*
* @return The number of items.
@@ -152,8 +185,11 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
}
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 @@
}
/**
- * 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 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 @@
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 @@
@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 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 @@
@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.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 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 @@
);
private Node mNext;
+ private boolean mIsPooled;
public void setNextPoolable(Node element) {
mNext = element;
@@ -1449,6 +1451,14 @@
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.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 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 @@
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 @@
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 @@
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.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 @@
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::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) {
- if (resultAdvances != NULL) {
- memcpy(resultAdvances, layout->getAdvances(), layout->getAdvancesCount() * sizeof(jfloat));
- }
- resultTotalAdvance = layout->getTotalAdvance();
- }
#else
- // Compute advances and return them
- TextLayoutCacheValue::computeValuesWithHarfbuzz(paint, chars, start, count, contextCount,
- dirFlags, resultAdvances, &resultTotalAdvance, NULL, NULL );
+ value = new TextLayoutCacheValue();
+ value->computeValues(paint, chars, start, count, contextCount, dirFlags);
#endif
+ if (value != NULL) {
+ if (resultAdvances != NULL) {
+ memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
+ }
+ resultTotalAdvance = value->getTotalAdvance();
+ }
}
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 e5c28489..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 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 @@
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 bf1d432f..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 7fb4f73..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..29c23a68 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 @@
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) {
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 5ed7966..b9c0d80 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -132,6 +132,7 @@
<assign-permission name="android.permission.BATTERY_STATS" uid="shell" />
<assign-permission name="android.permission.INTERNAL_SYSTEM_WINDOW" uid="shell" />
<assign-permission name="android.permission.INJECT_EVENTS" uid="shell" />
+ <assign-permission name="android.permission.RETRIEVE_WINDOW_CONTENT" uid="shell" />
<assign-permission name="android.permission.SET_ACTIVITY_WATCHER" uid="shell" />
<assign-permission name="android.permission.READ_INPUT_STATE" uid="shell" />
<assign-permission name="android.permission.SET_ORIENTATION" uid="shell" />
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 9ac1a00b..3c8aba3 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -100,7 +100,6 @@
public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
/**
- * @hide
* USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a
* target for offscreen rendering
*
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index 6487623..fac7144 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -51,7 +51,7 @@
public void skip(int i) {
int res = mPos + i;
- if ((res < 0) || (res >= mLen)) {
+ if ((res < 0) || (res > mLen)) {
throw new RSIllegalArgumentException("out of range argument: " + i);
}
mPos = res;
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index dc5fc84..83d4f6d 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -263,7 +263,7 @@
// direction is not affected by the rotation or mirroring of
// CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates 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 areas cannot be 0 or negative.
+ // point. The width and height of focus areas cannot be 0 or negative.
//
// The fifth element is the weight. Values for weight must range from 1 to
// 1000. The weight should be interpreted as a per-pixel weight - all
@@ -373,7 +373,7 @@
// direction is not affected by the rotation or mirroring of
// CAMERA_CMD_SET_DISPLAY_ORIENTATION. 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 metering areas cannot
+ // is the lower right point. The width and height of metering areas cannot
// be 0 or negative.
//
// The fifth element is the weight. Values for weight must range from 1 to
@@ -550,6 +550,7 @@
static const char PIXEL_FORMAT_YUV422I[]; // YUY2
static const char PIXEL_FORMAT_YUV420P[]; // YV12
static const char PIXEL_FORMAT_RGB565[];
+ static const char PIXEL_FORMAT_RGBA8888[];
static const char PIXEL_FORMAT_JPEG[];
// Values for focus mode settings.
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index c295315..9392cf2 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -146,6 +146,7 @@
const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
// Values for focus mode settings.
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index a54cf28..7634c6c 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -76,8 +76,9 @@
public static final int FILE_TYPE_PNG = 33;
public static final int FILE_TYPE_BMP = 34;
public static final int FILE_TYPE_WBMP = 35;
+ public static final int FILE_TYPE_WEBP = 36;
private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG;
- private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP;
+ private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WEBP;
// Playlist file types
public static final int FILE_TYPE_M3U = 41;
@@ -213,6 +214,7 @@
addFileType("PNG", FILE_TYPE_PNG, "image/png", MtpConstants.FORMAT_PNG);
addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp", MtpConstants.FORMAT_BMP);
addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
+ addFileType("WEBP", FILE_TYPE_WBMP, "image/webp");
addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
addFileType("M3U", FILE_TYPE_M3U, "application/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 8a180d8..6cb3847 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -26,13 +26,6 @@
#include <system/audio.h>
// ----------------------------------------------------------------------------
-// the sim build doesn't have gettid
-
-#ifndef HAVE_GETTID
-# define gettid getpid
-#endif
-
-// ----------------------------------------------------------------------------
namespace android {
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index ebe821f..07152d8 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -30,26 +30,6 @@
// foreground thread.
#ifndef DISABLE_GROUP_SCHEDULE_HACK
-/* 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
-
-static int myTid() {
-#ifdef HAVE_GETTID
- return gettid();
-#else
- return getpid();
-#endif
-}
-
#undef LOG_TAG
#define LOG_TAG "IMediaMetadataRetriever"
#include <utils/Log.h>
@@ -60,18 +40,18 @@
static void sendSchedPolicy(Parcel& data)
{
SchedPolicy policy;
- get_sched_policy(myTid(), &policy);
+ get_sched_policy(gettid(), &policy);
data.writeInt32(policy);
}
static void setSchedPolicy(const Parcel& data)
{
SchedPolicy policy = (SchedPolicy) data.readInt32();
- set_sched_policy(myTid(), policy);
+ set_sched_policy(gettid(), policy);
}
static void restoreSchedPolicy()
{
- set_sched_policy(myTid(), SP_FOREGROUND);
+ set_sched_policy(gettid(), SP_FOREGROUND);
}
}; // end namespace android
#endif
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 88157d2..8b953e0 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -23,13 +23,6 @@
#include <media/JetPlayer.h>
-#ifdef HAVE_GETTID
-static pid_t myTid() { return gettid(); }
-#else
-static pid_t myTid() { return getpid(); }
-#endif
-
-
namespace android
{
@@ -188,7 +181,7 @@
// signal main thread that we started
{
Mutex::Autolock l(mMutex);
- mTid = myTid();
+ mTid = gettid();
LOGV("JetPlayer::render(): render thread(%d) signal", mTid);
mCondition.signal();
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index eae93ff..54a6547 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -68,18 +68,6 @@
#include <OMX.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
-
namespace {
using android::media::Metadata;
using android::status_t;
@@ -387,14 +375,6 @@
return NO_ERROR;
}
-static int myTid() {
-#ifdef HAVE_GETTID
- return gettid();
-#else
- return getpid();
-#endif
-}
-
status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -426,7 +406,7 @@
}
result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", myTid());
+ snprintf(buffer, SIZE, "/proc/%d/maps", gettid());
FILE *f = fopen(buffer, "r");
if (f) {
while (!feof(f)) {
@@ -446,13 +426,13 @@
result.append("\n");
}
- snprintf(buffer, SIZE, "/proc/%d/fd", myTid());
+ snprintf(buffer, SIZE, "/proc/%d/fd", gettid());
DIR *d = opendir(buffer);
if (d) {
struct dirent *ent;
while((ent = readdir(d)) != NULL) {
if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", myTid(), ent->d_name);
+ snprintf(buffer, SIZE, "/proc/%d/fd/%s", gettid(), ent->d_name);
struct stat s;
if (lstat(buffer, &s) == 0) {
if ((s.st_mode & S_IFMT) == S_IFLNK) {
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 8f776b4..06fb103 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -40,18 +40,6 @@
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.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
-
namespace android {
extern player_type getPlayerType(const char* url);
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 589c625..7e04523 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -29,17 +29,12 @@
#include <libsonivox/eas_reverb.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <system/audio.h>
#include "MidiFile.h"
-#ifdef HAVE_GETTID
-static pid_t myTid() { return gettid(); }
-#else
-static pid_t myTid() { return getpid(); }
-#endif
-
// ----------------------------------------------------------------------------
namespace android {
@@ -455,7 +450,7 @@
// signal main thread that we started
{
Mutex::Autolock l(mMutex);
- mTid = myTid();
+ mTid = gettid();
LOGV("render thread(%d) signal", mTid);
mCondition.signal();
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f6a8b17..d0f6730 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2862,8 +2862,8 @@
* For historical reasons, any user data start
* with "\0xA9", must be followed by its assoicated
* language code.
- * 0x0012: locale en
- * 0x15c7: language 5575
+ * 0x0012: text string length
+ * 0x15c7: lang (locale) code: en
*/
writeInt32(0x001215c7);
writeLatitude(mLatitudex10000);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f806624..d4a8ddb 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -53,13 +53,6 @@
#include <media/EffectVisualizerApi.h>
// ----------------------------------------------------------------------------
-// the sim build doesn't have gettid
-
-#ifndef HAVE_GETTID
-# define gettid getpid
-#endif
-
-// ----------------------------------------------------------------------------
namespace android {
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index ef8d957..dd91788 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -39,13 +39,6 @@
#include <hardware/audio_policy.h>
#include <hardware/audio_policy_hal.h>
-// ----------------------------------------------------------------------------
-// the sim build doesn't have gettid
-
-#ifndef HAVE_GETTID
-# define gettid getpid
-#endif
-
namespace android {
static const char *kDeadlockedString = "AudioPolicyService may be deadlocked\n";
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index fba293c..86671d6 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,13 +16,7 @@
package com.android.server.accessibility;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.HandlerCaller.SomeArgs;
-import com.android.server.wm.WindowManagerService;
-
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.Manifest;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
@@ -37,7 +31,6 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -46,15 +39,27 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.IWindow;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
+import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.HandlerCaller.SomeArgs;
+import com.android.server.wm.WindowManagerService;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -64,6 +69,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class is instantiated by the system as a system level service and can be
@@ -80,12 +86,17 @@
private static final String LOG_TAG = "AccessibilityManagerService";
+ private static final String FUNCTION_REGISTER_EVENT_LISTENER =
+ "registerEventListener";
+
private static int sIdCounter = 0;
private static final int OWN_PROCESS_ID = android.os.Process.myPid();
private static final int DO_SET_SERVICE_INFO = 10;
+ private static int sNextWindowId;
+
final HandlerCaller mCaller;
final Context mContext;
@@ -103,6 +114,11 @@
private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
+ private final SparseArray<IAccessibilityInteractionConnection> mWindowIdToInteractionConnectionMap =
+ new SparseArray<IAccessibilityInteractionConnection>();
+
+ private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>();
+
private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':');
private PackageManager mPackageManager;
@@ -117,6 +133,10 @@
private boolean mHasInputFilter;
+ private final WindowManagerService mWindowManagerService;
+
+ private final SecurityPolicy mSecurityPolicy;
+
/**
* Handler for delayed event dispatch.
*/
@@ -145,6 +165,9 @@
mContext = context;
mPackageManager = mContext.getPackageManager();
mCaller = new HandlerCaller(context, this);
+ mWindowManagerService = (WindowManagerService) ServiceManager.getService(
+ Context.WINDOW_SERVICE);
+ mSecurityPolicy = new SecurityPolicy();
registerPackageChangeAndBootCompletedBroadcastReceiver();
registerSettingsContentObservers();
@@ -208,7 +231,6 @@
if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
-
// get the accessibility enabled setting on boot
mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
@@ -223,7 +245,7 @@
return;
}
-
+
super.onReceive(context, intent);
}
};
@@ -297,6 +319,7 @@
public boolean sendAccessibilityEvent(AccessibilityEvent event) {
synchronized (mLock) {
+ mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
notifyAccessibilityServicesDelayedLocked(event, false);
notifyAccessibilityServicesDelayedLocked(event, true);
}
@@ -352,7 +375,7 @@
public void executeMessage(Message message) {
switch (message.what) {
- case DO_SET_SERVICE_INFO:
+ case DO_SET_SERVICE_INFO: {
SomeArgs arguments = ((SomeArgs) message.obj);
AccessibilityServiceInfo info = (AccessibilityServiceInfo) arguments.arg1;
@@ -365,17 +388,73 @@
AccessibilityServiceInfo oldInfo = service.mAccessibilityServiceInfo;
if (oldInfo != null) {
oldInfo.updateDynamicallyConfigurableProperties(info);
- service.setAccessibilityServiceInfo(oldInfo);
+ service.setDynamicallyConfigurableProperties(oldInfo);
} else {
- service.setAccessibilityServiceInfo(info);
+ service.setDynamicallyConfigurableProperties(info);
}
}
- return;
+ } return;
default:
Slog.w(LOG_TAG, "Unknown message type: " + message.what);
}
}
+ public int addAccessibilityInteractionConnection(IWindow windowToken,
+ IAccessibilityInteractionConnection connection) throws RemoteException {
+ synchronized (mLock) {
+ final IWindow addedWindowToken = windowToken;
+ final int windowId = sNextWindowId++;
+ connection.asBinder().linkToDeath(new DeathRecipient() {
+ public void binderDied() {
+ synchronized (mLock) {
+ removeAccessibilityInteractionConnection(addedWindowToken);
+ }
+ }
+ }, 0);
+ mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder());
+ mWindowIdToInteractionConnectionMap.put(windowId, connection);
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
+ }
+ return windowId;
+ }
+ }
+
+ public void removeAccessibilityInteractionConnection(IWindow windowToken) {
+ synchronized (mLock) {
+ final int count = mWindowIdToWindowTokenMap.size();
+ for (int i = 0; i < count; i++) {
+ if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) {
+ final int windowId = mWindowIdToWindowTokenMap.keyAt(i);
+ mWindowIdToWindowTokenMap.remove(windowId);
+ mWindowIdToInteractionConnectionMap.remove(windowId);
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ public IAccessibilityServiceConnection registerEventListener(IEventListener listener) {
+ mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
+ FUNCTION_REGISTER_EVENT_LISTENER);
+ ComponentName componentName = new ComponentName("foo.bar", "FakeAccessibilityService");
+ synchronized (mLock) {
+ Service oldService = mComponentNameToServiceMap.get(componentName);
+ if (oldService != null) {
+ tryRemoveServiceLocked(oldService);
+ }
+ }
+ AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
+ accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+ accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+ Service service = new Service(componentName, accessibilityServiceInfo, true);
+ service.onServiceConnected(componentName, listener.asBinder());
+ return service;
+ }
+
/**
* Populates the cached list of installed {@link AccessibilityService}s.
*/
@@ -488,6 +567,12 @@
AccessibilityEvent event = service.mPendingEvents.get(eventType);
try {
+ if (mSecurityPolicy.canRetrieveWindowContent(service)) {
+ event.setConnection(service);
+ } else {
+ event.setSource(null);
+ }
+ event.setSealed(true);
listener.onAccessibilityEvent(event);
if (DEBUG) {
Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
@@ -646,7 +731,7 @@
if (isEnabled) {
if (enabledServices.contains(componentName)) {
if (service == null) {
- service = new Service(installedService);
+ service = new Service(componentName, installedService, false);
}
service.bind();
} else if (!enabledServices.contains(componentName)) {
@@ -683,8 +768,6 @@
* spoken feedback.
*/
private void updateInputFilterLocked() {
- WindowManagerService wm = (WindowManagerService)ServiceManager.getService(
- Context.WINDOW_SERVICE);
if (mIsEnabled) {
final boolean hasSpokenFeedbackServices = !getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
@@ -695,19 +778,14 @@
if (mInputFilter == null) {
mInputFilter = new AccessibilityInputFilter(mContext);
}
- wm.setInputFilter(mInputFilter);
+ mWindowManagerService.setInputFilter(mInputFilter);
mHasInputFilter = true;
- } else {
- if (mHasInputFilter) {
- wm.setInputFilter(null);
- mHasInputFilter = false;
- }
+ return;
}
- } else {
- if (mHasInputFilter) {
- wm.setInputFilter(null);
- mHasInputFilter = false;
- }
+ }
+ if (mHasInputFilter) {
+ mWindowManagerService.setInputFilter(null);
+ mHasInputFilter = false;
}
}
@@ -743,24 +821,38 @@
Intent mIntent;
+ boolean mCanRetrieveScreenContent;
+
+ boolean mIsFake;
+
+ final Callback mCallback = new Callback();
+
+ final AtomicInteger mInteractionIdCounter = new AtomicInteger();
+
// the events pending events to be dispatched to this service
final SparseArray<AccessibilityEvent> mPendingEvents =
new SparseArray<AccessibilityEvent>();
- Service(AccessibilityServiceInfo accessibilityServiceInfo) {
+ public Service(ComponentName componentName,
+ AccessibilityServiceInfo accessibilityServiceInfo, boolean isFake) {
mId = sIdCounter++;
- setAccessibilityServiceInfo(accessibilityServiceInfo);
- mIntent = new Intent().setComponent(mComponentName);
- mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
- com.android.internal.R.string.accessibility_binding_label);
- mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
- mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ mComponentName = componentName;
+ mAccessibilityServiceInfo = accessibilityServiceInfo;
+ mIsFake = isFake;
+ if (!isFake) {
+ mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
+ mIntent = new Intent().setComponent(mComponentName);
+ mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.accessibility_binding_label);
+ mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ } else {
+ mCanRetrieveScreenContent = true;
+ }
+ setDynamicallyConfigurableProperties(accessibilityServiceInfo);
}
- public void setAccessibilityServiceInfo(AccessibilityServiceInfo info) {
- mAccessibilityServiceInfo = info;
- ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
- mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
mEventTypes = info.eventTypes;
mFeedbackType = info.feedbackType;
String[] packageNames = info.packageNames;
@@ -781,7 +873,7 @@
* @return True if binding is successful.
*/
public boolean bind() {
- if (mService == null) {
+ if (!mIsFake && mService == null) {
return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE);
}
return false;
@@ -798,7 +890,9 @@
synchronized (mLock) {
tryRemoveServiceLocked(this);
}
- mContext.unbindService(this);
+ if (!mIsFake) {
+ mContext.unbindService(this);
+ }
mService = null;
return true;
}
@@ -832,6 +926,154 @@
}
}
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId) {
+ IAccessibilityInteractionConnection connection = null;
+ synchronized (mLock) {
+ final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
+ if (permissionGranted) {
+ connection = getConnectionToRetrievalAllowingWindowLocked();
+ }
+ }
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to a retrieve allowing window.");
+ }
+ return null;
+ }
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ connection.findAccessibilityNodeInfoByViewId(viewId, interactionId, mCallback);
+ AccessibilityNodeInfo info = mCallback.getFindAccessibilityNodeInfoResultAndClear(
+ interactionId);
+ if (info != null) {
+ info.setConnection(this);
+ }
+ info.setSealed(true);
+ return info;
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Error finding node.");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ return null;
+ }
+
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text) {
+ IAccessibilityInteractionConnection connection = null;
+ synchronized (mLock) {
+ final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
+ if (permissionGranted) {
+ connection = getConnectionToRetrievalAllowingWindowLocked();
+ }
+ }
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to focused window.");
+ }
+ return null;
+ }
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ connection.findAccessibilityNodeInfosByViewText(text, interactionId, mCallback);
+ List<AccessibilityNodeInfo> infos =
+ mCallback.getFindAccessibilityNodeInfosResultAndClear(interactionId);
+ if (infos != null) {
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ info.setConnection(this);
+ info.setSealed(true);
+ }
+ }
+ return infos;
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Error finding node.");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ return null;
+ }
+
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+ int accessibilityWindowId, int accessibilityViewId) {
+ IAccessibilityInteractionConnection connection = null;
+ synchronized (mLock) {
+ final boolean permissionGranted =
+ mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+ if (permissionGranted) {
+ connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
+ }
+ }
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to window: "
+ + accessibilityWindowId);
+ }
+ return null;
+ }
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityViewId,
+ interactionId, mCallback);
+ AccessibilityNodeInfo info =
+ mCallback.getFindAccessibilityNodeInfoResultAndClear(interactionId);
+ if (info != null) {
+ info.setConnection(this);
+ info.setSealed(true);
+ }
+ return info;
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Error requesting node with accessibilityViewId: "
+ + accessibilityViewId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ return null;
+ }
+
+ public boolean performAccessibilityAction(int accessibilityWindowId,
+ int accessibilityViewId, int action) {
+ IAccessibilityInteractionConnection connection = null;
+ synchronized (mLock) {
+ final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
+ accessibilityWindowId, action);
+ if (permissionGranted) {
+ connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
+ }
+ }
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to window: "
+ + accessibilityWindowId);
+ }
+ return false;
+ }
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ connection.performAccessibilityAction(accessibilityViewId, action, interactionId,
+ mCallback);
+ return mCallback.getPerformAccessibilityActionResult(interactionId);
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Error requesting node with accessibilityViewId: "
+ + accessibilityViewId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ return false;
+ }
+
public void onServiceDisconnected(ComponentName componentName) {
/* do nothing - #binderDied takes care */
}
@@ -849,5 +1091,171 @@
tryRemoveServiceLocked(this);
}
}
+
+ private IAccessibilityInteractionConnection getConnectionToRetrievalAllowingWindowLocked() {
+ final int windowId = mSecurityPolicy.getRetrievalAllowingWindowLocked();
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
+ }
+ return mWindowIdToInteractionConnectionMap.get(windowId);
+ }
+ }
+
+ final class SecurityPolicy {
+ private static final int VALID_ACTIONS = AccessibilityNodeInfo.ACTION_FOCUS
+ | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS | AccessibilityNodeInfo.ACTION_SELECT
+ | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
+
+ private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
+ AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END
+ | AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START
+ | AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
+ | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
+ | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
+ | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+
+ private int mRetrievalAlowingWindowId;
+
+ public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) {
+ final int windowId = event.getSourceAccessibilityWindowId();
+ final int eventType = event.getEventType();
+ if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) != 0) {
+ mRetrievalAlowingWindowId = windowId;
+ } else {
+ event.setSource(null);
+ }
+ }
+
+ public int getRetrievalAllowingWindowLocked() {
+ return mRetrievalAlowingWindowId;
+ }
+
+ public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
+ return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId);
+ }
+
+ public boolean canPerformActionLocked(Service service, int windowId, int action) {
+ return canRetrieveWindowContent(service)
+ && isRetrievalAllowingWindow(windowId)
+ && isActionPermitted(action);
+ }
+
+ public boolean canRetrieveWindowContent(Service service) {
+ return service.mCanRetrieveScreenContent;
+ }
+
+ private boolean isRetrievalAllowingWindow(int windowId) {
+ return (mRetrievalAlowingWindowId == windowId);
+ }
+
+ private boolean isActionPermitted(int action) {
+ return (VALID_ACTIONS & action) != 0;
+ }
+
+ private void enforceCallingPermission(String permission, String function) {
+ if (OWN_PROCESS_ID == Binder.getCallingPid()) {
+ return;
+ }
+ final int permissionStatus = mContext.checkCallingPermission(permission);
+ if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You do not have " + permission
+ + " required to call " + function);
+ }
+ }
+ }
+
+ final class Callback extends IAccessibilityInteractionConnectionCallback.Stub {
+ private static final long TIMEOUT_INTERACTION_MILLIS = 5000;
+
+ private int mInteractionId = -1;
+ private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult;
+ private List<AccessibilityNodeInfo> mFindAccessibilityNodeInfosResult;
+ private boolean mPerformAccessibilityActionResult;
+
+ public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info,
+ int interactionId) {
+ synchronized (mLock) {
+ if (interactionId > mInteractionId) {
+ mFindAccessibilityNodeInfoResult = info;
+ mInteractionId = interactionId;
+ }
+ mLock.notifyAll();
+ }
+ }
+
+ public AccessibilityNodeInfo getFindAccessibilityNodeInfoResultAndClear(int interactionId) {
+ synchronized (mLock) {
+ waitForResultTimedLocked(TIMEOUT_INTERACTION_MILLIS, interactionId);
+ AccessibilityNodeInfo result = mFindAccessibilityNodeInfoResult;
+ clearLocked();
+ return result;
+ }
+ }
+
+ public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
+ int interactionId) {
+ synchronized (mLock) {
+ if (interactionId > mInteractionId) {
+ mFindAccessibilityNodeInfosResult = infos;
+ mInteractionId = interactionId;
+ }
+ mLock.notifyAll();
+ }
+ }
+
+ public List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear(
+ int interactionId) {
+ synchronized (mLock) {
+ waitForResultTimedLocked(TIMEOUT_INTERACTION_MILLIS, interactionId);
+ List<AccessibilityNodeInfo> result = mFindAccessibilityNodeInfosResult;
+ clearLocked();
+ return result;
+ }
+ }
+
+ public void setPerformAccessibilityActionResult(boolean succeeded, int interactionId) {
+ synchronized (mLock) {
+ if (interactionId > mInteractionId) {
+ mPerformAccessibilityActionResult = succeeded;
+ mInteractionId = interactionId;
+ }
+ mLock.notifyAll();
+ }
+ }
+
+ public boolean getPerformAccessibilityActionResult(int interactionId) {
+ synchronized (mLock) {
+ waitForResultTimedLocked(TIMEOUT_INTERACTION_MILLIS, interactionId);
+ final boolean result = mPerformAccessibilityActionResult;
+ clearLocked();
+ return result;
+ }
+ }
+
+ public void clearLocked() {
+ mInteractionId = -1;
+ mFindAccessibilityNodeInfoResult = null;
+ mFindAccessibilityNodeInfosResult = null;
+ mPerformAccessibilityActionResult = false;
+ }
+
+ private void waitForResultTimedLocked(long waitTimeMillis, int interactionId) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ try {
+ if (mInteractionId == interactionId) {
+ return;
+ }
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ waitTimeMillis = TIMEOUT_INTERACTION_MILLIS - elapsedTimeMillis;
+ if (waitTimeMillis <= 0) {
+ return;
+ }
+ mLock.wait(waitTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
}
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index e8155b4..7ea0591 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -1212,8 +1212,8 @@
return null;
}
- for (String iface : ifaces) {
- for (String regex : mUpstreamIfaceRegexs) {
+ for (String regex : mUpstreamIfaceRegexs) {
+ for (String iface : ifaces) {
if (iface.matches(regex)) {
// verify it is active
InterfaceConfiguration ifcg = null;
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 3543275..5608402 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -16,6 +16,8 @@
package android.telephony;
+import android.util.Log;
+
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.gsm.SmsCbHeader;
@@ -58,10 +60,13 @@
try {
return new SmsCbMessage(pdu);
} catch (IllegalArgumentException e) {
+ Log.w(LOG_TAG, "Failed parsing SMS-CB pdu", e);
return null;
}
}
+ private static final String LOG_TAG = "SMSCB";
+
/**
* Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
*/
@@ -80,6 +85,8 @@
private static final char CARRIAGE_RETURN = 0x0d;
+ private static final int PDU_BODY_PAGE_LENGTH = 82;
+
private SmsCbHeader mHeader;
private String mLanguage;
@@ -149,6 +156,13 @@
return mHeader.updateNumber;
}
+ /**
+ * Parse and unpack the body text according to the encoding in the DCS.
+ * After completing successfully this method will have assigned the body
+ * text into mBody, and optionally the language code into mLanguage
+ *
+ * @param pdu The pdu
+ */
private void parseBody(byte[] pdu) {
int encoding;
boolean hasLanguageIndicator = false;
@@ -221,28 +235,81 @@
break;
}
+ if (mHeader.format == SmsCbHeader.FORMAT_UMTS) {
+ // Payload may contain multiple pages
+ int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
+
+ if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1)
+ * nrPages) {
+ throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match "
+ + nrPages + " pages");
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < nrPages; i++) {
+ // Each page is 82 bytes followed by a length octet indicating
+ // the number of useful octets within those 82
+ int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i;
+ int length = pdu[offset + PDU_BODY_PAGE_LENGTH];
+
+ if (length > PDU_BODY_PAGE_LENGTH) {
+ throw new IllegalArgumentException("Page length " + length
+ + " exceeds maximum value " + PDU_BODY_PAGE_LENGTH);
+ }
+
+ sb.append(unpackBody(pdu, encoding, offset, length, hasLanguageIndicator));
+ }
+ mBody = sb.toString();
+ } else {
+ // Payload is one single page
+ int offset = SmsCbHeader.PDU_HEADER_LENGTH;
+ int length = pdu.length - offset;
+
+ mBody = unpackBody(pdu, encoding, offset, length, hasLanguageIndicator);
+ }
+ }
+
+ /**
+ * Unpack body text from the pdu using the given encoding, position and
+ * length within the pdu
+ *
+ * @param pdu The pdu
+ * @param encoding The encoding, as derived from the DCS
+ * @param offset Position of the first byte to unpack
+ * @param length Number of bytes to unpack
+ * @param hasLanguageIndicator true if the body text is preceded by a
+ * language indicator. If so, this method will as a side-effect
+ * assign the extracted language code into mLanguage
+ * @return Body text
+ */
+ private String unpackBody(byte[] pdu, int encoding, int offset, int length,
+ boolean hasLanguageIndicator) {
+ String body = null;
+
switch (encoding) {
case SmsMessage.ENCODING_7BIT:
- mBody = GsmAlphabet.gsm7BitPackedToString(pdu, SmsCbHeader.PDU_HEADER_LENGTH,
- (pdu.length - SmsCbHeader.PDU_HEADER_LENGTH) * 8 / 7);
+ body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7);
- if (hasLanguageIndicator && mBody != null && mBody.length() > 2) {
- mLanguage = mBody.substring(0, 2);
- mBody = mBody.substring(3);
+ if (hasLanguageIndicator && body != null && body.length() > 2) {
+ // Language is two GSM characters followed by a CR.
+ // The actual body text is offset by 3 characters.
+ mLanguage = body.substring(0, 2);
+ body = body.substring(3);
}
break;
case SmsMessage.ENCODING_16BIT:
- int offset = SmsCbHeader.PDU_HEADER_LENGTH;
-
- if (hasLanguageIndicator && pdu.length >= SmsCbHeader.PDU_HEADER_LENGTH + 2) {
- mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu,
- SmsCbHeader.PDU_HEADER_LENGTH, 2);
+ if (hasLanguageIndicator && pdu.length >= offset + 2) {
+ // Language is two GSM characters.
+ // The actual body text is offset by 2 bytes.
+ mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2);
offset += 2;
+ length -= 2;
}
try {
- mBody = new String(pdu, offset, (pdu.length & 0xfffe) - offset, "utf-16");
+ body = new String(pdu, offset, (length & 0xfffe), "utf-16");
} catch (UnsupportedEncodingException e) {
// Eeeek
}
@@ -252,16 +319,18 @@
break;
}
- if (mBody != null) {
+ if (body != null) {
// Remove trailing carriage return
- for (int i = mBody.length() - 1; i >= 0; i--) {
- if (mBody.charAt(i) != CARRIAGE_RETURN) {
- mBody = mBody.substring(0, i + 1);
+ for (int i = body.length() - 1; i >= 0; i--) {
+ if (body.charAt(i) != CARRIAGE_RETURN) {
+ body = body.substring(0, i + 1);
break;
}
}
} else {
- mBody = "";
+ body = "";
}
+
+ return body;
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
index 5f27cfc..0945a38 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
@@ -17,8 +17,31 @@
package com.android.internal.telephony.gsm;
public class SmsCbHeader {
+ /**
+ * Length of SMS-CB header
+ */
public static final int PDU_HEADER_LENGTH = 6;
+ /**
+ * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
+ */
+ public static final int FORMAT_GSM = 1;
+
+ /**
+ * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
+ */
+ public static final int FORMAT_UMTS = 2;
+
+ /**
+ * Message type value as defined in 3gpp TS 25.324, section 11.1.
+ */
+ private static final int MESSAGE_TYPE_CBS_MESSAGE = 1;
+
+ /**
+ * Length of GSM pdus
+ */
+ private static final int PDU_LENGTH_GSM = 88;
+
public final int geographicalScope;
public final int messageCode;
@@ -33,27 +56,55 @@
public final int nrOfPages;
+ public final int format;
+
public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
throw new IllegalArgumentException("Illegal PDU");
}
- geographicalScope = (pdu[0] & 0xc0) >> 6;
- messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4);
- updateNumber = pdu[1] & 0x0f;
- messageIdentifier = (pdu[2] << 8) | pdu[3];
- dataCodingScheme = pdu[4];
+ if (pdu.length <= PDU_LENGTH_GSM) {
+ // GSM pdus are no more than 88 bytes
+ format = FORMAT_GSM;
+ geographicalScope = (pdu[0] & 0xc0) >> 6;
+ messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4);
+ updateNumber = pdu[1] & 0x0f;
+ messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff);
+ dataCodingScheme = pdu[4] & 0xff;
- // Check for invalid page parameter
- int pageIndex = (pdu[5] & 0xf0) >> 4;
- int nrOfPages = pdu[5] & 0x0f;
+ // Check for invalid page parameter
+ int pageIndex = (pdu[5] & 0xf0) >> 4;
+ int nrOfPages = pdu[5] & 0x0f;
- if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
+ if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
+ pageIndex = 1;
+ nrOfPages = 1;
+ }
+
+ this.pageIndex = pageIndex;
+ this.nrOfPages = nrOfPages;
+ } else {
+ // UMTS pdus are always at least 90 bytes since the payload includes
+ // a number-of-pages octet and also one length octet per page
+ format = FORMAT_UMTS;
+
+ int messageType = pdu[0];
+
+ if (messageType != MESSAGE_TYPE_CBS_MESSAGE) {
+ throw new IllegalArgumentException("Unsupported message type " + messageType);
+ }
+
+ messageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff;
+ geographicalScope = (pdu[3] & 0xc0) >> 6;
+ messageCode = ((pdu[3] & 0x3f) << 4) | ((pdu[4] & 0xf0) >> 4);
+ updateNumber = pdu[4] & 0x0f;
+ dataCodingScheme = pdu[5] & 0xff;
+
+ // We will always consider a UMTS message as having one single page
+ // since there's only one instance of the header, even though the
+ // actual payload may contain several pages.
pageIndex = 1;
nrOfPages = 1;
}
-
- this.pageIndex = pageIndex;
- this.nrOfPages = nrOfPages;
}
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java
index 7136ea0..b131a01 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java
@@ -69,6 +69,36 @@
doTestGeographicalScopeValue(pdu, (byte)0xC0, SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE);
}
+ public void testGetGeographicalScopeUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
+ (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
+ (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
+ (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
+ (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x34
+ };
+
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected geographical scope decoded",
+ SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE, msg.getGeographicalScope());
+ }
+
public void testGetMessageBody7Bit() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41,
@@ -92,6 +122,83 @@
msg.getMessageBody());
}
+ public void testGetMessageBody7BitUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
+ (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
+ (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
+ (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
+ (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x34
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+ }
+
+ public void testGetMessageBody7BitMultipageUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x01, (byte)0xC0, (byte)0x00, (byte)0x40,
+
+ (byte)0x02,
+
+ (byte)0xC6, (byte)0xB4, (byte)0x7C, (byte)0x4E, (byte)0x07, (byte)0xC1,
+ (byte)0xC3, (byte)0xE7, (byte)0xF2, (byte)0xAA, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A,
+ (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34,
+ (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x0A,
+
+ (byte)0xD3, (byte)0xF2, (byte)0xF8, (byte)0xED, (byte)0x26, (byte)0x83,
+ (byte)0xE0, (byte)0xE1, (byte)0x73, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A,
+ (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34,
+ (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x0A
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected multipage 7-bit string decoded",
+ "First page+Second page",
+ msg.getMessageBody());
+ }
+
public void testGetMessageBody7BitFull() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x40, (byte)0x11, (byte)0x41,
@@ -117,6 +224,38 @@
msg.getMessageBody());
}
+ public void testGetMessageBody7BitFullUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xC4, (byte)0xE5, (byte)0xB4,
+ (byte)0xFB, (byte)0x0C, (byte)0x2A, (byte)0xE3, (byte)0xC3, (byte)0x63,
+ (byte)0x3A, (byte)0x3B, (byte)0x0F, (byte)0xCA, (byte)0xCD, (byte)0x40,
+ (byte)0x63, (byte)0x74, (byte)0x58, (byte)0x1E, (byte)0x1E, (byte)0xD3,
+ (byte)0xCB, (byte)0xF2, (byte)0x39, (byte)0x88, (byte)0xFD, (byte)0x76,
+ (byte)0x9F, (byte)0x59, (byte)0xA0, (byte)0x76, (byte)0x39, (byte)0xEC,
+ (byte)0x4E, (byte)0xBB, (byte)0xCF, (byte)0x20, (byte)0x3A, (byte)0xBA,
+ (byte)0x2C, (byte)0x2F, (byte)0x83, (byte)0xD2, (byte)0x73, (byte)0x90,
+ (byte)0xFB, (byte)0x0D, (byte)0x82, (byte)0x87, (byte)0xC9, (byte)0xE4,
+ (byte)0xB4, (byte)0xFB, (byte)0x1C, (byte)0x02,
+
+ (byte)0x52
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals(
+ "Unexpected 7-bit string decoded",
+ "A GSM default alphabet message being exactly 93 characters long, " +
+ "meaning there is no padding!",
+ msg.getMessageBody());
+ }
+
public void testGetMessageBody7BitWithLanguage() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x04, (byte)0x11, (byte)0x41,
@@ -167,6 +306,38 @@
assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
}
+ public void testGetMessageBody7BitWithLanguageInBodyUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x10,
+
+ (byte)0x01,
+
+ (byte)0x73, (byte)0x7B, (byte)0x23, (byte)0x08, (byte)0x3A, (byte)0x4E,
+ (byte)0x9B, (byte)0x20, (byte)0x72, (byte)0xD9, (byte)0x1C, (byte)0xAE,
+ (byte)0xB3, (byte)0xE9, (byte)0xA0, (byte)0x30, (byte)0x1B, (byte)0x8E,
+ (byte)0x0E, (byte)0x8B, (byte)0xCB, (byte)0x74, (byte)0x50, (byte)0xBB,
+ (byte)0x3C, (byte)0x9F, (byte)0x87, (byte)0xCF, (byte)0x65, (byte)0xD0,
+ (byte)0x3D, (byte)0x4D, (byte)0x47, (byte)0x83, (byte)0xC6, (byte)0x61,
+ (byte)0xB9, (byte)0x3C, (byte)0x1D, (byte)0x3E, (byte)0x97, (byte)0x41,
+ (byte)0xF2, (byte)0x32, (byte)0xBD, (byte)0x2E, (byte)0x77, (byte)0x83,
+ (byte)0xE0, (byte)0x61, (byte)0x32, (byte)0x39, (byte)0xED, (byte)0x3E,
+ (byte)0x37, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x37
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
+ }
+
public void testGetMessageBody8Bit() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x44, (byte)0x11, (byte)0x41,
@@ -210,6 +381,81 @@
"A UCS2 message containing a \u0434 character", msg.getMessageBody());
}
+ public void testGetMessageBodyUcs2Umts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48,
+
+ (byte)0x01,
+
+ (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x55,
+ (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53, (byte)0x00, (byte)0x32,
+ (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D, (byte)0x00, (byte)0x65,
+ (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x61,
+ (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x20,
+ (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F, (byte)0x00, (byte)0x6E,
+ (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x69,
+ (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E,
+ (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x61,
+ (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34, (byte)0x00, (byte)0x20,
+ (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68, (byte)0x00, (byte)0x61,
+ (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x63,
+ (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x72,
+ (byte)0x00, (byte)0x0D, (byte)0x00, (byte)0x0D,
+
+ (byte)0x4E
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+ }
+
+ public void testGetMessageBodyUcs2MultipageUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x48,
+
+ (byte)0x02,
+
+ (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x41,
+ (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+
+ (byte)0x06,
+
+ (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42, (byte)0x00, (byte)0x42,
+ (byte)0x00, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+ (byte)0x0D, (byte)0x0D, (byte)0x0D, (byte)0x0D,
+
+ (byte)0x06
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected multipage UCS2 string decoded",
+ "AAABBB", msg.getMessageBody());
+ }
+
public void testGetMessageBodyUcs2WithLanguageInBody() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x00, (byte)0x32, (byte)0x11, (byte)0x11, (byte)0x78,
@@ -234,6 +480,37 @@
assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
}
+ public void testGetMessageBodyUcs2WithLanguageInBodyUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x00, (byte)0x32, (byte)0xC0, (byte)0x00, (byte)0x11,
+
+ (byte)0x01,
+
+ (byte)0x78, (byte)0x3C, (byte)0x00, (byte)0x41, (byte)0x00, (byte)0x20,
+ (byte)0x00, (byte)0x55, (byte)0x00, (byte)0x43, (byte)0x00, (byte)0x53,
+ (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x6D,
+ (byte)0x00, (byte)0x65, (byte)0x00, (byte)0x73, (byte)0x00, (byte)0x73,
+ (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x65,
+ (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x6F,
+ (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x61,
+ (byte)0x00, (byte)0x69, (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x69,
+ (byte)0x00, (byte)0x6E, (byte)0x00, (byte)0x67, (byte)0x00, (byte)0x20,
+ (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x20, (byte)0x04, (byte)0x34,
+ (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x68,
+ (byte)0x00, (byte)0x61, (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x61,
+ (byte)0x00, (byte)0x63, (byte)0x00, (byte)0x74, (byte)0x00, (byte)0x65,
+ (byte)0x00, (byte)0x72, (byte)0x00, (byte)0x0D,
+
+ (byte)0x50
+ };
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
+ }
+
public void testGetMessageIdentifier() {
byte[] pdu = {
(byte)0xC0, (byte)0x00, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
@@ -256,6 +533,35 @@
assertEquals("Unexpected message identifier decoded", 12345, msg.getMessageIdentifier());
}
+ public void testGetMessageIdentifierUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
+ (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
+ (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
+ (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
+ (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x34
+ };
+
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected message identifier decoded", 12345, msg.getMessageIdentifier());
+ }
+
public void testGetMessageCode() {
byte[] pdu = {
(byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
@@ -278,6 +584,35 @@
assertEquals("Unexpected message code decoded", 682, msg.getMessageCode());
}
+ public void testGetMessageCodeUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
+ (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
+ (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
+ (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
+ (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x34
+ };
+
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected message code decoded", 682, msg.getMessageCode());
+ }
+
public void testGetUpdateNumber() {
byte[] pdu = {
(byte)0x2A, (byte)0xA5, (byte)0x30, (byte)0x39, (byte)0x40, (byte)0x11, (byte)0x41,
@@ -299,4 +634,33 @@
assertEquals("Unexpected update number decoded", 5, msg.getUpdateNumber());
}
+
+ public void testGetUpdateNumberUmts() {
+ byte[] pdu = {
+ (byte)0x01, (byte)0x30, (byte)0x39, (byte)0x2A, (byte)0xA5, (byte)0x40,
+
+ (byte)0x01,
+
+ (byte)0x41, (byte)0xD0, (byte)0x71, (byte)0xDA, (byte)0x04, (byte)0x91,
+ (byte)0xCB, (byte)0xE6, (byte)0x70, (byte)0x9D, (byte)0x4D, (byte)0x07,
+ (byte)0x85, (byte)0xD9, (byte)0x70, (byte)0x74, (byte)0x58, (byte)0x5C,
+ (byte)0xA6, (byte)0x83, (byte)0xDA, (byte)0xE5, (byte)0xF9, (byte)0x3C,
+ (byte)0x7C, (byte)0x2E, (byte)0x83, (byte)0xEE, (byte)0x69, (byte)0x3A,
+ (byte)0x1A, (byte)0x34, (byte)0x0E, (byte)0xCB, (byte)0xE5, (byte)0xE9,
+ (byte)0xF0, (byte)0xB9, (byte)0x0C, (byte)0x92, (byte)0x97, (byte)0xE9,
+ (byte)0x75, (byte)0xB9, (byte)0x1B, (byte)0x04, (byte)0x0F, (byte)0x93,
+ (byte)0xC9, (byte)0x69, (byte)0xF7, (byte)0xB9, (byte)0xD1, (byte)0x68,
+ (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3, (byte)0xD1,
+ (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46, (byte)0xA3,
+ (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D, (byte)0x46,
+ (byte)0xA3, (byte)0xD1, (byte)0x68, (byte)0x34, (byte)0x1A, (byte)0x8D,
+ (byte)0x46, (byte)0xA3, (byte)0xD1, (byte)0x00,
+
+ (byte)0x34
+ };
+
+ SmsCbMessage msg = SmsCbMessage.createFromPdu(pdu);
+
+ assertEquals("Unexpected update number decoded", 5, msg.getUpdateNumber());
+ }
}
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 2aeb9e1..d067e7d 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -19,9 +19,9 @@
<string name="button3_text">Button3</string>
<string name="button4_text">Button4</string>
<string name="button_right_text">Right</string>
- <string name="button_after_text">After</string>
+ <string name="button_after_text">End</string>
<string name="button_left_text">Left</string>
- <string name="button_before_text">Before</string>
+ <string name="button_before_text">Start</string>
<string name="button_requestlayout_text">Request Layout</string>
<string name="textview_text">This is a text for a TextView</string>
<string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/globe.png b/tests/RenderScriptTests/PerfTest/res/drawable/globe.png
new file mode 100755
index 0000000..f9d6172
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/globe.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index 5377f12..3ba6ba4 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -113,16 +113,20 @@
private Allocation mTexOpaque;
private Allocation mTexTransparent;
private Allocation mTexChecker;
+ private Allocation mTexGlobe;
private Mesh m10by10Mesh;
private Mesh m100by100Mesh;
private Mesh mWbyHMesh;
private Mesh mTorus;
+ private Mesh mSingleMesh;
Font mFontSans;
Font mFontSerif;
private Allocation mTextAlloc;
+ private ScriptField_TexAllocs_s mTextureAllocs;
+
private ScriptC_rsbench mScript;
private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
@@ -253,6 +257,27 @@
return tmb.create(true);
}
+ /**
+ * Create a mesh with a single quad for the given width and height.
+ */
+ private Mesh getSingleMesh(float width, float height) {
+ Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+ 2, Mesh.TriangleMeshBuilder.TEXTURE_0);
+ float xOffset = width/2;
+ float yOffset = height/2;
+ tmb.setTexture(0, 0);
+ tmb.addVertex(-1.0f * xOffset, -1.0f * yOffset);
+ tmb.setTexture(1, 0);
+ tmb.addVertex(xOffset, -1.0f * yOffset);
+ tmb.setTexture(1, 1);
+ tmb.addVertex(xOffset, yOffset);
+ tmb.setTexture(0, 1);
+ tmb.addVertex(-1.0f * xOffset, yOffset);
+ tmb.addTriangle(0, 3, 1);
+ tmb.addTriangle(1, 3, 2);
+ return tmb.create(true);
+ }
+
private void initProgramStore() {
// Use stock the stock program store object
mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS);
@@ -392,11 +417,13 @@
mTexOpaque = loadTextureRGB(R.drawable.data);
mTexTransparent = loadTextureARGB(R.drawable.leaf);
mTexChecker = loadTextureRGB(R.drawable.checker);
+ mTexGlobe = loadTextureRGB(R.drawable.globe);
mScript.set_gTexTorus(mTexTorus);
mScript.set_gTexOpaque(mTexOpaque);
mScript.set_gTexTransparent(mTexTransparent);
mScript.set_gTexChecker(mTexChecker);
+ mScript.set_gTexGlobe(mTexGlobe);
}
private void initFonts() {
@@ -418,6 +445,8 @@
mScript.set_g100by100Mesh(m100by100Mesh);
mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4);
mScript.set_gWbyHMesh(mWbyHMesh);
+ mSingleMesh = getSingleMesh(50, 50);
+ mScript.set_gSingleMesh(mSingleMesh);
FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
FileA3D.IndexEntry entry = model.getIndexEntry(0);
@@ -517,6 +546,16 @@
Allocation.USAGE_GRAPHICS_RENDER_TARGET);
mScript.set_gRenderBufferDepth(offscreen);
+
+ mTextureAllocs = new ScriptField_TexAllocs_s(mRS, 100);
+ for (int i = 0; i < 100; i++) {
+ ScriptField_TexAllocs_s.Item texElem = new ScriptField_TexAllocs_s.Item();
+ texElem.texture = loadTextureRGB(R.drawable.globe);
+ mTextureAllocs.set(texElem, i, false);
+ }
+ mTextureAllocs.copyAll();
+ mScript.bind_gTexList100(mTextureAllocs);
+
mRS.bindRootScript(mScript);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index e7f5cd4..b6572fb 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -23,7 +23,7 @@
const int RS_MSG_TEST_DONE = 100;
const int RS_MSG_RESULTS_READY = 101;
-const int gMaxModes = 25;
+const int gMaxModes = 27;
int gMaxLoops;
// Allocation to send test names back to java
@@ -44,11 +44,19 @@
rs_allocation gTexTorus;
rs_allocation gTexTransparent;
rs_allocation gTexChecker;
+rs_allocation gTexGlobe;
+
+typedef struct TexAllocs_s {
+ rs_allocation texture;
+} TexAllocs;
+
+TexAllocs *gTexList100;
rs_mesh g10by10Mesh;
rs_mesh g100by100Mesh;
rs_mesh gWbyHMesh;
rs_mesh gTorusMesh;
+rs_mesh gSingleMesh;
rs_font gFontSans;
rs_font gFontSerif;
@@ -142,7 +150,7 @@
}
static void bindProgramVertexOrtho() {
- // Default vertex sahder
+ // Default vertex shader
rsgBindProgramVertex(gProgVertex);
// Setup the projection matrix
rs_matrix4x4 proj;
@@ -198,6 +206,33 @@
}
}
+// Display sample images in a mesh with different texture
+static void displayMeshWithMultiTexture(int meshMode) {
+ bindProgramVertexOrtho();
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendAlpha);
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+
+ int meshCount = (int)pow(10.0f, (float)(meshMode + 1));
+
+ float yPos = 0;
+ for (int y = 0; y < meshCount; y++) {
+ yPos = (y + 1) * 50;
+ float xPos = 0;
+ for (int x = 0; x < meshCount; x++) {
+ xPos = (x + 1) * 50;
+ rs_matrix4x4 matrix;
+ rsMatrixLoadTranslate(&matrix, xPos, yPos, 0);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ int i = (x + y * meshCount) % 100;
+ rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].texture);
+ rsgDrawMesh(gSingleMesh);
+ }
+ }
+}
+
static float gTorusRotation = 0;
static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
if (buffer == 0) {
@@ -497,6 +532,8 @@
"Geo test 25.6k heavy fragment heavy vertex",
"Geo test 51.2k heavy fragment heavy vertex",
"Geo test 204.8k small tries heavy fragment heavy vertex",
+ "Mesh with 10 by 10 texture",
+ "Mesh with 100 by 100 texture",
};
void getTestName(int testIndex) {
@@ -589,6 +626,12 @@
case 24:
displayPixelLightSamples(8, true);
break;
+ case 25:
+ displayMeshWithMultiTexture(0);
+ break;
+ case 26:
+ displayMeshWithMultiTexture(1);
+ break;
}
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 0129114..b212533 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -145,13 +145,10 @@
},
new Test("Priority notification") {
public void run() {
- Notification not = new Notification(StatusBarTest.this,
+ Notification not = new Notification(
R.drawable.stat_sys_phone,
"Incoming call from: Imperious Leader",
- System.currentTimeMillis()-(1000*60*60*24),
- "Imperious Leader",
- "(888) 555-5038",
- null
+ System.currentTimeMillis()-(1000*60*60*24)
);
not.flags |= Notification.FLAG_HIGH_PRIORITY;
Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class);
@@ -248,12 +245,10 @@
mHandler.postDelayed(new Runnable() {
public void run() {
mNotificationManager.notify(1,
- new Notification(StatusBarTest.this,
+ new Notification(
R.drawable.ic_statusbar_missedcall,
"tick tick tick",
- System.currentTimeMillis()-(1000*60*60*24),
- "(453) 123-2328",
- "", null
+ System.currentTimeMillis()-(1000*60*60*24)
));
}
}, 3000);