151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling/* 251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * Copyright (C) 2013 The Android Open Source Project 351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * 451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * Licensed under the Apache License, Version 2.0 (the "License"); 551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * you may not use this file except in compliance with the License. 651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * You may obtain a copy of the License at 751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * 851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * http://www.apache.org/licenses/LICENSE-2.0 951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * 1051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * Unless required by applicable law or agreed to in writing, software 1151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * distributed under the License is distributed on an "AS IS" BASIS, 1251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * See the License for the specific language governing permissions and 1451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling * limitations under the License. 1551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling */ 1651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 1751e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingpackage com.android.server; 1851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 1951e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingimport android.content.Context; 2051e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingimport android.content.pm.PackageManager; 2151e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingimport android.hardware.IConsumerIrService; 2251e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingimport android.os.PowerManager; 2351e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingimport android.util.Slog; 2451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 250c9d61f0989e5a85674fbbc24cf06dd3de1fc326Alex Rayimport java.lang.RuntimeException; 2651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 2751e95df8f24e9ea30775686b9e324b9a671213dcErik Gillingpublic class ConsumerIrService extends IConsumerIrService.Stub { 2851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private static final String TAG = "ConsumerIrService"; 2951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 3051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */ 3151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 326a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien private static native boolean halOpen(); 336a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien private static native int halTransmit(int carrierFrequency, int[] pattern); 346a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien private static native int[] halGetCarrierFrequencies(); 3551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 3651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private final Context mContext; 3751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private final PowerManager.WakeLock mWakeLock; 386a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien private final boolean mHasNativeHal; 3951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private final Object mHalLock = new Object(); 4051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 4151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling ConsumerIrService(Context context) { 4251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling mContext = context; 4351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling PowerManager pm = (PowerManager)context.getSystemService( 4451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling Context.POWER_SERVICE); 4551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 4651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling mWakeLock.setReferenceCounted(true); 4751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 486a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien mHasNativeHal = halOpen(); 490c9d61f0989e5a85674fbbc24cf06dd3de1fc326Alex Ray if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) { 506a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien if (!mHasNativeHal) { 510c9d61f0989e5a85674fbbc24cf06dd3de1fc326Alex Ray throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!"); 520c9d61f0989e5a85674fbbc24cf06dd3de1fc326Alex Ray } 536a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien } else if (mHasNativeHal) { 540c9d61f0989e5a85674fbbc24cf06dd3de1fc326Alex Ray throw new RuntimeException("IR HAL present, but FEATURE_CONSUMER_IR is not set!"); 5551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 5651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 5751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 5851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling @Override 5951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling public boolean hasIrEmitter() { 606a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien return mHasNativeHal; 6151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 6251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 6351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling private void throwIfNoIrEmitter() { 646a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien if (!mHasNativeHal) { 6551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throw new UnsupportedOperationException("IR emitter not available"); 6651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 6751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 6851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 6951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 7051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling @Override 7151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling public void transmit(String packageName, int carrierFrequency, int[] pattern) { 7251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR) 7351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling != PackageManager.PERMISSION_GRANTED) { 7451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throw new SecurityException("Requires TRANSMIT_IR permission"); 7551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 7651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 7751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling long totalXmitTime = 0; 7851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 7951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling for (int slice : pattern) { 8051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling if (slice <= 0) { 8151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throw new IllegalArgumentException("Non-positive IR slice"); 8251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 8351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling totalXmitTime += slice; 8451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 8551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 8651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling if (totalXmitTime > MAX_XMIT_TIME ) { 8751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throw new IllegalArgumentException("IR pattern too long"); 8851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 8951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 9051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throwIfNoIrEmitter(); 9151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 9251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling // Right now there is no mechanism to ensure fair queing of IR requests 9351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling synchronized (mHalLock) { 946a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien int err = halTransmit(carrierFrequency, pattern); 9551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 9651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling if (err < 0) { 9751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling Slog.e(TAG, "Error transmitting: " + err); 9851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 9951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 10051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 10151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 10251e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling @Override 10351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling public int[] getCarrierFrequencies() { 10451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR) 10551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling != PackageManager.PERMISSION_GRANTED) { 10651e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throw new SecurityException("Requires TRANSMIT_IR permission"); 10751e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 10851e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 10951e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling throwIfNoIrEmitter(); 11051e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling 11151e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling synchronized(mHalLock) { 1126a24ab1595aa53c97a7f51cc743aae521c89c87aConnor O'Brien return halGetCarrierFrequencies(); 11351e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 11451e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling } 11551e95df8f24e9ea30775686b9e324b9a671213dcErik Gilling} 116