diff options
Diffstat (limited to 'core/java')
25 files changed, 534 insertions, 237 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 4e340c0..c858e3c 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -19,22 +19,17 @@ package android.accessibilityservice; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.util.LocaleUtil; import android.util.Log; -import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.os.HandlerCaller; -import java.util.Locale; - /** * An accessibility service runs in the background and receives callbacks by the system * when {@link AccessibilityEvent}s are fired. Such events denote some state transition @@ -299,6 +294,16 @@ public abstract class AccessibilityService extends Service { public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; /** + * The user has performed a two finger tap gesture on the touch screen. + */ + public static final int GESTURE_TWO_FINGER_TAP = 19; + + /** + * The user has performed a two finger long press gesture on the touch screen. + */ + public static final int GESTURE_TWO_FINGER_LONG_PRESS = 20; + + /** * The {@link Intent} that must be declared as handled by the service. */ public static final String SERVICE_INTERFACE = @@ -342,8 +347,6 @@ public abstract class AccessibilityService extends Service { */ public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; - private static final int UNDEFINED = -1; - private static final String LOG_TAG = "AccessibilityService"; interface Callbacks { @@ -351,15 +354,13 @@ public abstract class AccessibilityService extends Service { public void onInterrupt(); public void onServiceConnected(); public void onSetConnectionId(int connectionId); - public void onGesture(int gestureId); + public boolean onGesture(int gestureId); } private int mConnectionId; private AccessibilityServiceInfo mInfo; - private int mLayoutDirection; - /** * Callback for {@link android.view.accessibility.AccessibilityEvent}s. * @@ -386,95 +387,43 @@ public abstract class AccessibilityService extends Service { /** * Called by the system when the user performs a specific gesture on the - * touch screen. + * touch screen. If the gesture is not handled in this callback the system + * may provide default handing. Therefore, one should return true from this + * function if overriding of default behavior is desired. + * + * <strong>Note:</strong> To receive gestures an accessibility service + * must declare that it can handle such by specifying the + * <code><{@link android.R.styleable#AccessibilityService_canHandleGestures + * canHandleGestures}></code> attribute. * * @param gestureId The unique id of the performed gesture. * + * @return Whether the gesture was handled. + * * @see #GESTURE_SWIPE_UP - * @see #GESTURE_SWIPE_DOWN - * @see #GESTURE_SWIPE_LEFT - * @see #GESTURE_SWIPE_RIGHT + * @see #GESTURE_SWIPE_UP_AND_LEFT * @see #GESTURE_SWIPE_UP_AND_DOWN + * @see #GESTURE_SWIPE_UP_AND_RIGHT + * @see #GESTURE_SWIPE_DOWN + * @see #GESTURE_SWIPE_DOWN_AND_LEFT * @see #GESTURE_SWIPE_DOWN_AND_UP + * @see #GESTURE_SWIPE_DOWN_AND_RIGHT + * @see #GESTURE_SWIPE_LEFT + * @see #GESTURE_SWIPE_LEFT_AND_UP * @see #GESTURE_SWIPE_LEFT_AND_RIGHT + * @see #GESTURE_SWIPE_LEFT_AND_DOWN + * @see #GESTURE_SWIPE_RIGHT + * @see #GESTURE_SWIPE_RIGHT_AND_UP * @see #GESTURE_SWIPE_RIGHT_AND_LEFT + * @see #GESTURE_SWIPE_RIGHT_AND_DOWN * @see #GESTURE_CLOCKWISE_CIRCLE * @see #GESTURE_COUNTER_CLOCKWISE_CIRCLE + * @see #GESTURE_TWO_FINGER_TAP + * @see #GESTURE_TWO_FINGER_LONG_PRESS */ - protected void onGesture(int gestureId) { + protected boolean onGesture(int gestureId) { // TODO: Describe the default gesture processing in the javaDoc once it is finalized. - - // Global actions. - switch (gestureId) { - case GESTURE_SWIPE_DOWN_AND_LEFT: { - performGlobalAction(GLOBAL_ACTION_BACK); - } return; - case GESTURE_SWIPE_DOWN_AND_RIGHT: { - performGlobalAction(GLOBAL_ACTION_HOME); - } return; - case GESTURE_SWIPE_UP_AND_LEFT: { - performGlobalAction(GLOBAL_ACTION_RECENTS); - } return; - case GESTURE_SWIPE_UP_AND_RIGHT: { - performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS); - } return; - } - - // Cache the id to avoid locking - final int connectionId = mConnectionId; - if (connectionId == UNDEFINED) { - throw new IllegalStateException("AccessibilityService not connected." - + " Did you receive a call of onServiceConnected()?"); - } - AccessibilityNodeInfo root = getRootInActiveWindow(); - if (root == null) { - return; - } - - AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); - if (current == null) { - current = root; - } - - // Local actions. - AccessibilityNodeInfo next = null; - switch (gestureId) { - case GESTURE_SWIPE_UP: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_OUT); - } break; - case GESTURE_SWIPE_DOWN: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_IN); - } break; - case GESTURE_SWIPE_LEFT: { - if (mLayoutDirection == View.LAYOUT_DIRECTION_LTR) { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_BACKWARD); - } else { // LAYOUT_DIRECTION_RTL - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_FORWARD); - } - } break; - case GESTURE_SWIPE_RIGHT: { - if (mLayoutDirection == View.LAYOUT_DIRECTION_LTR) { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_FORWARD); - } else { // LAYOUT_DIRECTION_RTL - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_BACKWARD); - } - } break; - case GESTURE_SWIPE_UP_AND_DOWN: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_UP); - } break; - case GESTURE_SWIPE_DOWN_AND_UP: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_DOWN); - } break; - case GESTURE_SWIPE_LEFT_AND_RIGHT: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_LEFT); - } break; - case GESTURE_SWIPE_RIGHT_AND_LEFT: { - next = current.focusSearch(View.ACCESSIBILITY_FOCUS_RIGHT); - } break; - } - if (next != null && !next.equals(current)) { - next.performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); - } + return false; } /** @@ -484,10 +433,7 @@ public abstract class AccessibilityService extends Service { * @return The root node if this service can retrieve window content. */ public AccessibilityNodeInfo getRootInActiveWindow() { - return AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByAccessibilityId(mConnectionId, - AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, - AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); + return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId); } /** @@ -509,7 +455,7 @@ public abstract class AccessibilityService extends Service { AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); if (connection != null) { try { - return connection.perfromGlobalAction(action); + return connection.performGlobalAction(action); } catch (RemoteException re) { Log.w(LOG_TAG, "Error while calling performGlobalAction", re); } @@ -572,18 +518,6 @@ public abstract class AccessibilityService extends Service { } } - @Override - public void onCreate() { - Locale locale = getResources().getConfiguration().locale; - mLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale); - } - - @Override - public void onConfigurationChanged(Configuration configuration) { - super.onConfigurationChanged(configuration); - mLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(configuration.locale); - } - /** * Implement to return the implementation of the internal accessibility * service interface. @@ -612,8 +546,8 @@ public abstract class AccessibilityService extends Service { } @Override - public void onGesture(int gestureId) { - AccessibilityService.this.onGesture(gestureId); + public boolean onGesture(int gestureId) { + return AccessibilityService.this.onGesture(gestureId); } }); } @@ -658,8 +592,10 @@ public abstract class AccessibilityService extends Service { mCaller.sendMessage(message); } - public void onGesture(int gestureId) { - Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId); + public void onGesture(int gestureId, IAccessibilityServiceClientCallback callback, + int interactionId) { + Message message = mCaller.obtainMessageIIO(DO_ON_GESTURE, gestureId, interactionId, + callback); mCaller.sendMessage(message); } @@ -692,7 +628,15 @@ public abstract class AccessibilityService extends Service { return; case DO_ON_GESTURE : final int gestureId = message.arg1; - mCallback.onGesture(gestureId); + final int interactionId = message.arg2; + IAccessibilityServiceClientCallback callback = + (IAccessibilityServiceClientCallback) message.obj; + final boolean handled = mCallback.onGesture(gestureId); + try { + callback.setGestureResult(gestureId, handled, interactionId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling back with the gesture resut.", re); + } return; default : Log.w(LOG_TAG, "Unknown message type " + message.what); diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index e77ed9a..7e6786b 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -224,6 +224,11 @@ public class AccessibilityServiceInfo implements Parcelable { private boolean mCanRetrieveWindowContent; /** + * Flag whether this accessibility service can handle gestures. + */ + private boolean mCanHandleGestures; + + /** * Resource id of the description of the accessibility service. */ private int mDescriptionResId; @@ -303,6 +308,8 @@ public class AccessibilityServiceInfo implements Parcelable { mCanRetrieveWindowContent = asAttributes.getBoolean( com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent, false); + mCanHandleGestures = asAttributes.getBoolean( + com.android.internal.R.styleable.AccessibilityService_canHandleGestures, false); TypedValue peekedValue = asAttributes.peekValue( com.android.internal.R.styleable.AccessibilityService_description); if (peekedValue != null) { @@ -378,13 +385,25 @@ public class AccessibilityServiceInfo implements Parcelable { * <strong>Statically set from * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> * </p> - * @return True window content can be retrieved. + * @return True if window content can be retrieved. */ public boolean getCanRetrieveWindowContent() { return mCanRetrieveWindowContent; } /** + * Whether this service can handle gestures. + * <p> + * <strong>Statically set from + * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> + * </p> + * @return True if the service can handle gestures. + */ + public boolean getCanHandleGestures() { + return mCanHandleGestures; + } + + /** * Gets the non-localized description of the accessibility service. * <p> * <strong>Statically set from diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index 588728c..0257aa4 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -16,6 +16,7 @@ package android.accessibilityservice; +import android.accessibilityservice.IAccessibilityServiceClientCallback; import android.accessibilityservice.IAccessibilityServiceConnection; import android.view.accessibility.AccessibilityEvent; @@ -32,5 +33,5 @@ import android.view.accessibility.AccessibilityEvent; void onInterrupt(); - void onGesture(int gestureId); + void onGesture(int gesture, in IAccessibilityServiceClientCallback callback, int interactionId); } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClientCallback.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClientCallback.aidl new file mode 100644 index 0000000..9061398 --- /dev/null +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClientCallback.aidl @@ -0,0 +1,30 @@ +/* +** Copyright 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.IAccessibilityServiceConnection; +import android.view.accessibility.AccessibilityEvent; + +/** + * Callback for IAccessibilityServiceClient. + * + * @hide + */ + oneway interface IAccessibilityServiceClientCallback { + + void setGestureResult(int gestureId, boolean handled, int interactionId); +} diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 1bd5387..6e85665 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -167,5 +167,5 @@ interface IAccessibilityServiceConnection { * @param action The action to perform. * @return Whether the action was performed. */ - boolean perfromGlobalAction(int action); + boolean performGlobalAction(int action); } diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java index c840bd6..1697df0 100644 --- a/core/java/android/accessibilityservice/UiTestAutomationBridge.java +++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java @@ -177,8 +177,8 @@ public class UiTestAutomationBridge { } @Override - public void onGesture(int gestureId) { - /* do nothing */ + public boolean onGesture(int gestureId) { + return false; } }); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 61a9dce..c1b8e7c 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -28,6 +28,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -206,6 +207,45 @@ public class AppWidgetHostView extends FrameLayout { super.dispatchRestoreInstanceState(jail); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int oldWidth = getMeasuredWidth(); + int oldHeight = getMeasuredHeight(); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int newWidth = getMeasuredWidth(); + int newHeight = getMeasuredHeight(); + + // TODO: this is just a hack for now -- we actually have the AppWidgetHost + // be responsible for updating the size of the widget. + if (oldWidth != newWidth || oldHeight != newHeight) { + final float density = mContext.getResources().getDisplayMetrics().density; + final int newWidthDips = (int) (newWidth / density); + final int newHeightDips = (int) (newHeight / density); + updateAppWidgetSize(null, newWidthDips, newHeightDips, newWidthDips, newHeightDips); + } + } + + /** + * Provide guidance about the size of this widget to the AppWidgetManager. This information + * gets embedded into the AppWidgetExtras and causes a callback to the AppWidgetProvider. + * + * @see AppWidgetProvider#onAppWidgetExtrasChanged(Context, AppWidgetManager, int, Bundle) + */ + public void updateAppWidgetSize(Bundle extras, int minWidth, int minHeight, int maxWidth, int maxHeight) { + if (extras == null) { + extras = new Bundle(); + } + extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_MIN_WIDTH, minWidth); + extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_MIN_HEIGHT, minHeight); + extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_MAX_WIDTH, maxWidth); + extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_MAX_HEIGHT, maxHeight); + updateAppWidgetExtras(extras); + } + + public void updateAppWidgetExtras(Bundle extras) { + AppWidgetManager.getInstance(mContext).updateAppWidgetExtras(mAppWidgetId, extras); + } + /** {@inheritDoc} */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index a7f7792..83ab817 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -19,6 +19,7 @@ package android.appwidget; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -109,6 +110,32 @@ public class AppWidgetManager { public static final String EXTRA_APPWIDGET_ID = "appWidgetId"; /** + * An bundle extra that contains the lower bound on the current width, in dips, of a widget instance. + */ + public static final String EXTRA_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth"; + + /** + * An bundle extra that contains the lower bound on the current height, in dips, of a widget instance. + */ + public static final String EXTRA_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight"; + + /** + * An bundle extra that contains the upper bound on the current width, in dips, of a widget instance. + */ + public static final String EXTRA_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth"; + + /** + * An bundle extra that contains the upper bound on the current width, in dips, of a widget instance. + */ + public static final String EXTRA_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight"; + + /** + * An intent extra which points to a bundle of extra information for a particular widget id. + * In particular this bundle can contain EXTRA_APPWIDGET_WIDTH and EXTRA_APPWIDGET_HEIGHT. + */ + public static final String EXTRA_APPWIDGET_EXTRAS = "appWidgetExtras"; + + /** * An intent extra that contains multiple appWidgetIds. * <p> * The value will be an int array that can be retrieved like this: @@ -161,6 +188,14 @@ public class AppWidgetManager { public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; /** + * Sent when the custom extras for an AppWidget change. + * + * @see AppWidgetProvider#onAppWidgetExtrasChanged AppWidgetProvider#onAppWidgetExtrasChanged( + * Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras) + */ + public static final String ACTION_APPWIDGET_EXTRAS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_EXTRAS"; + + /** * Sent when an instance of an AppWidget is deleted from its host. * * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds) @@ -252,6 +287,46 @@ public class AppWidgetManager { } /** + * Update the extras for a given widget instance. + * + * The extras can be used to embed additional information about this widget to be accessed + * by the associated widget's AppWidgetProvider. + * + * @see #getAppWidgetExtras(int) + * + * @param appWidgetId The AppWidget instances for which to set the RemoteViews. + * @param extras The extras to associate with this widget + */ + public void updateAppWidgetExtras(int appWidgetId, Bundle extras) { + try { + sService.updateAppWidgetExtras(appWidgetId, extras); + } + catch (RemoteException e) { + throw new RuntimeException("system server dead?", e); + } + } + + /** + * Get the extras associated with a given widget instance. + * + * The extras can be used to embed additional information about this widget to be accessed + * by the associated widget's AppWidgetProvider. + * + * @see #updateAppWidgetExtras(int, Bundle) + * + * @param appWidgetId The AppWidget instances for which to set the RemoteViews. + * @return The extras associated with the given widget instance. + */ + public Bundle getAppWidgetExtras(int appWidgetId) { + try { + return sService.getAppWidgetExtras(appWidgetId); + } + catch (RemoteException e) { + throw new RuntimeException("system server dead?", e); + } + } + + /** * Set the RemoteViews to use for the specified appWidgetId. * * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java index 00a5f0c..3cf40ae 100755 --- a/core/java/android/appwidget/AppWidgetProvider.java +++ b/core/java/android/appwidget/AppWidgetProvider.java @@ -74,6 +74,16 @@ public class AppWidgetProvider extends BroadcastReceiver { this.onDeleted(context, new int[] { appWidgetId }); } } + else if (AppWidgetManager.ACTION_APPWIDGET_EXTRAS_CHANGED.equals(action)) { + Bundle extras = intent.getExtras(); + if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID) + && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_EXTRAS)) { + int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); + Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_EXTRAS); + this.onAppWidgetExtrasChanged(context, AppWidgetManager.getInstance(context), + appWidgetId, widgetExtras); + } + } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) { this.onEnabled(context); } @@ -82,7 +92,7 @@ public class AppWidgetProvider extends BroadcastReceiver { } } // END_INCLUDE(onReceive) - + /** * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcast when * this AppWidget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews} @@ -102,7 +112,26 @@ public class AppWidgetProvider extends BroadcastReceiver { */ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { } - + + /** + * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_EXTRAS_CHANGED} + * broadcast when this widget has been layed out at a new size. + * + * {@more} + * + * @param context The {@link android.content.Context Context} in which this receiver is + * running. + * @param appWidgetManager A {@link AppWidgetManager} object you can call {@link + * AppWidgetManager#updateAppWidget} on. + * @param appWidgetId The appWidgetId of the widget who's size changed. + * @param newExtras The appWidgetId of the widget who's size changed. + * + * @see AppWidgetManager#ACTION_APPWIDGET_EXTRAS_CHANGED + */ + public void onAppWidgetExtrasChanged(Context context, AppWidgetManager appWidgetManager, + int appWidgetId, Bundle newExtras) { + } + /** * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DELETED} broadcast when * one or more AppWidget instances have been deleted. Override this method to implement diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 4fb710e..eb0a0c6 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -2442,13 +2442,13 @@ public class Camera { } /** - * Sets the rotation angle in degrees relative to the orientation of - * the camera. This affects the pictures returned from JPEG {@link - * PictureCallback}. The camera driver may set orientation in the - * EXIF header without rotating the picture. Or the driver may rotate - * the picture and the EXIF thumbnail. If the Jpeg picture is rotated, - * the orientation in the EXIF header will be missing or 1 (row #0 is - * top and column #0 is left side). + * Sets the clockwise rotation angle in degrees relative to the + * orientation of the camera. This affects the pictures returned from + * JPEG {@link PictureCallback}. The camera driver may set orientation + * in the EXIF header without rotating the picture. Or the driver may + * rotate the picture and the EXIF thumbnail. If the Jpeg picture is + * rotated, the orientation in the EXIF header will be missing or 1 + * (row #0 is top and column #0 is left side). * * <p>If applications want to rotate the picture to match the orientation * of what users see, apps should use {@link diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index b39b823..5ba1850 100755 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -268,6 +268,8 @@ public final class InputManager { synchronized (mInputDevicesLock) { int index = findInputDeviceListenerLocked(listener); if (index >= 0) { + InputDeviceListenerDelegate d = mInputDeviceListeners.get(index); + d.removeCallbacksAndMessages(null); mInputDeviceListeners.remove(index); } } diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index ddd00a4..39810ba 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -34,7 +34,7 @@ interface INfcAdapter INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg); int getState(); - boolean disable(); + boolean disable(boolean saveState); boolean enable(); boolean enableNdefPush(); boolean disableNdefPush(); diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 90f5bef..7bf9feb 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -574,9 +574,10 @@ public final class NfcAdapter { * * @hide */ + public boolean disable() { try { - return sService.disable(); + return sService.disable(true); } catch (RemoteException e) { attemptDeadServiceRecovery(e); return false; diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index ff5a467..dc58ef2 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -117,7 +117,7 @@ public class DynamicLayout extends Layout mObjects = new PackedObjectVector<Directions>(1); - mBlockEnds = new int[] { 0 }; + mBlockEndLines = new int[] { 0 }; mBlockIndices = new int[] { INVALID_BLOCK_INDEX }; mNumberOfBlocks = 1; @@ -391,23 +391,23 @@ public class DynamicLayout extends Layout int firstBlock = -1; int lastBlock = -1; for (int i = 0; i < mNumberOfBlocks; i++) { - if (mBlockEnds[i] >= startLine) { + if (mBlockEndLines[i] >= startLine) { firstBlock = i; break; } } for (int i = firstBlock; i < mNumberOfBlocks; i++) { - if (mBlockEnds[i] >= endLine) { + if (mBlockEndLines[i] >= endLine) { lastBlock = i; break; } } - final int lastBlockEndLine = mBlockEnds[lastBlock]; + final int lastBlockEndLine = mBlockEndLines[lastBlock]; boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 : - mBlockEnds[firstBlock - 1] + 1); + mBlockEndLines[firstBlock - 1] + 1); boolean createBlock = newLineCount > 0; - boolean createBlockAfter = endLine < mBlockEnds[lastBlock]; + boolean createBlockAfter = endLine < mBlockEndLines[lastBlock]; int numAddedBlocks = 0; if (createBlockBefore) numAddedBlocks++; @@ -419,27 +419,27 @@ public class DynamicLayout extends Layout if (newNumberOfBlocks == 0) { // Even when text is empty, there is actually one line and hence one block - mBlockEnds[0] = 0; + mBlockEndLines[0] = 0; mBlockIndices[0] = INVALID_BLOCK_INDEX; mNumberOfBlocks = 1; return; } - if (newNumberOfBlocks > mBlockEnds.length) { + if (newNumberOfBlocks > mBlockEndLines.length) { final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks); - int[] blockEnds = new int[newSize]; + int[] blockEndLines = new int[newSize]; int[] blockIndices = new int[newSize]; - System.arraycopy(mBlockEnds, 0, blockEnds, 0, firstBlock); + System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, firstBlock); System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock); - System.arraycopy(mBlockEnds, lastBlock + 1, - blockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); + System.arraycopy(mBlockEndLines, lastBlock + 1, + blockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); - mBlockEnds = blockEnds; + mBlockEndLines = blockEndLines; mBlockIndices = blockIndices; } else { - System.arraycopy(mBlockEnds, lastBlock + 1, - mBlockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); + System.arraycopy(mBlockEndLines, lastBlock + 1, + mBlockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); } @@ -447,24 +447,24 @@ public class DynamicLayout extends Layout mNumberOfBlocks = newNumberOfBlocks; final int deltaLines = newLineCount - (endLine - startLine + 1); for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) { - mBlockEnds[i] += deltaLines; + mBlockEndLines[i] += deltaLines; } int blockIndex = firstBlock; if (createBlockBefore) { - mBlockEnds[blockIndex] = startLine - 1; + mBlockEndLines[blockIndex] = startLine - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlock) { - mBlockEnds[blockIndex] = startLine + newLineCount - 1; + mBlockEndLines[blockIndex] = startLine + newLineCount - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlockAfter) { - mBlockEnds[blockIndex] = lastBlockEndLine + deltaLines; + mBlockEndLines[blockIndex] = lastBlockEndLine + deltaLines; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; } } @@ -473,10 +473,10 @@ public class DynamicLayout extends Layout * This package private method is used for test purposes only * @hide */ - void setBlocksDataForTest(int[] blockEnds, int[] blockIndices, int numberOfBlocks) { - mBlockEnds = new int[blockEnds.length]; + void setBlocksDataForTest(int[] blockEndLines, int[] blockIndices, int numberOfBlocks) { + mBlockEndLines = new int[blockEndLines.length]; mBlockIndices = new int[blockIndices.length]; - System.arraycopy(blockEnds, 0, mBlockEnds, 0, blockEnds.length); + System.arraycopy(blockEndLines, 0, mBlockEndLines, 0, blockEndLines.length); System.arraycopy(blockIndices, 0, mBlockIndices, 0, blockIndices.length); mNumberOfBlocks = numberOfBlocks; } @@ -484,8 +484,8 @@ public class DynamicLayout extends Layout /** * @hide */ - public int[] getBlockEnds() { - return mBlockEnds; + public int[] getBlockEndLines() { + return mBlockEndLines; } /** @@ -633,8 +633,8 @@ public class DynamicLayout extends Layout * @hide */ public static final int INVALID_BLOCK_INDEX = -1; - // Stores the line numbers of the last line of each block - private int[] mBlockEnds; + // Stores the line numbers of the last line of each block (inclusive) + private int[] mBlockEndLines; // The indices of this block's display list in TextView's internal display list array or // INVALID_BLOCK_INDEX if this block has been invalidated during an edition private int[] mBlockIndices; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 247f673..da1f64b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -59,6 +59,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.TypedValue; +import android.view.KeyCharacterMap.FallbackAction; import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; @@ -323,6 +324,8 @@ public final class ViewRootImpl implements ViewParent, private final int mDensity; + final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction(); + /** * Consistency verifier for debugging purposes. */ @@ -4383,6 +4386,31 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendMessage(msg); } + public void dispatchUnhandledKey(KeyEvent event) { + if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + final KeyCharacterMap kcm = event.getKeyCharacterMap(); + final int keyCode = event.getKeyCode(); + final int metaState = event.getMetaState(); + + KeyEvent fallbackEvent = null; + synchronized (mFallbackAction) { + // Check for fallback actions specified by the key character map. + if (kcm.getFallbackAction(keyCode, metaState, mFallbackAction)) { + int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; + fallbackEvent = KeyEvent.obtain( + event.getDownTime(), event.getEventTime(), + event.getAction(), mFallbackAction.keyCode, + event.getRepeatCount(), mFallbackAction.metaState, + event.getDeviceId(), event.getScanCode(), + flags, event.getSource(), null); + } + } + if (fallbackEvent != null) { + dispatchKey(fallbackEvent); + } + } + } + public void dispatchAppVisibility(boolean visible) { Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); msg.arg1 = visible ? 1 : 0; diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 35f0d9d..f73faf3 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -84,7 +84,7 @@ public final class AccessibilityInteractionClient private final Object mInstanceLock = new Object(); - private int mInteractionId = -1; + private volatile int mInteractionId = -1; private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; @@ -150,6 +150,18 @@ public final class AccessibilityInteractionClient } /** + * Gets the root {@link AccessibilityNodeInfo} in the currently active window. + * + * @param connectionId The id of a connection for interacting with the system. + * @return The root {@link AccessibilityNodeInfo} if found, null otherwise. + */ + public AccessibilityNodeInfo getRootInActiveWindow(int connectionId) { + return findAccessibilityNodeInfoByAccessibilityId(connectionId, + AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); + } + + /** * Finds an {@link AccessibilityNodeInfo} by accessibility id. * * @param connectionId The id of a connection for interacting with the system. diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index f429e09..2793081 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -3925,6 +3925,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mSelectCursorExtent.offset(dx, dy); mSelectCursorExtentTextQuad.offset(dx, dy); } + } else if (mHandleAlpha.getAlpha() > 0) { + // stop fading as we're not going to move with the layer. + mHandleAlphaAnimator.end(); } if (mAutoCompletePopup != null && mCurrentScrollingLayerId == mEditTextLayerId) { @@ -4418,9 +4421,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } canvas.restoreToCount(saveCount); - if (mSelectingText) { - drawTextSelectionHandles(canvas); - } + drawTextSelectionHandles(canvas); if (extras == DRAW_EXTRAS_CURSOR_RING) { if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) { @@ -4658,6 +4659,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } private void onZoomAnimationStart() { + if (!mSelectingText && mHandleAlpha.getAlpha() > 0) { + mHandleAlphaAnimator.end(); + } } private void onZoomAnimationEnd() { @@ -4688,6 +4692,36 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private final DrawFilter mScrollFilter = new PaintFlagsDrawFilter(SCROLL_BITS, 0); + private class SelectionHandleAlpha { + private int mAlpha = 0; + public void setAlpha(int alpha) { + mAlpha = alpha; + if (mSelectHandleCenter != null) { + mSelectHandleCenter.setAlpha(alpha); + mSelectHandleLeft.setAlpha(alpha); + mSelectHandleRight.setAlpha(alpha); + // TODO: Use partial invalidate + invalidate(); + } + } + + public int getAlpha() { + return mAlpha; + } + + } + + private void startSelectingText() { + mSelectingText = true; + mHandleAlphaAnimator.setIntValues(255); + mHandleAlphaAnimator.start(); + } + private void endSelectingText() { + mSelectingText = false; + mHandleAlphaAnimator.setIntValues(0); + mHandleAlphaAnimator.start(); + } + private void ensureSelectionHandles() { if (mSelectHandleCenter == null) { mSelectHandleCenter = mContext.getResources().getDrawable( @@ -4696,6 +4730,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc com.android.internal.R.drawable.text_select_handle_left); mSelectHandleRight = mContext.getResources().getDrawable( com.android.internal.R.drawable.text_select_handle_right); + mHandleAlpha.setAlpha(mHandleAlpha.getAlpha()); mSelectHandleCenterOffset = new Point(0, -mSelectHandleCenter.getIntrinsicHeight()); mSelectHandleLeftOffset = new Point(0, @@ -4707,31 +4742,40 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } private void drawTextSelectionHandles(Canvas canvas) { + if (mHandleAlpha.getAlpha() == 0) { + return; + } ensureSelectionHandles(); - int[] handles = new int[4]; - getSelectionHandles(handles); - int start_x = contentToViewDimension(handles[0]); - int start_y = contentToViewDimension(handles[1]); - int end_x = contentToViewDimension(handles[2]); - int end_y = contentToViewDimension(handles[3]); + if (mSelectingText) { + int[] handles = new int[4]; + getSelectionHandles(handles); + int start_x = contentToViewDimension(handles[0]); + int start_y = contentToViewDimension(handles[1]); + int end_x = contentToViewDimension(handles[2]); + int end_y = contentToViewDimension(handles[3]); + + if (mIsCaretSelection) { + // Caret handle is centered + start_x -= (mSelectHandleCenter.getIntrinsicWidth() / 2); + mSelectHandleCenter.setBounds(start_x, start_y, + start_x + mSelectHandleCenter.getIntrinsicWidth(), + start_y + mSelectHandleCenter.getIntrinsicHeight()); + } else { + // Magic formula copied from TextView + start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4; + mSelectHandleLeft.setBounds(start_x, start_y, + start_x + mSelectHandleLeft.getIntrinsicWidth(), + start_y + mSelectHandleLeft.getIntrinsicHeight()); + end_x -= mSelectHandleRight.getIntrinsicWidth() / 4; + mSelectHandleRight.setBounds(end_x, end_y, + end_x + mSelectHandleRight.getIntrinsicWidth(), + end_y + mSelectHandleRight.getIntrinsicHeight()); + } + } if (mIsCaretSelection) { - // Caret handle is centered - start_x -= (mSelectHandleCenter.getIntrinsicWidth() / 2); - mSelectHandleCenter.setBounds(start_x, start_y, - start_x + mSelectHandleCenter.getIntrinsicWidth(), - start_y + mSelectHandleCenter.getIntrinsicHeight()); mSelectHandleCenter.draw(canvas); } else { - // Magic formula copied from TextView - start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4; - mSelectHandleLeft.setBounds(start_x, start_y, - start_x + mSelectHandleLeft.getIntrinsicWidth(), - start_y + mSelectHandleLeft.getIntrinsicHeight()); - end_x -= mSelectHandleRight.getIntrinsicWidth() / 4; - mSelectHandleRight.setBounds(end_x, end_y, - end_x + mSelectHandleRight.getIntrinsicWidth(), - end_y + mSelectHandleRight.getIntrinsicHeight()); mSelectHandleLeft.draw(canvas); mSelectHandleRight.draw(canvas); } @@ -5385,7 +5429,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc selectionDone(); return false; } - mSelectingText = true; + startSelectingText(); mTouchMode = TOUCH_DRAG_MODE; return true; } @@ -5439,7 +5483,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc void selectionDone() { if (mSelectingText) { hidePasteButton(); - mSelectingText = false; + endSelectingText(); // finish is idempotent, so this is fine even if selectionDone was // called by mSelectCallback.onDestroyActionMode if (mSelectCallback != null) { @@ -6571,6 +6615,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private long mTrackballUpTime = 0; private long mLastCursorTime = 0; private Rect mLastCursorBounds; + private SelectionHandleAlpha mHandleAlpha = new SelectionHandleAlpha(); + private ObjectAnimator mHandleAlphaAnimator = + ObjectAnimator.ofInt(mHandleAlpha, "alpha", 0); // Set by default; BrowserActivity clears to interpret trackball data // directly for movement. Currently, the framework only passes diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 0c34037..6aff10a 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.net.http.SslError; import android.os.Message; import android.view.KeyEvent; +import android.view.ViewRootImpl; public class WebViewClient { @@ -273,6 +274,10 @@ public class WebViewClient { * @param event The key event. */ public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + ViewRootImpl root = view.getViewRootImpl(); + if (root != null) { + root.dispatchUnhandledKey(event); + } } /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index e68049c..53d5e0b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -403,7 +403,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te /** * Handles scrolling between positions within the list. */ - private PositionScroller mPositionScroller; + PositionScroller mPositionScroller; /** * The offset in pixels form the top of the AdapterView to the top @@ -3080,6 +3080,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return isClickable() || isLongClickable(); } + if (mPositionScroller != null) { + mPositionScroller.stop(); + } + if (mFastScroller != null) { boolean intercepted = mFastScroller.onTouchEvent(ev); if (intercepted) { @@ -3564,6 +3568,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te int action = ev.getAction(); View v; + if (mPositionScroller != null) { + mPositionScroller.stop(); + } + if (mFastScroller != null) { boolean intercepted = mFastScroller.onInterceptTouchEvent(ev); if (intercepted) { @@ -3748,7 +3756,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mScroller.fling(0, initialY, 0, initialVelocity, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); mTouchMode = TOUCH_MODE_FLING; - post(this); + postOnAnimation(this); if (PROFILE_FLINGING) { if (!mFlingProfilingStarted) { @@ -3766,7 +3774,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mScroller.springBack(0, mScrollY, 0, 0, 0, 0)) { mTouchMode = TOUCH_MODE_OVERFLING; invalidate(); - post(this); + postOnAnimation(this); } else { mTouchMode = TOUCH_MODE_REST; reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); @@ -3778,7 +3786,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te Integer.MIN_VALUE, Integer.MAX_VALUE, 0, getHeight()); mTouchMode = TOUCH_MODE_OVERFLING; invalidate(); - post(this); + postOnAnimation(this); } void edgeReached(int delta) { @@ -3800,7 +3808,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } invalidate(); - post(this); + postOnAnimation(this); } void startScroll(int distance, int duration) { @@ -3808,7 +3816,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mLastFlingY = initialY; mScroller.startScroll(0, initialY, 0, distance, duration); mTouchMode = TOUCH_MODE_FLING; - post(this); + postOnAnimation(this); } void endFling() { @@ -3907,7 +3915,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (more && !atEnd) { if (atEdge) invalidate(); mLastFlingY = y; - post(this); + postOnAnimation(this); } else { endFling(); @@ -3948,7 +3956,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } else { invalidate(); - post(this); + postOnAnimation(this); } } else { endFling(); @@ -3959,7 +3967,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - class PositionScroller implements Runnable { private static final int SCROLL_DURATION = 400; @@ -4009,7 +4016,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mBoundPos = INVALID_POSITION; mLastSeenPos = INVALID_POSITION; - post(this); + postOnAnimation(this); } void start(int position, int boundPosition) { @@ -4070,7 +4077,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mBoundPos = boundPosition; mLastSeenPos = INVALID_POSITION; - post(this); + postOnAnimation(this); } void startWithOffset(int position, int offset) { @@ -4080,6 +4087,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te void startWithOffset(int position, int offset, int duration) { stop(); + offset += getPaddingTop(); + mTargetPos = position; mOffsetFromTop = offset; mBoundPos = INVALID_POSITION; @@ -4108,7 +4117,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te (int) (duration / screenTravelCount); mLastSeenPos = INVALID_POSITION; - post(this); + postOnAnimation(this); } void stop() { @@ -4116,10 +4125,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } public void run() { - if (mTouchMode != TOUCH_MODE_FLING && mLastSeenPos != INVALID_POSITION) { - return; - } - final int listHeight = getHeight(); final int firstPos = mFirstPosition; @@ -4134,7 +4139,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (lastPos == mLastSeenPos) { // No new views, let things keep going. - post(this); + postOnAnimation(this); return; } @@ -4142,14 +4147,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int lastViewHeight = lastView.getHeight(); final int lastViewTop = lastView.getTop(); final int lastViewPixelsShowing = listHeight - lastViewTop; - final int extraScroll = lastPos < mItemCount - 1 ? mExtraScroll : mListPadding.bottom; + final int extraScroll = lastPos < mItemCount - 1 ? + Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom; - smoothScrollBy(lastViewHeight - lastViewPixelsShowing + extraScroll, - mScrollDuration); + final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll; + smoothScrollBy(scrollBy, mScrollDuration); mLastSeenPos = lastPos; if (lastPos < mTargetPos) { - post(this); + postOnAnimation(this); } break; } @@ -4166,21 +4172,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (nextPos == mLastSeenPos) { // No new views, let things keep going. - post(this); + postOnAnimation(this); return; } final View nextView = getChildAt(nextViewIndex); final int nextViewHeight = nextView.getHeight(); final int nextViewTop = nextView.getTop(); - final int extraScroll = mExtraScroll; + final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll); if (nextPos < mBoundPos) { smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll), mScrollDuration); mLastSeenPos = nextPos; - post(this); + postOnAnimation(this); } else { if (nextViewTop > extraScroll) { smoothScrollBy(nextViewTop - extraScroll, mScrollDuration); @@ -4192,7 +4198,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te case MOVE_UP_POS: { if (firstPos == mLastSeenPos) { // No new views, let things keep going. - post(this); + postOnAnimation(this); return; } @@ -4201,14 +4207,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } final int firstViewTop = firstView.getTop(); - final int extraScroll = firstPos > 0 ? mExtraScroll : mListPadding.top; + final int extraScroll = firstPos > 0 ? + Math.max(mExtraScroll, mListPadding.top) : mListPadding.top; smoothScrollBy(firstViewTop - extraScroll, mScrollDuration); mLastSeenPos = firstPos; if (firstPos > mTargetPos) { - post(this); + postOnAnimation(this); } break; } @@ -4230,12 +4237,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int lastViewHeight = lastView.getHeight(); final int lastViewTop = lastView.getTop(); final int lastViewPixelsShowing = listHeight - lastViewTop; + final int extraScroll = Math.max(mListPadding.top, mExtraScroll); mLastSeenPos = lastPos; if (lastPos > mBoundPos) { - smoothScrollBy(-(lastViewPixelsShowing - mExtraScroll), mScrollDuration); - post(this); + smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration); + postOnAnimation(this); } else { - final int bottom = listHeight - mExtraScroll; + final int bottom = listHeight - extraScroll; final int lastViewBottom = lastViewTop + lastViewHeight; if (bottom > lastViewBottom) { smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration); @@ -4270,10 +4278,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final float modifier = Math.min(Math.abs(screenTravelCount), 1.f); if (position < firstPos) { smoothScrollBy((int) (-getHeight() * modifier), mScrollDuration); - post(this); + postOnAnimation(this); } else if (position > lastPos) { smoothScrollBy((int) (getHeight() * modifier), mScrollDuration); - post(this); + postOnAnimation(this); } else { // On-screen, just scroll. final int targetTop = getChildAt(position - firstPos).getTop(); @@ -4620,7 +4628,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // invalidate before moving the children to avoid unnecessary invalidate // calls to bubble up from the children all the way to the top if (!awakenScrollBars()) { - invalidate(); + invalidate(); } offsetChildrenTopAndBottom(incrementalDeltaY); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 040a385..900f0d3 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1241,24 +1241,21 @@ public class Editor { } DynamicLayout dynamicLayout = (DynamicLayout) layout; - int[] blockEnds = dynamicLayout.getBlockEnds(); + int[] blockEndLines = dynamicLayout.getBlockEndLines(); int[] blockIndices = dynamicLayout.getBlockIndices(); final int numberOfBlocks = dynamicLayout.getNumberOfBlocks(); - final int mScrollX = mTextView.getScrollX(); - final int mScrollY = mTextView.getScrollY(); - canvas.translate(mScrollX, mScrollY); int endOfPreviousBlock = -1; int searchStartIndex = 0; for (int i = 0; i < numberOfBlocks; i++) { - int blockEnd = blockEnds[i]; + int blockEndLine = blockEndLines[i]; int blockIndex = blockIndices[i]; final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX; if (blockIsInvalid) { blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks, searchStartIndex); - // Dynamic layout internal block indices structure is updated from Editor + // Note how dynamic layout's internal block indices get updated from Editor blockIndices[i] = blockIndex; searchStartIndex = blockIndex + 1; } @@ -1272,28 +1269,38 @@ public class Editor { } if (!blockDisplayList.isValid()) { + final int blockBeginLine = endOfPreviousBlock + 1; + final int top = layout.getLineTop(blockBeginLine); + final int bottom = layout.getLineBottom(blockEndLine); + final HardwareCanvas hardwareCanvas = blockDisplayList.start(); try { - hardwareCanvas.setViewport(width, height); + hardwareCanvas.setViewport(width, bottom - top); // The dirty rect should always be null for a display list hardwareCanvas.onPreDraw(null); - hardwareCanvas.translate(-mScrollX, -mScrollY); - layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd); - hardwareCanvas.translate(mScrollX, mScrollY); + // drawText is always relative to TextView's origin, this translation brings + // this range of text back to the top of the viewport + hardwareCanvas.translate(0, -top); + layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine); + hardwareCanvas.translate(0, top); } finally { hardwareCanvas.onPostDraw(); blockDisplayList.end(); if (View.USE_DISPLAY_LIST_PROPERTIES) { - blockDisplayList.setLeftTopRightBottom(0, 0, width, height); + blockDisplayList.setLeftTopRightBottom(0, top, width, bottom); + // Same as drawDisplayList below, handled by our TextView's parent + blockDisplayList.setClipChildren(false); } } } + // TODO When View.USE_DISPLAY_LIST_PROPERTIES is the only code path, the + // width and height parameters should be removed and the bounds set above in + // setLeftTopRightBottom should be used instead for quick rejection. ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null, - DisplayList.FLAG_CLIP_CHILDREN); - endOfPreviousBlock = blockEnd; + 0 /* no child clipping, our TextView parent enforces it */); + endOfPreviousBlock = blockEndLine; } - canvas.translate(-mScrollX, -mScrollY); } else { // Boring layout is used for empty and hint text layout.drawText(canvas, firstLine, lastLine); @@ -1572,11 +1579,9 @@ public class Editor { } void onScrollChanged() { - if (mPositionListener != null) { - mPositionListener.onScrollChanged(); - } - // Internal scroll affects the clip boundaries - invalidateTextDisplayList(); + if (mPositionListener != null) { + mPositionListener.onScrollChanged(); + } } /** diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 0f1dab5..0a40d5e 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1463,6 +1463,9 @@ public class GridView extends AbsListView { mResurrectToPosition = position; } mLayoutMode = LAYOUT_SET_SELECTION; + if (mPositionScroller != null) { + mPositionScroller.stop(); + } requestLayout(); } @@ -1475,6 +1478,10 @@ public class GridView extends AbsListView { void setSelectionInt(int position) { int previousSelectedPosition = mNextSelectedPosition; + if (mPositionScroller != null) { + mPositionScroller.stop(); + } + setNextSelectedPositionInt(position); layoutChildren(); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 71700b3..5098523 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1926,6 +1926,9 @@ public class ListView extends AbsListView { mSyncRowId = mAdapter.getItemId(position); } + if (mPositionScroller != null) { + mPositionScroller.stop(); + } requestLayout(); } } @@ -1950,6 +1953,10 @@ public class ListView extends AbsListView { } } + if (mPositionScroller != null) { + mPositionScroller.stop(); + } + layoutChildren(); if (awakeScrollbars) { diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index 6a46929..c03694f 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -24,6 +24,8 @@ import android.app.IActivityManager; import android.app.ProgressDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetooth; +import android.nfc.NfcAdapter; +import android.nfc.INfcAdapter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -48,7 +50,7 @@ import android.view.WindowManager; public final class ShutdownThread extends Thread { // constants private static final String TAG = "ShutdownThread"; - private static final int MAX_NUM_PHONE_STATE_READS = 16; + private static final int MAX_NUM_PHONE_STATE_READS = 24; private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; // maximum time we wait for the shutdown broadcast before going on. private static final int MAX_BROADCAST_TIME = 10*1000; @@ -231,6 +233,7 @@ public final class ShutdownThread extends Thread { * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. */ public void run() { + boolean nfcOff; boolean bluetoothOff; boolean radioOff; @@ -284,16 +287,29 @@ public final class ShutdownThread extends Thread { } } + final INfcAdapter nfc = + INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc")); final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); final IBluetooth bluetooth = IBluetooth.Stub.asInterface(ServiceManager.checkService( BluetoothAdapter.BLUETOOTH_SERVICE)); - final IMountService mount = IMountService.Stub.asInterface( ServiceManager.checkService("mount")); - + + try { + nfcOff = nfc == null || + nfc.getState() == NfcAdapter.STATE_OFF; + if (!nfcOff) { + Log.w(TAG, "Turning off NFC..."); + nfc.disable(false); // Don't persist new state + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during NFC shutdown", ex); + nfcOff = true; + } + try { bluetoothOff = bluetooth == null || bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF; @@ -317,7 +333,7 @@ public final class ShutdownThread extends Thread { radioOff = true; } - Log.i(TAG, "Waiting for Bluetooth and Radio..."); + Log.i(TAG, "Waiting for NFC, Bluetooth and Radio..."); // Wait a max of 32 seconds for clean shutdown for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) { @@ -338,8 +354,17 @@ public final class ShutdownThread extends Thread { radioOff = true; } } - if (radioOff && bluetoothOff) { - Log.i(TAG, "Radio and Bluetooth shutdown complete."); + if (!nfcOff) { + try { + nfcOff = nfc.getState() == NfcAdapter.STATE_OFF; + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during NFC shutdown", ex); + nfcOff = true; + } + } + + if (radioOff && bluetoothOff && nfcOff) { + Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete."); break; } SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index fa0873d..b1b57e7 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Intent; import android.appwidget.AppWidgetProviderInfo; import com.android.internal.appwidget.IAppWidgetHost; +import android.os.Bundle; import android.os.IBinder; import android.widget.RemoteViews; @@ -42,6 +43,8 @@ interface IAppWidgetService { // for AppWidgetManager // void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views); + void updateAppWidgetExtras(int appWidgetId, in Bundle extras); + Bundle getAppWidgetExtras(int appWidgetId); void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views); void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId); diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java index adfd3dc..0a99f17 100644 --- a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java +++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java @@ -26,8 +26,11 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; import android.util.AttributeSet; import android.util.Log; +import android.util.StateSet; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; @@ -90,8 +93,14 @@ public class SizeAdaptiveLayout extends ViewGroup { private void initialize() { mModestyPanel = new View(getContext()); // If the SizeAdaptiveLayout has a solid background, use it as a transition hint. - if (getBackground() instanceof ColorDrawable) { - mModestyPanel.setBackgroundDrawable(getBackground()); + Drawable background = getBackground(); + if (background instanceof StateListDrawable) { + StateListDrawable sld = (StateListDrawable) background; + sld.setState(StateSet.WILD_CARD); + background = sld.getCurrent(); + } + if (background instanceof ColorDrawable) { + mModestyPanel.setBackgroundDrawable(background); } else { mModestyPanel.setBackgroundColor(Color.BLACK); } |
