diff options
16 files changed, 293 insertions, 159 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index a54a06f3d4c4..494b9b2c9f74 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2057,21 +2057,21 @@ package android.hardware.radio { method public abstract int cancel(); method public abstract void cancelAnnouncement(); method public abstract void close(); - method public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]); + method public abstract deprecated int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]); method public android.hardware.radio.ProgramList getDynamicProgramList(android.hardware.radio.ProgramList.Filter); method public abstract boolean getMute(); method public java.util.Map<java.lang.String, java.lang.String> getParameters(java.util.List<java.lang.String>); - method public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]); + method public abstract deprecated int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]); method public abstract deprecated java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>); method public abstract boolean hasControl(); method public abstract deprecated boolean isAnalogForced(); - method public abstract boolean isAntennaConnected(); + method public abstract deprecated boolean isAntennaConnected(); method public boolean isConfigFlagSet(int); method public boolean isConfigFlagSupported(int); method public abstract int scan(int, boolean); method public abstract deprecated void setAnalogForced(boolean); method public void setConfigFlag(int, boolean); - method public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig); + method public abstract deprecated int setConfiguration(android.hardware.radio.RadioManager.BandConfig); method public abstract int setMute(boolean); method public java.util.Map<java.lang.String, java.lang.String> setParameters(java.util.Map<java.lang.String, java.lang.String>); method public abstract boolean startBackgroundScan(); @@ -2080,13 +2080,13 @@ package android.hardware.radio { method public abstract void tune(android.hardware.radio.ProgramSelector); field public static final int DIRECTION_DOWN = 1; // 0x1 field public static final int DIRECTION_UP = 0; // 0x0 - field public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6 - field public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5 - field public static final int ERROR_CANCELLED = 2; // 0x2 - field public static final int ERROR_CONFIG = 4; // 0x4 - field public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0 - field public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3 - field public static final int ERROR_SERVER_DIED = 1; // 0x1 + field public static final deprecated int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6 + field public static final deprecated int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5 + field public static final deprecated int ERROR_CANCELLED = 2; // 0x2 + field public static final deprecated int ERROR_CONFIG = 4; // 0x4 + field public static final deprecated int ERROR_HARDWARE_FAILURE = 0; // 0x0 + field public static final deprecated int ERROR_SCAN_TIMEOUT = 3; // 0x3 + field public static final deprecated int ERROR_SERVER_DIED = 1; // 0x1 } public static abstract class RadioTuner.Callback { @@ -2094,15 +2094,16 @@ package android.hardware.radio { method public void onAntennaState(boolean); method public void onBackgroundScanAvailabilityChange(boolean); method public void onBackgroundScanComplete(); - method public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig); + method public deprecated void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig); method public void onControlChanged(boolean); method public void onEmergencyAnnouncement(boolean); - method public void onError(int); + method public deprecated void onError(int); method public deprecated void onMetadataChanged(android.hardware.radio.RadioMetadata); method public void onParametersUpdated(java.util.Map<java.lang.String, java.lang.String>); method public void onProgramInfoChanged(android.hardware.radio.RadioManager.ProgramInfo); method public void onProgramListChanged(); method public void onTrafficAnnouncement(boolean); + method public void onTuneFailed(int, android.hardware.radio.ProgramSelector); } } diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl index bf5e391794f5..429f1f351a93 100644 --- a/core/java/android/hardware/radio/ITuner.aidl +++ b/core/java/android/hardware/radio/ITuner.aidl @@ -64,8 +64,6 @@ interface ITuner { void cancelAnnouncement(); - RadioManager.ProgramInfo getProgramInformation(); - Bitmap getImage(int id); /** @@ -92,6 +90,4 @@ interface ITuner { * @return Vendor-specific key-value pairs, must be Map<String, String> */ Map getParameters(in List<String> keys); - - boolean isAntennaConnected(); } diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl index 54af30fcc35e..b32daa5a7609 100644 --- a/core/java/android/hardware/radio/ITunerCallback.aidl +++ b/core/java/android/hardware/radio/ITunerCallback.aidl @@ -17,12 +17,14 @@ package android.hardware.radio; import android.hardware.radio.ProgramList; +import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; /** {@hide} */ oneway interface ITunerCallback { void onError(int status); + void onTuneFailed(int result, in ProgramSelector selector); void onConfigurationChanged(in RadioManager.BandConfig config); void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info); void onTrafficAnnouncement(boolean active); diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java index ed20c4aad761..0edd05533dd3 100644 --- a/core/java/android/hardware/radio/RadioTuner.java +++ b/core/java/android/hardware/radio/RadioTuner.java @@ -64,7 +64,9 @@ public abstract class RadioTuner { * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native * service fails, </li> * </ul> + * @deprecated Only applicable for HAL 1.x. */ + @Deprecated public abstract int setConfiguration(RadioManager.BandConfig config); /** @@ -80,7 +82,10 @@ public abstract class RadioTuner { * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native * service fails, </li> * </ul> + * + * @deprecated Only applicable for HAL 1.x. */ + @Deprecated public abstract int getConfiguration(RadioManager.BandConfig[] config); @@ -228,7 +233,9 @@ public abstract class RadioTuner { * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native * service fails, </li> * </ul> + * @deprecated Use {@link onProgramInfoChanged} callback instead. */ + @Deprecated public abstract int getProgramInformation(RadioManager.ProgramInfo[] info); /** @@ -427,7 +434,10 @@ public abstract class RadioTuner { * Get current antenna connection state for current configuration. * Only valid if a configuration has been applied. * @return {@code true} if the antenna is connected, {@code false} otherwise. + * + * @deprecated Use {@link onAntennaState} callback instead */ + @Deprecated public abstract boolean isAntennaConnected(); /** @@ -446,20 +456,41 @@ public abstract class RadioTuner { public abstract boolean hasControl(); /** Indicates a failure of radio IC or driver. - * The application must close and re open the tuner */ + * The application must close and re open the tuner + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_HARDWARE_FAILURE = 0; /** Indicates a failure of the radio service. - * The application must close and re open the tuner */ + * The application must close and re open the tuner + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_SERVER_DIED = 1; - /** A pending seek or tune operation was cancelled */ + /** A pending seek or tune operation was cancelled + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_CANCELLED = 2; - /** A pending seek or tune operation timed out */ + /** A pending seek or tune operation timed out + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_SCAN_TIMEOUT = 3; - /** The requested configuration could not be applied */ + /** The requested configuration could not be applied + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_CONFIG = 4; - /** Background scan was interrupted due to hardware becoming temporarily unavailable. */ + /** Background scan was interrupted due to hardware becoming temporarily unavailable. + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; - /** Background scan failed due to other error, ie. HW failure. */ + /** Background scan failed due to other error, ie. HW failure. + * @deprecated See {@link onError} callback. + */ + @Deprecated public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; /** @@ -473,13 +504,29 @@ public abstract class RadioTuner { * status is one of {@link #ERROR_HARDWARE_FAILURE}, {@link #ERROR_SERVER_DIED}, * {@link #ERROR_CANCELLED}, {@link #ERROR_SCAN_TIMEOUT}, * {@link #ERROR_CONFIG} + * + * @deprecated Use {@link onTuneFailed} for tune, scan and step; + * other use cases (configuration, background scan) are already deprecated. */ public void onError(int status) {} + + /** + * Called when tune, scan or step operation fails. + * + * @param result cause of the failure + * @param selector ProgramSelector argument of tune that failed; + * null for scan and step. + */ + public void onTuneFailed(int result, @Nullable ProgramSelector selector) {} + /** * onConfigurationChanged() is called upon successful completion of * {@link RadioManager#openTuner(int, RadioManager.BandConfig, boolean, Callback, Handler)} * or {@link RadioTuner#setConfiguration(RadioManager.BandConfig)} + * + * @deprecated Only applicable for HAL 1.x. */ + @Deprecated public void onConfigurationChanged(RadioManager.BandConfig config) {} /** diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java index 91944bfd04f0..85f3115689cd 100644 --- a/core/java/android/hardware/radio/TunerAdapter.java +++ b/core/java/android/hardware/radio/TunerAdapter.java @@ -202,15 +202,17 @@ class TunerAdapter extends RadioTuner { @Override public int getProgramInformation(RadioManager.ProgramInfo[] info) { if (info == null || info.length != 1) { - throw new IllegalArgumentException("The argument must be an array of length 1"); + Log.e(TAG, "The argument must be an array of length 1"); + return RadioManager.STATUS_BAD_VALUE; } - try { - info[0] = mTuner.getProgramInformation(); - return RadioManager.STATUS_OK; - } catch (RemoteException e) { - Log.e(TAG, "service died", e); - return RadioManager.STATUS_DEAD_OBJECT; + + RadioManager.ProgramInfo current = mCallback.getCurrentProgramInformation(); + if (current == null) { + Log.w(TAG, "Didn't get program info yet"); + return RadioManager.STATUS_INVALID_OPERATION; } + info[0] = current; + return RadioManager.STATUS_OK; } @Override @@ -288,12 +290,20 @@ class TunerAdapter extends RadioTuner { @Override public boolean isAnalogForced() { - return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG); + try { + return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG); + } catch (UnsupportedOperationException ex) { + throw new IllegalStateException(ex); + } } @Override public void setAnalogForced(boolean isForced) { - setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced); + try { + setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced); + } catch (UnsupportedOperationException ex) { + throw new IllegalStateException(ex); + } } @Override @@ -343,11 +353,7 @@ class TunerAdapter extends RadioTuner { @Override public boolean isAntennaConnected() { - try { - return mTuner.isAntennaConnected(); - } catch (RemoteException e) { - throw new RuntimeException("service died", e); - } + return mCallback.isAntennaConnected(); } @Override diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java index b299ffe042b2..7437c40351db 100644 --- a/core/java/android/hardware/radio/TunerCallbackAdapter.java +++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java @@ -37,8 +37,12 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { @NonNull private final Handler mHandler; @Nullable ProgramList mProgramList; - @Nullable List<RadioManager.ProgramInfo> mLastCompleteList; // for legacy getProgramList call + + // cache for deprecated methods + boolean mIsAntennaConnected = true; + @Nullable List<RadioManager.ProgramInfo> mLastCompleteList; private boolean mDelayedCompleteCallback = false; + @Nullable RadioManager.ProgramInfo mCurrentProgramInfo; TunerCallbackAdapter(@NonNull RadioTuner.Callback callback, @Nullable Handler handler) { mCallback = callback; @@ -92,12 +96,46 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { } } + @Nullable RadioManager.ProgramInfo getCurrentProgramInformation() { + synchronized (mLock) { + return mCurrentProgramInfo; + } + } + + boolean isAntennaConnected() { + return mIsAntennaConnected; + } + @Override public void onError(int status) { mHandler.post(() -> mCallback.onError(status)); } @Override + public void onTuneFailed(int status, @Nullable ProgramSelector selector) { + mHandler.post(() -> mCallback.onTuneFailed(status, selector)); + + int errorCode; + switch (status) { + case RadioManager.STATUS_PERMISSION_DENIED: + case RadioManager.STATUS_DEAD_OBJECT: + errorCode = RadioTuner.ERROR_SERVER_DIED; + break; + case RadioManager.STATUS_ERROR: + case RadioManager.STATUS_NO_INIT: + case RadioManager.STATUS_BAD_VALUE: + case RadioManager.STATUS_INVALID_OPERATION: + Log.i(TAG, "Got an error with no mapping to the legacy API (" + status + + "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT"); + // fall through + case RadioManager.STATUS_TIMED_OUT: + default: + errorCode = RadioTuner.ERROR_SCAN_TIMEOUT; + } + mHandler.post(() -> mCallback.onError(errorCode)); + } + + @Override public void onConfigurationChanged(RadioManager.BandConfig config) { mHandler.post(() -> mCallback.onConfigurationChanged(config)); } @@ -109,6 +147,10 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { return; } + synchronized (mLock) { + mCurrentProgramInfo = info; + } + mHandler.post(() -> { mCallback.onProgramInfoChanged(info); @@ -129,6 +171,7 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { @Override public void onAntennaState(boolean connected) { + mIsAntennaConnected = connected; mHandler.post(() -> mCallback.onAntennaState(connected)); } diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java index 896fd15d90cd..370659eb99d9 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java @@ -122,6 +122,7 @@ public class RadioTunerTest { private void resetCallback() { verify(mCallback, atLeast(0)).onMetadataChanged(any()); + verify(mCallback, atLeast(0)).onProgramInfoChanged(any()); verifyNoMoreInteractions(mCallback); Mockito.reset(mCallback); } diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java index f9b35f53d4d5..e77cb7a7ad94 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java @@ -48,7 +48,7 @@ class Tuner extends ITuner.Stub { private boolean mIsClosed = false; private boolean mIsMuted = false; - private int mRegion; // TODO(b/62710330): find better solution to handle regions + private int mRegion; private final boolean mWithAudio; Tuner(@NonNull ITunerCallback clientCallback, int halRev, @@ -89,7 +89,6 @@ class Tuner extends ITuner.Stub { private native void nativeCancelAnnouncement(long nativeContext); - private native RadioManager.ProgramInfo nativeGetProgramInformation(long nativeContext); private native boolean nativeStartBackgroundScan(long nativeContext); private native List<RadioManager.ProgramInfo> nativeGetProgramList(long nativeContext, Map<String, String> vendorFilter); @@ -103,8 +102,6 @@ class Tuner extends ITuner.Stub { Map<String, String> parameters); private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys); - private native boolean nativeIsAntennaConnected(long nativeContext); - @Override public void close() { synchronized (mLock) { @@ -218,14 +215,6 @@ class Tuner extends ITuner.Stub { } @Override - public RadioManager.ProgramInfo getProgramInformation() { - synchronized (mLock) { - checkNotClosedLocked(); - return nativeGetProgramInformation(mNativeContext); - } - } - - @Override public Bitmap getImage(int id) { if (id == 0) { throw new IllegalArgumentException("Image ID is missing"); @@ -324,12 +313,4 @@ class Tuner extends ITuner.Stub { if (results == null) return Collections.emptyMap(); return results; } - - @Override - public boolean isAntennaConnected() { - synchronized (mLock) { - checkNotClosedLocked(); - return nativeIsAntennaConnected(mNativeContext); - } - } } diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java index 18f56ed58475..04c0e5788e7b 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.ProgramList; +import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; @@ -100,6 +101,11 @@ class TunerCallback implements ITunerCallback { } @Override + public void onTuneFailed(int result, ProgramSelector selector) { + Slog.e(TAG, "Not applicable for HAL 1.x"); + } + + @Override public void onConfigurationChanged(RadioManager.BandConfig config) { dispatch(() -> mClientCallback.onConfigurationChanged(config)); } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 7a95971ca517..3bb3d1fdd032 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -73,7 +73,26 @@ class Convert { } } - private static @NonNull Map<String, String> + static @NonNull ArrayList<VendorKeyValue> + vendorInfoToHal(@Nullable Map<String, String> info) { + if (info == null) return new ArrayList<>(); + + ArrayList<VendorKeyValue> list = new ArrayList<>(); + for (Map.Entry<String, String> entry : info.entrySet()) { + VendorKeyValue elem = new VendorKeyValue(); + elem.key = entry.getKey(); + elem.value = entry.getValue(); + if (elem.key == null || elem.value == null) { + Slog.w(TAG, "VendorKeyValue contains null pointers"); + continue; + } + list.add(elem); + } + + return list; + } + + static @NonNull Map<String, String> vendorInfoFromHal(@Nullable List<VendorKeyValue> info) { if (info == null) return Collections.emptyMap(); @@ -206,18 +225,23 @@ class Convert { false, // isCaptureSupported amfmConfigToBands(amfmConfig), - false, // isBgScanSupported is deprecated + true, // isBgScanSupported is deprecated supportedProgramTypes, supportedIdentifierTypes, vendorInfoFromHal(prop.vendorInfo) ); } - static @NonNull ProgramIdentifier programIdentifierToHal( + static void programIdentifierToHal(@NonNull ProgramIdentifier hwId, @NonNull ProgramSelector.Identifier id) { - ProgramIdentifier hwId = new ProgramIdentifier(); hwId.type = id.getType(); hwId.value = id.getValue(); + } + + static @NonNull ProgramIdentifier programIdentifierToHal( + @NonNull ProgramSelector.Identifier id) { + ProgramIdentifier hwId = new ProgramIdentifier(); + programIdentifierToHal(hwId, id); return hwId; } @@ -227,10 +251,22 @@ class Convert { return new ProgramSelector.Identifier(id.type, id.value); } + static @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector programSelectorToHal( + @NonNull ProgramSelector sel) { + android.hardware.broadcastradio.V2_0.ProgramSelector hwSel = + new android.hardware.broadcastradio.V2_0.ProgramSelector(); + + programIdentifierToHal(hwSel.primaryId, sel.getPrimaryId()); + Arrays.stream(sel.getSecondaryIds()).map(Convert::programIdentifierToHal). + forEachOrdered(hwSel.secondaryIds::add); + + return hwSel; + } + static @NonNull ProgramSelector programSelectorFromHal( @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) { ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream(). - map(id -> Objects.requireNonNull(programIdentifierFromHal(id))). + map(Convert::programIdentifierFromHal).map(Objects::requireNonNull). toArray(ProgramSelector.Identifier[]::new); return new ProgramSelector( @@ -286,4 +322,10 @@ class Convert { vendorInfoFromHal(hwAnnouncement.vendorInfo) ); } + + static <T> @Nullable ArrayList<T> listToArrayList(@Nullable List<T> list) { + if (list == null) return null; + if (list instanceof ArrayList) return (ArrayList) list; + return new ArrayList<>(list); + } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index 4dff9e06000a..50f032d659b7 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -18,6 +18,8 @@ package com.android.server.broadcastradio.hal2; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.hardware.radio.ITuner; import android.hardware.radio.RadioManager; import android.hardware.broadcastradio.V2_0.AmFmRegionConfig; @@ -76,15 +78,17 @@ class RadioModule { Mutable<ITunerSession> hwSession = new Mutable<>(); MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); - mService.openSession(cb, (int result, ITunerSession session) -> { - hwSession.value = session; - halResult.value = result; - }); + synchronized (mService) { + mService.openSession(cb, (result, session) -> { + hwSession.value = session; + halResult.value = result; + }); + } Convert.throwOnError("openSession", halResult.value); Objects.requireNonNull(hwSession.value); - return new TunerSession(hwSession.value, cb); + return new TunerSession(this, hwSession.value, cb); } public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes, @@ -103,10 +107,13 @@ class RadioModule { map(a -> Convert.announcementFromHal(a)).collect(Collectors.toList())); } }; - mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHandle) -> { - halResult.value = result; - hwCloseHandle.value = closeHandle; - }); + + synchronized (mService) { + mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> { + halResult.value = result; + hwCloseHandle.value = closeHnd; + }); + } Convert.throwOnError("addAnnouncementListener", halResult.value); return new android.hardware.radio.ICloseHandle.Stub() { @@ -119,4 +126,21 @@ class RadioModule { } }; } + + Bitmap getImage(int id) { + if (id == 0) throw new IllegalArgumentException("Image ID is missing"); + + byte[] rawImage; + synchronized (mService) { + List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id)); + rawImage = new byte[rawList.size()]; + for (int i = 0; i < rawList.size(); i++) { + rawImage[i] = rawList.get(i); + } + } + + if (rawImage == null || rawImage.length == 0) return null; + + return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length); + } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java index ed2a1b3ce851..3c4b49c91cf2 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java @@ -50,10 +50,14 @@ class TunerCallback extends ITunerCallback.Stub { } @Override - public void onTuneFailed(int result, ProgramSelector selector) {} + public void onTuneFailed(int result, ProgramSelector selector) { + dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector))); + } @Override - public void onCurrentProgramInfoChanged(ProgramInfo info) {} + public void onCurrentProgramInfoChanged(ProgramInfo info) { + dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info))); + } @Override public void onProgramListUpdated(ProgramListChunk chunk) { @@ -61,8 +65,12 @@ class TunerCallback extends ITunerCallback.Stub { } @Override - public void onAntennaStateChange(boolean connected) {} + public void onAntennaStateChange(boolean connected) { + dispatch(() -> mClientCb.onAntennaState(connected)); + } @Override - public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {} + public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { + dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); + } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java index 1ae7d20fb3fe..8efaa2a53572 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -41,6 +41,7 @@ class TunerSession extends ITuner.Stub { private final Object mLock = new Object(); + private final RadioModule mModule; private final ITunerSession mHwSession; private final TunerCallback mCallback; private boolean mIsClosed = false; @@ -50,7 +51,9 @@ class TunerSession extends ITuner.Stub { // necessary only for older APIs compatibility private RadioManager.BandConfig mDummyConfig = null; - TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) { + TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession, + @NonNull TunerCallback callback) { + mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); mCallback = Objects.requireNonNull(callback); notifyAudioServiceLocked(true); @@ -128,23 +131,29 @@ class TunerSession extends ITuner.Stub { } @Override - public void step(boolean directionDown, boolean skipSubChannel) { + public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException { synchronized (mLock) { checkNotClosedLocked(); + int halResult = mHwSession.step(!directionDown); + Convert.throwOnError("step", halResult); } } @Override - public void scan(boolean directionDown, boolean skipSubChannel) { + public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException { synchronized (mLock) { checkNotClosedLocked(); + int halResult = mHwSession.scan(!directionDown, skipSubChannel); + Convert.throwOnError("step", halResult); } } @Override - public void tune(ProgramSelector selector) { + public void tune(ProgramSelector selector) throws RemoteException { synchronized (mLock) { checkNotClosedLocked(); + int halResult = mHwSession.tune(Convert.programSelectorToHal(selector)); + Convert.throwOnError("tune", halResult); } } @@ -152,36 +161,25 @@ class TunerSession extends ITuner.Stub { public void cancel() { synchronized (mLock) { checkNotClosedLocked(); + Utils.maybeRethrow(mHwSession::cancel); } } @Override public void cancelAnnouncement() { - synchronized (mLock) { - checkNotClosedLocked(); - } - } - - @Override - public RadioManager.ProgramInfo getProgramInformation() { - synchronized (mLock) { - checkNotClosedLocked(); - return null; - } + Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in 2.x"); } @Override public Bitmap getImage(int id) { - synchronized (mLock) { - checkNotClosedLocked(); - return null; - } + return mModule.getImage(id); } @Override public boolean startBackgroundScan() { Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x"); - return false; + TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete()); + return true; } @Override @@ -240,7 +238,6 @@ class TunerSession extends ITuner.Stub { Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value); synchronized (mLock) { checkNotClosedLocked(); - int halResult = mHwSession.setConfigFlag(flag, value); Convert.throwOnError("setConfigFlag", halResult); } @@ -250,7 +247,8 @@ class TunerSession extends ITuner.Stub { public Map setParameters(Map parameters) { synchronized (mLock) { checkNotClosedLocked(); - return null; + return Convert.vendorInfoFromHal(Utils.maybeRethrow( + () -> mHwSession.setParameters(Convert.vendorInfoToHal(parameters)))); } } @@ -258,15 +256,8 @@ class TunerSession extends ITuner.Stub { public Map getParameters(List<String> keys) { synchronized (mLock) { checkNotClosedLocked(); - return null; - } - } - - @Override - public boolean isAntennaConnected() { - synchronized (mLock) { - checkNotClosedLocked(); - return true; + return Convert.vendorInfoFromHal(Utils.maybeRethrow( + () -> mHwSession.getParameters(Convert.listToArrayList(keys)))); } } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java index 3520f37880c5..384c9bab94b4 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java @@ -16,6 +16,9 @@ package com.android.server.broadcastradio.hal2; +import android.annotation.NonNull; +import android.os.RemoteException; + enum FrequencyBand { UNKNOWN, FM, @@ -37,4 +40,29 @@ class Utils { if (freq < 110000) return FrequencyBand.FM; return FrequencyBand.UNKNOWN; } + + interface FuncThrowingRemoteException<T> { + T exec() throws RemoteException; + } + + static <T> T maybeRethrow(@NonNull FuncThrowingRemoteException<T> r) { + try { + return r.exec(); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + return null; // unreachable + } + } + + interface VoidFuncThrowingRemoteException { + void exec() throws RemoteException; + } + + static void maybeRethrow(@NonNull VoidFuncThrowingRemoteException r) { + try { + r.exec(); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } } diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp index 98921465c673..176ae81a15e4 100644 --- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp +++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp @@ -249,6 +249,15 @@ static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jin Tuner::assignHalInterfaces(env, tuner, module.radioModule, halTuner); ALOGD("Opened tuner %p", halTuner.get()); + + bool isConnected = true; + halTuner->getConfiguration([&](Result result, const BandConfig& config) { + if (result == Result::OK) isConnected = config.antennaConnected; + }); + if (!isConnected) { + tunerCb->antennaStateChange(false); + } + return tuner.release(); } diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp index 42eb8739c9e7..42c1332194e1 100644 --- a/services/core/jni/BroadcastRadio/Tuner.cpp +++ b/services/core/jni/BroadcastRadio/Tuner.cpp @@ -352,39 +352,6 @@ static void nativeCancelAnnouncement(JNIEnv *env, jobject obj, jlong nativeConte convert::ThrowIfFailed(env, halTuner->cancelAnnouncement()); } -static jobject nativeGetProgramInformation(JNIEnv *env, jobject obj, jlong nativeContext) { - ALOGV("%s", __func__); - lock_guard<mutex> lk(gContextMutex); - auto& ctx = getNativeContext(nativeContext); - - auto halTuner10 = getHalTuner(ctx); - auto halTuner11 = ctx.mHalTuner11; - if (halTuner10 == nullptr) return nullptr; - - JavaRef<jobject> jInfo; - Result halResult; - Return<void> hidlResult; - if (halTuner11 != nullptr) { - hidlResult = halTuner11->getProgramInformation_1_1([&](Result result, - const V1_1::ProgramInfo& info) { - halResult = result; - if (result != Result::OK) return; - jInfo = convert::ProgramInfoFromHal(env, info); - }); - } else { - hidlResult = halTuner10->getProgramInformation([&](Result result, - const V1_0::ProgramInfo& info) { - halResult = result; - if (result != Result::OK) return; - jInfo = convert::ProgramInfoFromHal(env, info, ctx.mBand); - }); - } - - if (jInfo != nullptr) return jInfo.release(); - convert::ThrowIfFailed(env, hidlResult, halResult); - return nullptr; -} - static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) { ALOGV("%s", __func__); auto halTuner = getHalTuner11(nativeContext); @@ -541,21 +508,6 @@ static jobject nativeGetParameters(JNIEnv *env, jobject obj, jlong nativeContext return jResults.release(); } -static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) { - ALOGV("%s", __func__); - auto halTuner = getHalTuner(nativeContext); - if (halTuner == nullptr) return false; - - bool isConnected = false; - Result halResult; - auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) { - halResult = result; - isConnected = config.antennaConnected; - }); - convert::ThrowIfFailed(env, hidlResult, halResult); - return isConnected; -} - static const JNINativeMethod gTunerMethods[] = { { "nativeInit", "(IZI)J", (void*)nativeInit }, { "nativeFinalize", "(J)V", (void*)nativeFinalize }, @@ -570,8 +522,6 @@ static const JNINativeMethod gTunerMethods[] = { { "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune }, { "nativeCancel", "(J)V", (void*)nativeCancel }, { "nativeCancelAnnouncement", "(J)V", (void*)nativeCancelAnnouncement }, - { "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;", - (void*)nativeGetProgramInformation }, { "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan }, { "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;", (void*)nativeGetProgramList }, @@ -580,7 +530,6 @@ static const JNINativeMethod gTunerMethods[] = { { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced }, { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters }, { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters }, - { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected }, }; } // namespace Tuner |