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