blob: fc7d0d2afbd4a5aa1cb85eddc69f59ac4735439e [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.radio;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.lang.ref.WeakReference;
import java.util.UUID;
/**
* A RadioModule implements the RadioTuner interface for a broadcast radio tuner physically
* present on the device and exposed by the radio HAL.
*
* @hide
*/
public class RadioModule extends RadioTuner {
private long mNativeContext = 0;
private int mId;
private NativeEventHandlerDelegate mEventHandlerDelegate;
RadioModule(int moduleId, RadioManager.BandConfig config, boolean withAudio,
RadioTuner.Callback callback, Handler handler) {
mId = moduleId;
mEventHandlerDelegate = new NativeEventHandlerDelegate(callback, handler);
native_setup(new WeakReference<RadioModule>(this), config, withAudio);
}
private native void native_setup(Object module_this,
RadioManager.BandConfig config, boolean withAudio);
@Override
protected void finalize() {
native_finalize();
}
private native void native_finalize();
boolean initCheck() {
return mNativeContext != 0;
}
// RadioTuner implementation
public native void close();
public native int setConfiguration(RadioManager.BandConfig config);
public native int getConfiguration(RadioManager.BandConfig[] config);
public native int setMute(boolean mute);
public native boolean getMute();
public native int step(int direction, boolean skipSubChannel);
public native int scan(int direction, boolean skipSubChannel);
public native int tune(int channel, int subChannel);
public native int cancel();
public native int getProgramInformation(RadioManager.ProgramInfo[] info);
public native boolean isAntennaConnected();
public native boolean hasControl();
/* keep in sync with radio_event_type_t in system/core/include/system/radio.h */
static final int EVENT_HW_FAILURE = 0;
static final int EVENT_CONFIG = 1;
static final int EVENT_ANTENNA = 2;
static final int EVENT_TUNED = 3;
static final int EVENT_METADATA = 4;
static final int EVENT_TA = 5;
static final int EVENT_AF_SWITCH = 6;
static final int EVENT_EA = 7;
static final int EVENT_CONTROL = 100;
static final int EVENT_SERVER_DIED = 101;
private class NativeEventHandlerDelegate {
private final Handler mHandler;
NativeEventHandlerDelegate(final RadioTuner.Callback callback,
Handler handler) {
// find the looper for our new event handler
Looper looper;
if (handler != null) {
looper = handler.getLooper();
} else {
looper = Looper.getMainLooper();
}
// construct the event handler with this looper
if (looper != null) {
// implement the event handler delegate
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_HW_FAILURE:
if (callback != null) {
callback.onError(RadioTuner.ERROR_HARDWARE_FAILURE);
}
break;
case EVENT_CONFIG: {
RadioManager.BandConfig config = (RadioManager.BandConfig)msg.obj;
switch(msg.arg1) {
case RadioManager.STATUS_OK:
if (callback != null) {
callback.onConfigurationChanged(config);
}
break;
default:
if (callback != null) {
callback.onError(RadioTuner.ERROR_CONFIG);
}
break;
}
} break;
case EVENT_ANTENNA:
if (callback != null) {
callback.onAntennaState(msg.arg2 == 1);
}
break;
case EVENT_AF_SWITCH:
case EVENT_TUNED: {
RadioManager.ProgramInfo info = (RadioManager.ProgramInfo)msg.obj;
switch (msg.arg1) {
case RadioManager.STATUS_OK:
if (callback != null) {
callback.onProgramInfoChanged(info);
}
break;
case RadioManager.STATUS_TIMED_OUT:
if (callback != null) {
callback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
}
break;
case RadioManager.STATUS_INVALID_OPERATION:
default:
if (callback != null) {
callback.onError(RadioTuner.ERROR_CANCELLED);
}
break;
}
} break;
case EVENT_METADATA: {
RadioMetadata metadata = (RadioMetadata)msg.obj;
if (callback != null) {
callback.onMetadataChanged(metadata);
}
} break;
case EVENT_TA:
if (callback != null) {
callback.onTrafficAnnouncement(msg.arg2 == 1);
}
break;
case EVENT_EA:
if (callback != null) {
callback.onEmergencyAnnouncement(msg.arg2 == 1);
}
case EVENT_CONTROL:
if (callback != null) {
callback.onControlChanged(msg.arg2 == 1);
}
break;
case EVENT_SERVER_DIED:
if (callback != null) {
callback.onError(RadioTuner.ERROR_SERVER_DIED);
}
break;
default:
// Should not happen
break;
}
}
};
} else {
mHandler = null;
}
}
Handler handler() {
return mHandler;
}
}
@SuppressWarnings("unused")
private static void postEventFromNative(Object module_ref,
int what, int arg1, int arg2, Object obj) {
RadioModule module = (RadioModule)((WeakReference)module_ref).get();
if (module == null) {
return;
}
NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate;
if (delegate != null) {
Handler handler = delegate.handler();
if (handler != null) {
Message m = handler.obtainMessage(what, arg1, arg2, obj);
handler.sendMessage(m);
}
}
}
}