diff options
9 files changed, 175 insertions, 59 deletions
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 9b6515c9ebf1..6e383ae5b026 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -1654,8 +1654,8 @@ public class RadioManager { TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler); try { tuner = mService.openTuner(moduleId, config, withAudio, halCallback); - } catch (RemoteException e) { - Log.e(TAG, "Failed to open tuner", e); + } catch (RemoteException | IllegalArgumentException ex) { + Log.e(TAG, "Failed to open tuner", ex); return null; } if (tuner == null) { diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java index 864d17c2de9f..a8a896a9c452 100644 --- a/core/java/android/hardware/radio/TunerAdapter.java +++ b/core/java/android/hardware/radio/TunerAdapter.java @@ -63,6 +63,7 @@ class TunerAdapter extends RadioTuner { @Override public int setConfiguration(RadioManager.BandConfig config) { + if (config == null) return RadioManager.STATUS_BAD_VALUE; try { mTuner.setConfiguration(config); mBand = config.getType(); 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 a8d516405ea2..896fd15d90cd 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 @@ -149,6 +149,10 @@ public class RadioTunerTest { mRadioTuner = mRadioManager.openTuner(mModule.getId(), mFmBandConfig, withAudio, mCallback, null); + if (!withAudio) { + // non-audio sessions might not be supported - if so, then skip the test + assumeNotNull(mRadioTuner); + } assertNotNull(mRadioTuner); verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any()); resetCallback(); @@ -207,20 +211,8 @@ public class RadioTunerTest { public void testSetBadConfiguration() throws Throwable { openTuner(); - // set bad config - Constructor<RadioManager.AmBandConfig> configConstr = - RadioManager.AmBandConfig.class.getDeclaredConstructor( - int.class, int.class, int.class, int.class, int.class, boolean.class); - configConstr.setAccessible(true); - RadioManager.AmBandConfig badConfig = configConstr.newInstance( - 0 /*region*/, RadioManager.BAND_AM /*type*/, - 10000 /*lowerLimit*/, 1 /*upperLimit*/, 100 /*spacing*/, false /*stereo*/); - int ret = mRadioTuner.setConfiguration(badConfig); - assertEquals(RadioManager.STATUS_BAD_VALUE, ret); - verify(mCallback, never()).onConfigurationChanged(any()); - // set null config - ret = mRadioTuner.setConfiguration(null); + int ret = mRadioTuner.setConfiguration(null); assertEquals(RadioManager.STATUS_BAD_VALUE, ret); verify(mCallback, never()).onConfigurationChanged(any()); diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java index ef5166579cb3..7d3b670bdfa3 100644 --- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java @@ -94,7 +94,7 @@ public class BroadcastRadioService extends SystemService { } synchronized (mLock) { if (mHal2.hasModule(moduleId)) { - return mHal2.openSession(moduleId, callback); + return mHal2.openSession(moduleId, bandConfig, withAudio, callback); } else { return mHal1.openTuner(moduleId, bandConfig, withAudio, callback); } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java index 413a27ce9af0..9158ff0cb66f 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java @@ -17,6 +17,7 @@ package com.android.server.broadcastradio.hal2; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; @@ -80,14 +81,21 @@ public class BroadcastRadioService { return mModules.containsKey(id); } - public ITuner openSession(int moduleId, @NonNull ITunerCallback callback) { + public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig, + boolean withAudio, @NonNull ITunerCallback callback) { Objects.requireNonNull(callback); + if (!withAudio) { + throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.x"); + } + RadioModule module = mModules.get(moduleId); if (module == null) { throw new IllegalArgumentException("Invalid module ID"); } - return module.openSession(callback); + TunerSession session = module.openSession(callback); + session.setConfiguration(legacyConfig); + return session; } } 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 434e2620a324..2c129bbac33e 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -186,7 +186,7 @@ class Convert { false, // isCaptureSupported amfmConfigToBands(amfmConfig), - true, // isBgScanSupported is deprecated + false, // isBgScanSupported is deprecated supportedProgramTypes, supportedIdentifierTypes, vendorInfoFromHal(prop.vendorInfo)); 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 8a7ac7355b7e..45b21900ff33 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -63,7 +63,7 @@ class RadioModule { } } - public @NonNull ITuner openSession(@NonNull android.hardware.radio.ITunerCallback userCb) { + public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) { TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb)); Mutable<ITunerSession> hwSession = new Mutable<>(); MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); @@ -81,25 +81,6 @@ class RadioModule { Convert.throwOnError("openSession", halResult.value); Objects.requireNonNull(hwSession.value); - TunerSession session = new TunerSession(hwSession.value, cb); - - // send out legacy callback about band configuration - RadioManager.BandDescriptor[] bands = mProperties.getBands(); - if (bands != null && bands.length > 0) { - RadioManager.BandDescriptor descr = bands[0]; // just pick first - Mutable<RadioManager.BandConfig> config = new Mutable<>(); - if (descr instanceof RadioManager.FmBandDescriptor) { - config.value = new RadioManager.FmBandConfig((RadioManager.FmBandDescriptor)descr); - } else if (descr instanceof RadioManager.AmBandDescriptor) { - config.value = new RadioManager.AmBandConfig((RadioManager.AmBandDescriptor)descr); - } else { - Slog.w(TAG, "Descriptor is neither AM nor FM"); - } - if (config.value != null) { - TunerCallback.dispatch(() -> userCb.onConfigurationChanged(config.value)); - } - } - - return session; + return new TunerSession(hwSession.value, cb); } } 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 5ee6a4c693cd..c9084ee9517a 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java @@ -31,14 +31,14 @@ import java.util.Objects; class TunerCallback extends ITunerCallback.Stub { private static final String TAG = "BcRadio2Srv.cb"; - final android.hardware.radio.ITunerCallback mCb; + final android.hardware.radio.ITunerCallback mClientCb; interface RunnableThrowingRemoteException { void run() throws RemoteException; } TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) { - mCb = Objects.requireNonNull(clientCallback); + mClientCb = Objects.requireNonNull(clientCallback); } static void dispatch(RunnableThrowingRemoteException func) { 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 e8faf3dfa63f..c4ec94f1183b 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -18,10 +18,16 @@ package com.android.server.broadcastradio.hal2; import android.annotation.NonNull; import android.graphics.Bitmap; +import android.hardware.broadcastradio.V2_0.ConfigFlag; import android.hardware.broadcastradio.V2_0.ITunerSession; +import android.hardware.broadcastradio.V2_0.Result; import android.hardware.radio.ITuner; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; +import android.media.AudioSystem; +import android.os.RemoteException; +import android.util.MutableBoolean; +import android.util.MutableInt; import android.util.Slog; import java.util.List; @@ -30,16 +36,23 @@ import java.util.Objects; class TunerSession extends ITuner.Stub { private static final String TAG = "BcRadio2Srv.session"; + private static final String kAudioDeviceName = "Radio tuner source"; private final Object mLock = new Object(); private final ITunerSession mHwSession; private final TunerCallback mCallback; private boolean mIsClosed = false; + private boolean mIsAudioConnected = false; + private boolean mIsMuted = false; + + // necessary only for older APIs compatibility + private RadioManager.BandConfig mDummyConfig = null; TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) { mHwSession = Objects.requireNonNull(hwSession); mCallback = Objects.requireNonNull(callback); + notifyAudioServiceLocked(true); } @Override @@ -47,6 +60,7 @@ class TunerSession extends ITuner.Stub { synchronized (mLock) { if (mIsClosed) return; mIsClosed = true; + notifyAudioServiceLocked(false); } } @@ -61,77 +75,197 @@ class TunerSession extends ITuner.Stub { } } + private void notifyAudioServiceLocked(boolean connected) { + if (mIsAudioConnected == connected) return; + + Slog.d(TAG, "Notifying AudioService about new state: " + connected); + int ret = AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_FM_TUNER, + connected ? AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE, + null, kAudioDeviceName); + + if (ret == AudioSystem.AUDIO_STATUS_OK) { + mIsAudioConnected = connected; + } else { + Slog.e(TAG, "Failed to notify AudioService about new state: " + connected); + } + } + @Override - public void setConfiguration(RadioManager.BandConfig config) {} + public void setConfiguration(RadioManager.BandConfig config) { + synchronized (mLock) { + checkNotClosedLocked(); + mDummyConfig = Objects.requireNonNull(config); + Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x"); + TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config)); + } + } @Override public RadioManager.BandConfig getConfiguration() { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return mDummyConfig; + } } @Override - public void setMuted(boolean mute) {} + public void setMuted(boolean mute) { + synchronized (mLock) { + checkNotClosedLocked(); + if (mIsMuted == mute) return; + mIsMuted = mute; + notifyAudioServiceLocked(!mute); + } + } @Override public boolean isMuted() { - return false; + synchronized (mLock) { + checkNotClosedLocked(); + return mIsMuted; + } } @Override - public void step(boolean directionDown, boolean skipSubChannel) {} + public void step(boolean directionDown, boolean skipSubChannel) { + synchronized (mLock) { + checkNotClosedLocked(); + } + } @Override - public void scan(boolean directionDown, boolean skipSubChannel) {} + public void scan(boolean directionDown, boolean skipSubChannel) { + synchronized (mLock) { + checkNotClosedLocked(); + } + } @Override - public void tune(ProgramSelector selector) {} + public void tune(ProgramSelector selector) { + synchronized (mLock) { + checkNotClosedLocked(); + } + } @Override - public void cancel() {} + public void cancel() { + synchronized (mLock) { + checkNotClosedLocked(); + } + } @Override - public void cancelAnnouncement() {} + public void cancelAnnouncement() { + synchronized (mLock) { + checkNotClosedLocked(); + } + } @Override public RadioManager.ProgramInfo getProgramInformation() { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return null; + } } @Override public Bitmap getImage(int id) { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return null; + } } @Override public boolean startBackgroundScan() { + Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x"); return false; } @Override public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return null; + } + } + + private boolean getConfigFlag(int flag) { + Slog.v(TAG, "getConfigFlag " + ConfigFlag.toString(flag)); + synchronized (mLock) { + checkNotClosedLocked(); + + MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); + MutableBoolean flagState = new MutableBoolean(false); + try { + mHwSession.getConfigFlag(flag, (int result, boolean value) -> { + halResult.value = result; + flagState.value = value; + }); + } catch (RemoteException ex) { + throw new RuntimeException("Failed to get flag " + ConfigFlag.toString(flag), ex); + } + Convert.throwOnError("getConfigFlag", halResult.value); + + return flagState.value; + } + } + + private void setConfigFlag(int flag, boolean value) { + Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value); + synchronized (mLock) { + checkNotClosedLocked(); + + int halResult; + try { + halResult = mHwSession.setConfigFlag(flag, value); + } catch (RemoteException ex) { + throw new RuntimeException("Failed to set flag " + ConfigFlag.toString(flag), ex); + } + Convert.throwOnError("setConfigFlag", halResult); + } } @Override public boolean isAnalogForced() { - return false; + try { + return getConfigFlag(ConfigFlag.FORCE_ANALOG); + } catch (UnsupportedOperationException ex) { + throw new IllegalStateException(ex); + } } @Override - public void setAnalogForced(boolean isForced) {} + public void setAnalogForced(boolean isForced) { + try { + setConfigFlag(ConfigFlag.FORCE_ANALOG, isForced); + } catch (UnsupportedOperationException ex) { + throw new IllegalStateException(ex); + } + } @Override public Map setParameters(Map parameters) { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return null; + } } @Override public Map getParameters(List<String> keys) { - return null; + synchronized (mLock) { + checkNotClosedLocked(); + return null; + } } @Override public boolean isAntennaConnected() { - return true; + synchronized (mLock) { + checkNotClosedLocked(); + return true; + } } } |