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 /services/java/com/android/server/SensorService.java |
Initial Contribution
Diffstat (limited to 'services/java/com/android/server/SensorService.java')
-rw-r--r-- | services/java/com/android/server/SensorService.java | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java new file mode 100644 index 000000000000..f4b3f87f75e6 --- /dev/null +++ b/services/java/com/android/server/SensorService.java @@ -0,0 +1,219 @@ +/* + * 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 com.android.server; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.hardware.ISensorService; +import android.hardware.SensorManager; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.SystemProperties; +import android.util.Config; +import android.util.Log; +import com.android.internal.R; + +import java.util.ArrayList; + + +/** + * Class that manages the device's sensors. It register clients and activate + * the needed sensors. The sensor events themselves are not broadcasted from + * this service, instead, a file descriptor is provided to each client they + * can read events from. + */ + +class SensorService extends ISensorService.Stub { + private static final int SENSOR_NOTIFICATION_ACCURACY_LEVEL = 1; + private static final String TAG = SensorService.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + private static final int SENSOR_DISABLE = -1; + private NotificationManager mNotificationManager; + private int mCompassAccuracy = -1; + private final Context mContext; + + private final class Listener implements IBinder.DeathRecipient { + final IBinder mListener; + + int mSensors = 0; + int mDelay = 0x7FFFFFFF; + + Listener(IBinder listener) { + mListener = listener; + } + + void addSensor(int sensor, int delay) { + mSensors |= sensor; + if (mDelay > delay) + mDelay = delay; + } + + void removeSensor(int sensor) { + mSensors &= ~sensor; + } + + boolean hasSensor(int sensor) { + return ((mSensors & sensor) != 0); + } + + public void binderDied() { + if (localLOGV) Log.d(TAG, "sensor listener died"); + + synchronized(mListeners) { + mListeners.remove(this); + for (int sensor = SensorManager.SENSOR_MAX; sensor > 0; sensor >>>= 1) { + if (hasSensor(sensor)) { + try { + deactivateIfUnused(sensor); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in binderDied"); + } + } + } + mListeners.notify(); + } + } + } + + public SensorService(Context context) { + if (localLOGV) Log.d(TAG, "SensorService startup"); + _sensors_control_init(); + mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + mContext = context; + } + + public ParcelFileDescriptor getDataChanel() throws RemoteException { + return _sensors_control_open(); + } + + public void reportAccuracy(int sensor, int value) { + if ((sensor & (SensorManager.SENSOR_ORIENTATION|SensorManager.SENSOR_ORIENTATION_RAW)) != 0) { + synchronized (mNotificationManager) { + if (value != mCompassAccuracy) { + Log.d(TAG, "Compass needs calibration, accuracy=" + value); + if (!SystemProperties.getBoolean("debug.sensors.notification", false)) { + // don't show the sensors notification by default + return; + } + mCompassAccuracy = value; + if (value == -1) { + mNotificationManager.cancel(0); + } else { + if (value <= SENSOR_NOTIFICATION_ACCURACY_LEVEL) { + long token = Binder.clearCallingIdentity(); + try { + CharSequence banner = mContext.getString(R.string.compass_accuracy_banner); + CharSequence title = mContext.getString(R.string.compass_accuracy_notificaction_title); + CharSequence body = mContext.getString(R.string.compass_accuracy_notificaction_body); + Notification n = new Notification(R.drawable.stat_notify_calibrate_compass, + banner, System.currentTimeMillis()); + Intent bogusIntent = new Intent(mContext, SensorService.class); + PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, bogusIntent, + PendingIntent.FLAG_CANCEL_CURRENT|PendingIntent.FLAG_ONE_SHOT); + n.setLatestEventInfo(mContext, title, body, contentIntent); + mNotificationManager.notify(0, n); + } finally { + Binder.restoreCallingIdentity(token); + } + } else { + mNotificationManager.cancel(0); + } + } + } + } + } + } + + public boolean enableSensor(IBinder listener, int sensor, int enable) + throws RemoteException { + if (localLOGV) Log.d(TAG, "enableSensor " + sensor + " " + enable); + + if (listener == null) throw new NullPointerException("listener is null in enableSensor"); + + synchronized(mListeners) { + if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { + Log.w(TAG, "could not enable sensor " + sensor); + return false; + } + + IBinder binder = listener; + Listener l = null; + + int minDelay = enable; + int size = mListeners.size(); + for (int i = 0; i < size ; i++) { + Listener test = mListeners.get(i); + if (binder.equals(test.mListener)) { + l = test; + } + if (minDelay > test.mDelay) + minDelay = test.mDelay; + } + + if (l == null && enable!=SENSOR_DISABLE) { + l = new Listener(listener); + binder.linkToDeath(l, 0); + mListeners.add(l); + mListeners.notify(); + } + + if (l == null) { + throw new NullPointerException("no Listener object in enableSensor"); + } + + if (minDelay >= 0) { + _sensors_control_set_delay(minDelay); + } + + if (enable != SENSOR_DISABLE) { + l.addSensor(sensor, enable); + } else { + l.removeSensor(sensor); + deactivateIfUnused(sensor); + if (l.mSensors == 0) { + mListeners.remove(l); + binder.unlinkToDeath(l, 0); + mListeners.notify(); + } + } + } + return true; + } + + private void deactivateIfUnused(int sensor) throws RemoteException { + int size = mListeners.size(); + for (int i = 0; i < size ; i++) { + if (mListeners.get(i).hasSensor(sensor)) + return; + } + _sensors_control_activate(sensor, false); + reportAccuracy(sensor, -1); + } + + private ArrayList<Listener> mListeners = new ArrayList<Listener>(); + + private static native int _sensors_control_init(); + private static native ParcelFileDescriptor _sensors_control_open(); + private static native boolean _sensors_control_activate(int sensor, boolean activate); + private static native int _sensors_control_set_delay(int ms); +} |