diff options
Diffstat (limited to 'core/java/android')
34 files changed, 1732 insertions, 116 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 804aeaa..79890ef 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2109,7 +2109,39 @@ public class Activity extends ContextThemeWrapper public boolean onTrackballEvent(MotionEvent event) { return false; } - + + /** + * Called when a generic motion event was not handled by any of the + * views inside of the activity. + * <p> + * Generic motion events are dispatched to the focused view to describe + * the motions of input devices such as joysticks. The + * {@link MotionEvent#getSource() source} of the motion event specifies + * the class of input that was received. Implementations of this method + * must examine the bits in the source before processing the event. + * The following code example shows how this is done. + * </p> + * <code> + * public boolean onGenericMotionEvent(MotionEvent event) { + * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { + * float x = event.getX(); + * float y = event.getY(); + * // process the joystick motion + * return true; + * } + * return super.onGenericMotionEvent(event); + * } + * </code> + * + * @param event The generic motion event being processed. + * + * @return Return true if you have consumed the event, false if you haven't. + * The default implementation always returns false. + */ + public boolean onGenericMotionEvent(MotionEvent event) { + return false; + } + /** * Called whenever a key, touch, or trackball event is dispatched to the * activity. Implement this method if you wish to know that the user has @@ -2292,6 +2324,24 @@ public class Activity extends ContextThemeWrapper return onTrackballEvent(ev); } + /** + * Called to process generic motion events. You can override this to + * intercept all generic motion events before they are dispatched to the + * window. Be sure to call this implementation for generic motion events + * that should be handled normally. + * + * @param ev The generic motion event. + * + * @return boolean Return true if this event was consumed. + */ + public boolean dispatchGenericMotionEvent(MotionEvent ev) { + onUserInteraction(); + if (getWindow().superDispatchGenericMotionEvent(ev)) { + return true; + } + return onGenericMotionEvent(ev); + } + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { event.setClassName(getClass().getName()); event.setPackageName(getPackageName()); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 6f63990..8737e93 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -41,7 +41,9 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.hardware.IUsbManager; import android.hardware.SensorManager; +import android.hardware.UsbManager; import android.location.CountryDetector; import android.location.ICountryDetector; import android.location.ILocationManager; @@ -399,6 +401,12 @@ class ContextImpl extends Context { return new UiModeManager(); }}); + registerService(USB_SERVICE, new StaticServiceFetcher() { + public Object createStaticService() { + IBinder b = ServiceManager.getService(USB_SERVICE); + return new UsbManager(IUsbManager.Stub.asInterface(b)); + }}); + registerService(VIBRATOR_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new Vibrator(); diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index f4fa567..2bf1ff9 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -616,7 +616,39 @@ public class Dialog implements DialogInterface, Window.Callback, public boolean onTrackballEvent(MotionEvent event) { return false; } - + + /** + * Called when a generic motion event was not handled by any of the + * views inside of the dialog. + * <p> + * Generic motion events are dispatched to the focused view to describe + * the motions of input devices such as joysticks. The + * {@link MotionEvent#getSource() source} of the motion event specifies + * the class of input that was received. Implementations of this method + * must examine the bits in the source before processing the event. + * The following code example shows how this is done. + * </p> + * <code> + * public boolean onGenericMotionEvent(MotionEvent event) { + * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { + * float x = event.getX(); + * float y = event.getY(); + * // process the joystick motion + * return true; + * } + * return super.onGenericMotionEvent(event); + * } + * </code> + * + * @param event The generic motion event being processed. + * + * @return Return true if you have consumed the event, false if you haven't. + * The default implementation always returns false. + */ + public boolean onGenericMotionEvent(MotionEvent event) { + return false; + } + public void onWindowAttributesChanged(WindowManager.LayoutParams params) { if (mDecor != null) { mWindowManager.updateViewLayout(mDecor, params); @@ -705,6 +737,23 @@ public class Dialog implements DialogInterface, Window.Callback, return onTrackballEvent(ev); } + /** + * Called to process generic motion events. You can override this to + * intercept all generic motion events before they are dispatched to the + * window. Be sure to call this implementation for generic motion events + * that should be handled normally. + * + * @param ev The generic motion event. + * + * @return boolean Return true if this event was consumed. + */ + public boolean dispatchGenericMotionEvent(MotionEvent ev) { + if (mWindow.superDispatchGenericMotionEvent(ev)) { + return true; + } + return onGenericMotionEvent(ev); + } + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { event.setClassName(getClass().getName()); event.setPackageName(mContext.getPackageName()); diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 297d246..e82bad7 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -24,13 +24,12 @@ import android.database.Cursor; import android.database.CursorWrapper; import android.net.ConnectivityManager; import android.net.Uri; -import android.os.Binder; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.Downloads; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; -import android.util.Log; +import android.text.TextUtils; import android.util.Pair; import java.io.File; @@ -53,7 +52,6 @@ import java.util.List; * download in a notification or from the downloads UI. */ public class DownloadManager { - private static final String TAG = "DownloadManager"; /** * An identifier for a particular download, unique across the system. Clients use this ID to @@ -268,6 +266,13 @@ public class DownloadManager { public final static String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS"; /** + * Intent extra included with {@link #ACTION_VIEW_DOWNLOADS} to start DownloadApp in + * sort-by-size mode. + */ + public final static String INTENT_EXTRAS_SORT_BY_SIZE = + "android.app.DownloadManager.extra_sortBySize"; + + /** * Intent extra included with {@link #ACTION_DOWNLOAD_COMPLETE} intents, indicating the ID (as a * long) of the download that just completed. */ @@ -387,6 +392,10 @@ public class DownloadManager { mUri = uri; } + Request(String uriString) { + mUri = Uri.parse(uriString); + } + /** * Set the local destination for the downloaded file. Must be a file URI to a path on * external storage, and the calling application must have the WRITE_EXTERNAL_STORAGE @@ -1070,6 +1079,68 @@ public class DownloadManager { return null; } } + + /** + * Adds a file to the downloads database system, so it could appear in Downloads App + * (and thus become eligible for management by the Downloads App). + * <p> + * It is helpful to make the file scannable by MediaScanner by setting the param + * isMediaScannerScannable to true. It makes the file visible in media managing + * applications such as Gallery App, which could be a useful purpose of using this API. + * + * @param title the title that would appear for this file in Downloads App. + * @param description the description that would appear for this file in Downloads App. + * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files + * scanned by MediaScanner appear in the applications used to view media (for example, + * Gallery app). + * @param mimeType mimetype of the file. + * @param path absolute pathname to the file. The file should be world-readable, so that it can + * be managed by the Downloads App and any other app that is used to read it (for example, + * Gallery app to display the file, if the file contents represent a video/image). + * @param length length of the downloaded file + * @return an ID for the download entry added to the downloads app, unique across the system + * This ID is used to make future calls related to this download. + */ + public long completedDownload(String title, String description, + boolean isMediaScannerScannable, String mimeType, String path, long length) { + // make sure the input args are non-null/non-zero + validateArgumentIsNonEmpty("title", title); + validateArgumentIsNonEmpty("description", description); + validateArgumentIsNonEmpty("path", path); + validateArgumentIsNonEmpty("mimeType", mimeType); + if (length <= 0) { + throw new IllegalArgumentException(" invalid value for param: totalBytes"); + } + + // if there is already an entry with the given path name in downloads.db, return its id + Request request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD) + .setTitle(title) + .setDescription(description) + .setMimeType(mimeType); + ContentValues values = request.toContentValues(null); + values.put(Downloads.Impl.COLUMN_DESTINATION, + Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD); + values.put(Downloads.Impl._DATA, path); + values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_SUCCESS); + values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, length); + values.put(Downloads.Impl.COLUMN_MEDIA_SCANNED, + (isMediaScannerScannable) ? Request.SCANNABLE_VALUE_YES : + Request.SCANNABLE_VALUE_NO); + Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values); + if (downloadUri == null) { + return -1; + } + return Long.parseLong(downloadUri.getLastPathSegment()); + } + private static final String NON_DOWNLOADMANAGER_DOWNLOAD = + "non-dwnldmngr-download-dont-retry2download"; + + private static void validateArgumentIsNonEmpty(String paramName, String val) { + if (TextUtils.isEmpty(val)) { + throw new IllegalArgumentException(paramName + " can't be null"); + } + } + /** * Get the DownloadProvider URI for the download with the given ID. */ @@ -1144,7 +1215,8 @@ public class DownloadManager { private String getLocalUri() { long destinationType = getLong(getColumnIndex(Downloads.Impl.COLUMN_DESTINATION)); if (destinationType == Downloads.Impl.DESTINATION_FILE_URI || - destinationType == Downloads.Impl.DESTINATION_EXTERNAL) { + destinationType == Downloads.Impl.DESTINATION_EXTERNAL || + destinationType == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) { String localPath = getString(getColumnIndex(COLUMN_LOCAL_FILENAME)); if (localPath == null) { return null; diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index 7b083f1..aa1adcb 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -18,7 +18,7 @@ package android.bluetooth; import android.content.Context; import android.net.ConnectivityManager; -import android.net.DhcpInfo; +import android.net.DhcpInfoInternal; import android.net.LinkAddress; import android.net.LinkCapabilities; import android.net.LinkProperties; @@ -251,23 +251,12 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker { public void run() { //TODO(): Add callbacks for failure and success case. //Currently this thread runs independently. - DhcpInfo dhcpInfo = new DhcpInfo(); - if (!NetworkUtils.runDhcp(mIface, dhcpInfo)) { + DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); + if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); return; } - mLinkProperties.addLinkAddress(new LinkAddress( - NetworkUtils.intToInetAddress(dhcpInfo.ipAddress), - NetworkUtils.intToInetAddress(dhcpInfo.netmask))); - mLinkProperties.setGateway(NetworkUtils.intToInetAddress(dhcpInfo.gateway)); - InetAddress dns1Addr = NetworkUtils.intToInetAddress(dhcpInfo.dns1); - if (dns1Addr == null || dns1Addr.equals("0.0.0.0")) { - mLinkProperties.addDns(dns1Addr); - } - InetAddress dns2Addr = NetworkUtils.intToInetAddress(dhcpInfo.dns2); - if (dns2Addr == null || dns2Addr.equals("0.0.0.0")) { - mLinkProperties.addDns(dns2Addr); - } + mLinkProperties = dhcpInfoInternal.makeLinkProperties(); mLinkProperties.setInterfaceName(mIface); mNetworkInfo.setIsAvailable(true); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d14cf4d..051ae9e 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1663,6 +1663,16 @@ public abstract class Context { public static final String SIP_SERVICE = "sip"; /** + * Use with {@link #getSystemService} to retrieve a {@link + * android.hardware.UsbManager} for access to USB devices (as a USB host) + * and for controlling this device's behavior as a USB device. + * + * @see #getSystemService + * @see android.harware.UsbManager + */ + public static final String USB_SERVICE = "usb"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 68cb2bc..659b937 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -1406,6 +1406,7 @@ public class SyncManager implements OnAccountsUpdateListener { public void handleMessage(Message msg) { long earliestFuturePollTime = Long.MAX_VALUE; long nextPendingSyncTime = Long.MAX_VALUE; + // Setting the value here instead of a method because we want the dumpsys logs // to have the most recent value used. try { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 7676258..e8292cc 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3085,11 +3085,7 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } - if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - ai.enabled = true; - } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) { - ai.enabled = false; - } + ai.enabled = p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; return ai; } diff --git a/core/java/android/hardware/IUsbManager.aidl b/core/java/android/hardware/IUsbManager.aidl new file mode 100644 index 0000000..b50b6b9 --- /dev/null +++ b/core/java/android/hardware/IUsbManager.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010 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.hardware; + +import android.os.Bundle; +import android.os.ParcelFileDescriptor; + +/** @hide */ +interface IUsbManager +{ + /* Returns a list of all currently attached USB devices */ + void getDeviceList(out Bundle devices); + ParcelFileDescriptor openDevice(String deviceName); +} diff --git a/core/java/android/hardware/UsbConstants.java b/core/java/android/hardware/UsbConstants.java new file mode 100644 index 0000000..29a335c --- /dev/null +++ b/core/java/android/hardware/UsbConstants.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 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.hardware; + +/** + * Contains constants for the USB protocol. + * These constants correspond to definitions in linux/usb/ch9.h in the linux kernel. + */ +public final class UsbConstants { + + public static final int USB_ENDPOINT_DIR_MASK = 0x80; + public static final int USB_DIR_OUT = 0; + public static final int USB_DIR_IN = 0x80; + + public static final int USB_TYPE_MASK = (0x03 << 5); + public static final int USB_TYPE_STANDARD = (0x00 << 5); + public static final int USB_TYPE_CLASS = (0x01 << 5); + public static final int USB_TYPE_VENDOR = (0x02 << 5); + public static final int USB_TYPE_RESERVED = (0x03 << 5); + + public static final int USB_ENDPOINT_NUMBER_MASK = 0x0f; + + // flags for endpoint attributes + public static final int USB_ENDPOINT_XFERTYPE_MASK = 0x03; + public static final int USB_ENDPOINT_XFER_CONTROL = 0; + public static final int USB_ENDPOINT_XFER_ISOC = 1; + public static final int USB_ENDPOINT_XFER_BULK = 2; + public static final int USB_ENDPOINT_XFER_INT = 3; + + public static final int USB_CLASS_PER_INTERFACE = 0; + public static final int USB_CLASS_AUDIO = 1; + public static final int USB_CLASS_COMM = 2; + public static final int USB_CLASS_HID = 3; + public static final int USB_CLASS_PHYSICA = 5; + public static final int USB_CLASS_STILL_IMAGE = 6; + public static final int USB_CLASS_PRINTER = 7; + public static final int USB_CLASS_MASS_STORAGE = 8; + public static final int USB_CLASS_HUB = 9; + public static final int USB_CLASS_CDC_DATA = 0x0a; + public static final int USB_CLASS_CSCID = 0x0b; + public static final int USB_CLASS_CONTENT_SEC = 0x0d; + public static final int USB_CLASS_VIDEO = 0x0e; + public static final int USB_CLASS_WIRELESS_CONTROLLER = 0xe0; + public static final int USB_CLASS_MISC = 0xef; + public static final int USB_CLASS_APP_SPEC = 0xfe; + public static final int USB_CLASS_VENDOR_SPEC = 0xff; + public static final int USB_SUBCLASS_VENDOR_SPEC = 0xff; + +}
\ No newline at end of file diff --git a/core/java/android/hardware/UsbDevice.aidl b/core/java/android/hardware/UsbDevice.aidl new file mode 100644 index 0000000..6dfd43f --- /dev/null +++ b/core/java/android/hardware/UsbDevice.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010, 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.hardware; + +parcelable UsbDevice; diff --git a/core/java/android/hardware/UsbDevice.java b/core/java/android/hardware/UsbDevice.java new file mode 100644 index 0000000..e6b38be --- /dev/null +++ b/core/java/android/hardware/UsbDevice.java @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2010 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.hardware; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileDescriptor; + + +/** + * A class representing a USB device. + */ +public final class UsbDevice implements Parcelable { + + private static final String TAG = "UsbDevice"; + + private String mName; + private int mVendorId; + private int mProductId; + private int mClass; + private int mSubclass; + private int mProtocol; + private Parcelable[] mInterfaces; + + // used by the JNI code + private int mNativeContext; + + private UsbDevice() { + } + + + /** + * UsbDevice should only be instantiated by UsbService implementation + * @hide + */ + public UsbDevice(String name, int vendorId, int productId, + int Class, int subClass, int protocol, Parcelable[] interfaces) { + mName = name; + mVendorId = vendorId; + mProductId = productId; + mClass = Class; + mSubclass = subClass; + mProtocol = protocol; + mInterfaces = interfaces; + } + + /** + * Returns the name of the device. + * In the standard implementation, this is the path of the device file + * for the device in the usbfs file system. + * + * @return the device name + */ + public String getDeviceName() { + return mName; + } + + /** + * Returns a unique integer ID for the device. + * This is a convenience for clients that want to use an integer to represent + * the device, rather than the device name. + * IDs are not persistent across USB disconnects. + * + * @return the device ID + */ + public int getDeviceId() { + return getDeviceId(mName); + } + + /** + * Returns a vendor ID for the device. + * + * @return the device vendor ID + */ + public int getVendorId() { + return mVendorId; + } + + /** + * Returns a product ID for the device. + * + * @return the device product ID + */ + public int getProductId() { + return mProductId; + } + + /** + * Returns the devices's class field. + * Some useful constants for USB device classes can be found in + * {@link android.hardware.UsbConstants} + * + * @return the devices's class + */ + public int getDeviceClass() { + return mClass; + } + + /** + * Returns the device's subclass field. + * + * @return the device's subclass + */ + public int getDeviceSubclass() { + return mSubclass; + } + + /** + * Returns the device's subclass field. + * + * @return the device's protocol + */ + public int getDeviceProtocol() { + return mProtocol; + } + + /** + * Returns the number of {@link android.hardware.UsbInterface}s this device contains. + * + * @return the number of interfaces + */ + public int getInterfaceCount() { + return mInterfaces.length; + } + + /** + * Returns the {@link android.hardware.UsbInterface} at the given index. + * + * @return the interface + */ + public UsbInterface getInterface(int index) { + return (UsbInterface)mInterfaces[index]; + } + + /* package */ boolean open(ParcelFileDescriptor pfd) { + return native_open(mName, pfd.getFileDescriptor()); + } + + /** + * Releases all system resources related to the device. + */ + public void close() { + native_close(); + } + + /** + * Returns an integer file descriptor for the device, or + * -1 if the device is not opened. + * This is intended for passing to native code to access the device + */ + public int getFileDescriptor() { + return native_get_fd(); + } + + /** + * Claims exclusive access to a {@link android.hardware.UsbInterface}. + * This must be done before sending or receiving data on any + * {@link android.hardware.UsbEndpoint}s belonging to the interface + * @param intf the interface to claim + * @param force true to disconnect kernel driver if necessary + * @return true if the interface was successfully claimed + */ + public boolean claimInterface(UsbInterface intf, boolean force) { + return native_claim_interface(intf.getId(), force); + } + + /** + * Releases exclusive access to a {@link android.hardware.UsbInterface}. + * + * @return true if the interface was successfully released + */ + public boolean releaseInterface(UsbInterface intf) { + return native_release_interface(intf.getId()); + } + + /** + * Performs a control transaction on endpoint zero for this device. + * + * @param requestType request type for this transaction + * @param request request ID for this transaction + * @param value value field for this transaction + * @param index index field for this transaction + * @param buffer buffer for data portion of transaction, + * or null if no data needs to be sent or received + * @param length the length of the data to send or receive + * @return length of data transferred (or zero) for success, + * or negative value for failure + */ + public int sendControlRequest(int requestType, int request, int value, + int index, byte[] buffer, int length) { + return native_control_request(requestType, request, value, index, buffer, length); + } + + /** + * Waits for the result of a {@link android.hardware.UsbRequest#queue} operation + * Note that this may return requests queued on multiple {@link android.hardware.UsbEndpoint}s. + * When multiple endpoints are in use, {@link android.hardware.UsbRequest#getEndpoint} and + * {@link android.hardware.UsbRequest#getClientData} can be useful in determining how to process + * the result of this function. + * + * @return a completed USB request, or null if an error occurred + */ + public UsbRequest requestWait() { + UsbRequest request = native_request_wait(); + if (request != null) { + request.dequeue(); + } + return request; + } + + /** + * Returns the serial number for the device. + * This will return null if the device has not been opened. + * + * @return the device serial number + */ + public String getSerial() { + return native_get_serial(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof UsbDevice) { + return ((UsbDevice)o).mName.equals(mName); + } else if (o instanceof String) { + return ((String)o).equals(mName); + } else { + return false; + } + } + + @Override + public String toString() { + return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId + + ",mProductId=" + mProductId + ",mClass=" + mClass + + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + ",mInterfaces=" + mInterfaces + "]"; + } + + public static final Parcelable.Creator<UsbDevice> CREATOR = + new Parcelable.Creator<UsbDevice>() { + public UsbDevice createFromParcel(Parcel in) { + String name = in.readString(); + int vendorId = in.readInt(); + int productId = in.readInt(); + int clasz = in.readInt(); + int subClass = in.readInt(); + int protocol = in.readInt(); + Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader()); + UsbDevice result = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces); + for (int i = 0; i < interfaces.length; i++) { + ((UsbInterface)interfaces[i]).setDevice(result); + } + return result; + } + + public UsbDevice[] newArray(int size) { + return new UsbDevice[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mName); + parcel.writeInt(mVendorId); + parcel.writeInt(mProductId); + parcel.writeInt(mClass); + parcel.writeInt(mSubclass); + parcel.writeInt(mProtocol); + parcel.writeParcelableArray(mInterfaces, 0); + } + + public static int getDeviceId(String name) { + return native_get_device_id(name); + } + + public static String getDeviceName(int id) { + return native_get_device_name(id); + } + + private native boolean native_open(String deviceName, FileDescriptor pfd); + private native void native_close(); + private native int native_get_fd(); + private native boolean native_claim_interface(int interfaceID, boolean force); + private native boolean native_release_interface(int interfaceID); + private native int native_control_request(int requestType, int request, int value, + int index, byte[] buffer, int length); + private native UsbRequest native_request_wait(); + private native String native_get_serial(); + + private static native int native_get_device_id(String name); + private static native String native_get_device_name(int id); +} diff --git a/core/java/android/hardware/UsbEndpoint.aidl b/core/java/android/hardware/UsbEndpoint.aidl new file mode 100644 index 0000000..51fc67b --- /dev/null +++ b/core/java/android/hardware/UsbEndpoint.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 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.hardware; + +parcelable UsbEndpoint; diff --git a/core/java/android/hardware/UsbEndpoint.java b/core/java/android/hardware/UsbEndpoint.java new file mode 100644 index 0000000..8d4099d --- /dev/null +++ b/core/java/android/hardware/UsbEndpoint.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2010 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.hardware; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class representing an endpoint on a {@link android.hardware.UsbInterface}. + */ +public final class UsbEndpoint implements Parcelable { + + private int mAddress; + private int mAttributes; + private int mMaxPacketSize; + private int mInterval; + private UsbInterface mInterface; + + private UsbEndpoint() { + } + + /** + * UsbEndpoint should only be instantiated by UsbService implementation + * @hide + */ + public UsbEndpoint(int address, int attributes, int maxPacketSize, int interval) { + mAddress = address; + mAttributes = attributes; + mMaxPacketSize = maxPacketSize; + mInterval = interval; + } + + /** + * Returns the endpoint's address field. + * + * @return the endpoint's address + */ + public int getAddress() { + return mAddress; + } + + /** + * Extracts the endpoint's endpoint number from its address + * + * @return the endpoint's endpoint number + */ + public int getEndpointNumber() { + return mAddress & UsbConstants.USB_ENDPOINT_NUMBER_MASK; + } + + /** + * Returns the endpoint's direction. + * Returns {@link android.hardware.UsbConstants#USB_DIR_OUT} + * if the direction is host to device, and + * {@link android.hardware.UsbConstants#USB_DIR_IN} if the + * direction is device to host. + * + * @return the endpoint's direction + */ + public int getDirection() { + return mAddress & UsbConstants.USB_ENDPOINT_DIR_MASK; + } + + /** + * Returns the endpoint's attributes field. + * + * @return the endpoint's attributes + */ + public int getAttributes() { + return mAttributes; + } + + /** + * Returns the endpoint's type. + * Possible results are: + * <ul> + * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero) + * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint) + * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint) + * <li>{@link android.hardware.UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint) + * </ul> + * + * @return the endpoint's type + */ + public int getType() { + return mAttributes & UsbConstants.USB_ENDPOINT_XFERTYPE_MASK; + } + + /** + * Returns the endpoint's maximum packet size. + * + * @return the endpoint's maximum packet size + */ + public int getMaxPacketSize() { + return mMaxPacketSize; + } + + /** + * Returns the endpoint's interval field. + * + * @return the endpoint's interval + */ + public int getInterval() { + return mInterval; + } + + /** + * Returns the {@link android.hardware.UsbInterface} this endpoint belongs to. + * + * @return the endpoint's interface + */ + public UsbInterface getInterface() { + return mInterface; + } + + /** + * Returns the {@link android.hardware.UsbDevice} this endpoint belongs to. + * + * @return the endpoint's device + */ + public UsbDevice getDevice() { + return mInterface.getDevice(); + } + + // only used for parcelling + /* package */ void setInterface(UsbInterface intf) { + mInterface = intf; + } + + @Override + public String toString() { + return "UsbEndpoint[mAddress=" + mAddress + ",mAttributes=" + mAttributes + + ",mMaxPacketSize=" + mMaxPacketSize + ",mInterval=" + mInterval +"]"; + } + + public static final Parcelable.Creator<UsbEndpoint> CREATOR = + new Parcelable.Creator<UsbEndpoint>() { + public UsbEndpoint createFromParcel(Parcel in) { + int address = in.readInt(); + int attributes = in.readInt(); + int maxPacketSize = in.readInt(); + int interval = in.readInt(); + return new UsbEndpoint(address, attributes, maxPacketSize, interval); + } + + public UsbEndpoint[] newArray(int size) { + return new UsbEndpoint[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mAddress); + parcel.writeInt(mAttributes); + parcel.writeInt(mMaxPacketSize); + parcel.writeInt(mInterval); + } +} diff --git a/core/java/android/hardware/UsbInterface.aidl b/core/java/android/hardware/UsbInterface.aidl new file mode 100644 index 0000000..a715ccd --- /dev/null +++ b/core/java/android/hardware/UsbInterface.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 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.hardware; + +parcelable UsbInterface; diff --git a/core/java/android/hardware/UsbInterface.java b/core/java/android/hardware/UsbInterface.java new file mode 100644 index 0000000..deef81f --- /dev/null +++ b/core/java/android/hardware/UsbInterface.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 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.hardware; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class representing an interface on a {@link android.hardware.UsbDevice}. + */ +public final class UsbInterface implements Parcelable { + + private int mId; + private int mClass; + private int mSubclass; + private int mProtocol; + private UsbDevice mDevice; + private Parcelable[] mEndpoints; + + private UsbInterface() { + } + + /** + * UsbInterface should only be instantiated by UsbService implementation + * @hide + */ + public UsbInterface(int id, int Class, int subClass, int protocol, + Parcelable[] endpoints) { + mId = id; + mClass = Class; + mSubclass = subClass; + mProtocol = protocol; + mEndpoints = endpoints; + } + + /** + * Returns the interface's ID field. + * + * @return the interface's ID + */ + public int getId() { + return mId; + } + + /** + * Returns the interface's class field. + * Some useful constants for USB classes can be found in + * {@link android.hardware.UsbConstants} + * + * @return the interface's class + */ + public int getInterfaceClass() { + return mClass; + } + + /** + * Returns the interface's subclass field. + * + * @return the interface's subclass + */ + public int getInterfaceSubclass() { + return mSubclass; + } + + /** + * Returns the interface's protocol field. + * + * @return the interface's protocol + */ + public int getInterfaceProtocol() { + return mProtocol; + } + + /** + * Returns the number of {@link android.hardware.UsbEndpoint}s this interface contains. + * + * @return the number of endpoints + */ + public int getEndpointCount() { + return mEndpoints.length; + } + + /** + * Returns the {@link android.hardware.UsbEndpoint} at the given index. + * + * @return the endpoint + */ + public UsbEndpoint getEndpoint(int index) { + return (UsbEndpoint)mEndpoints[index]; + } + + /** + * Returns the {@link android.hardware.UsbDevice} this interface belongs to. + * + * @return the interface's device + */ + public UsbDevice getDevice() { + return mDevice; + } + + // only used for parcelling + /* package */ void setDevice(UsbDevice device) { + mDevice = device; + } + + @Override + public String toString() { + return "UsbInterface[mId=" + mId + ",mClass=" + mClass + + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol + + ",mEndpoints=" + mEndpoints + "]"; + } + + public static final Parcelable.Creator<UsbInterface> CREATOR = + new Parcelable.Creator<UsbInterface>() { + public UsbInterface createFromParcel(Parcel in) { + int id = in.readInt(); + int Class = in.readInt(); + int subClass = in.readInt(); + int protocol = in.readInt(); + Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader()); + UsbInterface result = new UsbInterface(id, Class, subClass, protocol, endpoints); + for (int i = 0; i < endpoints.length; i++) { + ((UsbEndpoint)endpoints[i]).setInterface(result); + } + return result; + } + + public UsbInterface[] newArray(int size) { + return new UsbInterface[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mId); + parcel.writeInt(mClass); + parcel.writeInt(mSubclass); + parcel.writeInt(mProtocol); + parcel.writeParcelableArray(mEndpoints, 0); + } +} diff --git a/core/java/android/hardware/UsbManager.java b/core/java/android/hardware/UsbManager.java index 18790d2..8fad210 100644 --- a/core/java/android/hardware/UsbManager.java +++ b/core/java/android/hardware/UsbManager.java @@ -17,17 +17,31 @@ package android.hardware; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.util.HashMap; /** - * Class for accessing USB state information. - * @hide + * This class allows you to access the state of USB, both in host and device mode. + * + * <p>You can obtain an instance of this class by calling + * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. + * + * {@samplecode + * UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); + * } */ public class UsbManager { + private static final String TAG = "UsbManager"; + /** - * Broadcast Action: A sticky broadcast for USB state change events. + * Broadcast Action: A sticky broadcast for USB state change events when in device mode. * * This is a sticky broadcast for clients that includes USB connected/disconnected state, * the USB configuration that is currently set and a bundle containing name/value pairs @@ -39,6 +53,22 @@ public class UsbManager { public static final String ACTION_USB_STATE = "android.hardware.action.USB_STATE"; + /** + * Broadcast Action: A broadcast for USB device attached event. + * + * This intent is sent when a USB device is attached to the USB bus when in host mode. + */ + public static final String ACTION_USB_DEVICE_ATTACHED = + "android.hardware.action.USB_DEVICE_ATTACHED"; + + /** + * Broadcast Action: A broadcast for USB device detached event. + * + * This intent is sent when a USB device is detached from the USB bus when in host mode. + */ + public static final String ACTION_USB_DEVICE_DETACHED = + "android.hardware.action.USB_DEVICE_DETACHED"; + /** * Boolean extra indicating whether USB is connected or disconnected. * Used in extras for the {@link #ACTION_USB_STATE} broadcast. @@ -87,6 +117,103 @@ public class UsbManager { */ public static final String USB_FUNCTION_DISABLED = "disabled"; + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and + * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts + * containing the device's ID (String). + */ + public static final String EXTRA_DEVICE_NAME = "device_name"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the device's vendor ID (int). + */ + public static final String EXTRA_VENDOR_ID = "vendor_id"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the device's product ID (int). + */ + public static final String EXTRA_PRODUCT_ID = "product_id"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the device's class (int). + */ + public static final String EXTRA_DEVICE_CLASS = "device_class"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the device's class (int). + */ + public static final String EXTRA_DEVICE_SUBCLASS = "device_subclass"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the device's class (int). + */ + public static final String EXTRA_DEVICE_PROTOCOL = "device_protocol"; + + /** + * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} broadcast + * containing the UsbDevice object for the device. + */ + public static final String EXTRA_DEVICE = "device"; + + private IUsbManager mService; + + /** + * {@hide} + */ + public UsbManager(IUsbManager service) { + mService = service; + } + + /** + * Returns a HashMap containing all USB devices currently attached. + * USB device name is the key for the returned HashMap. + * The result will be empty if no devices are attached, or if + * USB host mode is inactive or unsupported. + * + * @return HashMap containing all connected USB devices. + */ + public HashMap<String,UsbDevice> getDeviceList() { + Bundle bundle = new Bundle(); + try { + mService.getDeviceList(bundle); + HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>(); + for (String name : bundle.keySet()) { + result.put(name, (UsbDevice)bundle.get(name)); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getDeviceList", e); + return null; + } + } + + /** + * Opens the device so it can be used to send and receive + * data using {@link android.hardware.UsbRequest}. + * + * @param device the device to open + * @return true if we successfully opened the device + */ + public boolean openDevice(UsbDevice device) { + try { + ParcelFileDescriptor pfd = mService.openDevice(device.getDeviceName()); + if (pfd == null) { + return false; + } + boolean result = device.open(pfd); + pfd.close(); + return result; + } catch (Exception e) { + Log.e(TAG, "exception in UsbManager.openDevice", e); + return false; + } + } + private static File getFunctionEnableFile(String function) { return new File("/sys/class/usb_composite/" + function + "/enable"); } @@ -94,6 +221,9 @@ public class UsbManager { /** * Returns true if the specified USB function is supported by the kernel. * Note that a USB function maybe supported but disabled. + * + * @param function name of the USB function + * @return true if the USB function is supported. */ public static boolean isFunctionSupported(String function) { return getFunctionEnableFile(function).exists(); @@ -101,6 +231,9 @@ public class UsbManager { /** * Returns true if the specified USB function is currently enabled. + * + * @param function name of the USB function + * @return true if the USB function is enabled. */ public static boolean isFunctionEnabled(String function) { try { diff --git a/core/java/android/hardware/UsbRequest.java b/core/java/android/hardware/UsbRequest.java new file mode 100644 index 0000000..ae3a289 --- /dev/null +++ b/core/java/android/hardware/UsbRequest.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2010 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.hardware; + +import android.util.Log; + +import java.nio.ByteBuffer; + +/** + * A class representing USB request packet. + * This can be used for both reading and writing data to or from a + * {@link android.hardware.UsbDevice}. + * UsbRequests are sent asynchronously via {@link #queue} and the results + * are read by {@link android.hardware.UsbDevice#requestWait}. + */ +public class UsbRequest { + + private static final String TAG = "UsbRequest"; + + // used by the JNI code + private int mNativeContext; + + private UsbEndpoint mEndpoint; + + // for temporarily saving current buffer across queue and dequeue + private ByteBuffer mBuffer; + private int mLength; + + // for client use + private Object mClientData; + + public UsbRequest() { + } + + /** + * Initializes the request so it can read or write data on the given endpoint. + * Whether the request allows reading or writing depends on the direction of the endpoint. + * + * @param endpoint the endpoint to be used for this request. + * @return true if the request was successfully opened. + */ + public boolean initialize(UsbEndpoint endpoint) { + mEndpoint = endpoint; + return native_init(endpoint.getDevice(), + endpoint.getAddress(), endpoint.getAttributes(), + endpoint.getMaxPacketSize(), endpoint.getInterval()); + } + + /** + * Releases all resources related to this request. + */ + public void close() { + mEndpoint = null; + native_close(); + } + + @Override + protected void finalize() throws Throwable { + try { + if (mEndpoint != null) { + Log.v(TAG, "endpoint still open in finalize(): " + this); + close(); + } + } finally { + super.finalize(); + } + } + + /** + * Returns the endpoint for the request, or null if the request is not opened. + * + * @return the request's endpoint + */ + public UsbEndpoint getEndpoint() { + return mEndpoint; + } + + /** + * Returns the client data for the request. + * This can be used in conjunction with {@link #setClientData} + * to associate another object with this request, which can be useful for + * maintaining state between calls to {@link #queue} and + * {@link android.hardware.UsbDevice#requestWait} + * + * @return the client data for the request + */ + public Object getClientData() { + return mClientData; + } + + /** + * Sets the client data for the request. + * This can be used in conjunction with {@link #getClientData} + * to associate another object with this request, which can be useful for + * maintaining state between calls to {@link #queue} and + * {@link android.hardware.UsbDevice#requestWait} + * + * @param data the client data for the request + */ + public void setClientData(Object data) { + mClientData = data; + } + + /** + * Queues the request to send or receive data on its endpoint. + * For OUT endpoints, the given buffer data will be sent on the endpoint. + * For IN endpoints, the endpoint will attempt to read the given number of bytes + * into the specified buffer. + * If the queueing operation is successful, we return true and the result will be + * returned via {@link android.hardware.UsbDevice#requestWait} + * + * @param buffer the buffer containing the bytes to write, or location to store + * the results of a read + * @param length number of bytes to read or write + * @return true if the queueing operation succeeded + */ + public boolean queue(ByteBuffer buffer, int length) { + boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT); + boolean result; + if (buffer.isDirect()) { + result = native_queue_direct(buffer, length, out); + } else if (buffer.hasArray()) { + result = native_queue_array(buffer.array(), length, out); + } else { + throw new IllegalArgumentException("buffer is not direct and has no array"); + } + if (result) { + // save our buffer for when the request has completed + mBuffer = buffer; + mLength = length; + } + return result; + } + + /* package */ void dequeue() { + boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT); + if (mBuffer.isDirect()) { + native_dequeue_direct(); + } else { + native_dequeue_array(mBuffer.array(), mLength, out); + } + mBuffer = null; + mLength = 0; + } + + /** + * Cancels a pending queue operation. + * + * @return true if cancelling succeeded + */ + public boolean cancel() { + return native_cancel(); + } + + private native boolean native_init(UsbDevice device, int ep_address, int ep_attributes, + int ep_max_packet_size, int ep_interval); + private native void native_close(); + private native boolean native_queue_array(byte[] buffer, int length, boolean out); + private native void native_dequeue_array(byte[] buffer, int length, boolean out); + private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out); + private native void native_dequeue_direct(); + private native boolean native_cancel(); +} diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 9c81c19..e2660e4 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcelable; import android.os.Parcel; +import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. @@ -65,10 +66,7 @@ public class DhcpInfo implements Parcelable { } private static void putAddress(StringBuffer buf, int addr) { - buf.append(addr & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff); + buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress()); } /** Implement the Parcelable interface {@hide} */ diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java new file mode 100644 index 0000000..7d9bd52 --- /dev/null +++ b/core/java/android/net/DhcpInfoInternal.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 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.net; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.UnknownHostException; + +/** + * A simple object for retrieving the results of a DHCP request. + * Replaces (internally) the IPv4-only DhcpInfo class. + * @hide + */ +public class DhcpInfoInternal { + public String ipAddress; + public String gateway; + public int prefixLength; + + public String dns1; + public String dns2; + + public String serverAddress; + public int leaseDuration; + + public DhcpInfoInternal() { + } + + private int convertToInt(String addr) { + try { + InetAddress inetAddress = NetworkUtils.numericToInetAddress(addr); + if (inetAddress instanceof Inet4Address) { + return NetworkUtils.inetAddressToInt(inetAddress); + } + } catch (IllegalArgumentException e) {} + return 0; + } + + public DhcpInfo makeDhcpInfo() { + DhcpInfo info = new DhcpInfo(); + info.ipAddress = convertToInt(ipAddress); + info.gateway = convertToInt(gateway); + try { + InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress); + info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength); + } catch (IllegalArgumentException e) {} + info.dns1 = convertToInt(dns1); + info.dns2 = convertToInt(dns2); + info.serverAddress = convertToInt(serverAddress); + info.leaseDuration = leaseDuration; + return info; + } + + public LinkAddress makeLinkAddress() { + return new LinkAddress(NetworkUtils.numericToInetAddress(ipAddress), prefixLength); + } + + public LinkProperties makeLinkProperties() { + LinkProperties p = new LinkProperties(); + p.addLinkAddress(makeLinkAddress()); + p.setGateway(NetworkUtils.numericToInetAddress(gateway)); + p.addDns(NetworkUtils.numericToInetAddress(dns1)); + p.addDns(NetworkUtils.numericToInetAddress(dns2)); + return p; + } + + public String toString() { + return "addr: " + ipAddress + "/" + prefixLength + + " gateway: " + gateway + + " dns: " + dns1 + "," + dns2 + + " dhcpServer: " + serverAddress + + " leaseDuration: " + leaseDuration; + } +} diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 8a653dd..1c48e7d 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -77,7 +77,7 @@ public class NetworkUtils { * the IP address information. * @return {@code true} for success, {@code false} for failure */ - public native static boolean runDhcp(String interfaceName, DhcpInfo ipInfo); + public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo); /** * Shut down the DHCP client daemon. @@ -104,45 +104,20 @@ public class NetworkUtils { public native static String getDhcpError(); /** - * When static IP configuration has been specified, configure the network - * interface according to the values supplied. - * @param interfaceName the name of the interface to configure - * @param ipInfo the IP address, default gateway, and DNS server addresses - * with which to configure the interface. - * @return {@code true} for success, {@code false} for failure - */ - public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) { - return configureNative(interfaceName, - ipInfo.ipAddress, - ipInfo.netmask, - ipInfo.gateway, - ipInfo.dns1, - ipInfo.dns2); - } - - private native static boolean configureNative( - String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2); - - /** * Convert a IPv4 address from an integer to an InetAddress. - * @param hostAddr is an Int corresponding to the IPv4 address in network byte order - * @return the IP address as an {@code InetAddress}, returns null if - * unable to convert or if the int is an invalid address. + * @param hostAddress an int corresponding to the IPv4 address in network byte order */ public static InetAddress intToInetAddress(int hostAddress) { - InetAddress inetAddress; byte[] addressBytes = { (byte)(0xff & hostAddress), (byte)(0xff & (hostAddress >> 8)), (byte)(0xff & (hostAddress >> 16)), (byte)(0xff & (hostAddress >> 24)) }; try { - inetAddress = InetAddress.getByAddress(addressBytes); - } catch(UnknownHostException e) { - return null; + return InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + throw new AssertionError(); } - - return inetAddress; } /** @@ -175,6 +150,29 @@ public class NetworkUtils { } /** + * Create an InetAddress from a string where the string must be a standard + * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure + * but it will throw an IllegalArgumentException in that case. + * @param addrString + * @return the InetAddress + * @hide + */ + public static InetAddress numericToInetAddress(String addrString) + throws IllegalArgumentException { + // TODO - do this for real, using a hidden method on InetAddress that aborts + // instead of doing dns step + if (!InetAddress.isNumeric(addrString)) { + throw new IllegalArgumentException("numericToInetAddress with non numeric: " + + addrString); + } + try { + return InetAddress.getByName(addrString); + } catch (UnknownHostException e) { + throw new IllegalArgumentException(e); + } + } + + /** * Add a default route through the specified gateway. * @param interfaceName interface on which the route should be added * @param gw the IP address of the gateway to which the route is desired, diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 6d19f41..4991914 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -244,7 +244,7 @@ public class RecoverySystem { // algorithm is used by the signature (which should be // SHA1withRSA). - String da = sigInfo.getdigestAlgorithm(); + String da = sigInfo.getDigestAlgorithm(); String dea = sigInfo.getDigestEncryptionAlgorithm(); String alg = null; if (da == null || dea == null) { diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 013edd3..5557a0d 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -466,6 +466,12 @@ public final class Downloads { public static final int DESTINATION_SYSTEMCACHE_PARTITION = 5; /** + * This download was completed by the caller (i.e., NOT downloadmanager) + * and caller wants to have this download displayed in Downloads App. + */ + public static final int DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD = 6; + + /** * This download is allowed to run. */ public static final int CONTROL_RUN = 0; diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 7456acd..cd3bc3e 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -648,8 +648,7 @@ class BluetoothEventLoop { } else { Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address); } - } else if (BluetoothUuid.isInputDevice(uuid) && !isOtherInputDeviceConnected(address) && - isKeyboard(address)) { + } else if (BluetoothUuid.isInputDevice(uuid) && !isOtherInputDeviceConnected(address)) { BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext); authorized = inputDevice.getInputDevicePriority(device) > BluetoothInputDevice.PRIORITY_OFF; @@ -668,17 +667,6 @@ class BluetoothEventLoop { return authorized; } - private boolean isKeyboard(String address) { - BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address)); - int btDeviceClass = btClass.getDeviceClass(); - if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || - btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { - return true; - } - log("Incoming Connect: Input device class: " + btDeviceClass + " Not a keyboard"); - return false; - } - private boolean isOtherInputDeviceConnected(String address) { List<BluetoothDevice> devices = mBluetoothService.lookupInputDevicesMatchingStates(new int[] { diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 115370b..943a3ff 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -1727,15 +1727,6 @@ public class BluetoothService extends IBluetooth.Stub { getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) { return false; } - - BluetoothClass btClass = new BluetoothClass(getRemoteClass(device.getAddress())); - int btDeviceClass = btClass.getDeviceClass(); - if (btDeviceClass != BluetoothClass.Device.PERIPHERAL_KEYBOARD && - btDeviceClass != BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { - log("Input device btDeviceClass: " + btDeviceClass + " Not a keyboard"); - return false; - } - BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); if (state != null) { Message msg = new Message(); diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index baaa3ce..5ae65df 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -17,32 +17,33 @@ package android.text.format; import android.content.Context; +import android.net.NetworkUtils; /** * Utility class to aid in formatting common values that are not covered - * by the standard java.util.Formatter. + * by {@link java.util.Formatter} */ public final class Formatter { /** * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc - * + * * @param context Context to use to load the localized units - * @param number size value to be formated - * @return formated string with the number + * @param number size value to be formatted + * @return formatted string with the number */ public static String formatFileSize(Context context, long number) { return formatFileSize(context, number, false); } - + /** * Like {@link #formatFileSize}, but trying to generate shorter numbers - * (showing fewer digits of precisin). + * (showing fewer digits of precision). */ public static String formatShortFileSize(Context context, long number) { return formatFileSize(context, number, true); } - + private static String formatFileSize(Context context, long number, boolean shorter) { if (context == null) { return ""; @@ -92,21 +93,21 @@ public final class Formatter { getString(com.android.internal.R.string.fileSizeSuffix, value, context.getString(suffix)); } - + /** * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing * the IP address. The IP address is expected to be in little-endian format (LSB first). That * is, 0x01020304 will return "4.3.2.1". - * - * @param addr the IP address as a packed integer with LSB first. + * + * @param ipv4Address the IP address as a packed integer with LSB first. * @return string with canonical IP address format. + * + * @deprecated this method doesn't support IPv6 addresses. Prefer {@link + * java.net.InetAddress#getHostAddress()}, which supports both IPv4 and + * IPv6 addresses. */ - public static String formatIpAddress(int addr) { - StringBuffer buf = new StringBuffer(); - buf.append(addr & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff); - return buf.toString(); + @Deprecated + public static String formatIpAddress(int ipv4Address) { + return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress(); } } diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index dd04975..e799f76 100755 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -98,7 +98,16 @@ public final class InputDevice implements Parcelable { * Use {@link #getMotionRange} to query the range of positions. */ public static final int SOURCE_CLASS_POSITION = 0x00000008; - + + /** + * The input source is a joystick. + * + * A {@link MotionEvent} should be interpreted as absolute joystick movements. + * + * Use {@link #getMotionRange} to query the range of positions. + */ + public static final int SOURCE_CLASS_JOYSTICK = 0x00000010; + /** * The input source is unknown. */ @@ -117,7 +126,15 @@ public final class InputDevice implements Parcelable { * @see #SOURCE_CLASS_BUTTON */ public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON; - + + /** + * The input source is a game pad. + * (It may also be a {@link #SOURCE_JOYSTICK}). + * + * @see #SOURCE_CLASS_BUTTON + */ + public static final int SOURCE_GAMEPAD = 0x00000400 | SOURCE_CLASS_BUTTON; + /** * The input source is a touch screen pointing device. * @@ -148,7 +165,15 @@ public final class InputDevice implements Parcelable { * @see #SOURCE_CLASS_POSITION */ public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION; - + + /** + * The input source is a joystick. + * (It may also be a {@link #SOURCE_GAMEPAD}). + * + * @see #SOURCE_CLASS_JOYSTICK + */ + public static final int SOURCE_JOYSTICK = 0x01000000 | SOURCE_CLASS_JOYSTICK; + /** * A special input source constant that is used when filtering input devices * to match devices that provide any type of input source. diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 941331a..766969a 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -533,8 +533,40 @@ public class KeyEvent extends InputEvent implements Parcelable { /** Key code constant: App switch key. * Should bring up the application switcher dialog. */ public static final int KEYCODE_APP_SWITCH = 187; - - private static final int LAST_KEYCODE = KEYCODE_APP_SWITCH; + /** Key code constant: Generic Game Pad Button #1.*/ + public static final int KEYCODE_BUTTON_1 = 188; + /** Key code constant: Generic Game Pad Button #2.*/ + public static final int KEYCODE_BUTTON_2 = 189; + /** Key code constant: Generic Game Pad Button #3.*/ + public static final int KEYCODE_BUTTON_3 = 190; + /** Key code constant: Generic Game Pad Button #4.*/ + public static final int KEYCODE_BUTTON_4 = 191; + /** Key code constant: Generic Game Pad Button #5.*/ + public static final int KEYCODE_BUTTON_5 = 192; + /** Key code constant: Generic Game Pad Button #6.*/ + public static final int KEYCODE_BUTTON_6 = 193; + /** Key code constant: Generic Game Pad Button #7.*/ + public static final int KEYCODE_BUTTON_7 = 194; + /** Key code constant: Generic Game Pad Button #8.*/ + public static final int KEYCODE_BUTTON_8 = 195; + /** Key code constant: Generic Game Pad Button #9.*/ + public static final int KEYCODE_BUTTON_9 = 196; + /** Key code constant: Generic Game Pad Button #10.*/ + public static final int KEYCODE_BUTTON_10 = 197; + /** Key code constant: Generic Game Pad Button #11.*/ + public static final int KEYCODE_BUTTON_11 = 198; + /** Key code constant: Generic Game Pad Button #12.*/ + public static final int KEYCODE_BUTTON_12 = 199; + /** Key code constant: Generic Game Pad Button #13.*/ + public static final int KEYCODE_BUTTON_13 = 200; + /** Key code constant: Generic Game Pad Button #14.*/ + public static final int KEYCODE_BUTTON_14 = 201; + /** Key code constant: Generic Game Pad Button #15.*/ + public static final int KEYCODE_BUTTON_15 = 202; + /** Key code constant: Generic Game Pad Button #16.*/ + public static final int KEYCODE_BUTTON_16 = 203; + + private static final int LAST_KEYCODE = KEYCODE_BUTTON_16; // NOTE: If you add a new keycode here you must also add it to: // isSystem() @@ -741,6 +773,22 @@ public class KeyEvent extends InputEvent implements Parcelable { "KEYCODE_PROG_YELLOW", "KEYCODE_PROG_BLUE", "KEYCODE_APP_SWITCH", + "KEYCODE_BUTTON_1", + "KEYCODE_BUTTON_2", + "KEYCODE_BUTTON_3", + "KEYCODE_BUTTON_4", + "KEYCODE_BUTTON_5", + "KEYCODE_BUTTON_6", + "KEYCODE_BUTTON_7", + "KEYCODE_BUTTON_8", + "KEYCODE_BUTTON_9", + "KEYCODE_BUTTON_10", + "KEYCODE_BUTTON_11", + "KEYCODE_BUTTON_12", + "KEYCODE_BUTTON_13", + "KEYCODE_BUTTON_14", + "KEYCODE_BUTTON_15", + "KEYCODE_BUTTON_16", }; // Symbolic names of all metakeys in bit order from least significant to most significant. diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index b95de64..5db4895 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -26,7 +26,8 @@ import android.os.SystemClock; * class may hold either absolute or relative movements, depending on what * it is being used for. * <p> - * On pointing devices such as touch screens, pointer coordinates specify absolute + * On pointing devices with source class {@link InputDevice#SOURCE_CLASS_POINTER} + * such as touch screens, the pointer coordinates specify absolute * positions such as view X/Y coordinates. Each complete gesture is represented * by a sequence of motion events with actions that describe pointer state transitions * and movements. A gesture starts with a motion event with {@link #ACTION_DOWN} @@ -38,11 +39,18 @@ import android.os.SystemClock; * by a motion event with {@link #ACTION_UP} or when gesture is canceled * with {@link #ACTION_CANCEL}. * </p><p> - * On trackballs, the pointer coordinates specify relative movements as X/Y deltas. + * On trackball devices with source class {@link InputDevice#SOURCE_CLASS_TRACKBALL}, + * the pointer coordinates specify relative movements as X/Y deltas. * A trackball gesture consists of a sequence of movements described by motion * events with {@link #ACTION_MOVE} interspersed with occasional {@link #ACTION_DOWN} * or {@link #ACTION_UP} motion events when the trackball button is pressed or released. * </p><p> + * On joystick devices with source class {@link InputDevice#SOURCE_CLASS_JOYSTICK}, + * the pointer coordinates specify the absolute position of the joystick axes. + * The joystick axis values are normalized to a range of -1.0 to 1.0 where 0.0 corresponds + * to the center position. More information about the set of available axes and the + * range of motion can be obtained using {@link InputDevice#getMotionRange}. + * </p><p> * Motion events always report movements for all pointers at once. The number * of pointers only ever changes by one as individual pointers go up and down, * except when the gesture is canceled. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c64f564..fc999b0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4530,6 +4530,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Pass a generic motion event down to the focused view. + * + * @param event The motion event to be dispatched. + * @return True if the event was handled by the view, false otherwise. + */ + public boolean dispatchGenericMotionEvent(MotionEvent event) { + return onGenericMotionEvent(event); + } + + /** * Called when the window containing this view gains or loses window focus. * ViewGroups should override to route to their children. * @@ -5036,6 +5046,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Implement this method to handle generic motion events. + * <p> + * Generic motion events are dispatched to the focused view to describe + * the motions of input devices such as joysticks. The + * {@link MotionEvent#getSource() source} of the motion event specifies + * the class of input that was received. Implementations of this method + * must examine the bits in the source before processing the event. + * The following code example shows how this is done. + * </p> + * <code> + * public boolean onGenericMotionEvent(MotionEvent event) { + * if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { + * float x = event.getX(); + * float y = event.getY(); + * // process the joystick motion + * return true; + * } + * return super.onGenericMotionEvent(event); + * } + * </code> + * + * @param event The generic motion event being processed. + * + * @return Return true if you have consumed the event, false if you haven't. + * The default implementation always returns false. + */ + public boolean onGenericMotionEvent(MotionEvent event) { + return false; + } + + /** * Implement this method to handle touch screen motion events. * * @param event The motion event. diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 1313b78..08a3272 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1141,6 +1141,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * {@inheritDoc} */ @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) { + if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { + return super.dispatchGenericMotionEvent(event); + } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { + return mFocused.dispatchGenericMotionEvent(event); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!onFilterTouchEventForSecurity(ev)) { return false; diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 41fc6c6..a8772fe 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -128,6 +128,11 @@ public final class ViewRoot extends Handler implements ViewParent, final TrackballAxis mTrackballAxisX = new TrackballAxis(); final TrackballAxis mTrackballAxisY = new TrackballAxis(); + int mLastJoystickXDirection; + int mLastJoystickYDirection; + int mLastJoystickXKeyCode; + int mLastJoystickYKeyCode; + final int[] mTmpLocation = new int[2]; final TypedValue mTmpValue = new TypedValue(); @@ -1921,6 +1926,7 @@ public final class ViewRoot extends Handler implements ViewParent, public final static int DISPATCH_DRAG_EVENT = 1015; public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016; public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017; + public final static int DISPATCH_GENERIC_MOTION = 1018; @Override public void handleMessage(Message msg) { @@ -1957,6 +1963,9 @@ public final class ViewRoot extends Handler implements ViewParent, case DISPATCH_TRACKBALL: deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0); break; + case DISPATCH_GENERIC_MOTION: + deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0); + break; case DISPATCH_APP_VISIBILITY: handleAppVisibility(msg.arg1 != 0); break; @@ -2469,6 +2478,102 @@ public final class ViewRoot extends Handler implements ViewParent, } } + private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) { + final int source = event.getSource(); + final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0; + + // If there is no view, then the event will not be handled. + if (mView == null || !mAdded) { + if (isJoystick) { + updateJoystickDirection(event, false); + } + finishGenericMotionEvent(event, sendDone, false); + return; + } + + // Deliver the event to the view. + if (mView.dispatchGenericMotionEvent(event)) { + ensureTouchMode(false); + if (isJoystick) { + updateJoystickDirection(event, false); + } + finishGenericMotionEvent(event, sendDone, true); + return; + } + + if (isJoystick) { + // Translate the joystick event into DPAD keys and try to deliver those. + updateJoystickDirection(event, true); + finishGenericMotionEvent(event, sendDone, true); + } else { + finishGenericMotionEvent(event, sendDone, false); + } + } + + private void finishGenericMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { + event.recycle(); + if (sendDone) { + finishInputEvent(handled); + } + } + + private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) { + final long time = event.getEventTime(); + final int metaState = event.getMetaState(); + final int deviceId = event.getDeviceId(); + final int source = event.getSource(); + final int xDirection = joystickAxisValueToDirection(event.getX()); + final int yDirection = joystickAxisValueToDirection(event.getY()); + + if (xDirection != mLastJoystickXDirection) { + if (mLastJoystickXKeyCode != 0) { + deliverKeyEvent(new KeyEvent(time, time, + KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState, + deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); + mLastJoystickXKeyCode = 0; + } + + mLastJoystickXDirection = xDirection; + + if (xDirection != 0 && synthesizeNewKeys) { + mLastJoystickXKeyCode = xDirection > 0 + ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT; + deliverKeyEvent(new KeyEvent(time, time, + KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState, + deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); + } + } + + if (yDirection != mLastJoystickYDirection) { + if (mLastJoystickYKeyCode != 0) { + deliverKeyEvent(new KeyEvent(time, time, + KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState, + deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); + mLastJoystickYKeyCode = 0; + } + + mLastJoystickYDirection = yDirection; + + if (yDirection != 0 && synthesizeNewKeys) { + mLastJoystickYKeyCode = yDirection > 0 + ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP; + deliverKeyEvent(new KeyEvent(time, time, + KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState, + deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false); + } + } + } + + private static int joystickAxisValueToDirection(float value) { + if (value >= 0.5f) { + return 1; + } else if (value <= -0.5f) { + return -1; + } else { + return 0; + } + } + /** * Returns true if the key is used for keyboard navigation. * @param keyEvent The key event. @@ -3111,11 +3216,7 @@ public final class ViewRoot extends Handler implements ViewParent, } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { dispatchTrackball(event, sendDone); } else { - // TODO - Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event); - if (sendDone) { - finishInputEvent(false); - } + dispatchGenericMotion(event, sendDone); } } @@ -3140,7 +3241,14 @@ public final class ViewRoot extends Handler implements ViewParent, msg.arg1 = sendDone ? 1 : 0; sendMessageAtTime(msg, event.getEventTime()); } - + + private void dispatchGenericMotion(MotionEvent event, boolean sendDone) { + Message msg = obtainMessage(DISPATCH_GENERIC_MOTION); + msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; + sendMessageAtTime(msg, event.getEventTime()); + } + public void dispatchAppVisibility(boolean visible) { Message msg = obtainMessage(DISPATCH_APP_VISIBILITY); msg.arg1 = visible ? 1 : 0; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 217e731..2095a93 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -187,6 +187,18 @@ public abstract class Window { public boolean dispatchTrackballEvent(MotionEvent event); /** + * Called to process generic motion events. At the very least your + * implementation must call + * {@link android.view.Window#superDispatchGenericMotionEvent} to do the + * standard processing. + * + * @param event The generic motion event. + * + * @return boolean Return true if this event was consumed. + */ + public boolean dispatchGenericMotionEvent(MotionEvent event); + + /** * Called to process population of {@link AccessibilityEvent}s. * * @param event The event. @@ -1101,6 +1113,14 @@ public abstract class Window { public abstract boolean superDispatchTrackballEvent(MotionEvent event); /** + * Used by custom windows, such as Dialog, to pass the generic motion event + * further down the view hierarchy. Application developers should + * not need to implement or call this. + * + */ + public abstract boolean superDispatchGenericMotionEvent(MotionEvent event); + + /** * Retrieve the top-level window decor view (containing the standard * window frame/decorations and the client's content inside of that), which * can be added as a window to the window manager. diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index e440eb9..04062fe 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -45,6 +45,8 @@ import com.android.org.bouncycastle.crypto.digests.SHA1Digest; * are attached, as appropriate, to the request for revalidation of content. The * class also manages the cache size. * + * CacheManager may only be used if your activity contains a WebView. + * * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated |
