1/*
2 * Copyright (C) 2008 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
17package com.android.server.lights;
18
19import com.android.server.SystemService;
20
21import android.content.Context;
22import android.content.pm.PackageManager;
23import android.os.Handler;
24import android.os.IHardwareService;
25import android.os.Message;
26import android.os.Trace;
27import android.util.Slog;
28
29import java.io.FileInputStream;
30import java.io.FileOutputStream;
31
32public class LightsService extends SystemService {
33    static final String TAG = "LightsService";
34    static final boolean DEBUG = false;
35
36    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
37
38    private final class LightImpl extends Light {
39
40        private LightImpl(int id) {
41            mId = id;
42        }
43
44        @Override
45        public void setBrightness(int brightness) {
46            setBrightness(brightness, BRIGHTNESS_MODE_USER);
47        }
48
49        @Override
50        public void setBrightness(int brightness, int brightnessMode) {
51            synchronized (this) {
52                int color = brightness & 0x000000ff;
53                color = 0xff000000 | (color << 16) | (color << 8) | color;
54                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
55            }
56        }
57
58        @Override
59        public void setColor(int color) {
60            synchronized (this) {
61                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
62            }
63        }
64
65        @Override
66        public void setFlashing(int color, int mode, int onMS, int offMS) {
67            synchronized (this) {
68                setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
69            }
70        }
71
72        @Override
73        public void pulse() {
74            pulse(0x00ffffff, 7);
75        }
76
77        @Override
78        public void pulse(int color, int onMS) {
79            synchronized (this) {
80                if (mColor == 0 && !mFlashing) {
81                    setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
82                    mColor = 0;
83                    mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
84                }
85            }
86        }
87
88        @Override
89        public void turnOff() {
90            synchronized (this) {
91                setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
92            }
93        }
94
95        private void stopFlashing() {
96            synchronized (this) {
97                setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
98            }
99        }
100
101        private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
102            if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
103                if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
104                        + Integer.toHexString(color));
105                mColor = color;
106                mMode = mode;
107                mOnMS = onMS;
108                mOffMS = offMS;
109                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")");
110                try {
111                    setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
112                } finally {
113                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
114                }
115            }
116        }
117
118        private int mId;
119        private int mColor;
120        private int mMode;
121        private int mOnMS;
122        private int mOffMS;
123        private boolean mFlashing;
124    }
125
126    /* This class implements an obsolete API that was removed after eclair and re-added during the
127     * final moments of the froyo release to support flashlight apps that had been using the private
128     * IHardwareService API. This is expected to go away in the next release.
129     */
130    private final IHardwareService.Stub mLegacyFlashlightHack = new IHardwareService.Stub() {
131
132        private static final String FLASHLIGHT_FILE = "/sys/class/leds/spotlight/brightness";
133
134        public boolean getFlashlightEnabled() {
135            try {
136                FileInputStream fis = new FileInputStream(FLASHLIGHT_FILE);
137                int result = fis.read();
138                fis.close();
139                return (result != '0');
140            } catch (Exception e) {
141                return false;
142            }
143        }
144
145        public void setFlashlightEnabled(boolean on) {
146            final Context context = getContext();
147            if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
148                    != PackageManager.PERMISSION_GRANTED &&
149                    context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
150                    != PackageManager.PERMISSION_GRANTED) {
151                throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
152            }
153            try {
154                FileOutputStream fos = new FileOutputStream(FLASHLIGHT_FILE);
155                byte[] bytes = new byte[2];
156                bytes[0] = (byte)(on ? '1' : '0');
157                bytes[1] = '\n';
158                fos.write(bytes);
159                fos.close();
160            } catch (Exception e) {
161                // fail silently
162            }
163        }
164    };
165
166    public LightsService(Context context) {
167        super(context);
168
169        mNativePointer = init_native();
170
171        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
172            mLights[i] = new LightImpl(i);
173        }
174    }
175
176    @Override
177    public void onStart() {
178        publishBinderService("hardware", mLegacyFlashlightHack);
179        publishLocalService(LightsManager.class, mService);
180    }
181
182    private final LightsManager mService = new LightsManager() {
183        @Override
184        public com.android.server.lights.Light getLight(int id) {
185            if (id < LIGHT_ID_COUNT) {
186                return mLights[id];
187            } else {
188                return null;
189            }
190        }
191    };
192
193    @Override
194    protected void finalize() throws Throwable {
195        finalize_native(mNativePointer);
196        super.finalize();
197    }
198
199    private Handler mH = new Handler() {
200        @Override
201        public void handleMessage(Message msg) {
202            LightImpl light = (LightImpl)msg.obj;
203            light.stopFlashing();
204        }
205    };
206
207    private static native long init_native();
208    private static native void finalize_native(long ptr);
209
210    static native void setLight_native(long ptr, int light, int color, int mode,
211            int onMS, int offMS, int brightnessMode);
212
213    private long mNativePointer;
214}
215