diff --git a/Android.mk b/Android.mk index 00dc784410286..1140c6b452132 100644 --- a/Android.mk +++ b/Android.mk @@ -713,6 +713,7 @@ aidl_files := \ frameworks/base/core/java/android/print/PrintJobId.aidl \ frameworks/base/core/java/android/printservice/recommendation/RecommendationInfo.aidl \ frameworks/base/core/java/android/hardware/radio/RadioManager.aidl \ + frameworks/base/core/java/android/hardware/radio/RadioMetadata.aidl \ frameworks/base/core/java/android/hardware/usb/UsbDevice.aidl \ frameworks/base/core/java/android/hardware/usb/UsbInterface.aidl \ frameworks/base/core/java/android/hardware/usb/UsbEndpoint.aidl \ diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl index b32c6832b97ec..aed114e8d763a 100644 --- a/core/java/android/hardware/radio/ITunerCallback.aidl +++ b/core/java/android/hardware/radio/ITunerCallback.aidl @@ -17,10 +17,18 @@ package android.hardware.radio; import android.hardware.radio.RadioManager; +import android.hardware.radio.RadioMetadata; /** {@hide} */ oneway interface ITunerCallback { void onError(int status); void onConfigurationChanged(in RadioManager.BandConfig config); void onProgramInfoChanged(in RadioManager.ProgramInfo info); + void onMetadataChanged(in RadioMetadata metadata); + void onTrafficAnnouncement(boolean active); + void onEmergencyAnnouncement(boolean active); + void onAntennaState(boolean connected); + void onBackgroundScanAvailabilityChange(boolean isAvailable); + void onBackgroundScanComplete(); + void onProgramListChanged(); } diff --git a/core/java/android/hardware/radio/RadioMetadata.aidl b/core/java/android/hardware/radio/RadioMetadata.aidl new file mode 100644 index 0000000000000..cbf47134d5390 --- /dev/null +++ b/core/java/android/hardware/radio/RadioMetadata.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (C) 2017 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; + +/** @hide */ +parcelable RadioMetadata; diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java index 6e1232d844817..78d7b61e8d228 100644 --- a/core/java/android/hardware/radio/RadioTuner.java +++ b/core/java/android/hardware/radio/RadioTuner.java @@ -19,14 +19,9 @@ package android.hardware.radio; import android.annotation.NonNull; import android.annotation.Nullable; 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.List; -import java.util.UUID; /** * RadioTuner interface provides methods to control a radio tuner on the device: selecting and @@ -303,6 +298,16 @@ public abstract class RadioTuner { public static final int ERROR_SCAN_TIMEOUT = 3; /** The requested configuration could not be applied */ public static final int ERROR_CONFIG = 4; + /** + * Background scan was interrupted due to hardware becoming temporarily unavailable. + * @hide FutureFeature + */ + public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; + /** + * Background scan failed due to other error, ie. HW failure. + * @hide FutureFeature + */ + public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; /** * Callback provided by the client application when opening a {@link RadioTuner} diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java index ba85017f16aae..155ffa7845feb 100644 --- a/core/java/android/hardware/radio/TunerCallbackAdapter.java +++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java @@ -51,4 +51,39 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { public void onProgramInfoChanged(RadioManager.ProgramInfo info) { mHandler.post(() -> mCallback.onProgramInfoChanged(info)); } + + @Override + public void onMetadataChanged(RadioMetadata metadata) { + mHandler.post(() -> mCallback.onMetadataChanged(metadata)); + } + + @Override + public void onTrafficAnnouncement(boolean active) { + mHandler.post(() -> mCallback.onTrafficAnnouncement(active)); + } + + @Override + public void onEmergencyAnnouncement(boolean active) { + mHandler.post(() -> mCallback.onEmergencyAnnouncement(active)); + } + + @Override + public void onAntennaState(boolean connected) { + mHandler.post(() -> mCallback.onAntennaState(connected)); + } + + @Override + public void onBackgroundScanAvailabilityChange(boolean isAvailable) { + mHandler.post(() -> mCallback.onBackgroundScanAvailabilityChange(isAvailable)); + } + + @Override + public void onBackgroundScanComplete() { + mHandler.post(() -> mCallback.onBackgroundScanComplete()); + } + + @Override + public void onProgramListChanged() { + mHandler.post(() -> mCallback.onProgramListChanged()); + } } diff --git a/services/core/java/com/android/server/radio/TunerCallback.java b/services/core/java/com/android/server/radio/TunerCallback.java index fcc874b0ce939..d10f2c680511b 100644 --- a/services/core/java/com/android/server/radio/TunerCallback.java +++ b/services/core/java/com/android/server/radio/TunerCallback.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; +import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; import android.os.IBinder; import android.os.RemoteException; @@ -57,6 +58,18 @@ class TunerCallback implements ITunerCallback { nativeDetach(mNativeContext); } + private interface RunnableThrowingRemoteException { + void run() throws RemoteException; + } + + private void dispatch(RunnableThrowingRemoteException func) { + try { + func.run(); + } catch (RemoteException e) { + Slog.e(TAG, "client died", e); + } + } + // called from native side private void handleHwFailure() { onError(RadioTuner.ERROR_HARDWARE_FAILURE); @@ -65,29 +78,52 @@ class TunerCallback implements ITunerCallback { @Override public void onError(int status) { - try { - mClientCallback.onError(status); - } catch (RemoteException e) { - Slog.e(TAG, "client died", e); - } + dispatch(() -> mClientCallback.onError(status)); } @Override public void onConfigurationChanged(RadioManager.BandConfig config) { - try { - mClientCallback.onConfigurationChanged(config); - } catch (RemoteException e) { - Slog.e(TAG, "client died", e); - } + dispatch(() -> mClientCallback.onConfigurationChanged(config)); } @Override public void onProgramInfoChanged(RadioManager.ProgramInfo info) { - try { - mClientCallback.onProgramInfoChanged(info); - } catch (RemoteException e) { - Slog.e(TAG, "client died", e); - } + dispatch(() -> mClientCallback.onProgramInfoChanged(info)); + } + + @Override + public void onMetadataChanged(RadioMetadata metadata) { + dispatch(() -> mClientCallback.onMetadataChanged(metadata)); + } + + @Override + public void onTrafficAnnouncement(boolean active) { + dispatch(() -> mClientCallback.onTrafficAnnouncement(active)); + } + + @Override + public void onEmergencyAnnouncement(boolean active) { + dispatch(() -> mClientCallback.onEmergencyAnnouncement(active)); + } + + @Override + public void onAntennaState(boolean connected) { + dispatch(() -> mClientCallback.onAntennaState(connected)); + } + + @Override + public void onBackgroundScanAvailabilityChange(boolean isAvailable) { + dispatch(() -> mClientCallback.onBackgroundScanAvailabilityChange(isAvailable)); + } + + @Override + public void onBackgroundScanComplete() { + dispatch(() -> mClientCallback.onBackgroundScanComplete()); + } + + @Override + public void onProgramListChanged() { + dispatch(() -> mClientCallback.onProgramListChanged()); } @Override diff --git a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp index 1290c7ae89fbc..a3cfeffbafcc7 100644 --- a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp +++ b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp @@ -53,6 +53,13 @@ static struct { jmethodID onError; jmethodID onConfigurationChanged; jmethodID onProgramInfoChanged; + jmethodID onMetadataChanged; + jmethodID onTrafficAnnouncement; + jmethodID onEmergencyAnnouncement; + jmethodID onAntennaState; + jmethodID onBackgroundScanAvailabilityChange; + jmethodID onBackgroundScanComplete; + jmethodID onProgramListChanged; } TunerCallback; } gjni; @@ -63,6 +70,8 @@ enum class TunerError : jint { CANCELLED = 2, SCAN_TIMEOUT = 3, CONFIG = 4, + BACKGROUND_SCAN_UNAVAILABLE = 5, + BACKGROUND_SCAN_FAILED = 6, }; static Mutex gContextMutex; @@ -191,48 +200,93 @@ Return NativeCallback::tuneComplete_1_1(Result result, const V1_1::Program } Return NativeCallback::afSwitch(const V1_0::ProgramInfo& info) { - ALOGE("Not implemented: afSwitch"); - return Return(); + ALOGV("afSwitch()"); + return tuneComplete(Result::OK, info); } Return NativeCallback::afSwitch_1_1(const V1_1::ProgramInfo& info) { - ALOGE("Not implemented: afSwitch_1_1"); - return Return(); + ALOGV("afSwitch_1_1()"); + return tuneComplete_1_1(Result::OK, info); } Return NativeCallback::antennaStateChange(bool connected) { - ALOGE("Not implemented: antennaStateChange"); + ALOGV("antennaStateChange(%d)", connected); + + mCallbackThread.enqueue([this, connected](JNIEnv *env) { + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onAntennaState, connected); + }); + return Return(); } Return NativeCallback::trafficAnnouncement(bool active) { - ALOGE("Not implemented: trafficAnnouncement"); + ALOGV("trafficAnnouncement(%d)", active); + + mCallbackThread.enqueue([this, active](JNIEnv *env) { + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onTrafficAnnouncement, active); + }); + return Return(); } Return NativeCallback::emergencyAnnouncement(bool active) { - ALOGE("Not implemented: emergencyAnnouncement"); + ALOGV("emergencyAnnouncement(%d)", active); + + mCallbackThread.enqueue([this, active](JNIEnv *env) { + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onEmergencyAnnouncement, active); + }); + return Return(); } Return NativeCallback::newMetadata(uint32_t channel, uint32_t subChannel, const hidl_vec& metadata) { - ALOGE("Not implemented: newMetadata"); + // channel and subChannel are not used + ALOGV("newMetadata(%d, %d)", channel, subChannel); + + mCallbackThread.enqueue([this, metadata](JNIEnv *env) { + auto jMetadata = convert::MetadataFromHal(env, metadata); + if (jMetadata == nullptr) return; + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onMetadataChanged, jMetadata.get()); + }); + return Return(); } Return NativeCallback::backgroundScanAvailable(bool isAvailable) { - ALOGE("Not implemented: backgroundScanAvailable"); + ALOGV("backgroundScanAvailable(%d)", isAvailable); + + mCallbackThread.enqueue([this, isAvailable](JNIEnv *env) { + env->CallVoidMethod(mJCallback, + gjni.TunerCallback.onBackgroundScanAvailabilityChange, isAvailable); + }); + return Return(); } Return NativeCallback::backgroundScanComplete(ProgramListResult result) { - ALOGE("Not implemented: backgroundScanComplete"); + ALOGV("backgroundScanComplete(%d)", result); + + mCallbackThread.enqueue([this, result](JNIEnv *env) { + if (result == ProgramListResult::OK) { + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onBackgroundScanComplete); + } else { + auto cause = (result == ProgramListResult::UNAVAILABLE) ? + TunerError::BACKGROUND_SCAN_UNAVAILABLE : TunerError::BACKGROUND_SCAN_FAILED; + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onError, cause); + } + }); + return Return(); } Return NativeCallback::programListChanged() { - ALOGE("Not implemented: programListChanged"); + ALOGV("programListChanged()"); + + mCallbackThread.enqueue([this](JNIEnv *env) { + env->CallVoidMethod(mJCallback, gjni.TunerCallback.onProgramListChanged); + }); + return Return(); } @@ -310,6 +364,20 @@ void register_android_server_radio_TunerCallback(JavaVM *vm, JNIEnv *env) { "onConfigurationChanged", "(Landroid/hardware/radio/RadioManager$BandConfig;)V"); gjni.TunerCallback.onProgramInfoChanged = GetMethodIDOrDie(env, tunerCbClass, "onProgramInfoChanged", "(Landroid/hardware/radio/RadioManager$ProgramInfo;)V"); + gjni.TunerCallback.onMetadataChanged = GetMethodIDOrDie(env, tunerCbClass, + "onMetadataChanged", "(Landroid/hardware/radio/RadioMetadata;)V"); + gjni.TunerCallback.onTrafficAnnouncement = GetMethodIDOrDie(env, tunerCbClass, + "onTrafficAnnouncement", "(Z)V"); + gjni.TunerCallback.onEmergencyAnnouncement = GetMethodIDOrDie(env, tunerCbClass, + "onEmergencyAnnouncement", "(Z)V"); + gjni.TunerCallback.onAntennaState = GetMethodIDOrDie(env, tunerCbClass, + "onAntennaState", "(Z)V"); + gjni.TunerCallback.onBackgroundScanAvailabilityChange = GetMethodIDOrDie(env, tunerCbClass, + "onBackgroundScanAvailabilityChange", "(Z)V"); + gjni.TunerCallback.onBackgroundScanComplete = GetMethodIDOrDie(env, tunerCbClass, + "onBackgroundScanComplete", "()V"); + gjni.TunerCallback.onProgramListChanged = GetMethodIDOrDie(env, tunerCbClass, + "onProgramListChanged", "()V"); auto res = jniRegisterNativeMethods(env, "com/android/server/radio/TunerCallback", gTunerCallbackMethods, NELEM(gTunerCallbackMethods)); diff --git a/services/core/jni/com_android_server_radio_convert.cpp b/services/core/jni/com_android_server_radio_convert.cpp index 19abf8a0f0f07..3f24a36bae661 100644 --- a/services/core/jni/com_android_server_radio_convert.cpp +++ b/services/core/jni/com_android_server_radio_convert.cpp @@ -254,7 +254,7 @@ Direction DirectionToHal(bool directionDown) { return directionDown ? Direction::DOWN : Direction::UP; } -static JavaRef MetadataFromHal(JNIEnv *env, const hidl_vec metadata) { +JavaRef MetadataFromHal(JNIEnv *env, const hidl_vec &metadata) { ALOGV("MetadataFromHal()"); EnvWrapper wrap(env); diff --git a/services/core/jni/com_android_server_radio_convert.h b/services/core/jni/com_android_server_radio_convert.h index 6f6774b11b428..f2e7f9256aff2 100644 --- a/services/core/jni/com_android_server_radio_convert.h +++ b/services/core/jni/com_android_server_radio_convert.h @@ -39,6 +39,7 @@ V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region ®ion); V1_0::Direction DirectionToHal(bool directionDown); +JavaRef MetadataFromHal(JNIEnv *env, const hardware::hidl_vec &metadata); JavaRef ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info); JavaRef ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info);