diff options
| author | 2013-09-11 19:05:37 +0000 | |
|---|---|---|
| committer | 2013-09-11 19:05:38 +0000 | |
| commit | 7563d42331ed7df7f026c8921ae990ce2fca9efd (patch) | |
| tree | 04ec8a1746321f55edf783bb4bceb6485879dd63 | |
| parent | f702286c94f0df9fc147135c19f12ef34e8594c9 (diff) | |
| parent | 51e95df8f24e9ea30775686b9e324b9a671213dc (diff) | |
Merge "Add consumer IR framework" into klp-dev
| -rw-r--r-- | Android.mk | 1 | ||||
| -rw-r--r-- | api/current.txt | 14 | ||||
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 6 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 10 | ||||
| -rw-r--r-- | core/java/android/hardware/ConsumerIrManager.java | 153 | ||||
| -rw-r--r-- | core/java/android/hardware/IConsumerIrService.aidl | 26 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 7 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 8 | ||||
| -rw-r--r-- | services/java/com/android/server/ConsumerIrService.java | 130 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 5 | ||||
| -rw-r--r-- | services/jni/Android.mk | 1 | ||||
| -rw-r--r-- | services/jni/com_android_server_ConsumerIrService.cpp | 114 | ||||
| -rw-r--r-- | services/jni/onload.cpp | 3 |
13 files changed, 478 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk index 5d029822b7d2..dea3d4859796 100644 --- a/Android.mk +++ b/Android.mk @@ -120,6 +120,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/ICameraServiceListener.aidl \ core/java/android/hardware/ICamera.aidl \ core/java/android/hardware/ICameraClient.aidl \ + core/java/android/hardware/IConsumerIrService.aidl \ core/java/android/hardware/IProCameraUser.aidl \ core/java/android/hardware/IProCameraCallbacks.aidl \ core/java/android/hardware/camera2/ICameraDeviceUser.aidl \ diff --git a/api/current.txt b/api/current.txt index e43b1516dc87..aa768b5d3d63 100644 --- a/api/current.txt +++ b/api/current.txt @@ -129,6 +129,7 @@ package android { field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ"; field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE"; field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW"; + field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR"; field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; @@ -5968,6 +5969,7 @@ package android.content { field public static final java.lang.String CAPTIONING_SERVICE = "captioning"; field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard"; field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity"; + field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir"; field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2 field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1 field public static final int CONTEXT_RESTRICTED = 4; // 0x4 @@ -10622,6 +10624,18 @@ package android.hardware { field public int width; } + public final class ConsumerIrManager { + method public android.hardware.ConsumerIrManager.CarrierFrequencyRange[] getCarrierFrequencies(); + method public boolean hasIrEmitter(); + method public void transmit(int, int[]); + } + + public final class ConsumerIrManager.CarrierFrequencyRange { + ctor public ConsumerIrManager.CarrierFrequencyRange(int, int); + method public int getMaxFrequency(); + method public int getMinFrequency(); + } + public abstract interface FlushCompleteListener { method public abstract void onFlushCompleted(android.hardware.Sensor); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index fe8c50666361..8e9f3bbc6e53 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -47,6 +47,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.hardware.ConsumerIrManager; import android.hardware.ISerialManager; import android.hardware.SerialManager; import android.hardware.SystemSensorManager; @@ -580,6 +581,11 @@ class ContextImpl extends Context { return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(), UserHandle.getAppId(Process.myUid())); }}); + + registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + return new ConsumerIrManager(ctx); + }}); } static ContextImpl getImpl(Context context) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7b15e63b4bb0..92a9c7c84ab1 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2401,6 +2401,16 @@ public abstract class Context { public static final String PRINT_SERVICE = "print"; /** + * Use with {@link #getSystemService} to retrieve a + * {@link android.hardware.ConsumerIrManager} for transmitting infrared + * signals from the device. + * + * @see #getSystemService + * @see android.hardware.ConsumerIrManager + */ + public static final String CONSUMER_IR_SERVICE = "consumer_ir"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java new file mode 100644 index 000000000000..baa743c04cd2 --- /dev/null +++ b/core/java/android/hardware/ConsumerIrManager.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2013 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.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +/** + * Class that operates consumer infrared on the device. + * + * <p> + * To obtain an instance of the system infrared transmitter, call + * {@link Context#getSystemService} with {@link Context#CONSUMER_IR} as the argument. + * </p> + */ +public final class ConsumerIrManager { + private static final String TAG = "ConsumerIr"; + + private final String mPackageName; + private final IConsumerIrService mService; + + /** + * @hide to prevent subclassing from outside of the framework + */ + public ConsumerIrManager(Context context) { + mPackageName = context.getPackageName(); + mService = IConsumerIrService.Stub.asInterface( + ServiceManager.getService(Context.CONSUMER_IR_SERVICE)); + } + + /** + * Check whether the device has an infrared emitter. + * + * @return true if the device has an infrared emitter, else false. + */ + public boolean hasIrEmitter() { + if (mService == null) { + Log.w(TAG, "no consumer ir service."); + return false; + } + + try { + return mService.hasIrEmitter(); + } catch (RemoteException e) { + } + return false; + } + + /** + * Tansmit and infrared pattern + * <p> + * This method is synchronous; when it returns the pattern has + * been transmitted. Only patterns shorter than 2 seconds will + * be transmitted. + * </p> + * + * @param carrierFrequency The IR carrier frequency in Hertz. + * @param pattern The alternating on/off pattern in microseconds to transmit. + */ + public void transmit(int carrierFrequency, int[] pattern) { + if (mService == null) { + Log.w(TAG, "failed to transmit; no consumer ir service."); + return; + } + + try { + mService.transmit(mPackageName, carrierFrequency, pattern); + } catch (RemoteException e) { + Log.w(TAG, "failed to transmit.", e); + } + } + + /** + * Represents a range of carrier frequencies (inclusive) on which the + * infrared transmitter can transmit + */ + public final class CarrierFrequencyRange { + private final int mMinFrequency; + private final int mMaxFrequency; + + /** + * Create a segment of a carrier frequency range. + * + * @param min The minimum transmittable frequency in this range segment. + * @param max The maximum transmittable frequency in this range segment. + */ + public CarrierFrequencyRange(int min, int max) { + mMinFrequency = min; + mMaxFrequency = max; + } + + /** + * Get the minimum (inclusive) frequency in this range segment. + */ + public int getMinFrequency() { + return mMinFrequency; + } + + /** + * Get the maximum (inclusive) frequency in this range segment. + */ + public int getMaxFrequency() { + return mMaxFrequency; + } + }; + + /** + * Query the infrared transmitter's supported carrier frequencies + * + * @return an array of {@link #CarrierFreqRange} objects representing + * the ranges that the transmitter can support, or null if there was + * an error communicating with the Consumer IR Service. + */ + public CarrierFrequencyRange[] getCarrierFrequencies() { + if (mService == null) { + Log.w(TAG, "no consumer ir service."); + return null; + } + + try { + int[] freqs = mService.getCarrierFrequencies(); + if (freqs.length % 2 != 0) { + Log.w(TAG, "consumer ir service returned an uneven number of frequencies."); + return null; + } + CarrierFrequencyRange[] range = new CarrierFrequencyRange[freqs.length / 2]; + + for (int i = 0; i < freqs.length; i += 2) { + range[i / 2] = new CarrierFrequencyRange(freqs[i], freqs[i+1]); + } + return range; + } catch (RemoteException e) { + } + return null; + } + +} diff --git a/core/java/android/hardware/IConsumerIrService.aidl b/core/java/android/hardware/IConsumerIrService.aidl new file mode 100644 index 000000000000..c79bd1958226 --- /dev/null +++ b/core/java/android/hardware/IConsumerIrService.aidl @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2013, 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; + +/** {@hide} */ +interface IConsumerIrService +{ + boolean hasIrEmitter(); + void transmit(String packageName, int carrierFrequency, in int[] pattern); + int[] getCarrierFrequencies(); +} + diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 83a0c5646068..bbef318495e0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -899,6 +899,13 @@ android:label="@string/permlab_wakeLock" android:description="@string/permdesc_wakeLock" /> + <!-- Allows using the device's IR transmitter, if available --> + <permission android:name="android.permission.TRANSMIT_IR" + android:permissionGroup="android.permission-group.AFFECTS_BATTERY" + android:protectionLevel="normal" + android:label="@string/permlab_transmitIr" + android:description="@string/permdesc_transmitIr" /> + <!-- ==================================================== --> <!-- Permissions related to changing audio settings --> <!-- ==================================================== --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 18ac09ddbae8..fa6ecc84a2da 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1596,6 +1596,14 @@ <string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_transmitIr">transmit infrared</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string> + + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_devicePower" product="tablet">power tablet on or off</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_devicePower" product="default">power phone on or off</string> diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/java/com/android/server/ConsumerIrService.java new file mode 100644 index 000000000000..07f2a413259d --- /dev/null +++ b/services/java/com/android/server/ConsumerIrService.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2013 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.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.database.ContentObserver; +import android.hardware.input.InputManager; +import android.hardware.IConsumerIrService; +import android.os.Handler; +import android.os.PowerManager; +import android.os.Process; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Binder; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.os.WorkSource; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Slog; +import android.view.InputDevice; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.ListIterator; + +public class ConsumerIrService extends IConsumerIrService.Stub { + private static final String TAG = "ConsumerIrService"; + + private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */ + + private static native int halOpen(); + private static native int halTransmit(int halObject, int carrierFrequency, int[] pattern); + private static native int[] halGetCarrierFrequencies(int halObject); + + private final Context mContext; + private final PowerManager.WakeLock mWakeLock; + private final int mHal; + private final Object mHalLock = new Object(); + + ConsumerIrService(Context context) { + mContext = context; + PowerManager pm = (PowerManager)context.getSystemService( + Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock.setReferenceCounted(true); + + mHal = halOpen(); + if (mHal == 0) { + Slog.w(TAG, "No IR HAL loaded"); + } + } + + @Override + public boolean hasIrEmitter() { + return mHal != 0; + } + + private void throwIfNoIrEmitter() { + if (mHal == 0) { + throw new UnsupportedOperationException("IR emitter not available"); + } + } + + + @Override + public void transmit(String packageName, int carrierFrequency, int[] pattern) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires TRANSMIT_IR permission"); + } + + long totalXmitTime = 0; + + for (int slice : pattern) { + if (slice <= 0) { + throw new IllegalArgumentException("Non-positive IR slice"); + } + totalXmitTime += slice; + } + + if (totalXmitTime > MAX_XMIT_TIME ) { + throw new IllegalArgumentException("IR pattern too long"); + } + + throwIfNoIrEmitter(); + + // Right now there is no mechanism to ensure fair queing of IR requests + synchronized (mHalLock) { + int err = halTransmit(mHal, carrierFrequency, pattern); + + if (err < 0) { + Slog.e(TAG, "Error transmitting: " + err); + } + } + } + + @Override + public int[] getCarrierFrequencies() { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires TRANSMIT_IR permission"); + } + + throwIfNoIrEmitter(); + + synchronized(mHalLock) { + return halGetCarrierFrequencies(mHal); + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0bbdcfb230e3..d38756f6fb13 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -154,6 +154,7 @@ class ServerThread { CommonTimeManagementService commonTimeMgmtService = null; InputManagerService inputManager = null; TelephonyRegistry telephonyRegistry = null; + ConsumerIrService consumerIr = null; // Create a handler thread just for the window manager to enjoy. HandlerThread wmHandlerThread = new HandlerThread("WindowManager"); @@ -284,6 +285,10 @@ class ServerThread { vibrator = new VibratorService(context); ServiceManager.addService("vibrator", vibrator); + Slog.i(TAG, "Consumer IR Service"); + consumerIr = new ConsumerIrService(context); + ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr); + // only initialize the power service after we have started the // lights service, content providers and the battery service. power.init(context, lights, ActivityManagerService.self(), battery, diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 93d8e078181a..98e9b3085736 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_AssetAtlasService.cpp \ + com_android_server_ConsumerIrService.cpp \ com_android_server_input_InputApplicationHandle.cpp \ com_android_server_input_InputManagerService.cpp \ com_android_server_input_InputWindowHandle.cpp \ diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/jni/com_android_server_ConsumerIrService.cpp new file mode 100644 index 000000000000..ed964fe28b18 --- /dev/null +++ b/services/jni/com_android_server_ConsumerIrService.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 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. + */ + +#define LOG_TAG "ConsumerIrService" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include <stdlib.h> +#include <utils/misc.h> +#include <utils/Log.h> +#include <hardware/hardware.h> +#include <hardware/consumerir.h> +#include <ScopedPrimitiveArray.h> + +namespace android { + +static jint halOpen(JNIEnv *env, jobject obj) { + hw_module_t const* module; + consumerir_device_t *dev; + int err; + + err = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &module); + if (err != 0) { + ALOGE("Can't open consumer IR HW Module, error: %d", err); + return 0; + } + + err = module->methods->open(module, CONSUMERIR_TRANSMITTER, + (hw_device_t **) &dev); + if (err < 0) { + ALOGE("Can't open consumer IR transmitter, error: %d", err); + return 0; + } + + return reinterpret_cast<jint>(dev); +} + +static jint halTransmit(JNIEnv *env, jobject obj, jint halObject, + jint carrierFrequency, jintArray pattern) { + int ret; + + consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject); + ScopedIntArrayRO cPattern(env, pattern); + if (cPattern.get() == NULL) { + return -EINVAL; + } + jsize patternLength = cPattern.size(); + + ret = dev->transmit(dev, carrierFrequency, cPattern.get(), patternLength); + + return reinterpret_cast<jint>(ret); +} + +static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj, + jint halObject) { + consumerir_device_t *dev = (consumerir_device_t *) halObject; + consumerir_freq_range_t *ranges; + int len; + + len = dev->get_num_carrier_freqs(dev); + if (len <= 0) + return NULL; + + ranges = new consumerir_freq_range_t[len]; + + len = dev->get_carrier_freqs(dev, ranges); + if (len <= 0) { + delete[] ranges; + return NULL; + } + + int i; + ScopedIntArrayRW freqsOut(env, env->NewIntArray(len*2)); + jint *arr = freqsOut.get(); + if (arr == NULL) { + delete[] ranges; + return NULL; + } + for (i = 0; i < len; i++) { + arr[i*2] = ranges[i].min; + arr[i*2+1] = ranges[i].max; + } + + delete[] ranges; + return freqsOut.getJavaArray(); +} + +static JNINativeMethod method_table[] = { + { "halOpen", "()I", (void *)halOpen }, + { "halTransmit", "(II[I)I", (void *)halTransmit }, + { "halGetCarrierFrequencies", "(I)[I", (void *)halGetCarrierFrequencies}, +}; + +int register_android_server_ConsumerIrService(JNIEnv *env) { + return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService", + method_table, NELEM(method_table)); +} + +}; diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 5427277c905d..efc34a2aca41 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -21,6 +21,7 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); +int register_android_server_ConsumerIrService(JNIEnv *env); int register_android_server_InputApplicationHandle(JNIEnv* env); int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); @@ -65,6 +66,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_location_FlpHardwareProvider(env); register_android_server_connectivity_Vpn(env); register_android_server_AssetAtlasService(env); + register_android_server_ConsumerIrService(env); + return JNI_VERSION_1_4; } |