diff options
Diffstat (limited to 'core/java/android')
17 files changed, 353 insertions, 406 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 3da35d3..4e340c0 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -259,13 +259,51 @@ public abstract class AccessibilityService extends Service { public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; /** + * The user has performed a left and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; + + /** + * The user has performed a left and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; + + /** + * The user has performed a right and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; + + /** + * The user has performed a right and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; + + /** + * The user has performed an up and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; + + /** + * The user has performed an up and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; + + /** + * The user has performed an down and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; + + /** + * The user has performed an down and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; + + /** * The {@link Intent} that must be declared as handled by the service. */ public static final String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; - private static final int UNDEFINED = -1; - /** * Name under which an AccessibilityService component publishes information * about itself. This meta-data must reference an XML resource containing an @@ -284,6 +322,28 @@ public abstract class AccessibilityService extends Service { */ public static final String SERVICE_META_DATA = "android.accessibilityservice"; + /** + * Action to go back. + */ + public static final int GLOBAL_ACTION_BACK = 1; + + /** + * Action to go home. + */ + public static final int GLOBAL_ACTION_HOME = 2; + + /** + * Action to open the recents. + */ + public static final int GLOBAL_ACTION_RECENTS = 3; + + /** + * Action to open the notifications. + */ + public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; + + private static final int UNDEFINED = -1; + private static final String LOG_TAG = "AccessibilityService"; interface Callbacks { @@ -344,23 +404,39 @@ public abstract class AccessibilityService extends Service { protected void 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 = AccessibilityInteractionClient.getInstance() - .findAccessibilityNodeInfoByAccessibilityId(connectionId, - AccessibilityNodeInfo.ACTIVE_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, - AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS); + AccessibilityNodeInfo root = getRootInActiveWindow(); if (root == null) { return; } - AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY); + + AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); if (current == null) { current = root; } + + // Local actions. AccessibilityNodeInfo next = null; switch (gestureId) { case GESTURE_SWIPE_UP: { @@ -402,6 +478,46 @@ public abstract class AccessibilityService extends Service { } /** + * Gets the root node in the currently active window if this service + * can retrieve window content. + * + * @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); + } + + /** + * Performs a global action. Such an action can be performed + * at any moment regardless of the current application or user + * location in that application. For example going back, going + * home, opening recents, etc. + * + * @param action The action to perform. + * @return Whether the action was successfully performed. + * + * @see #GLOBAL_ACTION_BACK + * @see #GLOBAL_ACTION_HOME + * @see #GLOBAL_ACTION_NOTIFICATIONS + * @see #GLOBAL_ACTION_RECENTS + */ + public final boolean performGlobalAction(int action) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (connection != null) { + try { + return connection.perfromGlobalAction(action); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Error while calling performGlobalAction", re); + } + } + return false; + } + + /** * Gets the an {@link AccessibilityServiceInfo} describing this * {@link AccessibilityService}. This method is useful if one wants * to change some of the dynamically configurable properties at diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 30da9db..1bd5387 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -160,4 +160,12 @@ interface IAccessibilityServiceConnection { * @return The associated accessibility service info. */ AccessibilityServiceInfo getServiceInfo(); + + /** + * Performs a global action, such as going home, going back, etc. + * + * @param action The action to perform. + * @return Whether the action was performed. + */ + boolean perfromGlobalAction(int action); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 1c820dc..35bc7ff 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -549,7 +549,7 @@ import java.util.HashMap; * super.onCreate(savedInstanceState); * * SharedPreferences mPrefs = getSharedPreferences(); - * mCurViewMode = mPrefs.getInt("view_mode" DAY_VIEW_MODE); + * mCurViewMode = mPrefs.getInt("view_mode", DAY_VIEW_MODE); * } * * protected void onPause() { diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 55f29e6..0713127 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -347,9 +347,9 @@ public class DownloadManager { private CharSequence mTitle; private CharSequence mDescription; private String mMimeType; - private boolean mRoamingAllowed = true; private int mAllowedNetworkTypes = ~0; // default to all network types allowed - private boolean mAllowedOverMetered = true; + private boolean mRoamingAllowed = true; + private boolean mMeteredAllowed = true; private boolean mIsVisibleInDownloadsUi = true; private boolean mScannable = false; private boolean mUseSystemCache = false; @@ -624,17 +624,6 @@ public class DownloadManager { } /** - * Set whether this download may proceed over a metered network - * connection. By default, metered networks are allowed. - * - * @see ConnectivityManager#isActiveNetworkMetered() - */ - public Request setAllowedOverMetered(boolean allow) { - mAllowedOverMetered = allow; - return this; - } - - /** * Set whether this download may proceed over a roaming connection. By default, roaming is * allowed. * @param allowed whether to allow a roaming connection to be used @@ -646,6 +635,17 @@ public class DownloadManager { } /** + * Set whether this download may proceed over a metered network + * connection. By default, metered networks are allowed. + * + * @see ConnectivityManager#isActiveNetworkMetered() + */ + public Request setAllowedOverMetered(boolean allow) { + mMeteredAllowed = allow; + return this; + } + + /** * Set whether this download should be displayed in the system's Downloads UI. True by * default. * @param isVisible whether to display this download in the Downloads UI @@ -687,10 +687,10 @@ public class DownloadManager { putIfNonNull(values, Downloads.Impl.COLUMN_DESCRIPTION, mDescription); putIfNonNull(values, Downloads.Impl.COLUMN_MIME_TYPE, mMimeType); - // TODO: add COLUMN_ALLOW_METERED and persist values.put(Downloads.Impl.COLUMN_VISIBILITY, mNotificationVisibility); values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes); values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed); + values.put(Downloads.Impl.COLUMN_ALLOW_METERED, mMeteredAllowed); values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, mIsVisibleInDownloadsUi); return values; @@ -1340,9 +1340,6 @@ public class DownloadManager { case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR: return ERROR_FILE_ALREADY_EXISTS; - case Downloads.Impl.STATUS_BLOCKED: - return ERROR_BLOCKED; - default: return ERROR_UNKNOWN; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 4d5238c..6f95e26 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -34,5 +34,8 @@ interface INotificationManager void cancelToast(String pkg, ITransientNotification callback); void enqueueNotificationWithTag(String pkg, String tag, int id, in Notification notification, inout int[] idReceived); void cancelNotificationWithTag(String pkg, String tag, int id); + + void setNotificationsEnabledForPackage(String pkg, boolean enabled); + boolean areNotificationsEnabledForPackage(String pkg); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 22d84f0..b581f99 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -190,12 +190,6 @@ public class Notification implements Parcelable public RemoteViews contentView; /** - * The view that will represent this notification in the pop-up "intruder alert" dialog. - * @hide - */ - public RemoteViews intruderView; - - /** * A large-format version of {@link #contentView}, giving the Notification an * opportunity to show more detail. The system UI may choose to show this * instead of the normal content view at its discretion. @@ -590,9 +584,6 @@ public class Notification implements Parcelable actions = parcel.createTypedArray(Action.CREATOR); if (parcel.readInt() != 0) { - intruderView = RemoteViews.CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() != 0) { bigContentView = RemoteViews.CREATOR.createFromParcel(parcel); } } @@ -658,9 +649,6 @@ public class Notification implements Parcelable for(int i=0; i<this.actions.length; i++) { that.actions[i] = this.actions[i].clone(); } - if (this.intruderView != null) { - that.intruderView = this.intruderView.clone(); - } if (this.bigContentView != null) { that.bigContentView = this.bigContentView.clone(); } @@ -755,13 +743,6 @@ public class Notification implements Parcelable parcel.writeTypedArray(actions, 0); - if (intruderView != null) { - parcel.writeInt(1); - intruderView.writeToParcel(parcel, 0); - } else { - parcel.writeInt(0); - } - if (bigContentView != null) { parcel.writeInt(1); bigContentView.writeToParcel(parcel, 0); @@ -942,8 +923,6 @@ public class Notification implements Parcelable private Bundle mExtras; private int mPriority; private ArrayList<Action> mActions = new ArrayList<Action>(3); - private boolean mCanHasIntruder; - private boolean mIntruderActionsShowText; private boolean mUseChronometer; /** @@ -1349,38 +1328,6 @@ public class Notification implements Parcelable return this; } - /** - * Specify whether this notification should pop up as an - * "intruder alert" (a small window that shares the screen with the - * current activity). This sort of notification is (as the name implies) - * very intrusive, so use it sparingly for notifications that require - * the user's attention. - * - * Notes: - * <ul> - * <li>Intruder alerts only show when the screen is on.</li> - * <li>Intruder alerts take precedence over fullScreenIntents.</li> - * </ul> - * - * @param intrude Whether to pop up an intruder alert (default false). - */ - public Builder setUsesIntruderAlert(boolean intrude) { - mCanHasIntruder = intrude; - return this; - } - - /** - * Control text on intruder alert action buttons. By default, action - * buttons in intruders do not show textual labels. - * - * @param showActionText Whether to show text labels beneath action - * icons (default false). - */ - public Builder setIntruderActionsShowText(boolean showActionText) { - mIntruderActionsShowText = showActionText; - return this; - } - private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; @@ -1506,45 +1453,6 @@ public class Notification implements Parcelable return applyStandardTemplateWithActions(R.layout.notification_template_base); } - private RemoteViews makeIntruderView(boolean showLabels) { - RemoteViews intruderView = new RemoteViews(mContext.getPackageName(), - R.layout.notification_intruder_content); - if (mLargeIcon != null) { - intruderView.setImageViewBitmap(R.id.icon, mLargeIcon); - intruderView.setViewVisibility(R.id.icon, View.VISIBLE); - } else if (mSmallIcon != 0) { - intruderView.setImageViewResource(R.id.icon, mSmallIcon); - intruderView.setViewVisibility(R.id.icon, View.VISIBLE); - } else { - intruderView.setViewVisibility(R.id.icon, View.GONE); - } - if (mContentTitle != null) { - intruderView.setTextViewText(R.id.title, mContentTitle); - } - if (mContentText != null) { - intruderView.setTextViewText(R.id.text, mContentText); - } - if (mActions.size() > 0) { - intruderView.setViewVisibility(R.id.actions, View.VISIBLE); - int N = mActions.size(); - if (N>3) N=3; - final int[] BUTTONS = { R.id.action0, R.id.action1, R.id.action2 }; - for (int i=0; i<N; i++) { - final Action action = mActions.get(i); - final int buttonId = BUTTONS[i]; - - intruderView.setViewVisibility(buttonId, View.VISIBLE); - intruderView.setTextViewText(buttonId, showLabels ? action.title : null); - intruderView.setTextViewCompoundDrawables(buttonId, 0, action.icon, 0, 0); - intruderView.setContentDescription(buttonId, action.title); - intruderView.setOnClickPendingIntent(buttonId, action.actionIntent); - } - } else { - intruderView.setViewVisibility(R.id.actions, View.GONE); - } - return intruderView; - } - private RemoteViews generateActionButton(Action action) { RemoteViews button = new RemoteViews(mContext.getPackageName(), R.layout.notification_action); button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0); @@ -1579,9 +1487,6 @@ public class Notification implements Parcelable n.ledOffMS = mLedOffMs; n.defaults = mDefaults; n.flags = mFlags; - if (mCanHasIntruder) { - n.intruderView = makeIntruderView(mIntruderActionsShowText); - } n.bigContentView = makeBigContentView(); if (mLedOnMs != 0 && mLedOffMs != 0) { n.flags |= FLAG_SHOW_LIGHTS; diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 640b47b..4fb710e 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -234,48 +234,6 @@ public class Camera { }; /** - * Creates a new Camera object to access a particular hardware camera. - * - * <p>When <code>force</code> is set to false, this will throw an exception - * if the same camera is already opened by other clients. If true, the other - * client will be disconnected from the camera they opened. If the device - * can only support one camera running at a time, all camera-using clients - * will be disconnected from their cameras. - * - * <p>A camera being held by an application can be taken away by other - * applications at any time. Before the camera is taken, applications will - * get {@link #CAMERA_ERROR_RELEASED} and have some time to clean up. Apps - * receiving this callback must immediately stop video recording and then - * call {@link #release()} on their camera object. Otherwise, it will be - * released by the frameworks in a short time. After receiving - * CAMERA_ERROR_RELEASED, apps should not call any method except <code> - * release</code> and {@link #isReleased()}. After a camera is taken away, - * all methods will throw exceptions except <code>isReleased</code> and - * <code>release</code>. Apps can use <code>isReleased</code> to see if the - * camera has been taken away. If the camera is taken away, the apps can - * silently finish themselves or show a dialog. - * - * <p>Applications with android.permission.KEEP_CAMERA can request to keep - * the camera. That is, the camera will not be taken by other applications - * while it is opened. The permission can only be obtained by trusted - * platform applications, such as those implementing lock screen security - * features. - * - * @param cameraId the hardware camera to access, between 0 and - * {@link #getNumberOfCameras()}-1. - * @param force true to take the ownership from the existing client if the - * camera has been opened by other clients. - * @param keep true if the applications do not want other apps to take the - * camera. Only the apps with android.permission.KEEP_CAMERA can keep - * the camera. - * @return a new Camera object, connected, locked and ready for use. - * @hide - */ - public static Camera open(int cameraId, boolean force, boolean keep) { - return new Camera(cameraId, force, keep); - } - - /** * Creates a new Camera object to access a particular hardware camera. If * the same camera is opened by other applications, this will throw a * RuntimeException. @@ -305,7 +263,7 @@ public class Camera { * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName) */ public static Camera open(int cameraId) { - return new Camera(cameraId, false, false); + return new Camera(cameraId); } /** @@ -320,13 +278,13 @@ public class Camera { for (int i = 0; i < numberOfCameras; i++) { getCameraInfo(i, cameraInfo); if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { - return new Camera(i, false, false); + return new Camera(i); } } return null; } - Camera(int cameraId, boolean force, boolean keep) { + Camera(int cameraId) { mShutterCallback = null; mRawImageCallback = null; mJpegCallback = null; @@ -343,7 +301,7 @@ public class Camera { mEventHandler = null; } - native_setup(new WeakReference<Camera>(this), cameraId, force, keep); + native_setup(new WeakReference<Camera>(this), cameraId); } /** @@ -356,8 +314,7 @@ public class Camera { release(); } - private native final void native_setup(Object camera_this, int cameraId, - boolean force, boolean keep); + private native final void native_setup(Object camera_this, int cameraId); private native final void native_release(); @@ -372,18 +329,6 @@ public class Camera { } /** - * Whether the camera is released. When any camera method throws an - * exception, applications can use this to check whether the camera has been - * taken by other clients. If true, it means other clients have taken the - * camera. The applications can silently finish themselves or show a dialog. - * - * @return whether the camera is released. - * @see #open(int, boolean, boolean) - * @hide - */ - public native final boolean isReleased(); - - /** * Unlocks the camera to allow another process to access it. * Normally, the camera is locked to the process with an active Camera * object until {@link #release()} is called. To allow rapid handoff @@ -1377,17 +1322,6 @@ public class Camera { public static final int CAMERA_ERROR_UNKNOWN = 1; /** - * Camera was released because another client has opened the camera. The - * application should call {@link #release()} after getting this. The apps - * should not call any method except <code>release</code> and {@link #isReleased()} - * after this. - * - * @see Camera.ErrorCallback - * @hide - */ - public static final int CAMERA_ERROR_RELEASED = 2; - - /** * Media server died. In this case, the application must release the * Camera object and instantiate a new one. * @see Camera.ErrorCallback diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 11f9445..f7f0263 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -113,19 +113,16 @@ public class Environment { = getDirectory("ANDROID_SECURE_DATA", "/data/secure"); private static final File EXTERNAL_STORAGE_DIRECTORY - = getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"); + = getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"); - private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY - = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"), - "Android"), "data"); + private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY = new File(new File( + getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "data"); - private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY - = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"), - "Android"), "media"); + private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY = new File(new File( + getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "media"); - private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY - = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"), - "Android"), "obb"); + private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY = new File(new File( + getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "obb"); private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache"); diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index cd8d51f..31ad12b 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -329,6 +329,14 @@ public final class Downloads { public static final String COLUMN_IS_PUBLIC_API = "is_public_api"; /** + * The name of the column holding a bitmask of allowed network types. This is only used for + * public API downloads. + * <P>Type: INTEGER</P> + * <P>Owner can Init/Read</P> + */ + public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types"; + + /** * The name of the column indicating whether roaming connections can be used. This is only * used for public API downloads. * <P>Type: BOOLEAN</P> @@ -337,12 +345,12 @@ public final class Downloads { public static final String COLUMN_ALLOW_ROAMING = "allow_roaming"; /** - * The name of the column holding a bitmask of allowed network types. This is only used for - * public API downloads. - * <P>Type: INTEGER</P> + * The name of the column indicating whether metered connections can be used. This is only + * used for public API downloads. + * <P>Type: BOOLEAN</P> * <P>Owner can Init/Read</P> */ - public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types"; + public static final String COLUMN_ALLOW_METERED = "allow_metered"; /** * Whether or not this download should be displayed in the system's Downloads UI. Defaults @@ -701,7 +709,10 @@ public final class Downloads { * blocked by {@link NetworkPolicyManager}. * * @hide + * @deprecated since behavior now uses + * {@link #STATUS_WAITING_FOR_NETWORK} */ + @Deprecated public static final int STATUS_BLOCKED = 498; /** {@hide} */ diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 38945c2..79d0144 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -306,13 +306,11 @@ public final class MediaStore { /** * The width of the image/video in pixels. - * @hide */ public static final String WIDTH = "width"; /** * The height of the image/video in pixels. - * @hide */ public static final String HEIGHT = "height"; } diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 6c1a6bf..54c62ee 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -52,13 +52,16 @@ final class AccessibilityInteractionController { private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); - private final Handler mHandler = new PrivateHandler(); + private final Handler mHandler; private final ViewRootImpl mViewRootImpl; private final AccessibilityNodePrefetcher mPrefetcher; public AccessibilityInteractionController(ViewRootImpl viewRootImpl) { + // mView is never null - the caller has already checked. + Looper looper = viewRootImpl.mView.mContext.getMainLooper(); + mHandler = new PrivateHandler(looper); mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); } @@ -846,8 +849,8 @@ final class AccessibilityInteractionController { private final static int MSG_FIND_FOCUS = 5; private final static int MSG_FOCUS_SEARCH = 6; - public PrivateHandler() { - super(Looper.getMainLooper()); + public PrivateHandler(Looper looper) { + super(looper); } @Override diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index 12d7b12..1c61c6c 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -24,6 +24,7 @@ import android.util.SparseIntArray; import android.hardware.input.InputManager; import java.lang.Character; +import java.text.Normalizer; /** * Describes the keys provided by a keyboard device and their associated labels. @@ -135,6 +136,106 @@ public class KeyCharacterMap implements Parcelable { */ public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1; + /* + * This bit will be set in the return value of {@link #get(int, int)} if the + * key is a "dead key." + */ + public static final int COMBINING_ACCENT = 0x80000000; + + /** + * Mask the return value from {@link #get(int, int)} with this value to get + * a printable representation of the accent character of a "dead key." + */ + public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF; + + /* Characters used to display placeholders for dead keys. */ + private static final int ACCENT_ACUTE = '\u00B4'; + private static final int ACCENT_BREVE = '\u02D8'; + private static final int ACCENT_CARON = '\u02C7'; + private static final int ACCENT_CEDILLA = '\u00B8'; + private static final int ACCENT_COMMA_ABOVE = '\u1FBD'; + private static final int ACCENT_COMMA_ABOVE_RIGHT = '\u02BC'; + private static final int ACCENT_DOT_ABOVE = '\u02D9'; + private static final int ACCENT_DOUBLE_ACUTE = '\u02DD'; + private static final int ACCENT_GRAVE = '\u02CB'; + private static final int ACCENT_CIRCUMFLEX = '\u02C6'; + private static final int ACCENT_MACRON = '\u00AF'; + private static final int ACCENT_MACRON_BELOW = '\u02CD'; + private static final int ACCENT_OGONEK = '\u02DB'; + private static final int ACCENT_REVERSED_COMMA_ABOVE = '\u02BD'; + private static final int ACCENT_RING_ABOVE = '\u02DA'; + private static final int ACCENT_TILDE = '\u02DC'; + private static final int ACCENT_TURNED_COMMA_ABOVE = '\u02BB'; + private static final int ACCENT_UMLAUT = '\u00A8'; + + /* Legacy dead key display characters used in previous versions of the API. + * We still support these characters by mapping them to their non-legacy version. */ + private static final int ACCENT_GRAVE_LEGACY = '`'; + private static final int ACCENT_CIRCUMFLEX_LEGACY = '^'; + private static final int ACCENT_TILDE_LEGACY = '~'; + + /** + * Maps Unicode combining diacritical to display-form dead key. + */ + private static final SparseIntArray sCombiningToAccent = new SparseIntArray(); + private static final SparseIntArray sAccentToCombining = new SparseIntArray(); + static { + addCombining('\u0300', ACCENT_GRAVE); + addCombining('\u0301', ACCENT_ACUTE); + addCombining('\u0302', ACCENT_CIRCUMFLEX); + addCombining('\u0303', ACCENT_TILDE); + addCombining('\u0304', ACCENT_MACRON); + addCombining('\u0306', ACCENT_BREVE); + addCombining('\u0307', ACCENT_DOT_ABOVE); + addCombining('\u0308', ACCENT_UMLAUT); + //addCombining('\u0309', ACCENT_HOOK_ABOVE); + addCombining('\u030A', ACCENT_RING_ABOVE); + addCombining('\u030B', ACCENT_DOUBLE_ACUTE); + addCombining('\u030C', ACCENT_CARON); + //addCombining('\u030D', ACCENT_VERTICAL_LINE_ABOVE); + //addCombining('\u030E', ACCENT_DOUBLE_VERTICAL_LINE_ABOVE); + //addCombining('\u030F', ACCENT_DOUBLE_GRAVE); + //addCombining('\u0310', ACCENT_CANDRABINDU); + //addCombining('\u0311', ACCENT_INVERTED_BREVE); + addCombining('\u0312', ACCENT_TURNED_COMMA_ABOVE); + addCombining('\u0313', ACCENT_COMMA_ABOVE); + addCombining('\u0314', ACCENT_REVERSED_COMMA_ABOVE); + addCombining('\u0315', ACCENT_COMMA_ABOVE_RIGHT); + //addCombining('\u031B', ACCENT_HORN); + //addCombining('\u0323', ACCENT_DOT_BELOW); + //addCombining('\u0326', ACCENT_COMMA_BELOW); + addCombining('\u0327', ACCENT_CEDILLA); + addCombining('\u0328', ACCENT_OGONEK); + //addCombining('\u0329', ACCENT_VERTICAL_LINE_BELOW); + addCombining('\u0331', ACCENT_MACRON_BELOW); + //addCombining('\u0342', ACCENT_PERISPOMENI); + //addCombining('\u0344', ACCENT_DIALYTIKA_TONOS); + //addCombining('\u0345', ACCENT_YPOGEGRAMMENI); + + // One-way mappings to equivalent preferred accents. + sCombiningToAccent.append('\u0340', ACCENT_GRAVE); + sCombiningToAccent.append('\u0341', ACCENT_ACUTE); + sCombiningToAccent.append('\u0343', ACCENT_COMMA_ABOVE); + + // One-way legacy mappings to preserve compatibility with older applications. + sAccentToCombining.append(ACCENT_GRAVE_LEGACY, '\u0300'); + sAccentToCombining.append(ACCENT_CIRCUMFLEX_LEGACY, '\u0302'); + sAccentToCombining.append(ACCENT_TILDE_LEGACY, '\u0303'); + } + + private static void addCombining(int combining, int accent) { + sCombiningToAccent.append(combining, accent); + sAccentToCombining.append(accent, combining); + } + + /** + * Maps combinations of (display-form) combining key and second character + * to combined output character. + * These mappings are derived from the Unicode NFC tables as needed. + */ + private static final SparseIntArray sDeadKeyCache = new SparseIntArray(); + private static final StringBuilder sDeadKeyBuilder = new StringBuilder(); + public static final Parcelable.Creator<KeyCharacterMap> CREATOR = new Parcelable.Creator<KeyCharacterMap>() { public KeyCharacterMap createFromParcel(Parcel in) { @@ -230,9 +331,9 @@ public class KeyCharacterMap implements Parcelable { metaState = KeyEvent.normalizeMetaState(metaState); char ch = nativeGetCharacter(mPtr, keyCode, metaState); - int map = COMBINING.get(ch); + int map = sCombiningToAccent.get(ch); if (map != 0) { - return map; + return map | COMBINING_ACCENT; } else { return ch; } @@ -346,7 +447,25 @@ public class KeyCharacterMap implements Parcelable { * @return The combined character, or 0 if the characters cannot be combined. */ public static int getDeadChar(int accent, int c) { - return DEAD.get((accent << 16) | c); + int combining = sAccentToCombining.get(accent); + if (combining == 0) { + return 0; + } + + final int combination = (combining << 16) | c; + int combined; + synchronized (sDeadKeyCache) { + combined = sDeadKeyCache.get(combination, -1); + if (combined == -1) { + sDeadKeyBuilder.setLength(0); + sDeadKeyBuilder.append((char)c); + sDeadKeyBuilder.append((char)combining); + String result = Normalizer.normalize(sDeadKeyBuilder, Normalizer.Form.NFC); + combined = result.length() == 1 ? result.charAt(0) : 0; + sDeadKeyCache.put(combination, combined); + } + } + return combined; } /** @@ -560,159 +679,6 @@ public class KeyCharacterMap implements Parcelable { } /** - * Maps Unicode combining diacritical to display-form dead key - * (display character shifted left 16 bits). - */ - private static SparseIntArray COMBINING = new SparseIntArray(); - - /** - * Maps combinations of (display-form) dead key and second character - * to combined output character. - */ - private static SparseIntArray DEAD = new SparseIntArray(); - - /* - * TODO: Change the table format to support full 21-bit-wide - * accent characters and combined characters if ever necessary. - */ - private static final int ACUTE = '\u00B4' << 16; - private static final int GRAVE = '`' << 16; - private static final int CIRCUMFLEX = '^' << 16; - private static final int TILDE = '~' << 16; - private static final int UMLAUT = '\u00A8' << 16; - - /* - * This bit will be set in the return value of {@link #get(int, int)} if the - * key is a "dead key." - */ - public static final int COMBINING_ACCENT = 0x80000000; - /** - * Mask the return value from {@link #get(int, int)} with this value to get - * a printable representation of the accent character of a "dead key." - */ - public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF; - - static { - COMBINING.put('\u0300', (GRAVE >> 16) | COMBINING_ACCENT); - COMBINING.put('\u0301', (ACUTE >> 16) | COMBINING_ACCENT); - COMBINING.put('\u0302', (CIRCUMFLEX >> 16) | COMBINING_ACCENT); - COMBINING.put('\u0303', (TILDE >> 16) | COMBINING_ACCENT); - COMBINING.put('\u0308', (UMLAUT >> 16) | COMBINING_ACCENT); - - DEAD.put(ACUTE | 'A', '\u00C1'); - DEAD.put(ACUTE | 'C', '\u0106'); - DEAD.put(ACUTE | 'E', '\u00C9'); - DEAD.put(ACUTE | 'G', '\u01F4'); - DEAD.put(ACUTE | 'I', '\u00CD'); - DEAD.put(ACUTE | 'K', '\u1E30'); - DEAD.put(ACUTE | 'L', '\u0139'); - DEAD.put(ACUTE | 'M', '\u1E3E'); - DEAD.put(ACUTE | 'N', '\u0143'); - DEAD.put(ACUTE | 'O', '\u00D3'); - DEAD.put(ACUTE | 'P', '\u1E54'); - DEAD.put(ACUTE | 'R', '\u0154'); - DEAD.put(ACUTE | 'S', '\u015A'); - DEAD.put(ACUTE | 'U', '\u00DA'); - DEAD.put(ACUTE | 'W', '\u1E82'); - DEAD.put(ACUTE | 'Y', '\u00DD'); - DEAD.put(ACUTE | 'Z', '\u0179'); - DEAD.put(ACUTE | 'a', '\u00E1'); - DEAD.put(ACUTE | 'c', '\u0107'); - DEAD.put(ACUTE | 'e', '\u00E9'); - DEAD.put(ACUTE | 'g', '\u01F5'); - DEAD.put(ACUTE | 'i', '\u00ED'); - DEAD.put(ACUTE | 'k', '\u1E31'); - DEAD.put(ACUTE | 'l', '\u013A'); - DEAD.put(ACUTE | 'm', '\u1E3F'); - DEAD.put(ACUTE | 'n', '\u0144'); - DEAD.put(ACUTE | 'o', '\u00F3'); - DEAD.put(ACUTE | 'p', '\u1E55'); - DEAD.put(ACUTE | 'r', '\u0155'); - DEAD.put(ACUTE | 's', '\u015B'); - DEAD.put(ACUTE | 'u', '\u00FA'); - DEAD.put(ACUTE | 'w', '\u1E83'); - DEAD.put(ACUTE | 'y', '\u00FD'); - DEAD.put(ACUTE | 'z', '\u017A'); - DEAD.put(CIRCUMFLEX | 'A', '\u00C2'); - DEAD.put(CIRCUMFLEX | 'C', '\u0108'); - DEAD.put(CIRCUMFLEX | 'E', '\u00CA'); - DEAD.put(CIRCUMFLEX | 'G', '\u011C'); - DEAD.put(CIRCUMFLEX | 'H', '\u0124'); - DEAD.put(CIRCUMFLEX | 'I', '\u00CE'); - DEAD.put(CIRCUMFLEX | 'J', '\u0134'); - DEAD.put(CIRCUMFLEX | 'O', '\u00D4'); - DEAD.put(CIRCUMFLEX | 'S', '\u015C'); - DEAD.put(CIRCUMFLEX | 'U', '\u00DB'); - DEAD.put(CIRCUMFLEX | 'W', '\u0174'); - DEAD.put(CIRCUMFLEX | 'Y', '\u0176'); - DEAD.put(CIRCUMFLEX | 'Z', '\u1E90'); - DEAD.put(CIRCUMFLEX | 'a', '\u00E2'); - DEAD.put(CIRCUMFLEX | 'c', '\u0109'); - DEAD.put(CIRCUMFLEX | 'e', '\u00EA'); - DEAD.put(CIRCUMFLEX | 'g', '\u011D'); - DEAD.put(CIRCUMFLEX | 'h', '\u0125'); - DEAD.put(CIRCUMFLEX | 'i', '\u00EE'); - DEAD.put(CIRCUMFLEX | 'j', '\u0135'); - DEAD.put(CIRCUMFLEX | 'o', '\u00F4'); - DEAD.put(CIRCUMFLEX | 's', '\u015D'); - DEAD.put(CIRCUMFLEX | 'u', '\u00FB'); - DEAD.put(CIRCUMFLEX | 'w', '\u0175'); - DEAD.put(CIRCUMFLEX | 'y', '\u0177'); - DEAD.put(CIRCUMFLEX | 'z', '\u1E91'); - DEAD.put(GRAVE | 'A', '\u00C0'); - DEAD.put(GRAVE | 'E', '\u00C8'); - DEAD.put(GRAVE | 'I', '\u00CC'); - DEAD.put(GRAVE | 'N', '\u01F8'); - DEAD.put(GRAVE | 'O', '\u00D2'); - DEAD.put(GRAVE | 'U', '\u00D9'); - DEAD.put(GRAVE | 'W', '\u1E80'); - DEAD.put(GRAVE | 'Y', '\u1EF2'); - DEAD.put(GRAVE | 'a', '\u00E0'); - DEAD.put(GRAVE | 'e', '\u00E8'); - DEAD.put(GRAVE | 'i', '\u00EC'); - DEAD.put(GRAVE | 'n', '\u01F9'); - DEAD.put(GRAVE | 'o', '\u00F2'); - DEAD.put(GRAVE | 'u', '\u00F9'); - DEAD.put(GRAVE | 'w', '\u1E81'); - DEAD.put(GRAVE | 'y', '\u1EF3'); - DEAD.put(TILDE | 'A', '\u00C3'); - DEAD.put(TILDE | 'E', '\u1EBC'); - DEAD.put(TILDE | 'I', '\u0128'); - DEAD.put(TILDE | 'N', '\u00D1'); - DEAD.put(TILDE | 'O', '\u00D5'); - DEAD.put(TILDE | 'U', '\u0168'); - DEAD.put(TILDE | 'V', '\u1E7C'); - DEAD.put(TILDE | 'Y', '\u1EF8'); - DEAD.put(TILDE | 'a', '\u00E3'); - DEAD.put(TILDE | 'e', '\u1EBD'); - DEAD.put(TILDE | 'i', '\u0129'); - DEAD.put(TILDE | 'n', '\u00F1'); - DEAD.put(TILDE | 'o', '\u00F5'); - DEAD.put(TILDE | 'u', '\u0169'); - DEAD.put(TILDE | 'v', '\u1E7D'); - DEAD.put(TILDE | 'y', '\u1EF9'); - DEAD.put(UMLAUT | 'A', '\u00C4'); - DEAD.put(UMLAUT | 'E', '\u00CB'); - DEAD.put(UMLAUT | 'H', '\u1E26'); - DEAD.put(UMLAUT | 'I', '\u00CF'); - DEAD.put(UMLAUT | 'O', '\u00D6'); - DEAD.put(UMLAUT | 'U', '\u00DC'); - DEAD.put(UMLAUT | 'W', '\u1E84'); - DEAD.put(UMLAUT | 'X', '\u1E8C'); - DEAD.put(UMLAUT | 'Y', '\u0178'); - DEAD.put(UMLAUT | 'a', '\u00E4'); - DEAD.put(UMLAUT | 'e', '\u00EB'); - DEAD.put(UMLAUT | 'h', '\u1E27'); - DEAD.put(UMLAUT | 'i', '\u00EF'); - DEAD.put(UMLAUT | 'o', '\u00F6'); - DEAD.put(UMLAUT | 't', '\u1E97'); - DEAD.put(UMLAUT | 'u', '\u00FC'); - DEAD.put(UMLAUT | 'w', '\u1E85'); - DEAD.put(UMLAUT | 'x', '\u1E8D'); - DEAD.put(UMLAUT | 'y', '\u00FF'); - } - - /** * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded. */ public static class UnavailableException extends AndroidRuntimeException { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0ded5f9..bd054bc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6359,16 +6359,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public boolean performAccessibilityAction(int action) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { - final long now = SystemClock.uptimeMillis(); - // Send down. - MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, - getWidth() / 2, getHeight() / 2, 0); - onTouchEvent(event); - // Send up. - event.setAction(MotionEvent.ACTION_UP); - onTouchEvent(event); - // Clean up. - event.recycle(); + if (isClickable()) { + performClick(); + } + } break; + case AccessibilityNodeInfo.ACTION_LONG_CLICK: { + if (isLongClickable()) { + performLongClick(); + } } break; case AccessibilityNodeInfo.ACTION_FOCUS: { if (!hasFocus()) { @@ -13846,13 +13844,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ public Insets getLayoutInsets() { if (mLayoutInsets == null) { - if (mBackground == null) { - mLayoutInsets = Insets.NONE; - } else { - Rect insetRect = new Rect(); - boolean hasInsets = mBackground.getLayoutInsets(insetRect); - mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE; - } + mLayoutInsets = (mBackground == null) ? Insets.NONE : mBackground.getLayoutInsets(); } return mLayoutInsets; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 6371963..91e945b 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5792,11 +5792,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5889,11 +5891,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5943,9 +5947,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (widthDiference != 0) { return -widthDiference; } - // Return nondeterministically one of them since we do - // not want to ignore any views. - return 1; + // Just break the tie somehow. The accessibliity ids are unique + // and stable, hence this is deterministic tie breaking. + return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId(); } private void init(ViewGroup root, View view) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1472993..3d40b2f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2665,6 +2665,7 @@ public final class ViewRootImpl implements ViewParent, private final static int MSG_PROCESS_INPUT_EVENTS = 19; private final static int MSG_DISPATCH_SCREEN_STATE = 20; private final static int MSG_INVALIDATE_DISPLAY_LIST = 21; + private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22; final class ViewRootHandler extends Handler { @Override @@ -2712,6 +2713,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_DISPATCH_SCREEN_STATE"; case MSG_INVALIDATE_DISPLAY_LIST: return "MSG_INVALIDATE_DISPLAY_LIST"; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: + return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; } return super.getMessageName(message); } @@ -2921,6 +2924,9 @@ public final class ViewRootImpl implements ViewParent, case MSG_INVALIDATE_DISPLAY_LIST: { invalidateDisplayLists(); } break; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { + setAccessibilityFocusedHost(null); + } break; } } } @@ -5066,7 +5072,7 @@ public final class ViewRootImpl implements ViewParent, } } else { ensureNoConnection(); - setAccessibilityFocusedHost(null); + mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 1071c65..c5f2062 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -84,7 +84,7 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Action that gives input focus to the node. */ - public static final int ACTION_FOCUS = 0x00000001; + public static final int ACTION_FOCUS = 0x00000001; /** * Action that clears input focus of the node. @@ -102,19 +102,24 @@ public class AccessibilityNodeInfo implements Parcelable { public static final int ACTION_CLEAR_SELECTION = 0x00000008; /** - * Action that gives accessibility focus to the node. + * Action that clicks on the node info. */ - public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000010; + public static final int ACTION_CLICK = 0x00000010; /** - * Action that clears accessibility focus of the node. + * Action that clicks on the node. + */ + public static final int ACTION_LONG_CLICK = 0x00000020; + + /** + * Action that gives accessibility focus to the node. */ - public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000020; + public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; /** - * Action that clicks on the node info./AccessibilityNodeInfoCache.java + * Action that clears accessibility focus of the node. */ - public static final int ACTION_CLICK = 0x00000040; + public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; /** * The input focus. @@ -278,9 +283,9 @@ public class AccessibilityNodeInfo implements Parcelable { (root != null) ? root.getAccessibilityViewId() : UNDEFINED; mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); } - + /** - * Find the view that has the input focus. The search starts from + * Find the view that has the specified focus type. The search starts from * the view represented by this node info. * * @param focus The focus to find. One of {@link #FOCUS_INPUT} or diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java index 0541d5d..655db31 100644 --- a/core/java/android/webkit/WebCoreThreadWatchdog.java +++ b/core/java/android/webkit/WebCoreThreadWatchdog.java @@ -16,6 +16,7 @@ package android.webkit; +import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; @@ -146,6 +147,7 @@ class WebCoreThreadWatchdog implements Runnable { break; case TIMED_OUT: + if ((mContext == null) || !(mContext instanceof Activity)) return; new AlertDialog.Builder(mContext) .setMessage(com.android.internal.R.string.webpage_unresponsive) .setPositiveButton(com.android.internal.R.string.force_close, |
