1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.hardware.IConsumerIrService;
22 import android.os.PowerManager;
23 import android.util.Slog;
24 
25 import java.lang.RuntimeException;
26 
27 public class ConsumerIrService extends IConsumerIrService.Stub {
28     private static final String TAG = "ConsumerIrService";
29 
30     private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
31 
halOpen()32     private static native long halOpen();
halTransmit(long halObject, int carrierFrequency, int[] pattern)33     private static native int halTransmit(long halObject, int carrierFrequency, int[] pattern);
halGetCarrierFrequencies(long halObject)34     private static native int[] halGetCarrierFrequencies(long halObject);
35 
36     private final Context mContext;
37     private final PowerManager.WakeLock mWakeLock;
38     private final long mNativeHal;
39     private final Object mHalLock = new Object();
40 
ConsumerIrService(Context context)41     ConsumerIrService(Context context) {
42         mContext = context;
43         PowerManager pm = (PowerManager)context.getSystemService(
44                 Context.POWER_SERVICE);
45         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
46         mWakeLock.setReferenceCounted(true);
47 
48         mNativeHal = halOpen();
49         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
50             if (mNativeHal == 0) {
51                 throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
52             }
53         } else if (mNativeHal != 0) {
54             throw new RuntimeException("IR HAL present, but FEATURE_CONSUMER_IR is not set!");
55         }
56     }
57 
58     @Override
hasIrEmitter()59     public boolean hasIrEmitter() {
60         return mNativeHal != 0;
61     }
62 
throwIfNoIrEmitter()63     private void throwIfNoIrEmitter() {
64         if (mNativeHal == 0) {
65             throw new UnsupportedOperationException("IR emitter not available");
66         }
67     }
68 
69 
70     @Override
transmit(String packageName, int carrierFrequency, int[] pattern)71     public void transmit(String packageName, int carrierFrequency, int[] pattern) {
72         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
73                 != PackageManager.PERMISSION_GRANTED) {
74             throw new SecurityException("Requires TRANSMIT_IR permission");
75         }
76 
77         long totalXmitTime = 0;
78 
79         for (int slice : pattern) {
80             if (slice <= 0) {
81                 throw new IllegalArgumentException("Non-positive IR slice");
82             }
83             totalXmitTime += slice;
84         }
85 
86         if (totalXmitTime > MAX_XMIT_TIME ) {
87             throw new IllegalArgumentException("IR pattern too long");
88         }
89 
90         throwIfNoIrEmitter();
91 
92         // Right now there is no mechanism to ensure fair queing of IR requests
93         synchronized (mHalLock) {
94             int err = halTransmit(mNativeHal, carrierFrequency, pattern);
95 
96             if (err < 0) {
97                 Slog.e(TAG, "Error transmitting: " + err);
98             }
99         }
100     }
101 
102     @Override
getCarrierFrequencies()103     public int[] getCarrierFrequencies() {
104         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.TRANSMIT_IR)
105                 != PackageManager.PERMISSION_GRANTED) {
106             throw new SecurityException("Requires TRANSMIT_IR permission");
107         }
108 
109         throwIfNoIrEmitter();
110 
111         synchronized(mHalLock) {
112             return halGetCarrierFrequencies(mNativeHal);
113         }
114     }
115 }
116