summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java57
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl66
-rw-r--r--core/java/android/accessibilityservice/UiTestAutomationBridge.java418
-rw-r--r--core/java/android/animation/LayoutTransition.java110
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java24
-rw-r--r--core/java/android/annotation/SuppressLint.java38
-rw-r--r--core/java/android/annotation/TargetApi.java35
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/LoaderManager.java56
-rw-r--r--core/java/android/content/AsyncTaskLoader.java146
-rw-r--r--core/java/android/content/CancellationSignal.java (renamed from core/java/android/content/CancelationSignal.java)52
-rw-r--r--core/java/android/content/ContentProvider.java20
-rw-r--r--core/java/android/content/ContentProviderClient.java12
-rw-r--r--core/java/android/content/ContentProviderNative.java18
-rw-r--r--core/java/android/content/ContentResolver.java16
-rw-r--r--core/java/android/content/CursorLoader.java16
-rw-r--r--core/java/android/content/ICancellationSignal.aidl (renamed from core/java/android/content/ICancelationSignal.aidl)2
-rw-r--r--core/java/android/content/IContentProvider.java4
-rw-r--r--core/java/android/content/Intent.java11
-rw-r--r--core/java/android/content/Loader.java101
-rw-r--r--core/java/android/content/OperationCanceledException.java2
-rw-r--r--core/java/android/content/res/Configuration.java1
-rw-r--r--core/java/android/database/DatabaseUtils.java6
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java100
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java22
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java26
-rw-r--r--core/java/android/database/sqlite/SQLiteDirectCursorDriver.java10
-rw-r--r--core/java/android/database/sqlite/SQLiteProgram.java6
-rw-r--r--core/java/android/database/sqlite/SQLiteQuery.java12
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java16
-rw-r--r--core/java/android/database/sqlite/SQLiteSession.java154
-rw-r--r--core/java/android/net/ConnectivityManager.java11
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl2
-rw-r--r--core/java/android/net/NetworkPolicy.java50
-rw-r--r--core/java/android/os/AsyncTask.java2
-rw-r--r--core/java/android/provider/MediaStore.java8
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/view/AccessibilityNodeInfoCache.java171
-rw-r--r--core/java/android/view/ActionMode.java12
-rw-r--r--core/java/android/view/Choreographer.java24
-rw-r--r--core/java/android/view/GLES20Canvas.java27
-rw-r--r--core/java/android/view/GLES20DisplayList.java8
-rw-r--r--core/java/android/view/HardwareRenderer.java11
-rw-r--r--core/java/android/view/View.java60
-rw-r--r--core/java/android/view/ViewGroup.java44
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java142
-rw-r--r--core/java/android/view/ViewRootImpl.java301
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java141
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java15
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java11
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl8
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl4
-rw-r--r--core/java/android/webkit/Network.java4
-rw-r--r--core/java/android/webkit/WebCoreThreadWatchdog.java39
-rw-r--r--core/java/android/webkit/WebView.java392
-rw-r--r--core/java/android/webkit/WebViewCore.java38
-rw-r--r--core/java/android/widget/GridLayout.java8
-rw-r--r--core/java/android/widget/ListView.java1
-rw-r--r--core/java/android/widget/NumberPicker.java10
-rw-r--r--core/java/android/widget/TextView.java71
-rw-r--r--core/java/com/android/internal/util/FastMath.java6
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java7
63 files changed, 2309 insertions, 894 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 211be52..a463a62 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,8 +17,10 @@
package android.accessibilityservice;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -218,10 +220,17 @@ public abstract class AccessibilityService extends Service {
private static final String LOG_TAG = "AccessibilityService";
- private AccessibilityServiceInfo mInfo;
+ interface Callbacks {
+ public void onAccessibilityEvent(AccessibilityEvent event);
+ public void onInterrupt();
+ public void onServiceConnected();
+ public void onSetConnectionId(int connectionId);
+ }
private int mConnectionId;
+ private AccessibilityServiceInfo mInfo;
+
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
*
@@ -282,27 +291,49 @@ public abstract class AccessibilityService extends Service {
*/
@Override
public final IBinder onBind(Intent intent) {
- return new IEventListenerWrapper(this);
+ return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
+ @Override
+ public void onServiceConnected() {
+ AccessibilityService.this.onServiceConnected();
+ }
+
+ @Override
+ public void onInterrupt() {
+ AccessibilityService.this.onInterrupt();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ AccessibilityService.this.onAccessibilityEvent(event);
+ }
+
+ @Override
+ public void onSetConnectionId( int connectionId) {
+ mConnectionId = connectionId;
+ }
+ });
}
/**
* Implements the internal {@link IEventListener} interface to convert
* incoming calls to it back to calls on an {@link AccessibilityService}.
*/
- class IEventListenerWrapper extends IEventListener.Stub
+ static class IEventListenerWrapper extends IEventListener.Stub
implements HandlerCaller.Callback {
+ static final int NO_ID = -1;
+
private static final int DO_SET_SET_CONNECTION = 10;
private static final int DO_ON_INTERRUPT = 20;
private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
private final HandlerCaller mCaller;
- private final AccessibilityService mTarget;
+ private final Callbacks mCallback;
- public IEventListenerWrapper(AccessibilityService context) {
- mTarget = context;
- mCaller = new HandlerCaller(context, this);
+ public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
+ mCallback = callback;
+ mCaller = new HandlerCaller(context, looper, this);
}
public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
@@ -326,12 +357,13 @@ public abstract class AccessibilityService extends Service {
case DO_ON_ACCESSIBILITY_EVENT :
AccessibilityEvent event = (AccessibilityEvent) message.obj;
if (event != null) {
- mTarget.onAccessibilityEvent(event);
+ AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
+ mCallback.onAccessibilityEvent(event);
event.recycle();
}
return;
case DO_ON_INTERRUPT :
- mTarget.onInterrupt();
+ mCallback.onInterrupt();
return;
case DO_SET_SET_CONNECTION :
final int connectionId = message.arg1;
@@ -340,12 +372,11 @@ public abstract class AccessibilityService extends Service {
if (connection != null) {
AccessibilityInteractionClient.getInstance().addConnection(connectionId,
connection);
- mConnectionId = connectionId;
- mTarget.onServiceConnected();
+ mCallback.onSetConnectionId(connectionId);
+ mCallback.onServiceConnected();
} else {
AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
- mConnectionId = AccessibilityInteractionClient.NO_ID;
- // TODO: Do we need a onServiceDisconnected callback?
+ mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
}
return;
default :
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e53b313..c9468eb 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -32,8 +32,13 @@ interface IAccessibilityServiceConnection {
/**
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
- * @param accessibilityWindowId A unique window id.
- * @param accessibilityNodeId A unique view id or virtual descendant id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
@@ -46,57 +51,58 @@ interface IAccessibilityServiceConnection {
/**
* Finds {@link AccessibilityNodeInfo}s by View text. The match is case
* insensitive containment. The search is performed in the window whose
- * id is specified and starts from the View whose accessibility id is
+ * id is specified and starts from the node whose accessibility id is
* specified.
*
- * @param text The searched text.
- * @param accessibilityWindowId A unique window id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
- * where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
- * @param interactionId The id of the interaction for matching with the callback result.
- * @param callback Callback which to receive the result.
- * @param threadId The id of the calling thread.
- * @return The current window scale, where zero means a failure.
- */
- float findAccessibilityNodeInfosByText(String text, int accessibilityWindowId,
- long accessibilityNodeId, int interractionId,
- IAccessibilityInteractionConnectionCallback callback, long threadId);
-
- /**
- * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
- * insensitive containment. The search is performed in the currently
- * active window and start from the root View in the window.
- *
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param text The searched text.
- * @param accessibilityId The id of the view from which to start searching.
- * Use {@link android.view.View#NO_ID} to start from the root.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
* @return The current window scale, where zero means a failure.
*/
- float findAccessibilityNodeInfosByTextInActiveWindow(String text,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+ String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId);
/**
- * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
- * in the currently active window and starts from the root View in the window.
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
*
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param id The id of the node.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
* @return The current window scale, where zero means a failure.
*/
- float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, long threadId);
+ float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId,
+ int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ long threadId);
/**
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
*
- * @param accessibilityWindowId The id of the window.
- * @param accessibilityNodeId A unique view id or virtual descendant id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param action The action to perform.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
new file mode 100644
index 0000000..9d48efc
--- /dev/null
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2012 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 android.accessibilityservice.AccessibilityService.Callbacks;
+import android.accessibilityservice.AccessibilityService.IEventListenerWrapper;
+import android.content.Context;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.internal.util.Predicate;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class represents a bridge that can be used for UI test
+ * automation. It is responsible for connecting to the system,
+ * keeping track of the last accessibility event, and exposing
+ * window content querying APIs. This class is designed to be
+ * used from both an Android application and a Java program
+ * run from the shell.
+ *
+ * @hide
+ */
+public class UiTestAutomationBridge {
+
+ private static final String LOG_TAG = UiTestAutomationBridge.class.getSimpleName();
+
+ public static final int ACTIVE_WINDOW_ID = -1;
+
+ public static final long ROOT_NODE_ID = -1;
+
+ private static final int TIMEOUT_REGISTER_SERVICE = 5000;
+
+ private final Object mLock = new Object();
+
+ private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
+
+ private IEventListenerWrapper mListener;
+
+ private AccessibilityEvent mLastEvent;
+
+ private volatile boolean mWaitingForEventDelivery;
+
+ private volatile boolean mUnprocessedEventAvailable;
+
+ /**
+ * Gets the last received {@link AccessibilityEvent}.
+ *
+ * @return The event.
+ */
+ public AccessibilityEvent getLastAccessibilityEvent() {
+ return mLastEvent;
+ }
+
+ /**
+ * Callback for receiving an {@link AccessibilityEvent}.
+ *
+ * <strong>Note:</strong> This method is <strong>NOT</strong>
+ * executed on the application main thread. The client are
+ * responsible for proper synchronization.
+ *
+ * @param event The received event.
+ */
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ /* hook - do nothing */
+ }
+
+ /**
+ * Callback for requests to stop feedback.
+ *
+ * <strong>Note:</strong> This method is <strong>NOT</strong>
+ * executed on the application main thread. The client are
+ * responsible for proper synchronization.
+ */
+ public void onInterrupt() {
+ /* hook - do nothing */
+ }
+
+ /**
+ * Connects this service.
+ *
+ * @throws IllegalStateException If already connected.
+ */
+ public void connect() {
+ if (isConnected()) {
+ throw new IllegalStateException("Already connected.");
+ }
+
+ // Serialize binder calls to a handler on a dedicated thread
+ // different from the main since we expose APIs that block
+ // the main thread waiting for a result the deliver of which
+ // on the main thread will prevent that thread from waking up.
+ // The serialization is needed also to ensure that events are
+ // examined in delivery order. Otherwise, a fair locking
+ // is needed for making sure the binder calls are interleaved
+ // with check for the expected event and also to make sure the
+ // binder threads are allowed to proceed in the received order.
+ HandlerThread handlerThread = new HandlerThread("UiTestAutomationBridge");
+ handlerThread.start();
+ Looper looper = handlerThread.getLooper();
+
+ mListener = new IEventListenerWrapper(null, looper, new Callbacks() {
+ @Override
+ public void onServiceConnected() {
+ /* do nothing */
+ }
+
+ @Override
+ public void onInterrupt() {
+ UiTestAutomationBridge.this.onInterrupt();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ while (true) {
+ if (!mWaitingForEventDelivery) {
+ break;
+ }
+ if (!mUnprocessedEventAvailable) {
+ mUnprocessedEventAvailable = true;
+ mLastEvent = AccessibilityEvent.obtain(event);
+ mLock.notifyAll();
+ break;
+ }
+ try {
+ mLock.wait();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ UiTestAutomationBridge.this.onAccessibilityEvent(event);
+ }
+
+ @Override
+ public void onSetConnectionId(int connectionId) {
+ synchronized (mLock) {
+ mConnectionId = connectionId;
+ mLock.notifyAll();
+ }
+ }
+ });
+
+ final IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+ info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
+ try {
+ manager.registerUiTestAutomationService(mListener, info);
+ } catch (RemoteException re) {
+ throw new IllegalStateException("Cound not register UiAutomationService.", re);
+ }
+
+ synchronized (mLock) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ if (isConnected()) {
+ return;
+ }
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = TIMEOUT_REGISTER_SERVICE - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ throw new IllegalStateException("Cound not register UiAutomationService.");
+ }
+ try {
+ mLock.wait(remainingTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+
+ /**
+ * Disconnects this service.
+ *
+ * @throws IllegalStateException If already disconnected.
+ */
+ public void disconnect() {
+ if (!isConnected()) {
+ throw new IllegalStateException("Already disconnected.");
+ }
+
+ IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+ try {
+ manager.unregisterUiTestAutomationService(mListener);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while unregistering UiTestAutomationService", re);
+ }
+ }
+
+ /**
+ * Gets whether this service is connected.
+ *
+ * @return True if connected.
+ */
+ public boolean isConnected() {
+ return (mConnectionId != AccessibilityInteractionClient.NO_ID);
+ }
+
+ /**
+ * Executes a command and waits for a specific accessibility event type up
+ * to a given timeout.
+ *
+ * @param command The command to execute before starting to wait for the event.
+ * @param predicate Predicate for recognizing the awaited event.
+ * @param timeoutMillis The max wait time in milliseconds.
+ */
+ public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
+ Predicate<AccessibilityEvent> predicate, long timeoutMillis)
+ throws TimeoutException, Exception {
+ synchronized (mLock) {
+ // Prepare to wait for an event.
+ mWaitingForEventDelivery = true;
+ mUnprocessedEventAvailable = false;
+ if (mLastEvent != null) {
+ mLastEvent.recycle();
+ mLastEvent = null;
+ }
+ // Execute the command.
+ command.run();
+ // Wait for the event.
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ // If the expected event is received, that's it.
+ if ((mUnprocessedEventAvailable && predicate.apply(mLastEvent))) {
+ mWaitingForEventDelivery = false;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ return mLastEvent;
+ }
+ // Ask for another event.
+ mWaitingForEventDelivery = true;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ // Check if timed out and if not wait.
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ mWaitingForEventDelivery = false;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ throw new TimeoutException("Expacted event not received within: "
+ + timeoutMillis + " ms.");
+ }
+ try {
+ mLock.wait(remainingTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by accessibility id in the active
+ * window. The search is performed from the root node.
+ *
+ * @param accessibilityNodeId A unique view id or virtual descendant id for
+ * which to search.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityIdInActiveWindow(
+ long accessibilityNodeId) {
+ return findAccessibilityNodeInfoByAccessibilityId(ACTIVE_WINDOW_ID, accessibilityNodeId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id for
+ * which to search.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+ int accessibilityWindowId, long accessibilityNodeId) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ accessibilityWindowId, accessibilityNodeId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id in the active
+ * window. The search is performed from the root node.
+ *
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+ return findAccessibilityNodeInfoByViewId(ACTIVE_WINDOW_ID, ROOT_NODE_ID, viewId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+ long accessibilityNodeId, int viewId) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByViewId(connectionId, accessibilityWindowId,
+ accessibilityNodeId, viewId);
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by View text in the active
+ * window. The search is performed from the root node.
+ *
+ * @param text The searched text.
+ * @return The current window scale, where zero means a failure.
+ */
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(String text) {
+ return findAccessibilityNodeInfosByText(ACTIVE_WINDOW_ID, ROOT_NODE_ID, text);
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+ * insensitive containment. The search is performed in the window whose
+ * id is specified and starts from the node whose accessibility id is
+ * specified.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+ * @param text The searched text.
+ * @return The current window scale, where zero means a failure.
+ */
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ long accessibilityNodeId, String text) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfosByText(connectionId, accessibilityWindowId,
+ accessibilityNodeId, text);
+ }
+
+ /**
+ * Performs an accessibility action on an {@link AccessibilityNodeInfo}
+ * in the active window.
+ *
+ * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+ * @param action The action to perform.
+ * @return Whether the action was performed.
+ */
+ public boolean performAccessibilityActionInActiveWindow(long accessibilityNodeId, int action) {
+ return performAccessibilityAction(ACTIVE_WINDOW_ID, accessibilityNodeId, action);
+ }
+
+ /**
+ * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+ * @param action The action to perform.
+ * @return Whether the action was performed.
+ */
+ public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
+ int action) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance().performAccessibilityAction(connectionId,
+ accessibilityWindowId, accessibilityNodeId, action);
+ }
+
+ private void ensureValidConnection(int connectionId) {
+ if (connectionId == AccessibilityInteractionClient.NO_ID) {
+ throw new IllegalStateException("UiAutomationService not connected."
+ + " Did you call #register()?");
+ }
+ }
+}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 894f428..634e4d8 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -960,17 +960,17 @@ public class LayoutTransition {
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
- if (mListeners != null) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator anim) {
- currentAppearingAnimations.remove(child);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ currentAppearingAnimations.remove(child);
+ if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
}
}
- });
- }
+ }
+ });
currentAppearingAnimations.put(child, anim);
anim.start();
}
@@ -998,17 +998,19 @@ public class LayoutTransition {
anim.setStartDelay(mDisappearingDelay);
anim.setDuration(mDisappearingDuration);
anim.setTarget(child);
- if (mListeners != null) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator anim) {
- currentDisappearingAnimations.remove(child);
+ final float preAnimAlpha = child.getAlpha();
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ currentDisappearingAnimations.remove(child);
+ child.setAlpha(preAnimAlpha);
+ if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
}
}
- });
- }
+ }
+ });
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
@@ -1024,18 +1026,25 @@ public class LayoutTransition {
*
* @param parent The ViewGroup to which the View is being added.
* @param child The View being added to the ViewGroup.
+ * @param changesLayout Whether the removal will cause changes in the layout of other views
+ * in the container. INVISIBLE views becoming VISIBLE will not cause changes and thus will not
+ * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
- public void addChild(ViewGroup parent, View child) {
+ private void addChild(ViewGroup parent, View child, boolean changesLayout) {
// Want disappearing animations to finish up before proceeding
cancel(DISAPPEARING);
- // Also, cancel changing animations so that we start fresh ones from current locations
- cancel(CHANGE_APPEARING);
+ if (changesLayout) {
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_APPEARING);
+ }
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, APPEARING);
}
}
- runChangeTransition(parent, child, APPEARING);
+ if (changesLayout) {
+ runChangeTransition(parent, child, APPEARING);
+ }
runAppearingTransition(parent, child);
}
@@ -1048,8 +1057,31 @@ public class LayoutTransition {
* @param parent The ViewGroup to which the View is being added.
* @param child The View being added to the ViewGroup.
*/
+ public void addChild(ViewGroup parent, View child) {
+ addChild(parent, child, true);
+ }
+
+ /**
+ * @deprecated Use {@link #showChild(android.view.ViewGroup, android.view.View, int)}.
+ */
+ @Deprecated
public void showChild(ViewGroup parent, View child) {
- addChild(parent, child);
+ addChild(parent, child, true);
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be made visible in the
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The ViewGroup in which the View is being made visible.
+ * @param child The View being made visible.
+ * @param oldVisibility The previous visibility value of the child View, either
+ * {@link View#GONE} or {@link View#INVISIBLE}.
+ */
+ public void showChild(ViewGroup parent, View child, int oldVisibility) {
+ addChild(parent, child, oldVisibility == View.GONE);
}
/**
@@ -1060,18 +1092,25 @@ public class LayoutTransition {
*
* @param parent The ViewGroup from which the View is being removed.
* @param child The View being removed from the ViewGroup.
+ * @param changesLayout Whether the removal will cause changes in the layout of other views
+ * in the container. Views becoming INVISIBLE will not cause changes and thus will not
+ * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
- public void removeChild(ViewGroup parent, View child) {
+ private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
// Want appearing animations to finish up before proceeding
cancel(APPEARING);
- // Also, cancel changing animations so that we start fresh ones from current locations
- cancel(CHANGE_DISAPPEARING);
+ if (changesLayout) {
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_DISAPPEARING);
+ }
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, DISAPPEARING);
}
}
- runChangeTransition(parent, child, DISAPPEARING);
+ if (changesLayout) {
+ runChangeTransition(parent, child, DISAPPEARING);
+ }
runDisappearingTransition(parent, child);
}
@@ -1084,8 +1123,31 @@ public class LayoutTransition {
* @param parent The ViewGroup from which the View is being removed.
* @param child The View being removed from the ViewGroup.
*/
+ public void removeChild(ViewGroup parent, View child) {
+ removeChild(parent, child, true);
+ }
+
+ /**
+ * @deprecated Use {@link #hideChild(android.view.ViewGroup, android.view.View, int)}.
+ */
+ @Deprecated
public void hideChild(ViewGroup parent, View child) {
- removeChild(parent, child);
+ removeChild(parent, child, true);
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be hidden in
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The parent ViewGroup of the View being hidden.
+ * @param child The View being hidden.
+ * @param newVisibility The new visibility value of the child View, either
+ * {@link View#GONE} or {@link View#INVISIBLE}.
+ */
+ public void hideChild(ViewGroup parent, View child, int newVisibility) {
+ removeChild(parent, child, newVisibility == View.GONE);
}
/**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c7a129e..cc1efb9 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -19,6 +19,7 @@ package android.animation;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.view.Choreographer;
import android.view.animation.AccelerateDecelerateInterpolator;
@@ -52,6 +53,7 @@ public class ValueAnimator extends Animator {
/**
* Internal constants
*/
+ private static float sDurationScale = 1.0f;
/**
* Messages sent to timing handler: START is sent when an animation first begins.
@@ -158,10 +160,12 @@ public class ValueAnimator extends Animator {
//
// How long the animation should last in ms
- private long mDuration = 300;
+ private long mDuration = (long)(300 * sDurationScale);
+ private long mUnscaledDuration = 300;
// The amount of time in ms to delay starting the animation after start() is called
private long mStartDelay = 0;
+ private long mUnscaledStartDelay = 0;
// The number of times the animation will repeat. The default is 0, which means the animation
// will play only once
@@ -217,6 +221,14 @@ public class ValueAnimator extends Animator {
*/
public static final int INFINITE = -1;
+
+ /**
+ * @hide
+ */
+ public static void setDurationScale(float durationScale) {
+ sDurationScale = durationScale;
+ }
+
/**
* Creates a new ValueAnimator object. This default constructor is primarily for
* use internally; the factory methods which take parameters are more generally
@@ -453,7 +465,8 @@ public class ValueAnimator extends Animator {
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
- mDuration = duration;
+ mUnscaledDuration = duration;
+ mDuration = (long)(duration * sDurationScale);
return this;
}
@@ -463,7 +476,7 @@ public class ValueAnimator extends Animator {
* @return The length of the animation, in milliseconds.
*/
public long getDuration() {
- return mDuration;
+ return mUnscaledDuration;
}
/**
@@ -658,7 +671,7 @@ public class ValueAnimator extends Animator {
* @return the number of milliseconds to delay running the animation
*/
public long getStartDelay() {
- return mStartDelay;
+ return mUnscaledStartDelay;
}
/**
@@ -668,7 +681,8 @@ public class ValueAnimator extends Animator {
* @param startDelay The amount of the delay, in milliseconds
*/
public void setStartDelay(long startDelay) {
- this.mStartDelay = startDelay;
+ this.mStartDelay = (long)(startDelay * sDurationScale);
+ mUnscaledStartDelay = startDelay;
}
/**
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 0000000..ea17890
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+ project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+ /**
+ * This sets the target api level for the type..
+ */
+ int value();
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9807b89..3c5f53a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4413,7 +4413,7 @@ public final class ActivityThread {
});
}
- public static final ActivityThread systemMain() {
+ public static ActivityThread systemMain() {
HardwareRenderer.disable(true);
ActivityThread thread = new ActivityThread();
thread.attach(true);
@@ -4454,6 +4454,8 @@ public final class ActivityThread {
ActivityThread thread = new ActivityThread();
thread.attach(false);
+ AsyncTask.init();
+
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index d83d2e6..ff71ee7 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.content.Loader;
+import android.content.Loader.OnLoadCanceledListener;
import android.os.Bundle;
import android.util.DebugUtils;
import android.util.Log;
@@ -219,7 +220,8 @@ class LoaderManagerImpl extends LoaderManager {
boolean mCreatingLoader;
- final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+ final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+ Loader.OnLoadCanceledListener<Object> {
final int mId;
final Bundle mArgs;
LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -271,6 +273,7 @@ class LoaderManagerImpl extends LoaderManager {
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
+ mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
@@ -329,11 +332,21 @@ class LoaderManagerImpl extends LoaderManager {
// Let the loader know we're done with it
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}
}
-
+
+ void cancel() {
+ if (DEBUG) Log.v(TAG, " Canceling: " + this);
+ if (mStarted && mLoader != null && mListenerRegistered) {
+ if (!mLoader.cancelLoad()) {
+ onLoadCanceled(mLoader);
+ }
+ }
+ }
+
void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
@@ -361,6 +374,7 @@ class LoaderManagerImpl extends LoaderManager {
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
}
mLoader.reset();
}
@@ -368,8 +382,38 @@ class LoaderManagerImpl extends LoaderManager {
mPendingLoader.destroy();
}
}
-
- @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+ @Override
+ public void onLoadCanceled(Loader<Object> loader) {
+ if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+ if (mDestroyed) {
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- destroyed");
+ return;
+ }
+
+ if (mLoaders.get(mId) != this) {
+ // This cancellation message is not coming from the current active loader.
+ // We don't care about it.
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- not active");
+ return;
+ }
+
+ LoaderInfo pending = mPendingLoader;
+ if (pending != null) {
+ // There is a new request pending and we were just
+ // waiting for the old one to cancel or complete before starting
+ // it. So now it is time, switch over to the new loader.
+ if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
+ mPendingLoader = null;
+ mLoaders.put(mId, null);
+ destroy();
+ installLoader(pending);
+ }
+ }
+
+ @Override
+ public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
if (mDestroyed) {
@@ -632,7 +676,9 @@ class LoaderManagerImpl extends LoaderManager {
} else {
// Now we have three active loaders... we'll queue
// up this request to be processed once one of the other loaders
- // finishes.
+ // finishes or is canceled.
+ if (DEBUG) Log.v(TAG, " Current loader is running; attempting to cancel");
+ info.cancel();
if (info.mPendingLoader != null) {
if (DEBUG) Log.v(TAG, " Removing pending loader: " + info.mPendingLoader);
info.mPendingLoader.destroy();
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 944ca6b..da51952 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -53,19 +53,33 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
static final boolean DEBUG = false;
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
+ private final CountDownLatch mDone = new CountDownLatch(1);
- D result;
+ // Set to true to indicate that the task has been posted to a handler for
+ // execution at a later time. Used to throttle updates.
boolean waiting;
- private CountDownLatch done = new CountDownLatch(1);
-
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
- result = AsyncTaskLoader.this.onLoadInBackground();
- if (DEBUG) Slog.v(TAG, this + " <<< doInBackground");
- return result;
+ try {
+ D data = AsyncTaskLoader.this.onLoadInBackground();
+ if (DEBUG) Slog.v(TAG, this + " <<< doInBackground");
+ return data;
+ } catch (OperationCanceledException ex) {
+ if (!isCancelled()) {
+ // onLoadInBackground threw a canceled exception spuriously.
+ // This is problematic because it means that the LoaderManager did not
+ // cancel the Loader itself and still expects to receive a result.
+ // Additionally, the Loader's own state will not have been updated to
+ // reflect the fact that the task was being canceled.
+ // So we treat this case as an unhandled exception.
+ throw ex;
+ }
+ if (DEBUG) Slog.v(TAG, this + " <<< doInBackground (was canceled)");
+ return null;
+ }
}
/* Runs on the UI thread */
@@ -75,25 +89,37 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread */
@Override
- protected void onCancelled() {
+ protected void onCancelled(D data) {
if (DEBUG) Slog.v(TAG, this + " onCancelled");
try {
- AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+ AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread, when the waiting task is posted to a handler.
+ * This method is only executed when task execution was deferred (waiting was true). */
@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
+
+ /* Used for testing purposes to wait for the task to complete. */
+ public void waitForLoader() {
+ try {
+ mDone.await();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
}
volatile LoadTask mTask;
@@ -109,7 +135,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
/**
* Set amount to throttle updates by. This is the minimum time from
- * when the last {@link #onLoadInBackground()} call has completed until
+ * when the last {@link #loadInBackground()} call has completed until
* a new load is scheduled.
*
* @param delayMS Amount of delay, in milliseconds.
@@ -130,24 +156,9 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
executePendingTask();
}
- /**
- * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
- * for more info. Must be called on the main thread of the process.
- *
- * <p>Cancelling is not an immediate operation, since the load is performed
- * in a background thread. If there is currently a load in progress, this
- * method requests that the load be cancelled, and notes this is the case;
- * once the background thread has completed its work its remaining state
- * will be cleared. If another load request comes in during this time,
- * it will be held until the cancelled load is complete.
- *
- * @return Returns <tt>false</tt> if the task could not be cancelled,
- * typically because it has already completed normally, or
- * because {@link #startLoading()} hasn't been called; returns
- * <tt>true</tt> otherwise.
- */
- public boolean cancelLoad() {
- if (DEBUG) Slog.v(TAG, "cancelLoad: mTask=" + mTask);
+ @Override
+ protected boolean onCancelLoad() {
+ if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
if (mTask != null) {
if (mCancellingTask != null) {
// There was a pending task already waiting for a previous
@@ -173,7 +184,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
if (cancelled) {
mCancellingTask = mTask;
- onCancelLoadInBackground();
+ cancelLoadInBackground();
}
mTask = null;
return cancelled;
@@ -184,7 +195,10 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
/**
* Called if the task was canceled before it was completed. Gives the class a chance
- * to properly dispose of the result.
+ * to clean up post-cancellation and to properly dispose of the result.
+ *
+ * @param data The value that was returned by {@link #loadInBackground}, or null
+ * if the task threw {@link OperationCanceledException}.
*/
public void onCanceled(D data) {
}
@@ -218,6 +232,8 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mCancellingTask = null;
+ if (DEBUG) Slog.v(TAG, "Delivering cancellation");
+ deliverCancellation();
executePendingTask();
}
}
@@ -240,38 +256,72 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
}
/**
+ * Called on a worker thread to perform the actual load and to return
+ * the result of the load operation.
+ *
+ * Implementations should not deliver the result directly, but should return them
+ * from this method, which will eventually end up calling {@link #deliverResult} on
+ * the UI thread. If implementations need to process the results on the UI thread
+ * they may override {@link #deliverResult} and do so there.
+ *
+ * To support cancellation, this method should periodically check the value of
+ * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+ * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+ * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+ *
+ * When the load is canceled, this method may either return normally or throw
+ * {@link OperationCanceledException}. In either case, the {@link Loader} will
+ * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+ * result object, if any.
+ *
+ * @return The result of the load operation.
+ *
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #isLoadInBackgroundCanceled
+ * @see #cancelLoadInBackground
+ * @see #onCanceled
*/
public abstract D loadInBackground();
/**
- * Called on a worker thread to perform the actual load. Implementations should not deliver the
- * result directly, but should return them from this method, which will eventually end up
- * calling {@link #deliverResult} on the UI thread. If implementations need to process
- * the results on the UI thread they may override {@link #deliverResult} and do so
- * there.
+ * Calls {@link #loadInBackground()}.
+ *
+ * This method is reserved for use by the loader framework.
+ * Subclasses should override {@link #loadInBackground} instead of this method.
+ *
+ * @return The result of the load operation.
*
- * @return Implementations must return the result of their load operation.
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #loadInBackground
*/
protected D onLoadInBackground() {
return loadInBackground();
}
/**
- * Override this method to try to abort the computation currently taking
- * place on a background thread.
+ * Called on the main thread to abort a load in progress.
+ *
+ * Override this method to abort the current invocation of {@link #loadInBackground}
+ * that is running in the background on a worker thread.
*
- * Note that when this method is called, it is possible that {@link #loadInBackground}
- * has not started yet or has already completed.
+ * This method should do nothing if {@link #loadInBackground} has not started
+ * running or if it has already finished.
+ *
+ * @see #loadInBackground
*/
- protected void onCancelLoadInBackground() {
+ public void cancelLoadInBackground() {
}
/**
- * Returns true if the current execution of {@link #loadInBackground()} is being canceled.
+ * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
+ *
+ * @return True if the current invocation of {@link #loadInBackground} is being canceled.
*
- * @return True if the current execution of {@link #loadInBackground()} is being canceled.
+ * @see #loadInBackground
*/
- protected boolean isLoadInBackgroundCanceled() {
+ public boolean isLoadInBackgroundCanceled() {
return mCancellingTask != null;
}
@@ -288,11 +338,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
public void waitForLoader() {
LoadTask task = mTask;
if (task != null) {
- try {
- task.done.await();
- } catch (InterruptedException e) {
- // Ignore
- }
+ task.waitForLoader();
}
}
diff --git a/core/java/android/content/CancelationSignal.java b/core/java/android/content/CancellationSignal.java
index 58cf59d..2dbbe54 100644
--- a/core/java/android/content/CancelationSignal.java
+++ b/core/java/android/content/CancellationSignal.java
@@ -21,15 +21,15 @@ import android.os.RemoteException;
/**
* Provides the ability to cancel an operation in progress.
*/
-public final class CancelationSignal {
+public final class CancellationSignal {
private boolean mIsCanceled;
private OnCancelListener mOnCancelListener;
- private ICancelationSignal mRemote;
+ private ICancellationSignal mRemote;
/**
- * Creates a cancelation signal, initially not canceled.
+ * Creates a cancellation signal, initially not canceled.
*/
- public CancelationSignal() {
+ public CancellationSignal() {
}
/**
@@ -55,7 +55,7 @@ public final class CancelationSignal {
}
/**
- * Cancels the operation and signals the cancelation listener.
+ * Cancels the operation and signals the cancellation listener.
* If the operation has not yet started, then it will be canceled as soon as it does.
*/
public void cancel() {
@@ -76,17 +76,23 @@ public final class CancelationSignal {
}
/**
- * Sets the cancelation listener to be called when canceled.
- * If {@link CancelationSignal#cancel} has already been called, then the provided
+ * Sets the cancellation listener to be called when canceled.
+ *
+ * This method is intended to be used by the recipient of a cancellation signal
+ * such as a database or a content provider to handle cancellation requests
+ * while performing a long-running operation. This method is not intended to be
+ * used by applications themselves.
+ *
+ * If {@link CancellationSignal#cancel} has already been called, then the provided
* listener is invoked immediately.
*
- * The listener is called while holding the cancelation signal's lock which is
+ * The listener is called while holding the cancellation signal's lock which is
* also held while registering or unregistering the listener. Because of the lock,
* it is not possible for the listener to run after it has been unregistered.
- * This design choice makes it easier for clients of {@link CancelationSignal} to
+ * This design choice makes it easier for clients of {@link CancellationSignal} to
* prevent race conditions related to listener registration and unregistration.
*
- * @param listener The cancelation listener, or null to remove the current listener.
+ * @param listener The cancellation listener, or null to remove the current listener.
*/
public void setOnCancelListener(OnCancelListener listener) {
synchronized (this) {
@@ -104,7 +110,7 @@ public final class CancelationSignal {
*
* @hide
*/
- public void setRemote(ICancelationSignal remote) {
+ public void setRemote(ICancellationSignal remote) {
synchronized (this) {
mRemote = remote;
if (mIsCanceled && remote != null) {
@@ -118,47 +124,47 @@ public final class CancelationSignal {
/**
* Creates a transport that can be returned back to the caller of
- * a Binder function and subsequently used to dispatch a cancelation signal.
+ * a Binder function and subsequently used to dispatch a cancellation signal.
*
- * @return The new cancelation signal transport.
+ * @return The new cancellation signal transport.
*
* @hide
*/
- public static ICancelationSignal createTransport() {
+ public static ICancellationSignal createTransport() {
return new Transport();
}
/**
- * Given a locally created transport, returns its associated cancelation signal.
+ * Given a locally created transport, returns its associated cancellation signal.
*
* @param transport The locally created transport, or null if none.
- * @return The associated cancelation signal, or null if none.
+ * @return The associated cancellation signal, or null if none.
*
* @hide
*/
- public static CancelationSignal fromTransport(ICancelationSignal transport) {
+ public static CancellationSignal fromTransport(ICancellationSignal transport) {
if (transport instanceof Transport) {
- return ((Transport)transport).mCancelationSignal;
+ return ((Transport)transport).mCancellationSignal;
}
return null;
}
/**
- * Listens for cancelation.
+ * Listens for cancellation.
*/
public interface OnCancelListener {
/**
- * Called when {@link CancelationSignal#cancel} is invoked.
+ * Called when {@link CancellationSignal#cancel} is invoked.
*/
void onCancel();
}
- private static final class Transport extends ICancelationSignal.Stub {
- final CancelationSignal mCancelationSignal = new CancelationSignal();
+ private static final class Transport extends ICancellationSignal.Stub {
+ final CancellationSignal mCancellationSignal = new CancellationSignal();
@Override
public void cancel() throws RemoteException {
- mCancelationSignal.cancel();
+ mCancellationSignal.cancel();
}
}
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index adbeb6a..12e3ccf 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -178,10 +178,10 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
- ICancelationSignal cancelationSignal) {
+ ICancellationSignal cancellationSignal) {
enforceReadPermission(uri);
return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
- CancelationSignal.fromTransport(cancelationSignal));
+ CancellationSignal.fromTransport(cancellationSignal));
}
@Override
@@ -263,8 +263,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
@Override
- public ICancelationSignal createCancelationSignal() throws RemoteException {
- return CancelationSignal.createTransport();
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ return CancellationSignal.createTransport();
}
private void enforceReadPermission(Uri uri) {
@@ -557,7 +557,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String selection, String[] selectionArgs, String sortOrder);
/**
- * Implement this to handle query requests from clients with support for cancelation.
+ * Implement this to handle query requests from clients with support for cancellation.
* This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
@@ -597,9 +597,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return c;</pre>
* <p>
* If you implement this method then you must also implement the version of
- * {@link #query(Uri, String[], String, String[], String)} that does not take a cancelation
- * provider to ensure correct operation on older versions of the Android Framework in
- * which the cancelation signal overload was not available.
+ * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
+ * signal to ensure correct operation on older versions of the Android Framework in
+ * which the cancellation signal overload was not available.
*
* @param uri The URI to query. This will be the full URI sent by the client;
* if the client is requesting a specific record, the URI will end in a record number
@@ -614,14 +614,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* The values will be bound as Strings.
* @param sortOrder How the rows in the cursor should be sorted.
* If null then the provider is free to define the sort order.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return a Cursor or null.
*/
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
return query(uri, projection, selection, selectionArgs, sortOrder);
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 9a1fa65..3ac5e07 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -52,15 +52,15 @@ public class ContentProviderClient {
/** See {@link ContentProvider#query ContentProvider.query} */
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder, CancelationSignal cancelationSignal)
+ String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
throws RemoteException {
- ICancelationSignal remoteCancelationSignal = null;
- if (cancelationSignal != null) {
- remoteCancelationSignal = mContentProvider.createCancelationSignal();
- cancelationSignal.setRemote(remoteCancelationSignal);
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ remoteCancellationSignal = mContentProvider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
}
return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
- remoteCancelationSignal);
+ remoteCancellationSignal);
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index e0e277a..eb83dbc 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -105,11 +105,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
- ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+ ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
- cancelationSignal);
+ cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
cursor, observer, getProviderName());
@@ -300,9 +300,9 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
{
data.enforceInterface(IContentProvider.descriptor);
- ICancelationSignal cancelationSignal = createCancelationSignal();
+ ICancellationSignal cancellationSignal = createCancellationSignal();
reply.writeNoException();
- reply.writeStrongBinder(cancelationSignal.asBinder());
+ reply.writeStrongBinder(cancellationSignal.asBinder());
return true;
}
}
@@ -334,7 +334,7 @@ final class ContentProviderProxy implements IContentProvider
}
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+ String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
@@ -363,7 +363,7 @@ final class ContentProviderProxy implements IContentProvider
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
- data.writeStrongBinder(cancelationSignal != null ? cancelationSignal.asBinder() : null);
+ data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
@@ -632,7 +632,7 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public ICancelationSignal createCancelationSignal() throws RemoteException {
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
@@ -642,9 +642,9 @@ final class ContentProviderProxy implements IContentProvider
data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
- ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+ ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
reply.readStrongBinder());
- return cancelationSignal;
+ return cancellationSignal;
} finally {
data.recycle();
reply.recycle();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e79475a..96a65da 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -335,7 +335,7 @@ public abstract class ContentResolver {
* @param sortOrder How to order the rows, formatted as an SQL ORDER BY
* clause (excluding the ORDER BY itself). Passing null will use the
* default sort order, which may be unordered.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A Cursor object, which is positioned before the first entry, or null
@@ -343,7 +343,7 @@ public abstract class ContentResolver {
*/
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
return null;
@@ -351,14 +351,14 @@ public abstract class ContentResolver {
try {
long startTime = SystemClock.uptimeMillis();
- ICancelationSignal remoteCancelationSignal = null;
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
- remoteCancelationSignal = provider.createCancelationSignal();
- cancelationSignal.setRemote(remoteCancelationSignal);
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ remoteCancellationSignal = provider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
}
Cursor qCursor = provider.query(uri, projection,
- selection, selectionArgs, sortOrder, remoteCancelationSignal);
+ selection, selectionArgs, sortOrder, remoteCancellationSignal);
if (qCursor == null) {
releaseProvider(provider);
return null;
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 6e4aca8..aed3728 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -48,7 +48,7 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> {
String mSortOrder;
Cursor mCursor;
- CancelationSignal mCancelationSignal;
+ CancellationSignal mCancellationSignal;
/* Runs on a worker thread */
@Override
@@ -57,11 +57,11 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
}
- mCancelationSignal = new CancelationSignal();
+ mCancellationSignal = new CancellationSignal();
}
try {
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
- mSelectionArgs, mSortOrder, mCancelationSignal);
+ mSelectionArgs, mSortOrder, mCancellationSignal);
if (cursor != null) {
// Ensure the cursor window is filled
cursor.getCount();
@@ -70,18 +70,18 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> {
return cursor;
} finally {
synchronized (this) {
- mCancelationSignal = null;
+ mCancellationSignal = null;
}
}
}
@Override
- protected void onCancelLoadInBackground() {
- super.onCancelLoadInBackground();
+ public void cancelLoadInBackground() {
+ super.cancelLoadInBackground();
synchronized (this) {
- if (mCancelationSignal != null) {
- mCancelationSignal.cancel();
+ if (mCancellationSignal != null) {
+ mCancellationSignal.cancel();
}
}
}
diff --git a/core/java/android/content/ICancelationSignal.aidl b/core/java/android/content/ICancellationSignal.aidl
index 3f5a24d..cf1c5d3 100644
--- a/core/java/android/content/ICancelationSignal.aidl
+++ b/core/java/android/content/ICancellationSignal.aidl
@@ -19,6 +19,6 @@ package android.content;
/**
* @hide
*/
-interface ICancelationSignal {
+interface ICancellationSignal {
oneway void cancel();
}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index f52157f..16478b7 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,7 +34,7 @@ import java.util.ArrayList;
*/
public interface IContentProvider extends IInterface {
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+ String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
@@ -51,7 +51,7 @@ public interface IContentProvider extends IInterface {
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException;
public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
- public ICancelationSignal createCancelationSignal() throws RemoteException;
+ public ICancellationSignal createCancellationSignal() throws RemoteException;
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fbc1b2b..ab62c44 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2957,6 +2957,13 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int FLAG_RECEIVER_REPLACE_PENDING = 0x20000000;
/**
+ * If set, when sending a broadcast the recipient is allowed to run at
+ * foreground priority, with a shorter timeout interval. During normal
+ * broadcasts the receivers are not automatically hoisted out of the
+ * background priority class.
+ */
+ public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
+ /**
* If set, when sending a broadcast <i>before boot has completed</i> only
* registered receivers will be called -- no BroadcastReceiver components
* will be launched. Sticky intent state will be recorded properly even
@@ -2969,14 +2976,14 @@ public class Intent implements Parcelable, Cloneable {
*
* @hide
*/
- public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x10000000;
+ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
- public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x08000000;
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
/**
* @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index ac05682..3052414 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -52,6 +52,7 @@ import java.io.PrintWriter;
public class Loader<D> {
int mId;
OnLoadCompleteListener<D> mListener;
+ OnLoadCanceledListener<D> mOnLoadCanceledListener;
Context mContext;
boolean mStarted = false;
boolean mAbandoned = false;
@@ -100,6 +101,23 @@ public class Loader<D> {
}
/**
+ * Interface that is implemented to discover when a Loader has been canceled
+ * before it finished loading its data. You do not normally need to implement
+ * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
+ * to find out when a Loader it is managing has been canceled so that it
+ * can schedule the next Loader. This interface should only be used if a
+ * Loader is not being used in conjunction with LoaderManager.
+ */
+ public interface OnLoadCanceledListener<D> {
+ /**
+ * Called on the thread that created the Loader when the load is canceled.
+ *
+ * @param loader the loader that canceled the load
+ */
+ public void onLoadCanceled(Loader<D> loader);
+ }
+
+ /**
* Stores away the application context associated with context.
* Since Loaders can be used across multiple activities it's dangerous to
* store the context directly; always use {@link #getContext()} to retrieve
@@ -127,6 +145,18 @@ public class Loader<D> {
}
/**
+ * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+ * Should only be called by subclasses.
+ *
+ * Must be called from the process's main thread.
+ */
+ public void deliverCancellation() {
+ if (mOnLoadCanceledListener != null) {
+ mOnLoadCanceledListener.onLoadCanceled(this);
+ }
+ }
+
+ /**
* @return an application context retrieved from the Context passed to the constructor.
*/
public Context getContext() {
@@ -171,6 +201,40 @@ public class Loader<D> {
}
/**
+ * Registers a listener that will receive callbacks when a load is canceled.
+ * The callback will be called on the process's main thread so it's safe to
+ * pass the results to widgets.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to register.
+ */
+ public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener != null) {
+ throw new IllegalStateException("There is already a listener registered");
+ }
+ mOnLoadCanceledListener = listener;
+ }
+
+ /**
+ * Unregisters a listener that was previously added with
+ * {@link #registerOnLoadCanceledListener}.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to unregister.
+ */
+ public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener == null) {
+ throw new IllegalStateException("No listener register");
+ }
+ if (mOnLoadCanceledListener != listener) {
+ throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+ }
+ mOnLoadCanceledListener = null;
+ }
+
+ /**
* Return whether this load has been started. That is, its {@link #startLoading()}
* has been called and no calls to {@link #stopLoading()} or
* {@link #reset()} have yet been made.
@@ -234,6 +298,43 @@ public class Loader<D> {
}
/**
+ * Attempt to cancel the current load task.
+ * Must be called on the main thread of the process.
+ *
+ * <p>Cancellation is not an immediate operation, since the load is performed
+ * in a background thread. If there is currently a load in progress, this
+ * method requests that the load be canceled, and notes this is the case;
+ * once the background thread has completed its work its remaining state
+ * will be cleared. If another load request comes in during this time,
+ * it will be held until the canceled load is complete.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ public boolean cancelLoad() {
+ return onCancelLoad();
+ }
+
+ /**
+ * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+ * This will always be called from the process's main thread.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ protected boolean onCancelLoad() {
+ return false;
+ }
+
+ /**
* Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
* loaded data set and load a new one. This simply calls through to the
* implementation's {@link #onForceLoad()}. You generally should only call this
diff --git a/core/java/android/content/OperationCanceledException.java b/core/java/android/content/OperationCanceledException.java
index 24afcfa..d783a07 100644
--- a/core/java/android/content/OperationCanceledException.java
+++ b/core/java/android/content/OperationCanceledException.java
@@ -19,7 +19,7 @@ package android.content;
/**
* An exception type that is thrown when an operation in progress is canceled.
*
- * @see CancelationSignal
+ * @see CancellationSignal
*/
public class OperationCanceledException extends RuntimeException {
public OperationCanceledException() {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6015668..e04b2f7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -347,6 +347,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
sb.append(" (no locale)");
}
switch (textLayoutDirection) {
+ case LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE: /* ltr not interesting */ break;
case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index b69d9bf..0022118 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -21,6 +21,7 @@ import org.apache.commons.codec.binary.Hex;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
+import android.content.OperationCanceledException;
import android.database.sqlite.SQLiteAbortException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
@@ -107,6 +108,9 @@ public class DatabaseUtils {
code = 9;
} else if (e instanceof OperationApplicationException) {
code = 10;
+ } else if (e instanceof OperationCanceledException) {
+ code = 11;
+ logException = false;
} else {
reply.writeException(e);
Log.e(TAG, "Writing exception to parcel", e);
@@ -178,6 +182,8 @@ public class DatabaseUtils {
throw new SQLiteDiskIOException(msg);
case 9:
throw new SQLiteException(msg);
+ case 11:
+ throw new OperationCanceledException(msg);
default:
reply.readException(code, msg);
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 710bd53..b5cef81 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -19,7 +19,7 @@ package android.database.sqlite;
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.OperationCanceledException;
import android.database.Cursor;
import android.database.CursorWindow;
@@ -84,7 +84,7 @@ import java.util.regex.Pattern;
*
* @hide
*/
-public final class SQLiteConnection implements CancelationSignal.OnCancelListener {
+public final class SQLiteConnection implements CancellationSignal.OnCancelListener {
private static final String TAG = "SQLiteConnection";
private static final boolean DEBUG = false;
@@ -110,11 +110,11 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
private boolean mOnlyAllowReadOnlyOperations;
- // The number of times attachCancelationSignal has been called.
+ // The number of times attachCancellationSignal has been called.
// Because SQLite statement execution can be re-entrant, we keep track of how many
- // times we have attempted to attach a cancelation signal to the connection so that
+ // times we have attempted to attach a cancellation signal to the connection so that
// we can ensure that we detach the signal at the right time.
- private int mCancelationSignalAttachCount;
+ private int mCancellationSignalAttachCount;
private static native int nativeOpen(String path, int openFlags, String label,
boolean enableTrace, boolean enableProfile);
@@ -355,14 +355,14 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public void execute(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -374,11 +374,11 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
nativeExecute(mConnectionPtr, statement.mStatementPtr);
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -396,7 +396,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>long</code>, or zero if none.
*
@@ -405,7 +405,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLong(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -417,11 +417,11 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -439,7 +439,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>String</code>, or null if none.
*
@@ -448,7 +448,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* @throws OperationCanceledException if the operation was canceled.
*/
public String executeForString(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -460,11 +460,11 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -483,7 +483,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The file descriptor for a shared memory region that contains
* the value of the first column in the first row of the result set as a BLOB,
* or null if none.
@@ -493,7 +493,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* @throws OperationCanceledException if the operation was canceled.
*/
public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -506,13 +506,13 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
int fd = nativeExecuteForBlobFileDescriptor(
mConnectionPtr, statement.mStatementPtr);
return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -531,7 +531,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
@@ -539,7 +539,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* @throws OperationCanceledException if the operation was canceled.
*/
public int executeForChangedRowCount(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -552,12 +552,12 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
return nativeExecuteForChangedRowCount(
mConnectionPtr, statement.mStatementPtr);
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -576,7 +576,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The row id of the last row that was inserted, or 0 if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
@@ -584,7 +584,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -597,12 +597,12 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
return nativeExecuteForLastInsertedRowId(
mConnectionPtr, statement.mStatementPtr);
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -629,7 +629,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
* so that it does. Must be greater than or equal to <code>startPos</code>.
* @param countAllRows True to count all rows that the query would return
* regagless of whether they fit in the window.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were counted during query execution. Might
* not be all rows in the result set unless <code>countAllRows</code> is true.
*
@@ -639,7 +639,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
*/
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -658,7 +658,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- attachCancelationSignal(cancelationSignal);
+ attachCancellationSignal(cancellationSignal);
try {
final long result = nativeExecuteForCursorWindow(
mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
@@ -669,7 +669,7 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
window.setStartPosition(actualPos);
return countedRows;
} finally {
- detachCancelationSignal(cancelationSignal);
+ detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
@@ -751,40 +751,40 @@ public final class SQLiteConnection implements CancelationSignal.OnCancelListene
recyclePreparedStatement(statement);
}
- private void attachCancelationSignal(CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ private void attachCancellationSignal(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
- mCancelationSignalAttachCount += 1;
- if (mCancelationSignalAttachCount == 1) {
- // Reset cancelation flag before executing the statement.
+ mCancellationSignalAttachCount += 1;
+ if (mCancellationSignalAttachCount == 1) {
+ // Reset cancellation flag before executing the statement.
nativeResetCancel(mConnectionPtr, true /*cancelable*/);
// After this point, onCancel() may be called concurrently.
- cancelationSignal.setOnCancelListener(this);
+ cancellationSignal.setOnCancelListener(this);
}
}
}
- private void detachCancelationSignal(CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- assert mCancelationSignalAttachCount > 0;
+ private void detachCancellationSignal(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ assert mCancellationSignalAttachCount > 0;
- mCancelationSignalAttachCount -= 1;
- if (mCancelationSignalAttachCount == 0) {
+ mCancellationSignalAttachCount -= 1;
+ if (mCancellationSignalAttachCount == 0) {
// After this point, onCancel() cannot be called concurrently.
- cancelationSignal.setOnCancelListener(null);
+ cancellationSignal.setOnCancelListener(null);
- // Reset cancelation flag after executing the statement.
+ // Reset cancellation flag after executing the statement.
nativeResetCancel(mConnectionPtr, false /*cancelable*/);
}
}
}
- // CancelationSignal.OnCancelationListener callback.
+ // CancellationSignal.OnCancelListener callback.
// This method may be called on a different thread than the executing statement.
- // However, it will only be called between calls to attachCancelationSignal and
- // detachCancelationSignal, while a statement is executing. We can safely assume
+ // However, it will only be called between calls to attachCancellationSignal and
+ // detachCancellationSignal, while a statement is executing. We can safely assume
// that the SQLite connection is still alive.
@Override
public void onCancel() {
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index d335738..236948e 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -18,7 +18,7 @@ package android.database.sqlite;
import dalvik.system.CloseGuard;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.OperationCanceledException;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.os.SystemClock;
@@ -284,7 +284,7 @@ public final class SQLiteConnectionPool implements Closeable {
* @param sql If not null, try to find a connection that already has
* the specified SQL statement in its prepared statement cache.
* @param connectionFlags The connection request flags.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The connection that was acquired, never null.
*
* @throws IllegalStateException if the pool has been closed.
@@ -292,8 +292,8 @@ public final class SQLiteConnectionPool implements Closeable {
* @throws OperationCanceledException if the operation was canceled.
*/
public SQLiteConnection acquireConnection(String sql, int connectionFlags,
- CancelationSignal cancelationSignal) {
- return waitForConnection(sql, connectionFlags, cancelationSignal);
+ CancellationSignal cancellationSignal) {
+ return waitForConnection(sql, connectionFlags, cancellationSignal);
}
/**
@@ -503,7 +503,7 @@ public final class SQLiteConnectionPool implements Closeable {
// Might throw.
private SQLiteConnection waitForConnection(String sql, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
final boolean wantPrimaryConnection =
(connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
@@ -512,8 +512,8 @@ public final class SQLiteConnectionPool implements Closeable {
throwIfClosedLocked();
// Abort if canceled.
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
// Try to acquire a connection.
@@ -550,9 +550,9 @@ public final class SQLiteConnectionPool implements Closeable {
mConnectionWaiterQueue = waiter;
}
- if (cancelationSignal != null) {
+ if (cancellationSignal != null) {
final int nonce = waiter.mNonce;
- cancelationSignal.setOnCancelListener(new CancelationSignal.OnCancelListener() {
+ cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
@Override
public void onCancel() {
synchronized (mLock) {
@@ -588,8 +588,8 @@ public final class SQLiteConnectionPool implements Closeable {
final SQLiteConnection connection = waiter.mAssignedConnection;
final RuntimeException ex = waiter.mException;
if (connection != null || ex != null) {
- if (cancelationSignal != null) {
- cancelationSignal.setOnCancelListener(null);
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(null);
}
recycleConnectionWaiterLocked(waiter);
if (connection != null) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 7db7bfb..505f83e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.ContentValues;
import android.content.OperationCanceledException;
import android.content.res.Resources;
@@ -967,7 +967,7 @@ public class SQLiteDatabase extends SQLiteClosable {
* default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -976,9 +976,9 @@ public class SQLiteDatabase extends SQLiteClosable {
*/
public Cursor query(boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit, CancelationSignal cancelationSignal) {
+ String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
- groupBy, having, orderBy, limit, cancelationSignal);
+ groupBy, having, orderBy, limit, cancellationSignal);
}
/**
@@ -1049,7 +1049,7 @@ public class SQLiteDatabase extends SQLiteClosable {
* default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -1059,13 +1059,13 @@ public class SQLiteDatabase extends SQLiteClosable {
public Cursor queryWithFactory(CursorFactory cursorFactory,
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
- String having, String orderBy, String limit, CancelationSignal cancelationSignal) {
+ String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
throwIfNotOpen(); // fail fast
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
- findEditTable(table), cancelationSignal);
+ findEditTable(table), cancellationSignal);
}
/**
@@ -1163,15 +1163,15 @@ public class SQLiteDatabase extends SQLiteClosable {
* @param selectionArgs You may include ?s in where clause in the query,
* which will be replaced by the values from selectionArgs. The
* values will be bound as Strings.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
public Cursor rawQuery(String sql, String[] selectionArgs,
- CancelationSignal cancelationSignal) {
- return rawQueryWithFactory(null, sql, selectionArgs, null, cancelationSignal);
+ CancellationSignal cancellationSignal) {
+ return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
}
/**
@@ -1201,7 +1201,7 @@ public class SQLiteDatabase extends SQLiteClosable {
* which will be replaced by the values from selectionArgs. The
* values will be bound as Strings.
* @param editTable the name of the first table, which is editable
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -1209,11 +1209,11 @@ public class SQLiteDatabase extends SQLiteClosable {
*/
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
- String editTable, CancelationSignal cancelationSignal) {
+ String editTable, CancellationSignal cancellationSignal) {
throwIfNotOpen(); // fail fast
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
- cancelationSignal);
+ cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
}
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index c490dc6..3375e74 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -29,19 +29,19 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver {
private final SQLiteDatabase mDatabase;
private final String mEditTable;
private final String mSql;
- private final CancelationSignal mCancelationSignal;
+ private final CancellationSignal mCancellationSignal;
private SQLiteQuery mQuery;
public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
mDatabase = db;
mEditTable = editTable;
mSql = sql;
- mCancelationSignal = cancelationSignal;
+ mCancellationSignal = cancellationSignal;
}
public Cursor query(CursorFactory factory, String[] selectionArgs) {
- final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancelationSignal);
+ final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index f3da2a6..9f0edfb 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.database.DatabaseUtils;
import java.util.Arrays;
@@ -38,7 +38,7 @@ public abstract class SQLiteProgram extends SQLiteClosable {
private final Object[] mBindArgs;
SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
- CancelationSignal cancelationSignalForPrepare) {
+ CancellationSignal cancellationSignalForPrepare) {
mDatabase = db;
mSql = sql.trim();
@@ -57,7 +57,7 @@ public abstract class SQLiteProgram extends SQLiteClosable {
SQLiteStatementInfo info = new SQLiteStatementInfo();
db.getThreadSession().prepare(mSql,
db.getThreadDefaultConnectionFlags(assumeReadOnly),
- cancelationSignalForPrepare, info);
+ cancellationSignalForPrepare, info);
mReadOnly = info.readOnly;
mColumnNames = info.columnNames;
mNumParameters = info.numParameters;
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index df2e260..30e77b5 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.OperationCanceledException;
import android.database.CursorWindow;
import android.util.Log;
@@ -31,12 +31,12 @@ import android.util.Log;
public final class SQLiteQuery extends SQLiteProgram {
private static final String TAG = "SQLiteQuery";
- private final CancelationSignal mCancelationSignal;
+ private final CancellationSignal mCancellationSignal;
- SQLiteQuery(SQLiteDatabase db, String query, CancelationSignal cancelationSignal) {
- super(db, query, null, cancelationSignal);
+ SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
+ super(db, query, null, cancellationSignal);
- mCancelationSignal = cancelationSignal;
+ mCancellationSignal = cancellationSignal;
}
/**
@@ -61,7 +61,7 @@ public final class SQLiteQuery extends SQLiteProgram {
try {
int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
window, startPos, requiredPos, countAllRows, getConnectionFlags(),
- mCancelationSignal);
+ mCancellationSignal);
return numRows;
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 89469cb..6f84b5e 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.OperationCanceledException;
import android.database.Cursor;
import android.database.DatabaseUtils;
@@ -292,7 +292,7 @@ public class SQLiteQueryBuilder
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder) {
return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
- null /* limit */, null /* cancelationSignal */);
+ null /* limit */, null /* cancellationSignal */);
}
/**
@@ -362,7 +362,7 @@ public class SQLiteQueryBuilder
* will use the default sort order, which may be unordered.
* @param limit Limits the number of rows returned by the query,
* formatted as LIMIT clause. Passing null denotes no LIMIT clause.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return a cursor over the result set
@@ -371,7 +371,7 @@ public class SQLiteQueryBuilder
*/
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
- String having, String sortOrder, String limit, CancelationSignal cancelationSignal) {
+ String having, String sortOrder, String limit, CancellationSignal cancellationSignal) {
if (mTables == null) {
return null;
}
@@ -387,7 +387,7 @@ public class SQLiteQueryBuilder
String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
having, sortOrder, limit);
validateQuerySql(db, sqlForValidation,
- cancelationSignal); // will throw if query is invalid
+ cancellationSignal); // will throw if query is invalid
}
String sql = buildQuery(
@@ -400,7 +400,7 @@ public class SQLiteQueryBuilder
return db.rawQueryWithFactory(
mFactory, sql, selectionArgs,
SQLiteDatabase.findEditTable(mTables),
- cancelationSignal); // will throw if query is invalid
+ cancellationSignal); // will throw if query is invalid
}
/**
@@ -408,9 +408,9 @@ public class SQLiteQueryBuilder
* If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
*/
private void validateQuerySql(SQLiteDatabase db, String sql,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
db.getThreadSession().prepare(sql,
- db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancelationSignal, null);
+ db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java
index b5a3e31..43efb03 100644
--- a/core/java/android/database/sqlite/SQLiteSession.java
+++ b/core/java/android/database/sqlite/SQLiteSession.java
@@ -16,7 +16,7 @@
package android.database.sqlite;
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
import android.content.OperationCanceledException;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
@@ -280,7 +280,7 @@ public final class SQLiteSession {
* @param transactionListener The transaction listener, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
* called for the current transaction.
@@ -293,21 +293,21 @@ public final class SQLiteSession {
*/
public void beginTransaction(int transactionMode,
SQLiteTransactionListener transactionListener, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
throwIfTransactionMarkedSuccessful();
beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
- cancelationSignal);
+ cancellationSignal);
}
private void beginTransactionUnchecked(int transactionMode,
SQLiteTransactionListener transactionListener, int connectionFlags,
- CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
if (mTransactionStack == null) {
- acquireConnection(null, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(null, connectionFlags, cancellationSignal); // might throw
}
try {
// Set up the transaction such that we can back out safely
@@ -317,14 +317,14 @@ public final class SQLiteSession {
switch (transactionMode) {
case TRANSACTION_MODE_IMMEDIATE:
mConnection.execute("BEGIN IMMEDIATE;", null,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
break;
case TRANSACTION_MODE_EXCLUSIVE:
mConnection.execute("BEGIN EXCLUSIVE;", null,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
break;
default:
- mConnection.execute("BEGIN;", null, cancelationSignal); // might throw
+ mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
break;
}
}
@@ -335,7 +335,7 @@ public final class SQLiteSession {
transactionListener.onBegin(); // might throw
} catch (RuntimeException ex) {
if (mTransactionStack == null) {
- mConnection.execute("ROLLBACK;", null, cancelationSignal); // might throw
+ mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
throw ex;
}
@@ -384,7 +384,7 @@ public final class SQLiteSession {
* This method must be called exactly once for each call to {@link #beginTransaction}.
* </p>
*
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws IllegalStateException if there is no current transaction.
* @throws SQLiteException if an error occurs.
@@ -394,16 +394,16 @@ public final class SQLiteSession {
* @see #setTransactionSuccessful
* @see #yieldTransaction
*/
- public void endTransaction(CancelationSignal cancelationSignal) {
+ public void endTransaction(CancellationSignal cancellationSignal) {
throwIfNoTransaction();
assert mConnection != null;
- endTransactionUnchecked(cancelationSignal);
+ endTransactionUnchecked(cancellationSignal);
}
- private void endTransactionUnchecked(CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ private void endTransactionUnchecked(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
final Transaction top = mTransactionStack;
@@ -434,9 +434,9 @@ public final class SQLiteSession {
} else {
try {
if (successful) {
- mConnection.execute("COMMIT;", null, cancelationSignal); // might throw
+ mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
} else {
- mConnection.execute("ROLLBACK;", null, cancelationSignal); // might throw
+ mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
} finally {
releaseConnection(); // might throw
@@ -487,7 +487,7 @@ public final class SQLiteSession {
* @param throwIfUnsafe If true, then instead of returning false when no
* transaction is in progress, a nested transaction is in progress, or when
* the transaction has already been marked successful, throws {@link IllegalStateException}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the transaction was actually yielded.
*
* @throws IllegalStateException if <code>throwIfNested</code> is true and
@@ -500,7 +500,7 @@ public final class SQLiteSession {
* @see #endTransaction
*/
public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (throwIfUnsafe) {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
@@ -518,13 +518,13 @@ public final class SQLiteSession {
}
return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
}
private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
- CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
@@ -534,7 +534,7 @@ public final class SQLiteSession {
final int transactionMode = mTransactionStack.mMode;
final SQLiteTransactionListener listener = mTransactionStack.mListener;
final int connectionFlags = mConnectionFlags;
- endTransactionUnchecked(cancelationSignal); // might throw
+ endTransactionUnchecked(cancellationSignal); // might throw
if (sleepAfterYieldDelayMillis > 0) {
try {
@@ -545,7 +545,7 @@ public final class SQLiteSession {
}
beginTransactionUnchecked(transactionMode, listener, connectionFlags,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
return true;
}
@@ -566,24 +566,24 @@ public final class SQLiteSession {
* @param sql The SQL statement to prepare.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
* with information about the statement, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error.
* @throws OperationCanceledException if the operation was canceled.
*/
- public void prepare(String sql, int connectionFlags, CancelationSignal cancelationSignal,
+ public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
SQLiteStatementInfo outStatementInfo) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
mConnection.prepare(sql, outStatementInfo); // might throw
} finally {
@@ -598,25 +598,25 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public void execute(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- mConnection.execute(sql, bindArgs, cancelationSignal); // might throw
+ mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -629,7 +629,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>long</code>, or zero if none.
*
@@ -638,18 +638,18 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForLong(sql, bindArgs, cancelationSignal); // might throw
+ return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -662,7 +662,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>String</code>, or null if none.
*
@@ -671,18 +671,18 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForString(sql, bindArgs, cancelationSignal); // might throw
+ return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -696,7 +696,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The file descriptor for a shared memory region that contains
* the value of the first column in the first row of the result set as a BLOB,
* or null if none.
@@ -706,19 +706,19 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
- int connectionFlags, CancelationSignal cancelationSignal) {
+ int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -732,7 +732,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
@@ -740,19 +740,19 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForChangedRowCount(sql, bindArgs,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -766,7 +766,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The row id of the last row that was inserted, or 0 if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
@@ -774,19 +774,19 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForLastInsertedRowId(sql, bindArgs,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -808,7 +808,7 @@ public final class SQLiteSession {
* regagless of whether they fit in the window.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were counted during query execution. Might
* not be all rows in the result set unless <code>countAllRows</code> is true.
*
@@ -818,7 +818,7 @@ public final class SQLiteSession {
*/
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
- int connectionFlags, CancelationSignal cancelationSignal) {
+ int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -826,16 +826,16 @@ public final class SQLiteSession {
throw new IllegalArgumentException("window must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
window.clear();
return 0;
}
- acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForCursorWindow(sql, bindArgs,
window, startPos, requiredPos, countAllRows,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -854,7 +854,7 @@ public final class SQLiteSession {
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
- * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the statement was of a special form that was handled here,
* false otherwise.
*
@@ -863,36 +863,36 @@ public final class SQLiteSession {
* @throws OperationCanceledException if the operation was canceled.
*/
private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
- CancelationSignal cancelationSignal) {
- if (cancelationSignal != null) {
- cancelationSignal.throwIfCanceled();
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
}
final int type = DatabaseUtils.getSqlStatementType(sql);
switch (type) {
case DatabaseUtils.STATEMENT_BEGIN:
beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
- cancelationSignal);
+ cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_COMMIT:
setTransactionSuccessful();
- endTransaction(cancelationSignal);
+ endTransaction(cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_ABORT:
- endTransaction(cancelationSignal);
+ endTransaction(cancellationSignal);
return true;
}
return false;
}
private void acquireConnection(String sql, int connectionFlags,
- CancelationSignal cancelationSignal) {
+ CancellationSignal cancellationSignal) {
if (mConnection == null) {
assert mConnectionUseCount == 0;
mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
- cancelationSignal); // might throw
+ cancellationSignal); // might throw
mConnectionFlags = connectionFlags;
}
mConnectionUseCount += 1;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a569317..2eef8f4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -142,8 +142,19 @@ public class ConnectivityManager {
* If an application uses the network in the background, it should listen
* for this broadcast and stop using the background data if the value is
* {@code false}.
+ * <p>
+ *
+ * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
+ * of background data depends on several combined factors, and
+ * this broadcast is no longer sent. Instead, when background
+ * data is unavailable, {@link #getActiveNetworkInfo()} will now
+ * appear disconnected. During first boot after a platform
+ * upgrade, this broadcast will be sent once if
+ * {@link #getBackgroundDataSetting()} was {@code false} before
+ * the upgrade.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 633c38e..442535a 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -43,7 +43,7 @@ interface INetworkPolicyManager {
NetworkPolicy[] getNetworkPolicies();
/** Snooze limit on policy matching given template. */
- void snoozePolicy(in NetworkTemplate template);
+ void snoozeLimit(in NetworkTemplate template);
/** Control if background data is restricted system-wide. */
void setRestrictBackground(boolean restrictBackground);
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index d9ea700..04cf1a3 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -38,18 +38,25 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
public int cycleDay;
public long warningBytes;
public long limitBytes;
- public long lastSnooze;
+ public long lastWarningSnooze;
+ public long lastLimitSnooze;
public boolean metered;
private static final long DEFAULT_MTU = 1500;
- public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
- long lastSnooze, boolean metered) {
+ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+ long limitBytes, boolean metered) {
+ this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
+ }
+
+ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+ long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
this.template = checkNotNull(template, "missing NetworkTemplate");
this.cycleDay = cycleDay;
this.warningBytes = warningBytes;
this.limitBytes = limitBytes;
- this.lastSnooze = lastSnooze;
+ this.lastWarningSnooze = lastWarningSnooze;
+ this.lastLimitSnooze = lastLimitSnooze;
this.metered = metered;
}
@@ -58,7 +65,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
cycleDay = in.readInt();
warningBytes = in.readLong();
limitBytes = in.readLong();
- lastSnooze = in.readLong();
+ lastWarningSnooze = in.readLong();
+ lastLimitSnooze = in.readLong();
metered = in.readInt() != 0;
}
@@ -68,7 +76,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
dest.writeInt(cycleDay);
dest.writeLong(warningBytes);
dest.writeLong(limitBytes);
- dest.writeLong(lastSnooze);
+ dest.writeLong(lastWarningSnooze);
+ dest.writeLong(lastLimitSnooze);
dest.writeInt(metered ? 1 : 0);
}
@@ -78,6 +87,13 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
}
/**
+ * Test if given measurement is over {@link #warningBytes}.
+ */
+ public boolean isOverWarning(long totalBytes) {
+ return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
+ }
+
+ /**
* Test if given measurement is near enough to {@link #limitBytes} to be
* considered over-limit.
*/
@@ -88,6 +104,14 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
}
+ /**
+ * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
+ */
+ public void clearSnooze() {
+ lastWarningSnooze = SNOOZE_NEVER;
+ lastLimitSnooze = SNOOZE_NEVER;
+ }
+
/** {@inheritDoc} */
public int compareTo(NetworkPolicy another) {
if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -103,7 +127,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
@Override
public int hashCode() {
- return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze, metered);
+ return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
+ lastLimitSnooze, metered);
}
@Override
@@ -111,8 +136,10 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
if (obj instanceof NetworkPolicy) {
final NetworkPolicy other = (NetworkPolicy) obj;
return cycleDay == other.cycleDay && warningBytes == other.warningBytes
- && limitBytes == other.limitBytes && lastSnooze == other.lastSnooze
- && metered == other.metered && Objects.equal(template, other.template);
+ && limitBytes == other.limitBytes
+ && lastWarningSnooze == other.lastWarningSnooze
+ && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
+ && Objects.equal(template, other.template);
}
return false;
}
@@ -120,8 +147,9 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
@Override
public String toString() {
return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
- + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze
- + ", metered=" + metered;
+ + warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
+ + lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
+ + metered;
}
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 5e9abb7..fd6bed7 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -135,6 +135,8 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>There are a few threading rules that must be followed for this class to
* work properly:</p>
* <ul>
+ * <li>The AsyncTask class must be loaded on the UI thread. This is done
+ * automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
* <li>The task instance must be created on the UI thread.</li>
* <li>{@link #execute} must be invoked on the UI thread.</li>
* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 4e01672..d11219b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -62,6 +62,14 @@ public final class MediaStore {
public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
/**
+ * The method name used by the media scanner and mtp to tell the media provider to
+ * rescan and reclassify that have become unhidden because of renaming folders or
+ * removing nomedia files
+ * @hide
+ */
+ public static final String UNHIDE_CALL = "unhide";
+
+ /**
* Activity Action: Launch a music player.
* The activity should be able to play, browse, or manipulate music files stored on the device.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f14d27e..375e5e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1678,6 +1678,13 @@ public final class Settings {
public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
/**
+ * Scaling factor for Animator-based animations. This affects both the start delay and
+ * duration of all such animations. Setting to 0 will cause animations to end immediately.
+ * The default value is 1.
+ */
+ public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+ /**
* Scaling factor for normal window animations. Setting to 0 will disable window
* animations.
* @hide
@@ -2475,6 +2482,11 @@ public final class Settings {
Uri.parse("content://" + AUTHORITY + "/secure");
/**
+ * Whether user has enabled development settings.
+ */
+ public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+
+ /**
* Whether ADB is enabled.
*/
public static final String ADB_ENABLED = "adb_enabled";
diff --git a/core/java/android/view/AccessibilityNodeInfoCache.java b/core/java/android/view/AccessibilityNodeInfoCache.java
new file mode 100644
index 0000000..244a491
--- /dev/null
+++ b/core/java/android/view/AccessibilityNodeInfoCache.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.util.LongSparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Simple cache for AccessibilityNodeInfos. The cache is mapping an
+ * accessibility id to an info. The cache allows storing of
+ * <code>null</code> values. It also tracks accessibility events
+ * and invalidates accordingly.
+ *
+ * @hide
+ */
+public class AccessibilityNodeInfoCache {
+
+ private final boolean ENABLED = true;
+
+ /**
+ * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
+ */
+ public static AccessibilityNodeInfoCache newAccessibilityNodeInfoCache() {
+ return new AccessibilityNodeInfoCache();
+ }
+
+ /**
+ * @return A new <strong>synchronized</strong> AccessibilityNodeInfoCache.
+ */
+ public static AccessibilityNodeInfoCache newSynchronizedAccessibilityNodeInfoCache() {
+ return new AccessibilityNodeInfoCache() {
+ private final Object mLock = new Object();
+
+ @Override
+ public void clear() {
+ synchronized(mLock) {
+ super.clear();
+ }
+ }
+
+ @Override
+ public AccessibilityNodeInfo get(long accessibilityNodeId) {
+ synchronized(mLock) {
+ return super.get(accessibilityNodeId);
+ }
+ }
+
+ @Override
+ public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+ synchronized(mLock) {
+ super.put(accessibilityNodeId, info);
+ }
+ }
+
+ @Override
+ public void remove(long accessibilityNodeId) {
+ synchronized(mLock) {
+ super.remove(accessibilityNodeId);
+ }
+ }
+ };
+ }
+
+ private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;
+
+ private AccessibilityNodeInfoCache() {
+ if (ENABLED) {
+ mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
+ } else {
+ mCacheImpl = null;
+ }
+ }
+
+ /**
+ * The cache keeps track of {@link AccessibilityEvent}s and invalidates
+ * cached nodes as appropriate.
+ *
+ * @param event An event.
+ */
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ final int eventType = event.getEventType();
+ switch (eventType) {
+ case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_SCROLLED:
+ clear();
+ break;
+ case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+ case AccessibilityEvent.TYPE_VIEW_SELECTED:
+ case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
+ final long accessibilityNodeId = event.getSourceNodeId();
+ remove(accessibilityNodeId);
+ break;
+ }
+ }
+
+ /**
+ * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ * @return The cached {@link AccessibilityNodeInfo} or null if such not found.
+ */
+ public AccessibilityNodeInfo get(long accessibilityNodeId) {
+ if (ENABLED) {
+ return mCacheImpl.get(accessibilityNodeId);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ * @param info The {@link AccessibilityNodeInfo} to cache.
+ */
+ public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+ if (ENABLED) {
+ mCacheImpl.put(accessibilityNodeId, info);
+ }
+ }
+
+ /**
+ * Returns whether the cache contains an accessibility node id key.
+ *
+ * @param accessibilityNodeId The key for which to check.
+ * @return True if the key is in the cache.
+ */
+ public boolean containsKey(long accessibilityNodeId) {
+ if (ENABLED) {
+ return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Removes a cached {@link AccessibilityNodeInfo}.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ */
+ public void remove(long accessibilityNodeId) {
+ if (ENABLED) {
+ mCacheImpl.remove(accessibilityNodeId);
+ }
+ }
+
+ /**
+ * Clears the cache.
+ */
+ public void clear() {
+ if (ENABLED) {
+ mCacheImpl.clear();
+ }
+ }
+}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 34e7d4d..0349a2b 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,9 +18,15 @@ package android.view;
/**
- * Represents a contextual mode of the user interface. Action modes can be used for
- * modal interactions with content and replace parts of the normal UI until finished.
- * Examples of good action modes include selection modes, search, content editing, etc.
+ * Represents a contextual mode of the user interface. Action modes can be used to provide
+ * alternative interaction modes and replace parts of the normal UI until finished.
+ * Examples of good action modes include text selection and contextual actions.
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to provide contextual actions with {@code ActionMode},
+ * read the <a href="{@docRoot}guide/topics/ui/menu.html#context-menu">Menus</a>
+ * developer guide.</p>
+ * </div>
*/
public abstract class ActionMode {
private Object mTag;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 63de128..c86ea77 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -26,7 +26,7 @@ import android.os.SystemProperties;
import android.util.Log;
/**
- * Coodinates animations and drawing for UI on a particular thread.
+ * Coordinates animations and drawing for UI on a particular thread.
* @hide
*/
public final class Choreographer extends Handler {
@@ -94,8 +94,8 @@ public final class Choreographer extends Handler {
}
/**
- * Gets the choreographer for this thread.
- * Must be called on the UI thread.
+ * Gets the choreographer for the calling thread. Must be called from
+ * a thread that already has a {@link android.os.Looper} associated with it.
*
* @return The choreographer for this thread.
* @throws IllegalStateException if the thread does not have a looper.
@@ -163,6 +163,15 @@ public final class Choreographer extends Handler {
}
/**
+ * Return true if {@link #scheduleAnimation()} has been called but
+ * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
+ * not yet been called.
+ */
+ public boolean isAnimationScheduled() {
+ return mAnimationScheduled;
+ }
+
+ /**
* Schedules drawing to occur on the next frame synchronization boundary.
* Must be called on the UI thread.
*/
@@ -180,6 +189,15 @@ public final class Choreographer extends Handler {
}
}
+ /**
+ * Return true if {@link #scheduleDraw()} has been called but
+ * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
+ * not yet been called.
+ */
+ public boolean isDrawScheduled() {
+ return mDrawScheduled;
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c08a402..fa4dd25 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -189,7 +189,7 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native int nGetMaximumTextureWidth();
- private static native int nGetMaximumTextureHeight();
+ private static native int nGetMaximumTextureHeight();
///////////////////////////////////////////////////////////////////////////
// Setup
@@ -268,6 +268,24 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nFinish(int renderer);
+ /**
+ * Returns the size of the stencil buffer required by the underlying
+ * implementation.
+ *
+ * @return The minimum number of bits the stencil buffer must. Always >= 0.
+ *
+ * @hide
+ */
+ public static int getStencilSize() {
+ return nGetStencilSize();
+ }
+
+ private static native int nGetStencilSize();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Functor
+ ///////////////////////////////////////////////////////////////////////////
+
@Override
public boolean callDrawGLFunction(int drawGLFunction) {
return nCallDrawGLFunction(mRenderer, drawGLFunction);
@@ -275,7 +293,6 @@ class GLES20Canvas extends HardwareCanvas {
private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
-
///////////////////////////////////////////////////////////////////////////
// Memory
///////////////////////////////////////////////////////////////////////////
@@ -361,6 +378,12 @@ class GLES20Canvas extends HardwareCanvas {
private static native int nGetDisplayListSize(int displayList);
+ static void setDisplayListName(int displayList, String name) {
+ nSetDisplayListName(displayList, name);
+ }
+
+ private static native void nSetDisplayListName(int displayList, String name);
+
@Override
public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
return nDrawDisplayList(mRenderer,
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 0cb9449..969c9ab 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -31,10 +31,17 @@ class GLES20DisplayList extends DisplayList {
private GLES20RecordingCanvas mCanvas;
private boolean mValid;
+ // Used for debugging
+ private final String mName;
+
// The native display list will be destroyed when this object dies.
// DO NOT overwrite this reference once it is set.
private DisplayListFinalizer mFinalizer;
+ GLES20DisplayList(String name) {
+ mName = name;
+ }
+
int getNativeDisplayList() {
if (!mValid || mFinalizer == null) {
throw new IllegalStateException("The display list is not valid.");
@@ -75,6 +82,7 @@ class GLES20DisplayList extends DisplayList {
mCanvas.end(mFinalizer.mNativeDisplayList);
} else {
mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+ GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
}
mCanvas.recycle();
mCanvas = null;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 1c9cbbf..9e8a228 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -283,9 +283,12 @@ public abstract class HardwareRenderer {
* Creates a new display list that can be used to record batches of
* drawing operations.
*
+ * @param name The name of the display list, used for debugging purpose.
+ * May be null
+ *
* @return A new display list.
*/
- public abstract DisplayList createDisplayList();
+ public abstract DisplayList createDisplayList(String name);
/**
* Creates a new hardware layer. A hardware layer built by calling this
@@ -1047,7 +1050,7 @@ public abstract class HardwareRenderer {
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, 0,
+ EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
(dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
EGL_NONE
@@ -1094,8 +1097,8 @@ public abstract class HardwareRenderer {
}
@Override
- public DisplayList createDisplayList() {
- return new GLES20DisplayList();
+ public DisplayList createDisplayList(String name) {
+ return new GLES20DisplayList(name);
}
@Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8cac57d..7ba17b3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3761,8 +3761,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
- * Called when this view wants to give up focus. This will cause
- * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
+ * Called when this view wants to give up focus. If focus is cleared
+ * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
+ * <p>
+ * <strong>Note:</strong> When a View clears focus the framework is trying
+ * to give focus to the first focusable View from the top. Hence, if this
+ * View is the first from the top that can take focus, then its focus will
+ * not be cleared nor will the focus change callback be invoked.
+ * </p>
*/
public void clearFocus() {
if (DBG) {
@@ -3770,6 +3776,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
if ((mPrivateFlags & FOCUSED) != 0) {
+ // If this is the first focusable do not clear focus since the we
+ // try to give it focus every time a view clears its focus. Hence,
+ // the view that would gain focus already has it.
+ View firstFocusable = getFirstFocusable();
+ if (firstFocusable == this) {
+ return;
+ }
+
mPrivateFlags &= ~FOCUSED;
if (mParent != null) {
@@ -3778,9 +3792,24 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
onFocusChanged(false, 0, null);
refreshDrawableState();
+
+ // The view cleared focus and invoked the callbacks, so now is the
+ // time to give focus to the the first focusable to ensure that the
+ // gain focus is announced after clear focus.
+ if (firstFocusable != null) {
+ firstFocusable.requestFocus(FOCUS_FORWARD);
+ }
}
}
+ private View getFirstFocusable() {
+ ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ return viewRoot.focusSearch(null, FOCUS_FORWARD);
+ }
+ return null;
+ }
+
/**
* Called to clear the focus of a view that is about to be removed.
* Doesn't call clearChildFocus, which prevents this view from taking
@@ -6822,7 +6851,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if ((changed & VISIBILITY_MASK) != 0) {
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+ ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+ (flags & VISIBILITY_MASK));
((View) mParent).invalidate(true);
} else if (mParent != null) {
mParent.invalidateChild(this, null);
@@ -7282,6 +7312,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The degrees of rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotation() {
return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
}
@@ -7323,6 +7354,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The degrees of Y rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotationY() {
return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
}
@@ -7369,6 +7401,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The degrees of X rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotationX() {
return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
}
@@ -7416,6 +7449,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getPivotY()
* @return The scaling factor.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getScaleX() {
return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
}
@@ -7454,6 +7488,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getPivotY()
* @return The scaling factor.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getScaleY() {
return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
}
@@ -7492,6 +7527,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getPivotY()
* @return The x location of the pivot point.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getPivotX() {
return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
}
@@ -7536,6 +7572,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getPivotY()
* @return The y location of the pivot point.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getPivotY() {
return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
}
@@ -7576,6 +7613,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* <p>By default this is 1.0f.
* @return The opacity of the view.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getAlpha() {
return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
}
@@ -7589,6 +7627,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
* setting a hardware layer.</p>
*
+ * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
+ * performance implications. It is generally best to use the alpha property sparingly and
+ * transiently, as in the case of fading animations.</p>
+ *
* @param alpha The opacity of the view.
*
* @see #setLayerType(int, android.graphics.Paint)
@@ -7886,6 +7928,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The visual x position of this view, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
}
@@ -7908,6 +7951,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The visual y position of this view, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getY() {
return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
}
@@ -7931,6 +7975,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The horizontal position of this view relative to its left position, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationX() {
return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
}
@@ -7967,6 +8012,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return The vertical position of this view relative to its top position,
* in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationY() {
return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
}
@@ -10373,7 +10419,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
// we copy in child display lists into ours in drawChild()
mRecreateDisplayList = true;
if (mDisplayList == null) {
- mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+ final String name = getClass().getSimpleName();
+ mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
// If we're creating a new display list, make sure our parent gets invalidated
// since they will need to recreate their display list to account for this
// new child display list.
@@ -12654,6 +12701,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
}
+ if (getAccessibilityNodeProvider() != null) {
+ throw new IllegalStateException("Views with AccessibilityNodeProvider"
+ + " can't have children.");
+ }
+
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dda695f..d3af618 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -675,11 +675,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public void clearFocus() {
- super.clearFocus();
-
- // clear any child focus if it exists
- if (mFocused != null) {
+ if (DBG) {
+ System.out.println(this + " clearFocus()");
+ }
+ if (mFocused == null) {
+ super.clearFocus();
+ } else {
mFocused.clearFocus();
+ mFocused = null;
}
}
@@ -691,12 +694,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (DBG) {
System.out.println(this + " unFocus()");
}
-
- super.unFocus();
- if (mFocused != null) {
+ if (mFocused == null) {
+ super.unFocus();
+ } else {
mFocused.unFocus();
+ mFocused = null;
}
- mFocused = null;
}
/**
@@ -888,18 +891,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * Called when a view's visibility has changed. Notify the parent to take any appropriate
+ * action.
+ *
+ * @param child The view whose visibility has changed
+ * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
+ * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
* @hide
- * @param child
- * @param visibility
*/
- protected void onChildVisibilityChanged(View child, int visibility) {
+ protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
if (mTransition != null) {
- if (visibility == VISIBLE) {
- mTransition.showChild(this, child);
+ if (newVisibility == VISIBLE) {
+ mTransition.showChild(this, child, oldVisibility);
} else {
- mTransition.hideChild(this, child);
- }
- if (visibility != VISIBLE) {
+ mTransition.hideChild(this, child, newVisibility);
// Only track this on disappearing views - appearing views are already visible
// and don't need special handling during drawChild()
if (mVisibilityChangingChildren == null) {
@@ -914,7 +919,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// in all cases, for drags
if (mCurrentDrag != null) {
- if (visibility == VISIBLE) {
+ if (newVisibility == VISIBLE) {
notifyChildOfDrag(child);
}
}
@@ -3351,6 +3356,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
+ if (getAccessibilityNodeProvider() != null) {
+ throw new IllegalStateException("Views with AccessibilityNodeProvider"
+ + " can't have children.");
+ }
+
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 89a1ef2..0fdcd0f 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -113,6 +113,10 @@ public class ViewPropertyAnimator {
* on that list are added to the list of properties associated with that animator.
*/
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+ private Runnable mPendingSetupAction;
+ private Runnable mPendingCleanupAction;
+ private Runnable mPendingOnStartAction;
+ private Runnable mPendingOnEndAction;
/**
* Constants used to associate a property being requested and the mechanism used to set
@@ -199,6 +203,10 @@ public class ViewPropertyAnimator {
*/
private HashMap<Animator, PropertyBundle> mAnimatorMap =
new HashMap<Animator, PropertyBundle>();
+ private HashMap<Animator, Runnable> mAnimatorSetupMap;
+ private HashMap<Animator, Runnable> mAnimatorCleanupMap;
+ private HashMap<Animator, Runnable> mAnimatorOnStartMap;
+ private HashMap<Animator, Runnable> mAnimatorOnEndMap;
/**
* This is the information we need to set each property during the animation.
@@ -614,6 +622,93 @@ public class ViewPropertyAnimator {
}
/**
+ * The View associated with this ViewPropertyAnimator will have its
+ * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
+ * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation. This state
+ * is not persistent, either on the View or on this ViewPropertyAnimator: the layer type
+ * of the View will be restored when the animation ends to what it was when this method was
+ * called, and this setting on ViewPropertyAnimator is only valid for the next animation.
+ * Note that calling this method and then independently setting the layer type of the View
+ * (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will result
+ * in some inconsistency, including having the layer type restored to its pre-withLayer()
+ * value when the animation ends.
+ *
+ * @see View#setLayerType(int, android.graphics.Paint)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withLayer() {
+ mPendingSetupAction= new Runnable() {
+ @Override
+ public void run() {
+ mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ };
+ final int currentLayerType = mView.getLayerType();
+ mPendingCleanupAction = new Runnable() {
+ @Override
+ public void run() {
+ mView.setLayerType(currentLayerType, null);
+ }
+ };
+ if (mAnimatorSetupMap == null) {
+ mAnimatorSetupMap = new HashMap<Animator, Runnable>();
+ }
+ if (mAnimatorCleanupMap == null) {
+ mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
+ }
+
+ return this;
+ }
+
+ /**
+ * Specifies an action to take place when the next animation runs. If there is a
+ * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
+ * action will run after that startDelay expires, when the actual animation begins.
+ * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
+ * choreographing ViewPropertyAnimator animations with other animations or actions
+ * in the application.
+ *
+ * @param runnable The action to run when the next animation starts.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withStartAction(Runnable runnable) {
+ mPendingOnStartAction = runnable;
+ if (runnable != null && mAnimatorOnStartMap == null) {
+ mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
+ }
+ return this;
+ }
+
+ /**
+ * Specifies an action to take place when the next animation ends. The action is only
+ * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
+ * that animation, the runnable will not run.
+ * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
+ * choreographing ViewPropertyAnimator animations with other animations or actions
+ * in the application.
+ *
+ * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
+ * <pre>
+ * Runnable endAction = new Runnable() {
+ * public void run() {
+ * view.animate().x(0);
+ * }
+ * };
+ * view.animate().x(200).onEnd(endAction);
+ * </pre>
+ *
+ * @param runnable The action to run when the next animation ends.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withEndAction(Runnable runnable) {
+ mPendingOnEndAction = runnable;
+ if (runnable != null && mAnimatorOnEndMap == null) {
+ mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
+ }
+ return this;
+ }
+
+ /**
* Starts the underlying Animator for a set of properties. We use a single animator that
* simply runs from 0 to 1, and then use that fractional value to set each property
* value accordingly.
@@ -630,6 +725,22 @@ public class ViewPropertyAnimator {
propertyMask |= nameValuesHolder.mNameConstant;
}
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+ if (mPendingSetupAction != null) {
+ mAnimatorSetupMap.put(animator, mPendingSetupAction);
+ mPendingSetupAction = null;
+ }
+ if (mPendingCleanupAction != null) {
+ mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
+ mPendingCleanupAction = null;
+ }
+ if (mPendingOnStartAction != null) {
+ mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
+ mPendingOnStartAction = null;
+ }
+ if (mPendingOnEndAction != null) {
+ mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
+ mPendingOnEndAction = null;
+ }
animator.addUpdateListener(mAnimatorEventListener);
animator.addListener(mAnimatorEventListener);
if (mStartDelaySet) {
@@ -800,6 +911,20 @@ public class ViewPropertyAnimator {
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
@Override
public void onAnimationStart(Animator animation) {
+ if (mAnimatorSetupMap != null) {
+ Runnable r = mAnimatorSetupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorSetupMap.remove(animation);
+ }
+ if (mAnimatorOnStartMap != null) {
+ Runnable r = mAnimatorOnStartMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorOnStartMap.remove(animation);
+ }
if (mListener != null) {
mListener.onAnimationStart(animation);
}
@@ -810,6 +935,9 @@ public class ViewPropertyAnimator {
if (mListener != null) {
mListener.onAnimationCancel(animation);
}
+ if (mAnimatorOnEndMap != null) {
+ mAnimatorOnEndMap.remove(animation);
+ }
}
@Override
@@ -824,6 +952,20 @@ public class ViewPropertyAnimator {
if (mListener != null) {
mListener.onAnimationEnd(animation);
}
+ if (mAnimatorOnEndMap != null) {
+ Runnable r = mAnimatorOnEndMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorOnEndMap.remove(animation);
+ }
+ if (mAnimatorCleanupMap != null) {
+ Runnable r = mAnimatorCleanupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorCleanupMap.remove(animation);
+ }
mAnimatorMap.remove(animation);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a4bdf4..cbf4b5a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,11 +18,13 @@ package android.view;
import android.Manifest;
import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
import android.app.ActivityManagerNative;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -52,6 +54,7 @@ import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Pool;
import android.util.Poolable;
import android.util.PoolableManager;
@@ -81,7 +84,6 @@ import com.android.internal.view.RootViewSurfaceTaker;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -139,6 +141,10 @@ public final class ViewRootImpl extends Handler implements ViewParent,
static final ArrayList<ComponentCallbacks> sConfigCallbacks
= new ArrayList<ComponentCallbacks>();
+ private static boolean sUseRenderThread = false;
+ private static boolean sRenderThreadQueried = false;
+ private static final Object[] sRenderThreadQueryLock = new Object[0];
+
long mLastTrackballTime = 0;
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -168,6 +174,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
View mView;
View mFocusedView;
View mRealFocusedView; // this is not set to null in touch mode
+ View mOldFocusedView;
int mViewVisibility;
boolean mAppVisible = true;
int mOrigWindowType = -1;
@@ -301,6 +308,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
+ AccessibilityPrefetchStrategy mAccessibilityPrefetchStrategy;
+
private final int mDensity;
/**
@@ -315,8 +324,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
- sWindowSession = Display.getWindowManager().openSession(
+ IWindowManager windowManager = Display.getWindowManager();
+ sWindowSession = windowManager.openSession(
imm.getClient(), imm.getInputContext());
+ float animatorScale = windowManager.getAnimationScale(2);
+ ValueAnimator.setDurationScale(animatorScale);
mInitialized = true;
} catch (RemoteException e) {
}
@@ -377,6 +389,31 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mChoreographer = Choreographer.getInstance();
}
+ /**
+ * @return True if the application requests the use of a separate render thread,
+ * false otherwise
+ */
+ private static boolean isRenderThreadRequested(Context context) {
+ synchronized (sRenderThreadQueryLock) {
+ if (!sRenderThreadQueried) {
+ final PackageManager packageManager = context.getPackageManager();
+ final String packageName = context.getApplicationInfo().packageName;
+ try {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+ PackageManager.GET_META_DATA);
+ if (applicationInfo.metaData != null) {
+ sUseRenderThread = applicationInfo.metaData.getBoolean(
+ "android.graphics.renderThread", false);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ } finally {
+ sRenderThreadQueried = true;
+ }
+ }
+ return sUseRenderThread;
+ }
+ }
+
public static void addFirstDrawHandler(Runnable callback) {
synchronized (sFirstDrawHandlers) {
if (!sFirstDrawComplete) {
@@ -447,7 +484,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
// If the application owns the surface, don't enable hardware acceleration
if (mSurfaceHolder == null) {
- enableHardwareAcceleration(attrs);
+ enableHardwareAcceleration(mView.getContext(), attrs);
}
boolean restore = false;
@@ -607,7 +644,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
- private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
+ private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -640,20 +677,27 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
&& forceHwAccelerated)) {
// Don't enable hardware acceleration when we're not on the main thread
- if (!HardwareRenderer.sSystemRendererDisabled
- && Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ if (!HardwareRenderer.sSystemRendererDisabled &&
+ Looper.getMainLooper() != Looper.myLooper()) {
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ "acceleration outside of the main thread, aborting");
return;
}
- final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+ boolean renderThread = isRenderThreadRequested(context);
+ if (renderThread) {
+ Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
+ }
+
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.destroy(true);
- }
+ }
+
+ final boolean translucent = attrs.format != PixelFormat.OPAQUE;
mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
= mAttachInfo.mHardwareRenderer != null;
+
} else if (fakeHwAccelerated) {
// The window had wanted to use hardware acceleration, but this
// is not allowed in its process. By setting this flag, it can
@@ -2226,32 +2270,33 @@ public final class ViewRootImpl extends Handler implements ViewParent,
public void requestChildFocus(View child, View focused) {
checkThread();
- if (mFocusedView != focused) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
- scheduleTraversals();
+
+ if (DEBUG_INPUT_RESIZE) {
+ Log.v(TAG, "Request child focus: focus now " + focused);
}
+
+ mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
+ scheduleTraversals();
+
mFocusedView = mRealFocusedView = focused;
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
- + mFocusedView);
}
public void clearChildFocus(View child) {
checkThread();
- View oldFocus = mFocusedView;
+ if (DEBUG_INPUT_RESIZE) {
+ Log.v(TAG, "Clearing child focus");
+ }
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
- mFocusedView = mRealFocusedView = null;
- if (mView != null && !mView.hasFocus()) {
- // If a view gets the focus, the listener will be invoked from requestChildFocus()
- if (!mView.requestFocus(View.FOCUS_FORWARD)) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
- }
- } else if (oldFocus != null) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
+ mOldFocusedView = mFocusedView;
+
+ // Invoke the listener only if there is no view to take focus
+ if (focusSearch(null, View.FOCUS_FORWARD) == null) {
+ mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
}
- }
+ mFocusedView = mRealFocusedView = null;
+ }
public void focusableViewAvailable(View v) {
checkThread();
@@ -2724,6 +2769,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mView.unFocus();
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
mFocusedView = null;
+ mOldFocusedView = null;
return true;
}
}
@@ -3438,11 +3484,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (args.localChanges != 0) {
if (mAttachInfo != null) {
mAttachInfo.mSystemUiVisibility =
- (mAttachInfo.mSystemUiVisibility&~args.localChanges)
- | (args.localValue&args.localChanges);
+ (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
+ (args.localValue & args.localChanges);
+ mAttachInfo.mRecomputeGlobalAttributes = true;
}
mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
- mAttachInfo.mRecomputeGlobalAttributes = true;
scheduleTraversals();
}
mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
@@ -3480,6 +3526,17 @@ public final class ViewRootImpl extends Handler implements ViewParent,
return mAccessibilityInteractionController;
}
+ public AccessibilityPrefetchStrategy getAccessibilityPrefetchStrategy() {
+ if (mView == null) {
+ throw new IllegalStateException("getAccessibilityPrefetchStrategy"
+ + " called when there is no mView");
+ }
+ if (mAccessibilityPrefetchStrategy == null) {
+ mAccessibilityPrefetchStrategy = new AccessibilityPrefetchStrategy();
+ }
+ return mAccessibilityPrefetchStrategy;
+ }
+
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
@@ -3585,7 +3642,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mView.debug();
}
- public void dumpGfxInfo(PrintWriter pw, int[] info) {
+ public void dumpGfxInfo(int[] info) {
if (mView != null) {
getGfxInfo(mView, info);
} else {
@@ -3697,7 +3754,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
* Represents a pending input event that is waiting in a queue.
*
* Input events are processed in serial order by the timestamp specified by
- * {@link InputEvent#getEventTime()}. In general, the input dispatcher delivers
+ * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
* one input event to the application at a time and waits for the application
* to finish handling it before delivering the next one.
*
@@ -3706,7 +3763,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
* needing a queue on the application's side.
*/
private static final class QueuedInputEvent {
- public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+ public static final int FLAG_DELIVER_POST_IME = 1;
public QueuedInputEvent mNext;
@@ -3980,6 +4037,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (mView == null) {
return false;
}
+ getAccessibilityPrefetchStrategy().onAccessibilityEvent(event);
mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
@@ -4539,6 +4597,13 @@ public final class ViewRootImpl extends Handler implements ViewParent,
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not wait.
+ try {
+ callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
@@ -4550,28 +4615,49 @@ public final class ViewRootImpl extends Handler implements ViewParent,
viewRootImpl.getAccessibilityInteractionController()
.performAccessibilityActionClientThread(accessibilityNodeId, action,
interactionId, callback, interogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setPerformAccessibilityActionResult(false, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
- public void findAccessibilityNodeInfoByViewId(int viewId,
+ public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
- .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
- interrogatingPid, interrogatingTid);
+ .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
+ interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setFindAccessibilityNodeInfoResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
- public void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
+ public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
- .findAccessibilityNodeInfosByTextClientThread(text, accessibilityNodeId,
+ .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
}
@@ -4649,6 +4735,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
long interrogatingTid) {
Message message = Message.obtain();
message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+ message.arg1 = interrogatingPid;
SomeArgs args = mPool.acquire();
args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
@@ -4671,40 +4758,47 @@ public final class ViewRootImpl extends Handler implements ViewParent,
public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
SomeArgs args = (SomeArgs) message.obj;
+ final int interrogatingPid = message.arg1;
final int accessibilityViewId = args.argi1;
final int virtualDescendantId = args.argi2;
final int interactionId = args.argi3;
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg1;
mPool.release(args);
- AccessibilityNodeInfo info = null;
+ List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
try {
View target = findViewByAccessibilityId(accessibilityViewId);
if (target != null && target.getVisibility() == View.VISIBLE) {
AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
if (provider != null) {
- info = provider.createAccessibilityNodeInfo(virtualDescendantId);
+ infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
} else if (virtualDescendantId == View.NO_ID) {
- info = target.createAccessibilityNodeInfo();
+ getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
+ interrogatingPid, target, infos);
}
}
} finally {
try {
- callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+ infos.clear();
} catch (RemoteException re) {
/* ignore - the other side will time out */
}
}
}
- public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
- long interrogatingTid) {
+ public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
+ int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ int interrogatingPid, long interrogatingTid) {
Message message = Message.obtain();
message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
- message.arg1 = viewId;
- message.arg2 = interactionId;
- message.obj = callback;
+ message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+ SomeArgs args = mPool.acquire();
+ args.argi1 = viewId;
+ args.argi2 = interactionId;
+ args.arg1 = callback;
+ message.obj = args;
// If the interrogation is performed by the same thread as the main UI
// thread in this process, set the message as a static reference so
// after this call completes the same thread but in the interrogating
@@ -4720,17 +4814,26 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
- final int viewId = message.arg1;
- final int interactionId = message.arg2;
+ final int accessibilityViewId = message.arg1;
+ SomeArgs args = (SomeArgs) message.obj;
+ final int viewId = args.argi1;
+ final int interactionId = args.argi2;
final IAccessibilityInteractionConnectionCallback callback =
- (IAccessibilityInteractionConnectionCallback) message.obj;
-
+ (IAccessibilityInteractionConnectionCallback) args.arg1;
+ mPool.release(args);
AccessibilityNodeInfo info = null;
try {
- View root = ViewRootImpl.this.mView;
- View target = root.findViewById(viewId);
- if (target != null && target.getVisibility() == View.VISIBLE) {
- info = target.createAccessibilityNodeInfo();
+ View root = null;
+ if (accessibilityViewId != View.NO_ID) {
+ root = findViewByAccessibilityId(accessibilityViewId);
+ } else {
+ root = ViewRootImpl.this.mView;
+ }
+ if (root != null) {
+ View target = root.findViewById(viewId);
+ if (target != null && target.getVisibility() == View.VISIBLE) {
+ info = target.createAccessibilityNodeInfo();
+ }
}
} finally {
try {
@@ -4741,8 +4844,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
- public void findAccessibilityNodeInfosByTextClientThread(String text,
- long accessibilityNodeId, int interactionId,
+ public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
+ String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
long interrogatingTid) {
Message message = Message.obtain();
@@ -4779,7 +4882,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mPool.release(args);
List<AccessibilityNodeInfo> infos = null;
try {
- View target = null;
+ View target;
if (accessibilityViewId != View.NO_ID) {
target = findViewByAccessibilityId(accessibilityViewId);
} else {
@@ -4934,4 +5037,88 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
}
+
+ /**
+ * This class encapsulates a prefetching strategy for the accessibility APIs for
+ * querying window content.It is responsible to prefetch a batch of
+ * AccessibilityNodeInfos in addition to the one for a requested node. It caches
+ * the ids of the prefeteched nodes such that they are fetched only once.
+ */
+ class AccessibilityPrefetchStrategy {
+ private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 100;
+
+ // We need to keep track of what we have sent for each interrogating
+ // process. Usually there will be only one such process but we
+ // should support the general case. Note that the accessibility event
+ // stream will take care of clearing caches of querying processes that
+ // are not longer alive, so we do not waste memory.
+ private final LongSparseArray<AccessibilityNodeInfoCache> mAccessibilityNodeInfoCaches =
+ new LongSparseArray<AccessibilityNodeInfoCache>();
+
+ private AccessibilityNodeInfoCache getCacheForInterrogatingPid(long interrogatingPid) {
+ AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.get(interrogatingPid);
+ if (cache == null) {
+ cache = AccessibilityNodeInfoCache.newAccessibilityNodeInfoCache();
+ mAccessibilityNodeInfoCaches.put(interrogatingPid, cache);
+ }
+ return cache;
+ }
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ final int cacheCount = mAccessibilityNodeInfoCaches.size();
+ for (int i = 0; i < cacheCount; i++) {
+ AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.valueAt(i);
+ cache.onAccessibilityEvent(event);
+ }
+ }
+
+ public void prefetchAccessibilityNodeInfos(long interrogatingPid, View root,
+ List<AccessibilityNodeInfo> outInfos) {
+ addAndCacheNotCachedNodeInfo(interrogatingPid, root, outInfos);
+ addAndCacheNotCachedPredecessorInfos(interrogatingPid, root, outInfos);
+ addAndCacheNotCachedDescendantInfos(interrogatingPid, root, outInfos);
+ }
+
+ private void addAndCacheNotCachedNodeInfo(long interrogatingPid,
+ View view, List<AccessibilityNodeInfo> outInfos) {
+ final long accessibilityNodeId = AccessibilityNodeInfo.makeNodeId(
+ view.getAccessibilityViewId(), View.NO_ID);
+ AccessibilityNodeInfoCache cache = getCacheForInterrogatingPid(interrogatingPid);
+ if (!cache.containsKey(accessibilityNodeId)) {
+ // Account for the ids of the fetched infos. The infos will be
+ // cached in the window querying process. We just need to know
+ // which infos are cached to avoid fetching a cached one again.
+ cache.put(accessibilityNodeId, null);
+ outInfos.add(view.createAccessibilityNodeInfo());
+ }
+ }
+
+ private void addAndCacheNotCachedPredecessorInfos(long interrogatingPid, View view,
+ List<AccessibilityNodeInfo> outInfos) {
+ ViewParent predecessor = view.getParent();
+ while (predecessor instanceof View
+ && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ View predecessorView = (View) predecessor;
+ addAndCacheNotCachedNodeInfo(interrogatingPid, predecessorView, outInfos);
+ predecessor = predecessor.getParent();
+ }
+ }
+
+ private void addAndCacheNotCachedDescendantInfos(long interrogatingPid, View view,
+ List<AccessibilityNodeInfo> outInfos) {
+ if (outInfos.size() > MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE
+ || view.getAccessibilityNodeProvider() != null) {
+ return;
+ }
+ addAndCacheNotCachedNodeInfo(interrogatingPid, view, outInfos);
+ if (view instanceof ViewGroup) {
+ ViewGroup rootGroup = (ViewGroup) view;
+ final int childCount = rootGroup.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = rootGroup.getChildAt(i);
+ addAndCacheNotCachedDescendantInfos(interrogatingPid, child, outInfos);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d711337..6bdc4e8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -490,7 +490,7 @@ public class WindowManagerImpl implements WindowManager {
for (int i = 0; i < count; i++) {
ViewRootImpl root = mRoots[i];
- root.dumpGfxInfo(pw, info);
+ root.dumpGfxInfo(info);
String name = root.getClass().getName() + '@' +
Integer.toHexString(hashCode());
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 95c070c..072fdd8 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -24,7 +24,9 @@ import android.os.SystemClock;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
+import android.view.AccessibilityNodeInfoCache;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -97,6 +99,11 @@ public final class AccessibilityInteractionClient
private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
new SparseArray<IAccessibilityServiceConnection>();
+ // The connection cache is shared between all interrogating threads since
+ // at any given time there is only one window allowing querying.
+ private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache =
+ AccessibilityNodeInfoCache.newSynchronizedAccessibilityNodeInfoCache();
+
/**
* @return The client for the current thread.
*/
@@ -145,7 +152,9 @@ public final class AccessibilityInteractionClient
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
* @param connectionId The id of a connection for interacting with the system.
- * @param accessibilityWindowId A unique window id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique node accessibility id
* (accessibility view and virtual descendant id).
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
@@ -155,16 +164,22 @@ public final class AccessibilityInteractionClient
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
+ AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(accessibilityNodeId);
+ if (cachedInfo != null) {
+ return cachedInfo;
+ }
final int interactionId = mInteractionIdCounter.getAndIncrement();
final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+ List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
- finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
- return info;
+ finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+ if (infos != null && !infos.isEmpty()) {
+ return infos.get(0);
+ }
}
} else {
if (DEBUG) {
@@ -181,22 +196,30 @@ public final class AccessibilityInteractionClient
}
/**
- * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
- * in the currently active window and starts from the root View in the window.
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
*
* @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id from where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param viewId The id of the view.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId,
- int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId,
+ int accessibilityWindowId, long accessibilityNodeId, int viewId) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final float windowScale =
- connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId,
- interactionId, this, Thread.currentThread().getId());
+ connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId,
+ accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
@@ -220,64 +243,27 @@ public final class AccessibilityInteractionClient
/**
* Finds {@link AccessibilityNodeInfo}s by View text. The match is case
- * insensitive containment. The search is performed in the currently
- * active window and starts from the root View in the window.
- *
- * @param connectionId The id of a connection for interacting with the system.
- * @param text The searched text.
- * @return A list of found {@link AccessibilityNodeInfo}s.
- */
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(
- int connectionId, String text) {
- try {
- IAccessibilityServiceConnection connection = getConnection(connectionId);
- if (connection != null) {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale =
- connection.findAccessibilityNodeInfosByTextInActiveWindow(text,
- interactionId, this, Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
- return infos;
- }
- } else {
- if (DEBUG) {
- Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
- }
- }
- } catch (RemoteException re) {
- if (DEBUG) {
- Log.w(LOG_TAG, "Error while calling remote"
- + " findAccessibilityNodeInfosByViewTextInActiveWindow", re);
- }
- }
- return null;
- }
-
- /**
- * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
* insensitive containment. The search is performed in the window whose
- * id is specified and starts from the View whose accessibility id is
+ * id is specified and starts from the node whose accessibility id is
* specified.
*
* @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id from where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
* @param text The searched text.
- * @param accessibilityWindowId A unique window id.
- * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id) from
- * where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
* @return A list of found {@link AccessibilityNodeInfo}s.
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId,
- String text, int accessibilityWindowId, long accessibilityNodeId) {
+ int accessibilityWindowId, long accessibilityNodeId, String text) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfosByText(text,
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ final float windowScale = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
@@ -304,7 +290,9 @@ public final class AccessibilityInteractionClient
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
*
* @param connectionId The id of a connection for interacting with the system.
- * @param accessibilityWindowId The id of the window.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
* @param action The action to perform.
* @return Whether the action was performed.
@@ -319,7 +307,7 @@ public final class AccessibilityInteractionClient
accessibilityWindowId, accessibilityNodeId, action, interactionId, this,
Thread.currentThread().getId());
if (success) {
- return getPerformAccessibilityActionResult(interactionId);
+ return getPerformAccessibilityActionResultAndClear(interactionId);
}
} else {
if (DEBUG) {
@@ -334,6 +322,24 @@ public final class AccessibilityInteractionClient
return false;
}
+ public void clearCache() {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "clearCache()");
+ }
+ sAccessibilityNodeInfoCache.clear();
+ }
+
+ public void removeCachedNode(long accessibilityNodeId) {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "removeCachedNode(" + accessibilityNodeId +")");
+ }
+ sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
+ }
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ sAccessibilityNodeInfoCache.onAccessibilityEvent(event);
+ }
+
/**
* Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
*
@@ -358,6 +364,9 @@ public final class AccessibilityInteractionClient
if (interactionId > mInteractionId) {
mFindAccessibilityNodeInfoResult = info;
mInteractionId = interactionId;
+ if (info != null) {
+ sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+ }
}
mInstanceLock.notifyAll();
}
@@ -386,8 +395,20 @@ public final class AccessibilityInteractionClient
int interactionId) {
synchronized (mInstanceLock) {
if (interactionId > mInteractionId) {
- mFindAccessibilityNodeInfosResult = infos;
+ // If the call is not an IPC, i.e. it is made from the same process, we need to
+ // instantiate new result list to avoid passing internal instances to clients.
+ final boolean isIpcCall = (queryLocalInterface(getInterfaceDescriptor()) == null);
+ if (!isIpcCall) {
+ mFindAccessibilityNodeInfosResult = new ArrayList<AccessibilityNodeInfo>(infos);
+ } else {
+ mFindAccessibilityNodeInfosResult = infos;
+ }
mInteractionId = interactionId;
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i ++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+ }
}
mInstanceLock.notifyAll();
}
@@ -399,7 +420,7 @@ public final class AccessibilityInteractionClient
* @param interactionId The interaction id to match the result with the request.
* @return Whether the action was performed.
*/
- private boolean getPerformAccessibilityActionResult(int interactionId) {
+ private boolean getPerformAccessibilityActionResultAndClear(int interactionId) {
synchronized (mInstanceLock) {
final boolean success = waitForResultTimedLocked(interactionId);
final boolean result = success ? mPerformAccessibilityActionResult : false;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6939c2c..d7d6792 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -380,8 +380,8 @@ public class AccessibilityNodeInfo implements Parcelable {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfosByText(mConnectionId, text, mWindowId,
- mSourceNodeId);
+ return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
+ text);
}
/**
@@ -903,6 +903,17 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the id of the source node.
+ *
+ * @return The id.
+ *
+ * @hide
+ */
+ public long getSourceNodeId() {
+ return mSourceNodeId;
+ }
+
+ /**
* Sets if this instance is sealed.
*
* @param sealed Whether is sealed.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 07aeb9a..b60f50e 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -564,6 +564,17 @@ public class AccessibilityRecord {
}
/**
+ * Gets the id of the source node.
+ *
+ * @return The id.
+ *
+ * @hide
+ */
+ public long getSourceNodeId() {
+ return mSourceNodeId;
+ }
+
+ /**
* Sets the unique id of the IAccessibilityServiceConnection over which
* this instance can send requests to the system.
*
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index a90c427..ae6869c 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -31,13 +31,13 @@ oneway interface IAccessibilityInteractionConnection {
IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid);
- void findAccessibilityNodeInfoByViewId(int id, int interactionId,
+ void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int id, int interactionId,
IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid);
- void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
- int interrogatingPid, long interrogatingTid);
+ void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+ long interrogatingTid);
void performAccessibilityAction(long accessibilityNodeId, int action, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c3794be..320c75d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -49,5 +49,7 @@ interface IAccessibilityManager {
void removeAccessibilityInteractionConnection(IWindow windowToken);
- void registerEventListener(IEventListener client);
+ void registerUiTestAutomationService(IEventListener listener, in AccessibilityServiceInfo info);
+
+ void unregisterUiTestAutomationService(IEventListener listener);
}
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 30bbb04..ee9b949 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -169,7 +169,9 @@ class Network {
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
return;
- NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+ final ConnectivityManager connManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo info = connManager.getActiveNetworkInfo();
if (info != null)
mRoaming = info.isRoaming();
};
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index d100260..0541d5d 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -40,9 +40,6 @@ class WebCoreThreadWatchdog implements Runnable {
// WebCore thread unresponsive.
private static final int TIMED_OUT = 101;
- // Message to tell the Watchdog thread to terminate.
- private static final int QUIT = 102;
-
// Wait 10s after hearing back from the WebCore thread before checking it's still alive.
private static final int HEARTBEAT_PERIOD = 10 * 1000;
@@ -57,7 +54,6 @@ class WebCoreThreadWatchdog implements Runnable {
private Handler mWebCoreThreadHandler;
private Handler mHandler;
private boolean mPaused;
- private boolean mPendingQuit;
private static WebCoreThreadWatchdog sInstance;
@@ -88,12 +84,6 @@ class WebCoreThreadWatchdog implements Runnable {
}
}
- public synchronized static void quit() {
- if (sInstance != null) {
- sInstance.quitWatchdog();
- }
- }
-
private void setContext(Context context) {
mContext = context;
}
@@ -103,19 +93,6 @@ class WebCoreThreadWatchdog implements Runnable {
mWebCoreThreadHandler = webCoreThreadHandler;
}
- private void quitWatchdog() {
- if (mHandler == null) {
- // The thread hasn't started yet, so set a flag to stop it starting.
- mPendingQuit = true;
- return;
- }
- // Clear any pending messages, and then post a quit to the WatchDog handler.
- mHandler.removeMessages(TIMED_OUT);
- mHandler.removeMessages(IS_ALIVE);
- mWebCoreThreadHandler.removeMessages(EventHub.HEARTBEAT);
- mHandler.obtainMessage(QUIT).sendToTarget();
- }
-
private void pauseWatchdog() {
mPaused = true;
@@ -146,12 +123,8 @@ class WebCoreThreadWatchdog implements Runnable {
mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD);
}
- private boolean createHandler() {
+ private void createHandler() {
synchronized (WebCoreThreadWatchdog.class) {
- if (mPendingQuit) {
- return false;
- }
-
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -206,15 +179,9 @@ class WebCoreThreadWatchdog implements Runnable {
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
break;
-
- case QUIT:
- Looper.myLooper().quit();
- break;
}
}
};
-
- return true;
}
}
@@ -222,9 +189,7 @@ class WebCoreThreadWatchdog implements Runnable {
public void run() {
Looper.prepare();
- if (!createHandler()) {
- return;
- }
+ createHandler();
// Send the initial control to WebViewCore and start the timeout timer as long as we aren't
// paused.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index cc8eef2..4a42e92 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -789,12 +789,18 @@ public class WebView extends AbsoluteLayout
// know to handle Shift and arrows natively first
private boolean mAccessibilityScriptInjected;
- static final boolean USE_JAVA_TEXT_SELECTION = true;
- static final boolean DEBUG_TEXT_HANDLES = false;
- private Region mTextSelectionRegion = new Region();
- private Paint mTextSelectionPaint;
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
+ private Rect mSelectCursorBase = new Rect();
+ private int mSelectCursorBaseLayerId;
+ private Rect mSelectCursorExtent = new Rect();
+ private int mSelectCursorExtentLayerId;
+ private Rect mSelectDraggingCursor;
+ private Point mSelectDraggingOffset = new Point();
+ static final int HANDLE_ID_START = 0;
+ static final int HANDLE_ID_END = 1;
+ static final int HANDLE_ID_BASE = 2;
+ static final int HANDLE_ID_EXTENT = 3;
static boolean sDisableNavcache = false;
// the color used to highlight the touch rectangles
@@ -2656,12 +2662,6 @@ public class WebView extends AbsoluteLayout
return mZoomManager.getScale();
}
- // Called by JNI. Returns the scale to apply to the text selection handles
- /* package */ float getTextHandleScale() {
- float density = mContext.getResources().getDisplayMetrics().density;
- return density / getScale();
- }
-
/**
* Compute the reading level scale of the WebView
* @param scale The current scale.
@@ -3852,6 +3852,16 @@ public class WebView extends AbsoluteLayout
if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
return;
}
+ if (mSelectingText) {
+ int dx = mScrollingLayerRect.left - x;
+ int dy = mScrollingLayerRect.top - y;
+ if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorBase.offset(dx, dy);
+ }
+ if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorExtent.offset(dx, dy);
+ }
+ }
nativeScrollLayer(mCurrentScrollingLayerId, x, y);
mScrollingLayerRect.left = x;
mScrollingLayerRect.top = y;
@@ -4624,12 +4634,7 @@ public class WebView extends AbsoluteLayout
* Select the word at the indicated content coordinates.
*/
boolean selectText(int x, int y) {
- if (!setUpSelect(true, x, y)) {
- return false;
- }
- nativeSetExtendSelection();
- mDrawSelectionPointer = false;
- mTouchMode = TOUCH_DRAG_MODE;
+ mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
return true;
}
@@ -4830,11 +4835,8 @@ public class WebView extends AbsoluteLayout
int extras = DRAW_EXTRAS_NONE;
if (mFindIsUp) {
extras = DRAW_EXTRAS_FIND;
- } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
+ } else if (mSelectingText) {
extras = DRAW_EXTRAS_SELECTION;
- nativeSetSelectionPointer(mNativeClass,
- mDrawSelectionPointer,
- mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
} else if (drawCursorRing) {
extras = DRAW_EXTRAS_CURSOR_RING;
}
@@ -4879,7 +4881,7 @@ public class WebView extends AbsoluteLayout
}
canvas.restoreToCount(saveCount);
- if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+ if (mSelectingText) {
drawTextSelectionHandles(canvas);
}
@@ -4901,30 +4903,12 @@ public class WebView extends AbsoluteLayout
}
private void drawTextSelectionHandles(Canvas canvas) {
- if (mTextSelectionPaint == null) {
- mTextSelectionPaint = new Paint();
- mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
- }
- mTextSelectionRegion.setEmpty();
- nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
- Rect r = new Rect();
- RegionIterator iter = new RegionIterator(mTextSelectionRegion);
- Rect clip = canvas.getClipBounds();
- while (iter.next(r)) {
- r.set(contentToViewDimension(r.left),
- contentToViewDimension(r.top),
- contentToViewDimension(r.right),
- contentToViewDimension(r.bottom));
- if (r.intersect(clip)) {
- canvas.drawRect(r, mTextSelectionPaint);
- }
- }
if (mSelectHandleLeft == null) {
mSelectHandleLeft = mContext.getResources().getDrawable(
com.android.internal.R.drawable.text_select_handle_left);
}
int[] handles = new int[4];
- nativeGetSelectionHandles(mNativeClass, handles);
+ getSelectionHandles(handles);
int start_x = contentToViewDimension(handles[0]);
int start_y = contentToViewDimension(handles[1]);
int end_x = contentToViewDimension(handles[2]);
@@ -4942,14 +4926,31 @@ public class WebView extends AbsoluteLayout
mSelectHandleRight.setBounds(end_x, end_y,
end_x + mSelectHandleRight.getIntrinsicWidth(),
end_y + mSelectHandleRight.getIntrinsicHeight());
- if (DEBUG_TEXT_HANDLES) {
- mSelectHandleLeft.setAlpha(125);
- mSelectHandleRight.setAlpha(125);
- }
mSelectHandleLeft.draw(canvas);
mSelectHandleRight.draw(canvas);
}
+ /**
+ * Takes an int[4] array as an output param with the values being
+ * startX, startY, endX, endY
+ */
+ private void getSelectionHandles(int[] handles) {
+ handles[0] = mSelectCursorBase.right;
+ handles[1] = mSelectCursorBase.bottom -
+ (mSelectCursorBase.height() / 4);
+ handles[2] = mSelectCursorExtent.left;
+ handles[3] = mSelectCursorExtent.bottom
+ - (mSelectCursorExtent.height() / 4);
+ if (!nativeIsBaseFirst(mNativeClass)) {
+ int swap = handles[0];
+ handles[0] = handles[2];
+ handles[2] = swap;
+ swap = handles[1];
+ handles[1] = handles[3];
+ handles[3] = swap;
+ }
+ }
+
// draw history
private boolean mDrawHistory = false;
private Picture mHistoryPicture = null;
@@ -5009,7 +5010,7 @@ public class WebView extends AbsoluteLayout
/* package */ void deleteSelection(int start, int end) {
mTextGeneration++;
WebViewCore.TextSelectionData data
- = new WebViewCore.TextSelectionData(start, end);
+ = new WebViewCore.TextSelectionData(start, end, 0);
mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
data);
}
@@ -5462,15 +5463,6 @@ public class WebView extends AbsoluteLayout
return pinScrollTo(mContentWidth, mScrollY, true, 0);
}
}
- if (mSelectingText) {
- int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
- int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
- -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
- int multiplier = event.getRepeatCount() + 1;
- moveSelection(xRate * multiplier, yRate * multiplier);
- return true;
- }
if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
playSoundEffect(keyCodeToSoundsEffect(keyCode));
return true;
@@ -5623,14 +5615,8 @@ public class WebView extends AbsoluteLayout
mGotCenterDown = false;
if (mSelectingText) {
- if (mExtendSelection) {
- copySelection();
- selectionDone();
- } else {
- mExtendSelection = true;
- nativeSetExtendSelection();
- invalidate(); // draw the i-beam instead of the arrow
- }
+ copySelection();
+ selectionDone();
return true; // discard press if copy in progress
}
@@ -5676,21 +5662,7 @@ public class WebView extends AbsoluteLayout
return false;
}
- /*
- * Enter selecting text mode, and see if CAB should be shown.
- * Returns true if the WebView is now in
- * selecting text mode (including if it was already in that mode, and this
- * method did nothing).
- */
- private boolean setUpSelect(boolean selectWord, int x, int y) {
- if (0 == mNativeClass) return false; // client isn't initialized
- if (inFullScreenMode()) return false;
- if (mSelectingText) return true;
- nativeResetSelection();
- if (selectWord && !nativeWordSelection(x, y)) {
- selectionDone();
- return false;
- }
+ private boolean startSelectActionMode() {
mSelectCallback = new SelectActionModeCallback();
mSelectCallback.setWebView(this);
if (startActionMode(mSelectCallback) == null) {
@@ -5699,52 +5671,41 @@ public class WebView extends AbsoluteLayout
selectionDone();
return false;
}
- mExtendSelection = false;
- mSelectingText = mDrawSelectionPointer = true;
- if (DEBUG_TEXT_HANDLES) {
- // Debugging text handles requires running in software mode
- setLayerType(LAYER_TYPE_SOFTWARE, null);
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ return true;
+ }
+
+ private void syncSelectionCursors() {
+ mSelectCursorBaseLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase);
+ mSelectCursorExtentLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent);
+ }
+
+ private boolean setupWebkitSelect() {
+ syncSelectionCursors();
+ if (!startSelectActionMode()) {
+ selectionDone();
+ return false;
}
- // don't let the picture change during text selection
- WebViewCore.pauseUpdatePicture(mWebViewCore);
- if (nativeHasCursorNode()) {
- Rect rect = nativeCursorNodeBounds();
- mSelectX = contentToViewX(rect.left);
- mSelectY = contentToViewY(rect.top);
- } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
- mSelectX = mScrollX + mLastTouchX;
- mSelectY = mScrollY + mLastTouchY;
+ mSelectingText = true;
+ mTouchMode = TOUCH_DRAG_MODE;
+ return true;
+ }
+
+ private void updateWebkitSelection() {
+ int[] handles = null;
+ if (mSelectingText) {
+ handles = new int[4];
+ handles[0] = mSelectCursorBase.centerX();
+ handles[1] = mSelectCursorBase.centerY();
+ handles[2] = mSelectCursorExtent.centerX();
+ handles[3] = mSelectCursorExtent.centerY();
} else {
- mSelectX = mScrollX + getViewWidth() / 2;
- mSelectY = mScrollY + getViewHeightWithTitle() / 2;
+ nativeSetTextSelection(mNativeClass, 0);
}
- nativeHideCursor();
- mMinAutoScrollX = 0;
- mMaxAutoScrollX = getViewWidth();
- mMinAutoScrollY = 0;
- mMaxAutoScrollY = getViewHeightWithTitle();
- mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
- viewToContentY(mSelectY), mScrollingLayerRect,
- mScrollingLayerBounds);
- if (mCurrentScrollingLayerId != 0) {
- if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
- mMinAutoScrollX = Math.max(mMinAutoScrollX,
- contentToViewX(mScrollingLayerBounds.left));
- mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
- contentToViewX(mScrollingLayerBounds.right));
- }
- if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
- mMinAutoScrollY = Math.max(mMinAutoScrollY,
- contentToViewY(mScrollingLayerBounds.top));
- mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
- contentToViewY(mScrollingLayerBounds.bottom));
- }
- }
- mMinAutoScrollX += SELECT_SCROLL;
- mMaxAutoScrollX -= SELECT_SCROLL;
- mMinAutoScrollY += SELECT_SCROLL;
- mMaxAutoScrollY -= SELECT_SCROLL;
- return true;
+ mWebViewCore.removeMessages(EventHub.SELECT_TEXT);
+ mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, handles);
}
/**
@@ -5755,7 +5716,6 @@ public class WebView extends AbsoluteLayout
@Deprecated
public void emulateShiftHeld() {
checkThread();
- setUpSelect(false, 0, 0);
}
/**
@@ -5764,17 +5724,7 @@ public class WebView extends AbsoluteLayout
* @hide This is an implementation detail.
*/
public void selectAll() {
- if (0 == mNativeClass) return; // client isn't initialized
- if (inFullScreenMode()) return;
- if (!mSelectingText) {
- // retrieve a point somewhere within the text
- Point select = nativeSelectableText();
- if (!selectText(select.x, select.y)) return;
- }
- nativeSelectAll();
- mDrawSelectionPointer = false;
- mExtendSelection = true;
- invalidate();
+ mWebViewCore.sendMessage(EventHub.SELECT_ALL);
}
/**
@@ -5783,17 +5733,11 @@ public class WebView extends AbsoluteLayout
void selectionDone() {
if (mSelectingText) {
mSelectingText = false;
- if (DEBUG_TEXT_HANDLES) {
- // Debugging text handles required running in software mode, set
- // back to default now
- setLayerType(LAYER_TYPE_NONE, null);
- }
// finish is idempotent, so this is fine even if selectionDone was
// called by mSelectCallback.onDestroyActionMode
mSelectCallback.finish();
mSelectCallback = null;
- WebViewCore.resumePriority();
- WebViewCore.resumeUpdatePicture(mWebViewCore);
+ updateWebkitSelection();
invalidate(); // redraw without selection
mAutoScrollX = 0;
mAutoScrollY = 0;
@@ -5821,7 +5765,7 @@ public class WebView extends AbsoluteLayout
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(selection);
int[] handles = new int[4];
- nativeGetSelectionHandles(mNativeClass, handles);
+ getSelectionHandles(handles);
mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles);
}
invalidate(); // remove selection region and pointer
@@ -5836,7 +5780,7 @@ public class WebView extends AbsoluteLayout
public void cutSelection() {
copySelection();
int[] handles = new int[4];
- nativeGetSelectionHandles(mNativeClass, handles);
+ getSelectionHandles(handles);
mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
}
@@ -5854,7 +5798,7 @@ public class WebView extends AbsoluteLayout
CharSequence pasteText = clipItem.getText();
if (pasteText != null) {
int[] handles = new int[4];
- nativeGetSelectionHandles(mNativeClass, handles);
+ getSelectionHandles(handles);
mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
mWebViewCore.sendMessage(EventHub.INSERT_TEXT,
pasteText.toString());
@@ -6406,13 +6350,28 @@ public class WebView extends AbsoluteLayout
EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
- if (mSelectingText) {
- mDrawSelectionPointer = false;
- mSelectionStarted = nativeStartSelection(contentX, contentY);
+ mSelectionStarted = false;
+ if (mSelectingText && mSelectHandleLeft != null
+ && mSelectHandleRight != null) {
+ int shiftedY = y - getTitleHeight() + mScrollY;
+ int shiftedX = x + mScrollX;
+ if (mSelectHandleLeft.getBounds()
+ .contains(shiftedX, shiftedY)) {
+ mSelectionStarted = true;
+ mSelectDraggingCursor = mSelectCursorBase;
+ } else if (mSelectHandleRight.getBounds()
+ .contains(shiftedX, shiftedY)) {
+ mSelectionStarted = true;
+ mSelectDraggingCursor = mSelectCursorExtent;
+ }
+ if (mSelectDraggingCursor != null) {
+ mSelectDraggingOffset.set(
+ mSelectDraggingCursor.left - contentX,
+ mSelectDraggingCursor.top - contentY);
+ }
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + contentX + "," + contentY);
}
- invalidate();
}
}
// Trigger the link
@@ -6478,6 +6437,26 @@ public class WebView extends AbsoluteLayout
removeTouchHighlight();
}
}
+ if (mSelectingText && mSelectionStarted) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
+ }
+ ViewParent parent = getParent();
+ if (parent != null) {
+ parent.requestDisallowInterceptTouchEvent(true);
+ }
+ if (deltaX != 0 || deltaY != 0) {
+ mSelectDraggingCursor.offsetTo(
+ contentX + mSelectDraggingOffset.x,
+ contentY + mSelectDraggingOffset.y);
+ updateWebkitSelection();
+ mLastTouchX = x;
+ mLastTouchY = y;
+ invalidate();
+ }
+ break;
+ }
+
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
|| eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
@@ -6520,30 +6499,6 @@ public class WebView extends AbsoluteLayout
} else {
mVelocityTracker.addMovement(ev);
}
- if (mSelectingText && mSelectionStarted) {
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
- }
- ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
- : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
- mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
- : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
- if ((mAutoScrollX != 0 || mAutoScrollY != 0)
- && !mSentAutoScrollMessage) {
- mSentAutoScrollMessage = true;
- mPrivateHandler.sendEmptyMessageDelayed(
- SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
- }
- if (deltaX != 0 || deltaY != 0) {
- nativeExtendSelection(contentX, contentY);
- invalidate();
- }
- break;
- }
if (mTouchMode != TOUCH_DRAG_MODE &&
mTouchMode != TOUCH_DRAG_LAYER_MODE) {
@@ -6758,7 +6713,7 @@ public class WebView extends AbsoluteLayout
} else {
if (mSelectingText) {
// tapping on selection or controls does nothing
- if (!nativeHitSelection(contentX, contentY)) {
+ if (!mSelectionStarted) {
selectionDone();
}
break;
@@ -7055,6 +7010,12 @@ public class WebView extends AbsoluteLayout
if (mOverScrollGlow != null) {
mOverScrollGlow.releaseAll();
}
+
+ if (mSelectingText) {
+ mSelectionStarted = false;
+ syncSelectionCursors();
+ invalidate();
+ }
}
private void cancelTouch() {
@@ -7119,8 +7080,6 @@ public class WebView extends AbsoluteLayout
private int mTrackballYMove = 0;
private boolean mSelectingText = false;
private boolean mSelectionStarted = false;
- private boolean mExtendSelection = false;
- private boolean mDrawSelectionPointer = false;
private static final int TRACKBALL_KEY_TIMEOUT = 1000;
private static final int TRACKBALL_TIMEOUT = 200;
private static final int TRACKBALL_WAIT = 100;
@@ -7189,14 +7148,8 @@ public class WebView extends AbsoluteLayout
mTrackballDown = false;
mTrackballUpTime = time;
if (mSelectingText) {
- if (mExtendSelection) {
- copySelection();
- selectionDone();
- } else {
- mExtendSelection = true;
- nativeSetExtendSelection();
- invalidate(); // draw the i-beam instead of the arrow
- }
+ copySelection();
+ selectionDone();
return true; // discard press if copy in progress
}
if (DebugFlags.WEB_VIEW) {
@@ -7239,42 +7192,6 @@ public class WebView extends AbsoluteLayout
return true;
}
- void moveSelection(float xRate, float yRate) {
- if (mNativeClass == 0)
- return;
- int width = getViewWidth();
- int height = getViewHeight();
- mSelectX += xRate;
- mSelectY += yRate;
- int maxX = width + mScrollX;
- int maxY = height + mScrollY;
- mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
- , mSelectX));
- mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
- , mSelectY));
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "moveSelection"
- + " mSelectX=" + mSelectX
- + " mSelectY=" + mSelectY
- + " mScrollX=" + mScrollX
- + " mScrollY=" + mScrollY
- + " xRate=" + xRate
- + " yRate=" + yRate
- );
- }
- nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
- int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
- : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
- : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- pinScrollBy(scrollX, scrollY, true, 0);
- Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
- requestRectangleOnScreen(select);
- invalidate();
- }
-
private int scaleTrackballX(float xRate, int width) {
int xMove = (int) (xRate / TRACKBALL_SCALE * width);
int nextXMove = xMove;
@@ -7328,21 +7245,6 @@ public class WebView extends AbsoluteLayout
float yRate = mTrackballRemainsY * 1000 / elapsed;
int viewWidth = getViewWidth();
int viewHeight = getViewHeight();
- if (mSelectingText) {
- if (!mDrawSelectionPointer) {
- // The last selection was made by touch, disabling drawing the
- // selection pointer. Allow the trackball to adjust the
- // position of the touch control.
- mSelectX = contentToViewX(nativeSelectionX());
- mSelectY = contentToViewY(nativeSelectionY());
- mDrawSelectionPointer = mExtendSelection = true;
- nativeSetExtendSelection();
- }
- moveSelection(scaleTrackballX(xRate, viewWidth),
- scaleTrackballY(yRate, viewHeight));
- mTrackballRemainsX = mTrackballRemainsY = 0;
- return;
- }
float ax = Math.abs(xRate);
float ay = Math.abs(yRate);
float maxA = Math.max(ax, ay);
@@ -9204,6 +9106,18 @@ public class WebView extends AbsoluteLayout
mInputConnection.setSelection(data.mStart, data.mEnd);
}
}
+
+ nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
+ if (data.mSelectTextPtr != 0) {
+ if (!mSelectingText) {
+ setupWebkitSelect();
+ } else if (!mSelectionStarted) {
+ syncSelectionCursors();
+ }
+ } else {
+ selectionDone();
+ }
+ invalidate();
}
// Class used to use a dropdown for a <select> element
@@ -9952,7 +9866,6 @@ public class WebView extends AbsoluteLayout
private native boolean nativeMoveCursor(int keyCode, int count,
boolean noScroll);
private native int nativeMoveGeneration();
- private native void nativeMoveSelection(int x, int y);
/**
* @return true if the page should get the shift and arrow keys, rather
* than select text/navigation.
@@ -9962,15 +9875,8 @@ public class WebView extends AbsoluteLayout
*/
private native boolean nativePageShouldHandleShiftAndArrows();
private native boolean nativePointInNavCache(int x, int y, int slop);
- // Like many other of our native methods, you must make sure that
- // mNativeClass is not null before calling this method.
- private native void nativeResetSelection();
- private native Point nativeSelectableText();
- private native void nativeSelectAll();
private native void nativeSelectBestAt(Rect rect);
private native void nativeSelectAt(int x, int y);
- private native int nativeSelectionX();
- private native int nativeSelectionY();
private native int nativeFindIndex();
private native void nativeSetExtendSelection();
private native void nativeSetFindIsEmpty();
@@ -10026,12 +9932,14 @@ public class WebView extends AbsoluteLayout
private native int nativeGetBackgroundColor();
native boolean nativeSetProperty(String key, String value);
native String nativeGetProperty(String key);
- private native void nativeGetTextSelectionRegion(int instance, Region region);
- private native void nativeGetSelectionHandles(int instance, int[] handles);
/**
* See {@link ComponentCallbacks2} for the trim levels and descriptions
*/
private static native void nativeOnTrimMemory(int level);
private static native void nativeSetPauseDrawing(int instance, boolean pause);
private static native boolean nativeDisableNavcache();
+ private static native void nativeSetTextSelection(int instance, int selection);
+ private static native int nativeGetHandleLayerId(int instance, int handle,
+ Rect cursorLocation);
+ private static native boolean nativeIsBaseFirst(int instance);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index fe51581..395a638 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -835,12 +835,14 @@ public final class WebViewCore {
}
static class TextSelectionData {
- public TextSelectionData(int start, int end) {
+ public TextSelectionData(int start, int end, int selectTextPtr) {
mStart = start;
mEnd = end;
+ mSelectTextPtr = selectTextPtr;
}
int mStart;
int mEnd;
+ int mSelectTextPtr;
}
static class TouchUpData {
@@ -1118,6 +1120,9 @@ public final class WebViewCore {
static final int COPY_TEXT = 210;
static final int DELETE_TEXT = 211;
static final int INSERT_TEXT = 212;
+ static final int SELECT_TEXT = 213;
+ static final int SELECT_WORD_AT = 214;
+ static final int SELECT_ALL = 215;
// Private handler for WebCore messages.
private Handler mHandler;
@@ -1194,7 +1199,6 @@ public final class WebViewCore {
mSettings.onDestroyed();
mNativeClass = 0;
mWebView = null;
- WebCoreThreadWatchdog.quit();
}
break;
@@ -1747,6 +1751,25 @@ public final class WebViewCore {
case INSERT_TEXT:
nativeInsertText(mNativeClass, (String) msg.obj);
break;
+ case SELECT_TEXT: {
+ int[] args = (int[]) msg.obj;
+ if (args == null) {
+ nativeClearTextSelection(mNativeClass);
+ } else {
+ nativeSelectText(mNativeClass, args[0],
+ args[1], args[2], args[3]);
+ }
+ break;
+ }
+ case SELECT_WORD_AT: {
+ int x = msg.arg1;
+ int y = msg.arg2;
+ nativeSelectWordAt(mNativeClass, x, y);
+ break;
+ }
+ case SELECT_ALL:
+ nativeSelectAll(mNativeClass);
+ break;
}
}
};
@@ -2700,11 +2723,11 @@ public final class WebViewCore {
// called by JNI
private void updateTextSelection(int pointer, int start, int end,
- int textGeneration) {
+ int textGeneration, int selectionPtr) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
- new TextSelectionData(start, end)).sendToTarget();
+ new TextSelectionData(start, end, selectionPtr)).sendToTarget();
}
}
@@ -2771,7 +2794,7 @@ public final class WebViewCore {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
- textGeneration, new TextSelectionData(selStart, selEnd))
+ textGeneration, new TextSelectionData(selStart, selEnd, 0))
.sendToTarget();
}
}
@@ -3026,4 +3049,9 @@ public final class WebViewCore {
*/
private native String nativeGetText(int nativeClass,
int startX, int startY, int endX, int endY);
+ private native void nativeSelectText(int nativeClass,
+ int startX, int startY, int endX, int endY);
+ private native void nativeClearTextSelection(int nativeClass);
+ private native void nativeSelectWordAt(int nativeClass, int x, int y);
+ private native void nativeSelectAll(int nativeClass);
}
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 7d58011..984ec79 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -842,9 +842,11 @@ public class GridLayout extends ViewGroup {
* @hide
*/
@Override
- protected void onChildVisibilityChanged(View child, int visibility) {
- super.onChildVisibilityChanged(child, visibility);
- invalidateStructure();
+ protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
+ super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
+ if (oldVisibility == GONE || newVisibility == GONE) {
+ invalidateStructure();
+ }
}
// Measurement
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e20d12a..67fd059 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1651,6 +1651,7 @@ public class ListView extends AbsListView {
// are focusable
if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+ focusLayoutRestoreView != null &&
focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
if (!focusWasTaken) {
// selected item didn't take focus, fine, but still want
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index d395fb2..84e86af 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -56,13 +56,13 @@ import com.android.internal.R;
/**
* A widget that enables the user to select a number form a predefined range.
* The widget presents an input field and up and down buttons for selecting the
- * current value. Pressing/long pressing the up and down buttons increments and
+ * current value. Pressing/long-pressing the up and down buttons increments and
* decrements the current value respectively. Touching the input field shows a
- * scroll wheel, tapping on which while shown and not moving allows direct edit
- * of the current value. Sliding motions up or down hide the buttons and the
- * input field, show the scroll wheel, and rotate the latter. Flinging is
+ * scroll wheel, which when touched allows direct edit
+ * of the current value. Sliding gestures up or down hide the buttons and the
+ * input filed, show and rotate the scroll wheel. Flinging is
* also supported. The widget enables mapping from positions to strings such
- * that instead the position index the corresponding string is displayed.
+ * that, instead of the position index, the corresponding string is displayed.
* <p>
* For an example of using this widget, see {@link android.widget.TimePicker}.
* </p>
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 40d8a77..164bc64 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -256,10 +256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mShadowRadius, mShadowDx, mShadowDy;
- private static final int PREDRAW_NOT_REGISTERED = 0;
- private static final int PREDRAW_PENDING = 1;
- private static final int PREDRAW_DONE = 2;
- private int mPreDrawState = PREDRAW_NOT_REGISTERED;
+ private boolean mPreDrawRegistered;
private TextUtils.TruncateAt mEllipsize = null;
@@ -365,8 +362,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private SpellChecker mSpellChecker;
- private boolean mSoftInputShownOnFocus = true;
-
// The alignment to pass to Layout, or null if not resolved.
private Layout.Alignment mLayoutAlignment;
@@ -2384,29 +2379,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets whether the soft input method will be made visible when this
- * TextView gets focused. The default is true.
- *
- * @attr ref android.R.styleable#TextView_softInputShownOnFocus
- * @hide
- */
- @android.view.RemotableViewMethod
- public final void setSoftInputShownOnFocus(boolean show) {
- mSoftInputShownOnFocus = show;
- }
-
- /**
- * Returns whether the soft input method will be made visible when this
- * TextView gets focused. The default is true.
- *
- * @attr ref android.R.styleable#TextView_softInputShownOnFocus
- * @hide
- */
- public final boolean getSoftInputShownOnFocus() {
- return mSoftInputShownOnFocus;
- }
-
- /**
* Returns the list of URLSpans attached to the text
* (by {@link Linkify} or otherwise) if any. You can call
* {@link URLSpan#getURL} on them to find where they link to
@@ -4387,26 +4359,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void registerForPreDraw() {
- final ViewTreeObserver observer = getViewTreeObserver();
-
- if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
- observer.addOnPreDrawListener(this);
- mPreDrawState = PREDRAW_PENDING;
- } else if (mPreDrawState == PREDRAW_DONE) {
- mPreDrawState = PREDRAW_PENDING;
+ if (!mPreDrawRegistered) {
+ getViewTreeObserver().addOnPreDrawListener(this);
+ mPreDrawRegistered = true;
}
-
- // else state is PREDRAW_PENDING, so keep waiting.
}
/**
* {@inheritDoc}
*/
public boolean onPreDraw() {
- if (mPreDrawState != PREDRAW_PENDING) {
- return true;
- }
-
if (mLayout == null) {
assumeLayout();
}
@@ -4457,7 +4419,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
startSelectionActionMode();
}
- mPreDrawState = PREDRAW_DONE;
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mPreDrawRegistered = false;
+
return !changed;
}
@@ -4492,10 +4456,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- final ViewTreeObserver observer = getViewTreeObserver();
- if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
+ if (mPreDrawRegistered) {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mPreDrawRegistered = false;
}
if (mError != null) {
@@ -4768,12 +4731,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
protected void onDraw(Canvas canvas) {
- if (mPreDrawState == PREDRAW_DONE) {
- final ViewTreeObserver observer = getViewTreeObserver();
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
- }
-
if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;
restartMarqueeIfNeeded();
@@ -5040,7 +4997,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mTextDisplayList == null || !mTextDisplayList.isValid() ||
!mTextDisplayListIsValid) {
if (mTextDisplayList == null) {
- mTextDisplayList = getHardwareRenderer().createDisplayList();
+ mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
}
final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -5539,7 +5496,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (imm != null && mSoftInputShownOnFocus) {
+ if (imm != null) {
imm.showSoftInput(this, 0);
}
}
@@ -8395,7 +8352,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (!mTextIsSelectable && mSoftInputShownOnFocus) {
+ if (!mTextIsSelectable) {
handled |= imm != null && imm.showSoftInput(this, 0);
}
@@ -10190,7 +10147,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
final boolean selectionStarted = mSelectionActionMode != null || willExtract;
- if (selectionStarted && !mTextIsSelectable && mSoftInputShownOnFocus) {
+ if (selectionStarted && !mTextIsSelectable) {
// Show the IME to be able to replace text, except when selecting non editable text.
final InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index efd0871..88a17e6 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -26,8 +26,8 @@ public class FastMath {
* thought it may return slightly different results. It does not try to
* handle (in any meaningful way) NaN or infinities.
*/
- public static int round(float x) {
- long lx = (long)(x * (65536 * 256f));
- return (int)((lx + 0x800000) >> 24);
+ public static int round(float value) {
+ long lx = (long) (value * (65536 * 256f));
+ return (int) ((lx + 0x800000) >> 24);
}
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index ebd355a..d51ced1 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -653,6 +653,7 @@ public class MultiWaveView extends View {
case MotionEvent.ACTION_CANCEL:
handleMove(event);
+ handleCancel(event);
handled = true;
break;
}
@@ -678,6 +679,12 @@ public class MultiWaveView extends View {
if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
switchToState(STATE_FINISH, event.getX(), event.getY());
}
+
+ private void handleCancel(MotionEvent event) {
+ if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
+ mActiveTarget = -1; // Drop the active target if canceled.
+ switchToState(STATE_FINISH, event.getX(), event.getY());
+ }
private void handleMove(MotionEvent event) {
if (!mDragging) {