OSDN Git Service

Implement part of ITunerSession interface.
authorTomasz Wasilczyk <twasilczyk@google.com>
Thu, 4 Jan 2018 20:26:40 +0000 (12:26 -0800)
committerTomasz Wasilczyk <twasilczyk@google.com>
Fri, 5 Jan 2018 03:43:59 +0000 (19:43 -0800)
Methods not covered are related to tuning or program list.

This makes 11 passing test cases and still 6 failing for the new HAL.

Test: instrumentation
Bug: 69958777
Change-Id: I2631d66d05774adb9e8fd42c8309e16f832c4478

core/java/android/hardware/radio/RadioManager.java
core/java/android/hardware/radio/TunerAdapter.java
core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
services/core/java/com/android/server/broadcastradio/hal2/Convert.java
services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java

index 9b6515c..6e383ae 100644 (file)
@@ -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) {
index 864d17c..a8a896a 100644 (file)
@@ -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();
index a8d5164..896fd15 100644 (file)
@@ -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());
 
index ef51665..7d3b670 100644 (file)
@@ -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);
                 }
index 413a27c..9158ff0 100644 (file)
@@ -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;
     }
 }
index 434e262..2c129bb 100644 (file)
@@ -186,7 +186,7 @@ class Convert {
                 false,  // isCaptureSupported
 
                 amfmConfigToBands(amfmConfig),
-                true,  // isBgScanSupported is deprecated
+                false,  // isBgScanSupported is deprecated
                 supportedProgramTypes,
                 supportedIdentifierTypes,
                 vendorInfoFromHal(prop.vendorInfo));
index 8a7ac73..45b2190 100644 (file)
@@ -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);
     }
 }
index 5ee6a4c..c9084ee 100644 (file)
@@ -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) {
index e8faf3d..c4ec94f 100644 (file)
@@ -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;
+        }
     }
 }