diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /core/java/android/hardware | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'core/java/android/hardware')
-rw-r--r-- | core/java/android/hardware/Camera.java | 633 | ||||
-rw-r--r-- | core/java/android/hardware/ISensorService.aidl | 30 | ||||
-rw-r--r-- | core/java/android/hardware/SensorListener.java | 46 | ||||
-rw-r--r-- | core/java/android/hardware/SensorManager.java | 619 | ||||
-rw-r--r-- | core/java/android/hardware/package.html | 5 |
5 files changed, 1333 insertions, 0 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java new file mode 100644 index 0000000..8330750 --- /dev/null +++ b/core/java/android/hardware/Camera.java @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2008 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 java.lang.ref.WeakReference; +import java.util.HashMap; + +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +/** + * The Camera class is used to connect/disconnect with the camera service, + * set capture settings, start/stop preview, snap a picture, and retrieve + * frames for encoding for video. + * <p>There is no default constructor for this class. Use {@link #open()} to + * get a Camera object.</p> + */ +public class Camera { + private static final String TAG = "Camera"; + + // These match the enum in libs/android_runtime/android_hardware_Camera.cpp + private static final int SHUTTER_CALLBACK = 0; + private static final int RAW_PICTURE_CALLBACK = 1; + private static final int JPEG_PICTURE_CALLBACK = 2; + private static final int PREVIEW_CALLBACK = 3; + private static final int AUTOFOCUS_CALLBACK = 4; + private static final int ERROR_CALLBACK = 5; + + private int mNativeContext; // accessed by native methods + private int mListenerContext; + private EventHandler mEventHandler; + private ShutterCallback mShutterCallback; + private PictureCallback mRawImageCallback; + private PictureCallback mJpegCallback; + private PreviewCallback mPreviewCallback; + private AutoFocusCallback mAutoFocusCallback; + private ErrorCallback mErrorCallback; + + /** + * Returns a new Camera object. + */ + public static Camera open() { + return new Camera(); + } + + Camera() { + mShutterCallback = null; + mRawImageCallback = null; + mJpegCallback = null; + mPreviewCallback = null; + + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else { + mEventHandler = null; + } + + native_setup(new WeakReference<Camera>(this)); + } + + protected void finalize() { + native_release(); + } + + private native final void native_setup(Object camera_this); + private native final void native_release(); + + + /** + * Disconnects and releases the Camera object resources. + * <p>It is recommended that you call this as soon as you're done with the + * Camera object.</p> + */ + public final void release() { + native_release(); + } + + /** + * Sets the SurfaceHolder to be used for a picture preview. If the surface + * changed since the last call, the screen will blank. Nothing happens + * if the same surface is re-set. + * + * @param holder the SurfaceHolder upon which to place the picture preview + */ + public final void setPreviewDisplay(SurfaceHolder holder) { + setPreviewDisplay(holder.getSurface()); + } + + private native final void setPreviewDisplay(Surface surface); + + /** + * Used to get a copy of each preview frame. + */ + public interface PreviewCallback + { + /** + * The callback that delivers the preview frames. + * + * @param data The contents of the preview frame in getPreviewFormat() + * format. + * @param camera The Camera service object. + */ + void onPreviewFrame(byte[] data, Camera camera); + }; + + /** + * Start drawing preview frames to the surface. + */ + public native final void startPreview(); + + /** + * Stop drawing preview frames to the surface. + */ + public native final void stopPreview(); + + /** + * Can be called at any time to instruct the camera to use a callback for + * each preview frame in addition to displaying it. + * + * @param cb A callback object that receives a copy of each preview frame. + * Pass null to stop receiving callbacks at any time. + */ + public final void setPreviewCallback(PreviewCallback cb) { + mPreviewCallback = cb; + setHasPreviewCallback(cb != null); + } + private native final void setHasPreviewCallback(boolean installed); + + private class EventHandler extends Handler + { + private Camera mCamera; + + public EventHandler(Camera c, Looper looper) { + super(looper); + mCamera = c; + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case SHUTTER_CALLBACK: + if (mShutterCallback != null) { + mShutterCallback.onShutter(); + } + return; + case RAW_PICTURE_CALLBACK: + if (mRawImageCallback != null) + mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera); + return; + + case JPEG_PICTURE_CALLBACK: + if (mJpegCallback != null) + mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera); + return; + + case PREVIEW_CALLBACK: + if (mPreviewCallback != null) + mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera); + return; + + case AUTOFOCUS_CALLBACK: + if (mAutoFocusCallback != null) + mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera); + return; + + case ERROR_CALLBACK: + Log.e(TAG, "Error " + msg.arg1); + if (mErrorCallback != null) + mErrorCallback.onError(msg.arg1, mCamera); + return; + + default: + Log.e(TAG, "Unknown message type " + msg.what); + return; + } + } + } + + private static void postEventFromNative(Object camera_ref, + int what, int arg1, int arg2, Object obj) + { + Camera c = (Camera)((WeakReference)camera_ref).get(); + if (c == null) + return; + + if (c.mEventHandler != null) { + Message m = c.mEventHandler.obtainMessage(what, arg1, arg2, obj); + c.mEventHandler.sendMessage(m); + } + } + + /** + * Handles the callback for the camera auto focus. + */ + public interface AutoFocusCallback + { + /** + * Callback for the camera auto focus. + * + * @param success true if focus was successful, false if otherwise + * @param camera the Camera service object + */ + void onAutoFocus(boolean success, Camera camera); + }; + + /** + * Registers a callback to be invoked when the auto focus responds. + * + * @param cb the callback to run + */ + public final void autoFocus(AutoFocusCallback cb) + { + mAutoFocusCallback = cb; + native_autoFocus(); + } + private native final void native_autoFocus(); + + /** + * An interface which contains a callback for the shutter closing after taking a picture. + */ + public interface ShutterCallback + { + /** + * Can be used to play a shutter sound as soon as the image has been captured, but before + * the data is available. + */ + void onShutter(); + } + + /** + * Handles the callback for when a picture is taken. + */ + public interface PictureCallback { + /** + * Callback for when a picture is taken. + * + * @param data a byte array of the picture data + * @param camera the Camera service object + */ + void onPictureTaken(byte[] data, Camera camera); + }; + + /** + * Registers a callback to be invoked when a picture is taken. + * + * @param raw the callback to run for raw images, may be null + * @param jpeg the callback to run for jpeg images, may be null + */ + public final void takePicture(ShutterCallback shutter, PictureCallback raw, + PictureCallback jpeg) { + mShutterCallback = shutter; + mRawImageCallback = raw; + mJpegCallback = jpeg; + native_takePicture(); + } + private native final void native_takePicture(); + + // These match the enum in libs/android_runtime/android_hardware_Camera.cpp + /** Unspecified camerar error. @see #ErrorCallback */ + public static final int CAMERA_ERROR_UNKNOWN = 1; + /** Media server died. In this case, the application must release the + * Camera object and instantiate a new one. @see #ErrorCallback */ + public static final int CAMERA_ERROR_SERVER_DIED = 100; + + /** + * Handles the camera error callback. + */ + public interface ErrorCallback + { + /** + * Callback for camera errors. + * @param error error code: + * <ul> + * <li>{@link #CAMERA_ERROR_UNKNOWN} + * <li>{@link #CAMERA_ERROR_SERVER_DIED} + * </ul> + * @param camera the Camera service object + */ + void onError(int error, Camera camera); + }; + + /** + * Registers a callback to be invoked when an error occurs. + * @param cb the callback to run + */ + public final void setErrorCallback(ErrorCallback cb) + { + mErrorCallback = cb; + } + + private native final void native_setParameters(String params); + private native final String native_getParameters(); + + /** + * Sets the Parameters for pictures from this Camera service. + * + * @param params the Parameters to use for this Camera service + */ + public void setParameters(Parameters params) { + Log.e(TAG, "setParameters()"); + //params.dump(); + native_setParameters(params.flatten()); + } + + /** + * Returns the picture Parameters for this Camera service. + */ + public Parameters getParameters() { + Parameters p = new Parameters(); + String s = native_getParameters(); + Log.e(TAG, "_getParameters: " + s); + p.unflatten(s); + return p; + } + + /** + * Handles the picture size (dimensions). + */ + public class Size { + /** + * Sets the dimensions for pictures. + * + * @param w the photo width (pixels) + * @param h the photo height (pixels) + */ + public Size(int w, int h) { + width = w; + height = h; + } + /** width of the picture */ + public int width; + /** height of the picture */ + public int height; + }; + + /** + * Handles the parameters for pictures created by a Camera service. + */ + public class Parameters { + private HashMap<String, String> mMap; + + private Parameters() { + mMap = new HashMap<String, String>(); + } + + /** + * Writes the current Parameters to the log. + * @hide + * @deprecated + */ + public void dump() { + Log.e(TAG, "dump: size=" + mMap.size()); + for (String k : mMap.keySet()) { + Log.e(TAG, "dump: " + k + "=" + mMap.get(k)); + } + } + + /** + * Creates a single string with all the parameters set in + * this Parameters object. + * <p>The {@link #unflatten(String)} method does the reverse.</p> + * + * @return a String with all values from this Parameters object, in + * semi-colon delimited key-value pairs + */ + public String flatten() { + StringBuilder flattened = new StringBuilder(); + for (String k : mMap.keySet()) { + flattened.append(k); + flattened.append("="); + flattened.append(mMap.get(k)); + flattened.append(";"); + } + // chop off the extra semicolon at the end + flattened.deleteCharAt(flattened.length()-1); + return flattened.toString(); + } + + /** + * Takes a flattened string of parameters and adds each one to + * this Parameters object. + * <p>The {@link #flatten()} method does the reverse.</p> + * + * @param flattened a String of parameters (key-value paired) that + * are semi-colon delimited + */ + public void unflatten(String flattened) { + mMap.clear(); + String[] pairs = flattened.split(";"); + for (String p : pairs) { + String[] kv = p.split("="); + if (kv.length == 2) + mMap.put(kv[0], kv[1]); + } + } + + public void remove(String key) { + mMap.remove(key); + } + + /** + * Sets a String parameter. + * + * @param key the key name for the parameter + * @param value the String value of the parameter + */ + public void set(String key, String value) { + if (key.indexOf('=') != -1 || key.indexOf(';') != -1) { + Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)"); + return; + } + if (value.indexOf('=') != -1 || value.indexOf(';') != -1) { + Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)"); + return; + } + + mMap.put(key, value); + } + + /** + * Sets an integer parameter. + * + * @param key the key name for the parameter + * @param value the int value of the parameter + */ + public void set(String key, int value) { + mMap.put(key, Integer.toString(value)); + } + + /** + * Returns the value of a String parameter. + * + * @param key the key name for the parameter + * @return the String value of the parameter + */ + public String get(String key) { + return mMap.get(key); + } + + /** + * Returns the value of an integer parameter. + * + * @param key the key name for the parameter + * @return the int value of the parameter + */ + public int getInt(String key) { + return Integer.parseInt(mMap.get(key)); + } + + /** + * Sets the dimensions for preview pictures. + * + * @param width the width of the pictures, in pixels + * @param height the height of the pictures, in pixels + */ + public void setPreviewSize(int width, int height) { + String v = Integer.toString(width) + "x" + Integer.toString(height); + set("preview-size", v); + } + + /** + * Returns the dimensions setting for preview pictures. + * + * @return a Size object with the height and width setting + * for the preview picture + */ + public Size getPreviewSize() { + String pair = get("preview-size"); + if (pair == null) + return null; + String[] dims = pair.split("x"); + if (dims.length != 2) + return null; + + return new Size(Integer.parseInt(dims[0]), + Integer.parseInt(dims[1])); + + } + + /** + * Sets the rate at which preview frames are received. + * + * @param fps the frame rate (frames per second) + */ + public void setPreviewFrameRate(int fps) { + set("preview-frame-rate", fps); + } + + /** + * Returns the setting for the rate at which preview frames + * are received. + * + * @return the frame rate setting (frames per second) + */ + public int getPreviewFrameRate() { + return getInt("preview-frame-rate"); + } + + /** + * Sets the image format for preview pictures. + * + * @param pixel_format the desired preview picture format + * (<var>PixelFormat.YCbCr_422_SP</var>, + * <var>PixelFormat.RGB_565</var>, or + * <var>PixelFormat.JPEG</var>) + * @see android.graphics.PixelFormat + */ + public void setPreviewFormat(int pixel_format) { + String s = cameraFormatForPixelFormat(pixel_format); + if (s == null) { + throw new IllegalArgumentException(); + } + + set("preview-format", s); + } + + /** + * Returns the image format for preview pictures. + * + * @return the PixelFormat int representing the preview picture format + */ + public int getPreviewFormat() { + return pixelFormatForCameraFormat(get("preview-format")); + } + + /** + * Sets the dimensions for pictures. + * + * @param width the width for pictures, in pixels + * @param height the height for pictures, in pixels + */ + public void setPictureSize(int width, int height) { + String v = Integer.toString(width) + "x" + Integer.toString(height); + set("picture-size", v); + } + + /** + * Returns the dimension setting for pictures. + * + * @return a Size object with the height and width setting + * for pictures + */ + public Size getPictureSize() { + String pair = get("picture-size"); + if (pair == null) + return null; + String[] dims = pair.split("x"); + if (dims.length != 2) + return null; + + return new Size(Integer.parseInt(dims[0]), + Integer.parseInt(dims[1])); + + } + + /** + * Sets the image format for pictures. + * + * @param pixel_format the desired picture format + * (<var>PixelFormat.YCbCr_422_SP</var>, + * <var>PixelFormat.RGB_565</var>, or + * <var>PixelFormat.JPEG</var>) + * @see android.graphics.PixelFormat + */ + public void setPictureFormat(int pixel_format) { + String s = cameraFormatForPixelFormat(pixel_format); + if (s == null) { + throw new IllegalArgumentException(); + } + + set("picture-format", s); + } + + /** + * Returns the image format for pictures. + * + * @return the PixelFormat int representing the picture format + */ + public int getPictureFormat() { + return pixelFormatForCameraFormat(get("picture-format")); + } + + private String cameraFormatForPixelFormat(int pixel_format) { + switch(pixel_format) { + case PixelFormat.YCbCr_422_SP: return "yuv422sp"; + case PixelFormat.RGB_565: return "rgb565"; + case PixelFormat.JPEG: return "jpeg"; + default: return null; + } + } + + private int pixelFormatForCameraFormat(String format) { + if (format == null) + return PixelFormat.UNKNOWN; + + if (format.equals("yuv422sp")) + return PixelFormat.YCbCr_422_SP; + + if (format.equals("rgb565")) + return PixelFormat.RGB_565; + + if (format.equals("jpeg")) + return PixelFormat.JPEG; + + return PixelFormat.UNKNOWN; + } + + }; +} + + diff --git a/core/java/android/hardware/ISensorService.aidl b/core/java/android/hardware/ISensorService.aidl new file mode 100644 index 0000000..b6ac3ab --- /dev/null +++ b/core/java/android/hardware/ISensorService.aidl @@ -0,0 +1,30 @@ +/* //device/java/android/android/hardware/ISensorService.aidl +** +** Copyright 2008, 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.ParcelFileDescriptor; + +/** + * {@hide} + */ +interface ISensorService +{ + ParcelFileDescriptor getDataChanel(); + boolean enableSensor(IBinder listener, int sensor, int enable); + oneway void reportAccuracy(int sensor, int value); +} diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java new file mode 100644 index 0000000..d676a5e --- /dev/null +++ b/core/java/android/hardware/SensorListener.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008 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; + +/** + * Used for receiving notifications from the SensorManager when + * sensor values have changed. + */ +public interface SensorListener { + + /** + * Called when sensor values have changed. + * The length and contents of the values array vary + * depending on which sensor is being monitored. + * See {@link android.hardware.SensorManager SensorManager} + * for details on possible sensor types and values. + * + * @param sensor The ID of the sensor being monitored + * @param values The new values for the sensor + */ + public void onSensorChanged(int sensor, float[] values); + + /** + * Called when the accuracy of a sensor has changed. + * See {@link android.hardware.SensorManager SensorManager} + * for details. + * + * @param sensor The ID of the sensor being monitored + * @param accuracy The new accuracy of this sensor + */ + public void onAccuracyChanged(int sensor, int accuracy); +} diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java new file mode 100644 index 0000000..9b88fff --- /dev/null +++ b/core/java/android/hardware/SensorManager.java @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2008 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.content.Context; +import android.os.Binder; +import android.os.Looper; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.Handler; +import android.os.Message; +import android.os.ServiceManager; +import android.util.Log; +import android.view.IRotationWatcher; +import android.view.IWindowManager; +import android.view.Surface; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Class that lets you access the device's sensors. Get an instance of this + * class by calling {@link android.content.Context#getSystemService(java.lang.String) + * Context.getSystemService()} with an argument of {@link android.content.Context#SENSOR_SERVICE}. + */ +public class SensorManager extends IRotationWatcher.Stub +{ + private static final String TAG = "SensorManager"; + + /** NOTE: sensor IDs must be a power of 2 */ + + /** A constant describing an orientation sensor. + * Sensor values are yaw, pitch and roll + * + * Yaw is the compass heading in degrees, range [0, 360[ + * 0 = North, 90 = East, 180 = South, 270 = West + * + * Pitch indicates the tilt of the top of the device, + * with range -90 to 90. + * Positive values indicate that the bottom of the device is tilted up + * and negative values indicate the top of the device is tilted up. + * + * Roll indicates the side to side tilt of the device, + * with range -90 to 90. + * Positive values indicate that the left side of the device is tilted up + * and negative values indicate the right side of the device is tilted up. + */ + public static final int SENSOR_ORIENTATION = 1 << 0; + + /** A constant describing an accelerometer. + * Sensor values are acceleration in the X, Y and Z axis, + * where the X axis has positive direction toward the right side of the device, + * the Y axis has positive direction toward the top of the device + * and the Z axis has positive direction toward the front of the device. + * + * The direction of the force of gravity is indicated by acceleration values in the + * X, Y and Z axes. The typical case where the device is flat relative to the surface + * of the Earth appears as -STANDARD_GRAVITY in the Z axis + * and X and Z values close to zero. + * + * Acceleration values are given in SI units (m/s^2) + * + */ + public static final int SENSOR_ACCELEROMETER = 1 << 1; + + /** A constant describing a temperature sensor + * Only the first value is defined for this sensor and it + * contains the ambient temperature in degree C. + */ + public static final int SENSOR_TEMPERATURE = 1 << 2; + + /** A constant describing a magnetic sensor + * Sensor values are the magnetic vector in the X, Y and Z axis, + * where the X axis has positive direction toward the right side of the device, + * the Y axis has positive direction toward the top of the device + * and the Z axis has positive direction toward the front of the device. + * + * Magnetic values are given in micro-Tesla (uT) + * + */ + public static final int SENSOR_MAGNETIC_FIELD = 1 << 3; + + /** A constant describing an ambient light sensor + * Only the first value is defined for this sensor and it contains + * the ambient light measure in lux. + * + */ + public static final int SENSOR_LIGHT = 1 << 4; + + /** A constant describing a proximity sensor + * Only the first value is defined for this sensor and it contains + * the distance between the sensor and the object in meters (m) + */ + public static final int SENSOR_PROXIMITY = 1 << 5; + + /** A constant describing a Tricorder + * When this sensor is available and enabled, the device can be + * used as a fully functional Tricorder. All values are returned in + * SI units. + */ + public static final int SENSOR_TRICORDER = 1 << 6; + + /** A constant describing an orientation sensor. + * Sensor values are yaw, pitch and roll + * + * Yaw is the compass heading in degrees, 0 <= range < 360 + * 0 = North, 90 = East, 180 = South, 270 = West + * + * This is similar to SENSOR_ORIENTATION except the data is not + * smoothed or filtered in any way. + */ + public static final int SENSOR_ORIENTATION_RAW = 1 << 7; + + /** A constant that includes all sensors */ + public static final int SENSOR_ALL = 0x7F; + + /** Smallest sensor ID */ + public static final int SENSOR_MIN = SENSOR_ORIENTATION; + + /** Largest sensor ID */ + public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1); + + + /** Index of the X value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int DATA_X = 0; + /** Index of the Y value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int DATA_Y = 1; + /** Index of the Z value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int DATA_Z = 2; + + /** Offset to the raw values in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int RAW_DATA_INDEX = 3; + + /** Index of the raw X value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int RAW_DATA_X = 3; + /** Index of the raw X value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int RAW_DATA_Y = 4; + /** Index of the raw X value in the array returned by + * {@link android.hardware.SensorListener#onSensorChanged} */ + public static final int RAW_DATA_Z = 5; + + + /** Standard gravity (g) on Earth. This value is equivalent to 1G */ + public static final float STANDARD_GRAVITY = 9.80665f; + + /** values returned by the accelerometer in various locations in the universe. + * all values are in SI units (m/s^2) */ + public static final float GRAVITY_SUN = 275.0f; + public static final float GRAVITY_MERCURY = 3.70f; + public static final float GRAVITY_VENUS = 8.87f; + public static final float GRAVITY_EARTH = 9.80665f; + public static final float GRAVITY_MOON = 1.6f; + public static final float GRAVITY_MARS = 3.71f; + public static final float GRAVITY_JUPITER = 23.12f; + public static final float GRAVITY_SATURN = 8.96f; + public static final float GRAVITY_URANUS = 8.69f; + public static final float GRAVITY_NEPTUN = 11.0f; + public static final float GRAVITY_PLUTO = 0.6f; + public static final float GRAVITY_DEATH_STAR_I = 0.000000353036145f; + public static final float GRAVITY_THE_ISLAND = 4.815162342f; + + + /** Maximum magnetic field on Earth's surface */ + public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f; + + /** Minimum magnetic field on Earth's surface */ + public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f; + + + /** Various luminance values during the day (lux) */ + public static final float LIGHT_SUNLIGHT_MAX = 120000.0f; + public static final float LIGHT_SUNLIGHT = 110000.0f; + public static final float LIGHT_SHADE = 20000.0f; + public static final float LIGHT_OVERCAST = 10000.0f; + public static final float LIGHT_SUNRISE = 400.0f; + public static final float LIGHT_CLOUDY = 100.0f; + /** Various luminance values during the night (lux) */ + public static final float LIGHT_FULLMOON = 0.25f; + public static final float LIGHT_NO_MOON = 0.001f; + + /** get sensor data as fast as possible */ + public static final int SENSOR_DELAY_FASTEST = 0; + /** rate suitable for games */ + public static final int SENSOR_DELAY_GAME = 1; + /** rate suitable for the user interface */ + public static final int SENSOR_DELAY_UI = 2; + /** rate (default) suitable for screen orientation changes */ + public static final int SENSOR_DELAY_NORMAL = 3; + + + /** The values returned by this sensor cannot be trusted, calibration + * is needed or the environment doesn't allow readings */ + public static final int SENSOR_STATUS_UNRELIABLE = 0; + + /** This sensor is reporting data with low accuracy, calibration with the + * environment is needed */ + public static final int SENSOR_STATUS_ACCURACY_LOW = 1; + + /** This sensor is reporting data with an average level of accuracy, + * calibration with the environment may improve the readings */ + public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; + + /** This sensor is reporting data with maximum accuracy */ + public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; + + + + private static final int SENSOR_DISABLE = -1; + private static final int SENSOR_ORDER_MASK = 0x1F; + private static final int SENSOR_STATUS_SHIFT = 28; + private ISensorService mSensorService; + private Looper mLooper; + + private static IWindowManager sWindowManager; + private static int sRotation = 0; + + /* The thread and the sensor list are global to the process + * but the actual thread is spawned on demand */ + static final private SensorThread sSensorThread = new SensorThread(); + static final private ArrayList<ListenerDelegate> sListeners = + new ArrayList<ListenerDelegate>(); + + + static private class SensorThread { + + private Thread mThread; + + // must be called with sListeners lock + void startLocked(ISensorService service) { + try { + if (mThread == null) { + ParcelFileDescriptor fd = service.getDataChanel(); + mThread = new Thread(new SensorThreadRunnable(fd, service), + SensorThread.class.getName()); + mThread.start(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in startLocked: ", e); + } + } + + private class SensorThreadRunnable implements Runnable { + private ISensorService mSensorService; + private ParcelFileDescriptor mSensorDataFd; + private final byte mAccuracies[] = new byte[32]; + SensorThreadRunnable(ParcelFileDescriptor fd, ISensorService service) { + mSensorDataFd = fd; + mSensorService = service; + Arrays.fill(mAccuracies, (byte)-1); + } + public void run() { + int sensors_of_interest; + float[] values = new float[6]; + Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); + + synchronized (sListeners) { + _sensors_data_open(mSensorDataFd.getFileDescriptor()); + try { + mSensorDataFd.close(); + } catch (IOException e) { + // *shrug* + Log.e(TAG, "IOException: ", e); + } + mSensorDataFd = null; + //mSensorDataFd. + // the first time, compute the sensors we need. this is not + // a big deal if it changes by the time we call + // _sensors_data_poll, it'll get recomputed for the next + // round. + sensors_of_interest = 0; + final int size = sListeners.size(); + for (int i=0 ; i<size ; i++) { + sensors_of_interest |= sListeners.get(i).mSensors; + if ((sensors_of_interest & SENSOR_ALL) == SENSOR_ALL) + break; + } + } + + while (true) { + // wait for an event + final int sensor_result = _sensors_data_poll(values, sensors_of_interest); + final int sensor_order = sensor_result & SENSOR_ORDER_MASK; + final int sensor = 1 << sensor_result; + int accuracy = sensor_result>>>SENSOR_STATUS_SHIFT; + + if ((sensors_of_interest & sensor)!=0) { + // show the notification only if someone is listening for + // this sensor + if (accuracy != mAccuracies[sensor_order]) { + try { + mSensorService.reportAccuracy(sensor, accuracy); + mAccuracies[sensor_order] = (byte)accuracy; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in reportAccuracy: ", e); + } + } else { + accuracy = -1; + } + } + + synchronized (sListeners) { + if (sListeners.isEmpty()) { + // we have no more listeners, terminate the thread + _sensors_data_close(); + mThread = null; + break; + } + // convert for the current screen orientation + mapSensorDataToWindow(sensor, values, SensorManager.getRotation()); + // report the sensor event to all listeners that + // care about it. + sensors_of_interest = 0; + final int size = sListeners.size(); + for (int i=0 ; i<size ; i++) { + ListenerDelegate listener = sListeners.get(i); + sensors_of_interest |= listener.mSensors; + if (listener.hasSensor(sensor)) { + // this is asynchronous (okay to call + // with sListeners lock held. + listener.onSensorChanged(sensor, values, accuracy); + } + } + } + } + } + } + } + + private class ListenerDelegate extends Binder { + + private SensorListener mListener; + private int mSensors; + private float[] mValuesPool; + + ListenerDelegate(SensorListener listener, int sensors) { + mListener = listener; + mSensors = sensors; + mValuesPool = new float[6]; + } + + int addSensors(int sensors) { + mSensors |= sensors; + return mSensors; + } + int removeSensors(int sensors) { + mSensors &= ~sensors; + return mSensors; + } + boolean hasSensor(int sensor) { + return ((mSensors & sensor) != 0); + } + + void onSensorChanged(int sensor, float[] values, int accuracy) { + float[] v; + synchronized (this) { + // remove the array from the pool + v = mValuesPool; + mValuesPool = null; + } + + if (v != null) { + v[0] = values[0]; + v[1] = values[1]; + v[2] = values[2]; + v[3] = values[3]; + v[4] = values[4]; + v[5] = values[5]; + } else { + // the pool was empty, we need to dup the array + v = values.clone(); + } + + Message msg = Message.obtain(); + msg.what = sensor; + msg.obj = v; + msg.arg1 = accuracy; + mHandler.sendMessage(msg); + } + + private final Handler mHandler = new Handler(mLooper) { + @Override public void handleMessage(Message msg) { + if (msg.arg1 >= 0) { + try { + mListener.onAccuracyChanged(msg.what, msg.arg1); + } catch (AbstractMethodError e) { + // old app that doesn't implement this method + // just ignore it. + } + } + mListener.onSensorChanged(msg.what, (float[])msg.obj); + synchronized (this) { + // put back the array into the pool + if (mValuesPool == null) { + mValuesPool = (float[])msg.obj; + } + } + } + }; + } + + /** + * {@hide} + */ + public SensorManager(Looper mainLooper) { + mSensorService = ISensorService.Stub.asInterface( + ServiceManager.getService(Context.SENSOR_SERVICE)); + + sWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService("window")); + + if (sWindowManager != null) { + // if it's null we're running in the system process + // which won't get the rotated values + try { + sWindowManager.watchRotation(this); + } catch (RemoteException e) { + } + } + + mLooper = mainLooper; + } + + /** @return available sensors */ + public int getSensors() { + return _sensors_data_get_sensors(); + } + + /** + * Registers a listener for given sensors. + * + * @param listener sensor listener object + * @param sensors a bit masks of the sensors to register to + * + * @return true if the sensor is supported and successfully enabled + */ + public boolean registerListener(SensorListener listener, int sensors) { + return registerListener(listener, sensors, SENSOR_DELAY_NORMAL); + } + + /** + * Registers a listener for given sensors. + * + * @param listener sensor listener object + * @param sensors a bit masks of the sensors to register to + * @param rate rate of events. This is only a hint to the system. events + * may be received faster or slower than the specified rate. Usually events + * are received faster. + * + * @return true if the sensor is supported and successfully enabled + */ + public boolean registerListener(SensorListener listener, int sensors, int rate) { + boolean result; + + int delay = -1; + switch (rate) { + case SENSOR_DELAY_FASTEST: + delay = 0; + break; + case SENSOR_DELAY_GAME: + delay = 20; + break; + case SENSOR_DELAY_UI: + delay = 60; + break; + case SENSOR_DELAY_NORMAL: + delay = 200; + break; + default: + return false; + } + + try { + synchronized (sListeners) { + ListenerDelegate l = null; + for (ListenerDelegate i : sListeners) { + if (i.mListener == listener) { + l = i; + break; + } + } + + if (l == null) { + l = new ListenerDelegate(listener, sensors); + result = mSensorService.enableSensor(l, sensors, delay); + if (result) { + sListeners.add(l); + sListeners.notify(); + } + if (!sListeners.isEmpty()) { + sSensorThread.startLocked(mSensorService); + } + } else { + result = mSensorService.enableSensor(l, sensors, delay); + if (result) { + l.addSensors(sensors); + } + } + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in registerListener: ", e); + result = false; + } + return result; + } + + /** + * Unregisters a listener for the sensors with which it is registered. + * + * @param listener a SensorListener object + * @param sensors a bit masks of the sensors to unregister from + */ + public void unregisterListener(SensorListener listener, int sensors) { + try { + synchronized (sListeners) { + final int size = sListeners.size(); + for (int i=0 ; i<size ; i++) { + ListenerDelegate l = sListeners.get(i); + if (l.mListener == listener) { + // disable these sensors + mSensorService.enableSensor(l, sensors, SENSOR_DISABLE); + // if we have no more sensors enabled on this listener, + // take it off the list. + if (l.removeSensors(sensors) == 0) + sListeners.remove(i); + break; + } + } + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in unregisterListener: ", e); + } + } + + /** + * Unregisters a listener for all sensors. + * + * @param listener a SensorListener object + */ + public void unregisterListener(SensorListener listener) { + unregisterListener(listener, SENSOR_ALL); + } + + + /** + * Helper function to convert the specified sensor's data to the windows's + * coordinate space from the device's coordinate space. + */ + + private static void mapSensorDataToWindow(int sensor, float[] values, int orientation) { + final float x = values[DATA_X]; + final float y = values[DATA_Y]; + final float z = values[DATA_Z]; + // copy the raw raw values... + values[RAW_DATA_X] = x; + values[RAW_DATA_Y] = y; + values[RAW_DATA_Z] = z; + // TODO: add support for 180 and 270 orientations + if (orientation == Surface.ROTATION_90) { + switch (sensor) { + case SENSOR_ACCELEROMETER: + case SENSOR_MAGNETIC_FIELD: + values[DATA_X] =-y; + values[DATA_Y] = x; + values[DATA_Z] = z; + break; + case SENSOR_ORIENTATION: + case SENSOR_ORIENTATION_RAW: + values[DATA_X] = x + ((x < 270) ? 90 : -270); + values[DATA_Y] = z; + values[DATA_Z] = y; + break; + } + } + } + + + private static native int _sensors_data_open(FileDescriptor fd); + private static native int _sensors_data_close(); + // returns the sensor's status in the top 4 bits of "res". + private static native int _sensors_data_poll(float[] values, int sensors); + private static native int _sensors_data_get_sensors(); + + /** {@hide} */ + public void onRotationChanged(int rotation) { + synchronized(sListeners) { + sRotation = rotation; + } + } + + private static int getRotation() { + synchronized(sListeners) { + return sRotation; + } + } +} + diff --git a/core/java/android/hardware/package.html b/core/java/android/hardware/package.html new file mode 100644 index 0000000..06788a6 --- /dev/null +++ b/core/java/android/hardware/package.html @@ -0,0 +1,5 @@ +<HTML> +<BODY> +Provides support for hardware devices that may not be present on every Android device. +</BODY> +</HTML> |