1/*
2 * Copyright (C) 2015 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 android.hardware.radio;
18
19import android.annotation.SystemApi;
20import android.content.Context;
21import android.content.Intent;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import java.lang.ref.WeakReference;
26import java.util.UUID;
27
28/**
29 * A RadioModule implements the RadioTuner interface for a broadcast radio tuner physically
30 * present on the device and exposed by the radio HAL.
31 *
32 * @hide
33 */
34public class RadioModule extends RadioTuner {
35    private long mNativeContext = 0;
36    private int mId;
37    private NativeEventHandlerDelegate mEventHandlerDelegate;
38
39    RadioModule(int moduleId, RadioManager.BandConfig config, boolean withAudio,
40            RadioTuner.Callback callback, Handler handler) {
41        mId = moduleId;
42        mEventHandlerDelegate = new NativeEventHandlerDelegate(callback, handler);
43        native_setup(new WeakReference<RadioModule>(this), config, withAudio);
44    }
45    private native void native_setup(Object module_this,
46            RadioManager.BandConfig config, boolean withAudio);
47
48    @Override
49    protected void finalize() {
50        native_finalize();
51    }
52    private native void native_finalize();
53
54    boolean initCheck() {
55        return mNativeContext != 0;
56    }
57
58    // RadioTuner implementation
59    public native void close();
60
61    public native int setConfiguration(RadioManager.BandConfig config);
62
63    public native int getConfiguration(RadioManager.BandConfig[] config);
64
65    public native int setMute(boolean mute);
66
67    public native boolean getMute();
68
69    public native int step(int direction, boolean skipSubChannel);
70
71    public native int scan(int direction, boolean skipSubChannel);
72
73    public native int tune(int channel, int subChannel);
74
75    public native int cancel();
76
77    public native int getProgramInformation(RadioManager.ProgramInfo[] info);
78
79    public native boolean isAntennaConnected();
80
81    public native boolean hasControl();
82
83
84    /* keep in sync with radio_event_type_t in system/core/include/system/radio.h */
85    static final int EVENT_HW_FAILURE = 0;
86    static final int EVENT_CONFIG = 1;
87    static final int EVENT_ANTENNA = 2;
88    static final int EVENT_TUNED = 3;
89    static final int EVENT_METADATA = 4;
90    static final int EVENT_TA = 5;
91    static final int EVENT_AF_SWITCH = 6;
92    static final int EVENT_EA = 7;
93    static final int EVENT_CONTROL = 100;
94    static final int EVENT_SERVER_DIED = 101;
95
96    private class NativeEventHandlerDelegate {
97        private final Handler mHandler;
98
99        NativeEventHandlerDelegate(final RadioTuner.Callback callback,
100                                   Handler handler) {
101            // find the looper for our new event handler
102            Looper looper;
103            if (handler != null) {
104                looper = handler.getLooper();
105            } else {
106                looper = Looper.getMainLooper();
107            }
108
109            // construct the event handler with this looper
110            if (looper != null) {
111                // implement the event handler delegate
112                mHandler = new Handler(looper) {
113                    @Override
114                    public void handleMessage(Message msg) {
115                        switch (msg.what) {
116                        case EVENT_HW_FAILURE:
117                            if (callback != null) {
118                                callback.onError(RadioTuner.ERROR_HARDWARE_FAILURE);
119                            }
120                            break;
121                        case EVENT_CONFIG: {
122                            RadioManager.BandConfig config = (RadioManager.BandConfig)msg.obj;
123                            switch(msg.arg1) {
124                            case RadioManager.STATUS_OK:
125                                if (callback != null) {
126                                    callback.onConfigurationChanged(config);
127                                }
128                                break;
129                            default:
130                                if (callback != null) {
131                                    callback.onError(RadioTuner.ERROR_CONFIG);
132                                }
133                                break;
134                            }
135                        } break;
136                        case EVENT_ANTENNA:
137                            if (callback != null) {
138                                callback.onAntennaState(msg.arg2 == 1);
139                            }
140                            break;
141                        case EVENT_AF_SWITCH:
142                        case EVENT_TUNED: {
143                            RadioManager.ProgramInfo info = (RadioManager.ProgramInfo)msg.obj;
144                            switch (msg.arg1) {
145                            case RadioManager.STATUS_OK:
146                                if (callback != null) {
147                                    callback.onProgramInfoChanged(info);
148                                }
149                                break;
150                            case RadioManager.STATUS_TIMED_OUT:
151                                if (callback != null) {
152                                    callback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
153                                }
154                                break;
155                            case RadioManager.STATUS_INVALID_OPERATION:
156                            default:
157                                if (callback != null) {
158                                    callback.onError(RadioTuner.ERROR_CANCELLED);
159                                }
160                                break;
161                            }
162                        } break;
163                        case EVENT_METADATA: {
164                            RadioMetadata metadata = (RadioMetadata)msg.obj;
165                            if (callback != null) {
166                                callback.onMetadataChanged(metadata);
167                            }
168                        } break;
169                        case EVENT_TA:
170                            if (callback != null) {
171                                callback.onTrafficAnnouncement(msg.arg2 == 1);
172                            }
173                            break;
174                        case EVENT_EA:
175                            if (callback != null) {
176                                callback.onEmergencyAnnouncement(msg.arg2 == 1);
177                            }
178                        case EVENT_CONTROL:
179                            if (callback != null) {
180                                callback.onControlChanged(msg.arg2 == 1);
181                            }
182                            break;
183                        case EVENT_SERVER_DIED:
184                            if (callback != null) {
185                                callback.onError(RadioTuner.ERROR_SERVER_DIED);
186                            }
187                            break;
188                        default:
189                            // Should not happen
190                            break;
191                        }
192                    }
193                };
194            } else {
195                mHandler = null;
196            }
197        }
198
199        Handler handler() {
200            return mHandler;
201        }
202    }
203
204
205    @SuppressWarnings("unused")
206    private static void postEventFromNative(Object module_ref,
207                                            int what, int arg1, int arg2, Object obj) {
208        RadioModule module = (RadioModule)((WeakReference)module_ref).get();
209        if (module == null) {
210            return;
211        }
212
213        NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate;
214        if (delegate != null) {
215            Handler handler = delegate.handler();
216            if (handler != null) {
217                Message m = handler.obtainMessage(what, arg1, arg2, obj);
218                handler.sendMessage(m);
219            }
220        }
221    }
222}
223
224