Update RadioTuner APIs for AIDL HAL migration

APIs in RadioTuner were updated to adopt broadcast radio HAL
migration to AIDL:
- New APIs seek and onConfigFlagUpdated were added since corresponding
  new interface methods were introduced in broadcast radio AIDL HAL.
- APIs only used in HIDL 1.x broadcast radio HAL were deprecated.
- The use of deprecated onError callback was replaced by onTuneFailed
  in tune, seek, scan and step APIs. Corresponding result types were
  also defined in RadioTuner.
- Multi-user behaviors for RadioTuner APIs were specified.
Meanwhile, a new DAB radio primary identifier was added, which was
extended to 44 bits to support Digital Multimedia Broadcasting (DMB)
radio.
The integer annotations in radio APIs were also improved.

Bug: 257337458
Test: atest com.android.server.broadcastradio
Test: atest android.hardware.radio.tests.unittests
Test: atest android.broadcastradio.cts
Change-Id: I46f0bdfae238de072e46f6561fa3f17c73dd45c8
This commit is contained in:
Weilin Xu
2022-11-24 00:25:37 +00:00
parent a13d8ed465
commit 81f50685cb
20 changed files with 510 additions and 149 deletions

View File

@@ -5267,11 +5267,12 @@ package android.hardware.radio {
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector> CREATOR;
field public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1; // 0x1
field public static final int IDENTIFIER_TYPE_DAB_DMB_SID_EXT = 14; // 0xe
field public static final int IDENTIFIER_TYPE_DAB_ENSEMBLE = 6; // 0x6
field public static final int IDENTIFIER_TYPE_DAB_FREQUENCY = 8; // 0x8
field public static final int IDENTIFIER_TYPE_DAB_SCID = 7; // 0x7
field public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
field public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
field @Deprecated public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
field @Deprecated public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
field public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10; // 0xa
field @Deprecated public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
@@ -5308,7 +5309,7 @@ package android.hardware.radio {
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector.Identifier> CREATOR;
}
@IntDef(prefix={"IDENTIFIER_TYPE_"}, value={android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_INVALID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_RDS_PI, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_SUBCHANNEL, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_NAME, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SCID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_MODULATION, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL}) @IntRange(from=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.IdentifierType {
@IntDef(prefix={"IDENTIFIER_TYPE_"}, value={android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_INVALID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_RDS_PI, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_SUBCHANNEL, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_NAME, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SCID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_MODULATION, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT}) @IntRange(from=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.IdentifierType {
}
@Deprecated @IntDef(prefix={"PROGRAM_TYPE_"}, value={android.hardware.radio.ProgramSelector.PROGRAM_TYPE_INVALID, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DAB, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DRMO, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_SXM}) @IntRange(from=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.ProgramType {
@@ -5523,30 +5524,31 @@ package android.hardware.radio {
public abstract class RadioTuner {
ctor public RadioTuner();
method public abstract int cancel();
method public abstract void cancelAnnouncement();
method public abstract void close();
method @Deprecated public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
method @Nullable public android.hardware.radio.ProgramList getDynamicProgramList(@Nullable android.hardware.radio.ProgramList.Filter);
method public abstract boolean getMute();
method @NonNull public java.util.Map<java.lang.String,java.lang.String> getParameters(@NonNull java.util.List<java.lang.String>);
method @Deprecated public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
method @Deprecated @NonNull public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(@Nullable java.util.Map<java.lang.String,java.lang.String>);
method public abstract boolean hasControl();
method @Deprecated public abstract boolean isAnalogForced();
method @Deprecated public abstract boolean isAntennaConnected();
method public boolean isConfigFlagSet(int);
method public boolean isConfigFlagSupported(int);
method public abstract int scan(int, boolean);
method @Deprecated public abstract void setAnalogForced(boolean);
method public void setConfigFlag(int, boolean);
method @Deprecated public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
method public abstract int setMute(boolean);
method @NonNull public java.util.Map<java.lang.String,java.lang.String> setParameters(@NonNull java.util.Map<java.lang.String,java.lang.String>);
method public abstract boolean startBackgroundScan();
method public abstract int step(int, boolean);
method @Deprecated public abstract int tune(int, int);
method public abstract void tune(@NonNull android.hardware.radio.ProgramSelector);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int cancel();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract void cancelAnnouncement();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract void close();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public android.hardware.radio.ProgramList getDynamicProgramList(@Nullable android.hardware.radio.ProgramList.Filter);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean getMute();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public java.util.Map<java.lang.String,java.lang.String> getParameters(@NonNull java.util.List<java.lang.String>);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(@Nullable java.util.Map<java.lang.String,java.lang.String>);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean hasControl();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean isAnalogForced();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean isAntennaConnected();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public boolean isConfigFlagSet(int);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public boolean isConfigFlagSupported(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int scan(int, boolean);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public int seek(int, boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract void setAnalogForced(boolean);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void setConfigFlag(int, boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int setMute(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public java.util.Map<java.lang.String,java.lang.String> setParameters(@NonNull java.util.Map<java.lang.String,java.lang.String>);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract boolean startBackgroundScan();
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int step(int, boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract int tune(int, int);
method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public abstract void tune(@NonNull android.hardware.radio.ProgramSelector);
field public static final int DIRECTION_DOWN = 1; // 0x1
field public static final int DIRECTION_UP = 0; // 0x0
field @Deprecated public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
@@ -5556,6 +5558,14 @@ package android.hardware.radio {
field @Deprecated public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0
field @Deprecated public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3
field @Deprecated public static final int ERROR_SERVER_DIED = 1; // 0x1
field public static final int TUNER_RESULT_CANCELED = 6; // 0x6
field public static final int TUNER_RESULT_INTERNAL_ERROR = 1; // 0x1
field public static final int TUNER_RESULT_INVALID_ARGUMENTS = 2; // 0x2
field public static final int TUNER_RESULT_INVALID_STATE = 3; // 0x3
field public static final int TUNER_RESULT_NOT_SUPPORTED = 4; // 0x4
field public static final int TUNER_RESULT_OK = 0; // 0x0
field public static final int TUNER_RESULT_TIMEOUT = 5; // 0x5
field public static final int TUNER_RESULT_UNKNOWN_ERROR = 7; // 0x7
}
public abstract static class RadioTuner.Callback {
@@ -5563,6 +5573,7 @@ package android.hardware.radio {
method public void onAntennaState(boolean);
method public void onBackgroundScanAvailabilityChange(boolean);
method public void onBackgroundScanComplete();
method public void onConfigFlagUpdated(int, boolean);
method @Deprecated public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
method public void onControlChanged(boolean);
method public void onEmergencyAnnouncement(boolean);

View File

@@ -49,7 +49,7 @@ interface ITuner {
/**
* @throws IllegalStateException if called out of sequence
*/
void scan(boolean directionDown, boolean skipSubChannel);
void seek(boolean directionDown, boolean skipSubChannel);
/**
* @throws IllegalArgumentException if invalid arguments are passed

View File

@@ -24,6 +24,13 @@ import android.hardware.radio.RadioMetadata;
/** {@hide} */
oneway interface ITunerCallback {
void onError(int status);
/**
* Callback called when tuning operations, such as tune, step, seek, failed.
*
* @param result Tuning result of {@link RadioTuner#TunerResultType} type.
* @param selector Program selector used for the tuning operation.
*/
void onTuneFailed(int result, in ProgramSelector selector);
void onConfigurationChanged(in RadioManager.BandConfig config);
void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info);
@@ -36,6 +43,18 @@ oneway interface ITunerCallback {
void onProgramListUpdated(in ProgramList.Chunk chunk);
/**
* Callback for passing updates to config flags from {@link IRadioService} to
* {@link RadioTuner}.
*
* @param flag Config flag (defined in {@link RadioManager.ConfigFlag}) updated
* @param value Updated value for the config flag
*/
void onConfigFlagUpdated(int flag, boolean value);
/**
* Callback for passing updates to vendor-specific parameter values from
* {@link IRadioService} to {@link RadioTuner}.
*
* @param parameters Vendor-specific key-value pairs
*/
void onParametersUpdated(in Map<String, String> parameters);

View File

@@ -167,7 +167,10 @@ public final class ProgramSelector implements Parcelable {
public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004;
/**
* @see {@link IDENTIFIER_TYPE_DAB_SID_EXT}
*
* @deprecated use {@link #IDENTIFIER_TYPE_DAB_DMB_SID_EXT} instead
*/
@Deprecated
public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5;
/**
* 28bit compound primary identifier for Digital Audio Broadcasting.
@@ -183,7 +186,10 @@ public final class ProgramSelector implements Parcelable {
*
* The remaining bits should be set to zeros when writing on the chip side
* and ignored when read.
*
* @deprecated use {@link #IDENTIFIER_TYPE_DAB_DMB_SID_EXT} instead
*/
@Deprecated
public static final int IDENTIFIER_TYPE_DAB_SID_EXT = IDENTIFIER_TYPE_DAB_SIDECC;
/** 16bit */
public static final int IDENTIFIER_TYPE_DAB_ENSEMBLE = 6;
@@ -197,7 +203,7 @@ public final class ProgramSelector implements Parcelable {
public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10;
/**
* 1: AM, 2:FM
* @deprecated use {@link IDENTIFIER_TYPE_DRMO_FREQUENCY} instead
* @deprecated use {@link #IDENTIFIER_TYPE_DRMO_FREQUENCY} instead
*/
@Deprecated
public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11;
@@ -205,6 +211,23 @@ public final class ProgramSelector implements Parcelable {
public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12;
/** 0-999 range */
public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13;
/**
* 44bit compound primary identifier for Digital Audio Broadcasting and
* Digital Multimedia Broadcasting.
*
* <p>Consists of (from the LSB):
* - 32bit: SId;
* - 8bit: ECC code;
* - 4bit: SCIdS.
*
* <p>SCIdS (Service Component Identifier within the Service) value
* of 0 represents the main service, while 1 and above represents
* secondary services.
*
* The remaining bits should be set to zeros when writing on the chip side
* and ignored when read.
*/
public static final int IDENTIFIER_TYPE_DAB_DMB_SID_EXT = 14;
/**
* Primary identifier for vendor-specific radio technology.
* The value format is determined by a vendor.
@@ -219,12 +242,12 @@ public final class ProgramSelector implements Parcelable {
*/
public static final int IDENTIFIER_TYPE_VENDOR_END = PROGRAM_TYPE_VENDOR_END;
/**
* @deprecated use {@link IDENTIFIER_TYPE_VENDOR_START} instead
* @deprecated use {@link #IDENTIFIER_TYPE_VENDOR_START} instead
*/
@Deprecated
public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = IDENTIFIER_TYPE_VENDOR_START;
/**
* @deprecated use {@link IDENTIFIER_TYPE_VENDOR_END} instead
* @deprecated use {@link #IDENTIFIER_TYPE_VENDOR_END} instead
*/
@Deprecated
public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = IDENTIFIER_TYPE_VENDOR_END;
@@ -245,6 +268,7 @@ public final class ProgramSelector implements Parcelable {
IDENTIFIER_TYPE_DRMO_MODULATION,
IDENTIFIER_TYPE_SXM_SERVICE_ID,
IDENTIFIER_TYPE_SXM_CHANNEL,
IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
})
@IntRange(from = IDENTIFIER_TYPE_VENDOR_START, to = IDENTIFIER_TYPE_VENDOR_END)
@Retention(RetentionPolicy.SOURCE)
@@ -285,7 +309,7 @@ public final class ProgramSelector implements Parcelable {
* Type of a radio technology.
*
* @return program type.
* @deprecated use {@link getPrimaryId} instead
* @deprecated use {@link #getPrimaryId} instead
*/
@Deprecated
public @ProgramType int getProgramType() {

View File

@@ -82,6 +82,24 @@ public class RadioManager {
/** Method return status: time out before operation completion */
public static final int STATUS_TIMED_OUT = -110;
/**
* Radio operation status types
*
* @hide
*/
@IntDef(prefix = { "STATUS_" }, value = {
STATUS_OK,
STATUS_ERROR,
STATUS_PERMISSION_DENIED,
STATUS_NO_INIT,
STATUS_BAD_VALUE,
STATUS_DEAD_OBJECT,
STATUS_INVALID_OPERATION,
STATUS_TIMED_OUT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface RadioStatusType{}
// keep in sync with radio_class_t in /system/core/incluse/system/radio.h
/** Radio module class supporting FM (including HD radio) and AM */
@@ -330,6 +348,7 @@ public class RadioManager {
* program list.
* @return the number of audio sources available.
*/
@RadioStatusType
public int getNumAudioSources() {
return mNumAudioSources;
}
@@ -1724,6 +1743,7 @@ public class RadioManager {
* </ul>
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioStatusType
public int listModules(List<ModuleProperties> modules) {
if (modules == null) {
Log.e(TAG, "the output list must not be empty");

View File

@@ -16,14 +16,20 @@
package android.hardware.radio;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.graphics.Bitmap;
import android.os.Handler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
/**
* RadioTuner interface provides methods to control a radio tuner on the device: selecting and
@@ -43,16 +49,21 @@ public abstract class RadioTuner {
public static final int DIRECTION_DOWN = 1;
/**
* Close the tuner interface. The {@link Callback} callback will not be called
* anymore and associated resources will be released.
* Must be called when the tuner is not needed to make hardware resources available to others.
* Close the tuner interface.
*
* <p>The {@link Callback} callback will not be called anymore and associated resources will be
* released. Must be called when the tuner is not needed to make hardware resources available
* to others.
* */
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract void close();
/**
* Set the active band configuration for this module.
* Must be a valid configuration obtained via buildConfig() from a valid BandDescriptor listed
* in the ModuleProperties of the module with the specified ID.
*
* <p>Must be a valid configuration obtained via buildConfig() from a valid BandDescriptor
* listed in the ModuleProperties of the module with the specified ID.
*
* @param config The desired band configuration (FmBandConfig or AmBandConfig).
* @return
* <ul>
@@ -67,10 +78,13 @@ public abstract class RadioTuner {
* @deprecated Only applicable for HAL 1.x.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int setConfiguration(RadioManager.BandConfig config);
/**
* Get current configuration.
*
* @param config a BandConfig array of lengh 1 where the configuration is returned.
* @return
* <ul>
@@ -86,11 +100,15 @@ public abstract class RadioTuner {
* @deprecated Only applicable for HAL 1.x.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int getConfiguration(RadioManager.BandConfig[] config);
/**
* Set mute state. When muted, the radio tuner audio source is not available for playback on
* Set mute state.
*
* <p>When muted, the radio tuner audio source is not available for playback on
* any audio device. when unmuted, the radio tuner audio source is output as a media source
* and renderd over the audio device selected for media use case.
* The radio tuner audio source is muted by default when the tuner is first attached.
@@ -107,6 +125,8 @@ public abstract class RadioTuner {
* service fails, </li>
* </ul>
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int setMute(boolean mute);
/**
@@ -115,13 +135,19 @@ public abstract class RadioTuner {
* @return {@code true} if the radio tuner audio source is muted or a problem occured
* retrieving the mute state, {@code false} otherwise.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract boolean getMute();
/**
* Step up or down by one channel spacing.
* The operation is asynchronous and {@link Callback}
* onProgramInfoChanged() will be called when step completes or
* onError() when cancelled or timeout.
*
* <p>The operation is asynchronous and {@link Callback#onProgramInfoChanged}
* will be called when step completes or {@link Callback#onTuneFailed}
* when timeout or canceled.
*
* <p>When this operation is called by users other than current user or system user, it is
* ignored silently.
*
* @param direction {@link #DIRECTION_UP} or {@link #DIRECTION_DOWN}.
* @param skipSubChannel indicates to skip sub channels when the configuration currently
* selected supports sub channel (e.g HD Radio). N/A otherwise.
@@ -136,13 +162,50 @@ public abstract class RadioTuner {
* service fails, </li>
* </ul>
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int step(int direction, boolean skipSubChannel);
/**
* Scan up or down to next valid station.
* The operation is asynchronous and {@link Callback}
* onProgramInfoChanged() will be called when scan completes or
* onError() when cancelled or timeout.
*
* <p>The operation is asynchronous and {@link Callback#onProgramInfoChanged}
* will be called when scan completes or {@link Callback#onTuneFailed}
* when timeout or canceled.
*
* <p>When this operation is called by users other than current user or system user, it is
* ignored silently.
*
* @param direction {@link #DIRECTION_UP} or {@link #DIRECTION_DOWN}.
* @param skipSubChannel indicates to skip sub channels when the configuration currently
* selected supports sub channel (e.g HD Radio). N/A otherwise.
* @return
* <ul>
* <li>{@link RadioManager#STATUS_OK} in case of success, </li>
* <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
* <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
* <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
* <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
* <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
* service fails, </li>
* </ul>
* @deprecated Use {@link #seek(int, boolean)} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int scan(int direction, boolean skipSubChannel);
/**
* Seek up or down to next valid station.
*
* <p>The operation is asynchronous and {@link Callback#onProgramInfoChanged}
* will be called when seek completes or {@link Callback#onTuneFailed}
* when timeout or canceled.
*
* <p>When this operation is called by users other than current user or system user, it is
* ignore silently.
*
* @param direction {@link #DIRECTION_UP} or {@link #DIRECTION_DOWN}.
* @param skipSubChannel indicates to skip sub channels when the configuration currently
* selected supports sub channel (e.g HD Radio). N/A otherwise.
@@ -157,13 +220,22 @@ public abstract class RadioTuner {
* service fails, </li>
* </ul>
*/
public abstract int scan(int direction, boolean skipSubChannel);
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public int seek(int direction, boolean skipSubChannel) {
throw new UnsupportedOperationException("Seeking is not supported");
}
/**
* Tune to a specific frequency.
* The operation is asynchronous and {@link Callback}
* onProgramInfoChanged() will be called when tune completes or
* onError() when cancelled or timeout.
*
* <p>The operation is asynchronous and {@link Callback#onProgramInfoChanged}
* will be called when tune completes or {@link Callback#onTuneFailed}
* when timeout or canceled.
*
* <p>When this operation is called by users other than current user or system user, it is
* ignored silently.
*
* @param channel the specific channel or frequency to tune to.
* @param subChannel the specific sub-channel to tune to. N/A if the selected configuration
* does not support cub channels.
@@ -177,25 +249,37 @@ public abstract class RadioTuner {
* <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
* service fails, </li>
* </ul>
* @deprecated Use {@link tune(ProgramSelector)} instead.
* @deprecated Use {@link #tune(ProgramSelector)} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int tune(int channel, int subChannel);
/**
* Tune to a program.
*
* The operation is asynchronous and {@link Callback} onProgramInfoChanged() will be called
* when tune completes or onError() when cancelled or on timeout.
* <p>The operation is asynchronous and {@link Callback#onProgramInfoChanged}
* will be called when tune completes or {@link Callback#onTuneFailed}
* when timeout or canceled.
*
* <p>When this operation is called by users other than current user or system user, it is
* ignored silently.
*
* @throws IllegalArgumentException if the provided selector is invalid
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract void tune(@NonNull ProgramSelector selector);
/**
* Cancel a pending scan or tune operation.
* If an operation is pending, {@link Callback} onError() will be called with
*
* <p>If an operation is pending, {@link Callback#onTuneFailed} will be called with
* {@link #ERROR_CANCELLED}.
*
* <p>When this operation is called by users other than current user or system
* user, it is ignored silently.
*
* @return
* <ul>
* <li>{@link RadioManager#STATUS_OK} in case of success, </li>
@@ -207,21 +291,27 @@ public abstract class RadioTuner {
* service fails, </li>
* </ul>
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int cancel();
/**
* Cancels traffic or emergency announcement.
*
* If there was no announcement to cancel, no action is taken.
* <p>If there was no announcement to cancel, no action is taken.
*
* There is a race condition between calling cancelAnnouncement and the actual announcement
* <p>There is a race condition between calling cancelAnnouncement and the actual announcement
* being finished, so onTrafficAnnouncement / onEmergencyAnnouncement callback should be
* tracked with proper locking.
* @deprecated Only applicable for HAL 1.x.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract void cancelAnnouncement();
/**
* Get current station information.
*
* @param info a ProgramInfo array of lengh 1 where the information is returned.
* @return
* <ul>
@@ -233,23 +323,27 @@ 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 Use {@link Callback#onProgramInfoChanged(RadioManager.ProgramInfo)} callback
* instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
@RadioManager.RadioStatusType
public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
/**
* Retrieves a {@link Bitmap} for the given image ID or null,
* if the image was missing from the tuner.
*
* This involves doing a call to the tuner, so the bitmap should be cached
* <p>This involves doing a call to the tuner, so the bitmap should be cached
* on the application side.
*
* If the method returns null for non-zero ID, it means the image was
* <p>If the method returns null for non-zero ID, it means the image was
* updated on the tuner side. There is a race conditon between fetching
* image for an old ID and tuner updating the image (and cleaning up the
* old image). In such case, a new ProgramInfo with updated image id will
* be sent with a {@link onProgramInfoChanged} callback.
* be sent with a {@link Callback#onProgramInfoChanged(RadioManager.ProgramInfo)}
* callback.
*
* @param id The image identifier, retrieved with
* {@link RadioMetadata#getBitmapId(String)}.
@@ -258,14 +352,16 @@ public abstract class RadioTuner {
* @hide This API is not thoroughly elaborated yet
*/
@SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract @Nullable Bitmap getMetadataImage(int id);
/**
* Initiates a background scan to update internally cached program list.
*
* It may not be necessary to initiate the scan explicitly - the scan MAY be performed on boot.
* <p>It may not be necessary to initiate the scan explicitly - the scan MAY be performed on
* boot.
*
* The operation is asynchronous and {@link Callback} backgroundScanComplete or onError will
* <p>The operation is asynchronous and {@link Callback} backgroundScanComplete or onError will
* be called if the return value of this call was {@code true}. As result of this call
* programListChanged may be triggered (if the scanned list differs).
*
@@ -273,13 +369,16 @@ public abstract class RadioTuner {
* is unavailable; ie. temporarily due to ongoing foreground playback in single-tuner device
* or permanently if the feature is not supported
* (see ModuleProperties#isBackgroundScanningSupported()).
* @deprecated Only applicable for HAL 1.x.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract boolean startBackgroundScan();
/**
* Get the list of discovered radio stations.
*
* To get the full list, set filter to null or empty map.
* <p>To get the full list, set filter to null or empty map.
* Keys must be prefixed with unique vendor Java-style namespace,
* eg. 'com.somecompany.parameter1'.
*
@@ -288,24 +387,27 @@ public abstract class RadioTuner {
* @throws IllegalStateException if the scan is in progress or has not been started,
* startBackgroundScan() call may fix it.
* @throws IllegalArgumentException if the vendorFilter argument is not valid.
* @deprecated Use {@link getDynamicProgramList} instead.
* @deprecated Use {@link #getDynamicProgramList(ProgramList.Filter)} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract @NonNull List<RadioManager.ProgramInfo>
getProgramList(@Nullable Map<String, String> vendorFilter);
/**
* Get the dynamic list of discovered radio stations.
*
* The list object is updated asynchronously; to get the updates register
* with {@link ProgramList#addListCallback}.
* <p>The list object is updated asynchronously; to get the updates register
* with {@link ProgramList#registerListCallback(ProgramList.ListCallback)}
* or {@link ProgramList#registerListCallback(Executor, ProgramList.ListCallback)}.
*
* When the returned object is no longer used, it must be closed.
* <p>When the returned object is no longer used, it must be closed.
*
* @param filter filter for the list, or null to get the full list.
* @return the dynamic program list object, close it after use
* or {@code null} if program list is not supported by the tuner
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public @Nullable ProgramList getDynamicProgramList(@Nullable ProgramList.Filter filter) {
return null;
}
@@ -316,26 +418,28 @@ public abstract class RadioTuner {
* @throws IllegalStateException if the switch is not supported at current
* configuration.
* @return {@code true} if analog is forced, {@code false} otherwise.
* @deprecated Use {@link isConfigFlagSet(int)} instead.
* @deprecated Use {@link #isConfigFlagSet(int)} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract boolean isAnalogForced();
/**
* Forces the analog playback for the supporting radio technology.
*
* User may disable digital playback for FM HD Radio or hybrid FM/DAB with
* <p>User may disable digital playback for FM HD Radio or hybrid FM/DAB with
* this option. This is purely user choice, ie. does not reflect digital-
* analog handover managed from the HAL implementation side.
*
* Some radio technologies may not support this, ie. DAB.
* <p>Some radio technologies may not support this, ie. DAB.
*
* @param isForced {@code true} to force analog, {@code false} for a default behaviour.
* @throws IllegalStateException if the switch is not supported at current
* configuration.
* @deprecated Use {@link setConfigFlag(int, boolean)} instead.
* @deprecated Use {@link #setConfigFlag(int, boolean)} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract void setAnalogForced(boolean isForced);
/**
@@ -344,6 +448,7 @@ public abstract class RadioTuner {
* @param flag Flag to check.
* @return True, if the flag is supported.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public boolean isConfigFlagSupported(@RadioManager.ConfigFlag int flag) {
return false;
}
@@ -351,29 +456,34 @@ public abstract class RadioTuner {
/**
* Fetches the current setting of a given config flag.
*
* The success/failure result is consistent with isConfigFlagSupported.
* <p>The success/failure result is consistent with isConfigFlagSupported.
*
* @param flag Flag to fetch.
* @return The current value of the flag.
* @throws IllegalStateException if the flag is not applicable right now.
* @throws UnsupportedOperationException if the flag is not supported at all.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public boolean isConfigFlagSet(@RadioManager.ConfigFlag int flag) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("isConfigFlagSet is not supported");
}
/**
* Sets the config flag.
*
* The success/failure result is consistent with isConfigFlagSupported.
* <p>The success/failure result is consistent with isConfigFlagSupported.
*
* <p>When this operation is called by users other than current user or system user,
* it is ignored silently.
*
* @param flag Flag to set.
* @param value The new value of a given flag.
* @throws IllegalStateException if the flag is not applicable right now.
* @throws UnsupportedOperationException if the flag is not supported at all.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public void setConfigFlag(@RadioManager.ConfigFlag int flag, boolean value) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Setting config flag is not supported");
}
/**
@@ -381,30 +491,37 @@ public abstract class RadioTuner {
* The framework does not interpret the parameters, they are passed
* in an opaque manner between a vendor application and HAL.
*
* Framework does not make any assumptions on the keys or values, other than
* <p>Framework does not make any assumptions on the keys or values, other than
* ones stated in VendorKeyValue documentation (a requirement of key
* prefixes).
* See VendorKeyValue at hardware/interfaces/broadcastradio/2.0/types.hal.
* See VendorKeyValue at hardware/interfaces/broadcastradio/2.0/types.hal for
* HIDL 2.0 HAL or
* hardware/interfaces/broadcastradio/aidl/android/hardware/broadcastradio/VendorKeyValue.aidl
* for AIDL HAL.
*
* For each pair in the result map, the key will be one of the keys
* <p>For each pair in the result map, the key will be one of the keys
* contained in the input (possibly with wildcards expanded), and the value
* will be a vendor-specific result status (such as "OK" or an error code).
* The implementation may choose to return an empty map, or only return
* a status for a subset of the provided inputs, at its discretion.
*
* Application and HAL must not use keys with unknown prefix. In particular,
* <p>Application and HAL must not use keys with unknown prefix. In particular,
* it must not place a key-value pair in results vector for unknown key from
* parameters vector - instead, an unknown key should simply be ignored.
* In other words, results vector may contain a subset of parameter keys
* (however, the framework doesn't enforce a strict subset - the only
* formal requirement is vendor domain prefix for keys).
*
* <p>When this operation is called by users other than current user or system user,
* it is ignored silently.
*
* @param parameters Vendor-specific key-value pairs.
* @return Operation completion status for parameters being set.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public @NonNull Map<String, String>
setParameters(@NonNull Map<String, String> parameters) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Setting parameters is not supported");
}
/**
@@ -412,23 +529,24 @@ public abstract class RadioTuner {
* The framework does not interpret the parameters, they are passed
* in an opaque manner between a vendor application and HAL.
*
* Framework does not cache set/get requests, so it's possible for
* <p>Framework does not cache set/get requests, so it's possible for
* getParameter to return a different value than previous setParameter call.
*
* The syntax and semantics of keys are up to the vendor (as long as prefix
* <p>The syntax and semantics of keys are up to the vendor (as long as prefix
* rules are obeyed). For instance, vendors may include some form of
* wildcard support. In such case, result vector may be of different size
* than requested keys vector. However, wildcards are not recognized by
* framework and they are passed as-is to the HAL implementation.
*
* Unknown keys must be ignored and not placed into results vector.
* <p>Unknown keys must be ignored and not placed into results vector.
*
* @param keys Parameter keys to fetch.
* @return Vendor-specific key-value pairs.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public @NonNull Map<String, String>
getParameters(@NonNull List<String> keys) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Getting parameters is not supported");
}
/**
@@ -436,14 +554,16 @@ public abstract class RadioTuner {
* 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 Use {@link Callback#onAntennaState(boolean)} callback instead
*/
@Deprecated
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract boolean isAntennaConnected();
/**
* Indicates if this client actually controls the tuner.
* Control is always granted after
*
* <p>Control is always granted after
* {@link RadioManager#openTuner(int,
* RadioManager.BandConfig, boolean, Callback, Handler)}
* returns a non null tuner interface.
@@ -451,48 +571,102 @@ public abstract class RadioTuner {
* When this happens, {@link Callback#onControlChanged(boolean)} is received.
* The client can either wait for control to be returned (which is indicated by the same
* callback) or close and reopen the tuner interface.
*
* @return {@code true} if this interface controls the tuner,
* {@code false} otherwise or if a problem occured retrieving the state.
*/
@RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
public abstract boolean hasControl();
/** Indicates a failure of radio IC or driver.
* The application must close and re open the tuner
* @deprecated See {@link onError} callback.
*
* <p>The application must close and re open the tuner
*
* @deprecated See {@link RadioTuner.Callback#onError(int)} 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
* @deprecated See {@link onError} callback.
*
* <p>The application must close and re open the tuner
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_SERVER_DIED = 1;
/** A pending seek or tune operation was cancelled
* @deprecated See {@link onError} callback.
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_CANCELLED = 2;
/** A pending seek or tune operation timed out
* @deprecated See {@link onError} callback.
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_SCAN_TIMEOUT = 3;
/** The requested configuration could not be applied
* @deprecated See {@link onError} callback.
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_CONFIG = 4;
/** Background scan was interrupted due to hardware becoming temporarily unavailable.
* @deprecated See {@link onError} callback.
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5;
/** Background scan failed due to other error, ie. HW failure.
* @deprecated See {@link onError} callback.
* @deprecated See {@link RadioTuner.Callback#onError(int)} callback.
*/
@Deprecated
public static final int ERROR_BACKGROUND_SCAN_FAILED = 6;
/** Result when a tune, seek, or step operation runs without error.
*/
public static final int TUNER_RESULT_OK = 0;
/** Result when internal error occurs in HAL.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_INTERNAL_ERROR = 1;
/** Result used when the input argument for the method is invalid.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_INVALID_ARGUMENTS = 2;
/** Result when HAL is of invalid state.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_INVALID_STATE = 3;
/** Result when the operation is not supported.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_NOT_SUPPORTED = 4;
/** Result when a tune, seek, or step operation is timeout
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_TIMEOUT = 5;
/** Result when a tune, seek, or step operation is canceled before processed.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_CANCELED = 6;
/** Result when a tune, seek, or step operation fails due to unknown error.
* See {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} callback.
*/
public static final int TUNER_RESULT_UNKNOWN_ERROR = 7;
/**
* Tuning operation result types
*
* @hide
*/
@IntDef(prefix = { "TUNER_RESULT_" }, value = {
TUNER_RESULT_OK,
TUNER_RESULT_INTERNAL_ERROR,
TUNER_RESULT_INVALID_ARGUMENTS,
TUNER_RESULT_INVALID_STATE,
TUNER_RESULT_NOT_SUPPORTED,
TUNER_RESULT_TIMEOUT,
TUNER_RESULT_CANCELED,
TUNER_RESULT_UNKNOWN_ERROR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface TunerResultType{}
/**
* Callback provided by the client application when opening a {@link RadioTuner}
@@ -506,8 +680,9 @@ public abstract class RadioTuner {
* {@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.
* @deprecated Use {@link RadioTuner.Callback#onTuneFailed(int, ProgramSelector)} for
* tune, scan and step; other use cases (configuration, background scan)
* are already deprecated.
*/
public void onError(int status) {}
@@ -518,7 +693,7 @@ public abstract class RadioTuner {
* @param selector ProgramSelector argument of tune that failed;
* null for scan and step.
*/
public void onTuneFailed(int result, @Nullable ProgramSelector selector) {}
public void onTuneFailed(@TunerResultType int result, @Nullable ProgramSelector selector) {}
/**
* onConfigurationChanged() is called upon successful completion of
@@ -533,7 +708,7 @@ public abstract class RadioTuner {
/**
* Called when program info (including metadata) for the current program has changed.
*
* It happens either upon successful completion of {@link RadioTuner#step(int, boolean)},
* <p>It happens either upon successful completion of {@link RadioTuner#step(int, boolean)},
* {@link RadioTuner#scan(int, boolean)}, {@link RadioTuner#tune(int, int)}; when
* a switching to alternate frequency occurs; or when metadata is updated.
*/
@@ -589,16 +764,29 @@ public abstract class RadioTuner {
/**
* Called when available program list changed.
*
* Use {@link RadioTuner#getProgramList(String)} to get an actual list.
* Use {@link RadioTuner#getProgramList(Map)} to get an actual list.
*/
public void onProgramListChanged() {}
/**
* Called when config flags are updated asynchronously due to internal events
* in broadcast radio HAL.
*
* {@link RadioTuner#setConfigFlag(int, boolean)} must not trigger this
* callback.
*
* @param flag Config flag updated
* @param value Value of the updated config flag
*/
public void onConfigFlagUpdated(@RadioManager.ConfigFlag int flag, boolean value) {}
/**
* Generic callback for passing updates to vendor-specific parameter values.
* The framework does not interpret the parameters, they are passed
*
* <p>The framework does not interpret the parameters, they are passed
* in an opaque manner between a vendor application and HAL.
*
* It's up to the HAL implementation if and how to implement this callback,
* <p>It's up to the HAL implementation if and how to implement this callback,
* as long as it obeys the prefix rule. In particular, only selected keys
* may be notified this way. However, setParameters must not trigger
* this callback, while an internal event can change parameters

View File

@@ -154,7 +154,7 @@ final class TunerAdapter extends RadioTuner {
@Override
public int scan(int direction, boolean skipSubChannel) {
try {
mTuner.scan(/* directionDown= */ direction == RadioTuner.DIRECTION_DOWN,
mTuner.seek(/* directionDown= */ direction == RadioTuner.DIRECTION_DOWN,
skipSubChannel);
} catch (IllegalStateException e) {
Log.e(TAG, "Can't scan", e);
@@ -166,6 +166,21 @@ final class TunerAdapter extends RadioTuner {
return RadioManager.STATUS_OK;
}
@Override
public int seek(int direction, boolean skipSubChannel) {
try {
mTuner.seek(/* directionDown= */ direction == RadioTuner.DIRECTION_DOWN,
skipSubChannel);
} catch (IllegalStateException e) {
Log.e(TAG, "Can't seek", e);
return RadioManager.STATUS_INVALID_OPERATION;
} catch (RemoteException e) {
Log.e(TAG, "Service died", e);
return RadioManager.STATUS_DEAD_OBJECT;
}
return RadioManager.STATUS_OK;
}
@Override
public int tune(int channel, int subChannel) {
try {

View File

@@ -245,6 +245,11 @@ final class TunerCallbackAdapter extends ITunerCallback.Stub {
});
}
@Override
public void onConfigFlagUpdated(@RadioManager.ConfigFlag int flag, boolean value) {
mHandler.post(() -> mCallback.onConfigFlagUpdated(flag, value));
}
@Override
public void onParametersUpdated(Map<String, String> parameters) {
mHandler.post(() -> mCallback.onParametersUpdated(parameters));

View File

@@ -17,6 +17,7 @@ package android.hardware.radio.tests.functional;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -335,8 +336,10 @@ public class RadioTunerTest {
assertEquals(RadioManager.STATUS_OK, scanRet);
assertEquals(RadioManager.STATUS_OK, cancelRet);
verify(mCallback, after(kCancelTimeoutMs).atMost(1)).onError(RadioTuner.ERROR_CANCELLED);
verify(mCallback, after(kCancelTimeoutMs).atMost(1))
.onTuneFailed(eq(RadioTuner.TUNER_RESULT_CANCELED), any());
verify(mCallback, atMost(1)).onProgramInfoChanged(any());
Mockito.reset(mCallback);
}
@Test

View File

@@ -129,6 +129,18 @@ public final class DefaultRadioTunerTest {
}
};
@Test
public void seek_forRadioTuner_throwsException() {
UnsupportedOperationException thrown = assertThrows(
UnsupportedOperationException.class, () -> {
DEFAULT_RADIO_TUNER.seek(RadioTuner.DIRECTION_DOWN,
/* skipSubChannel= */ false);
});
assertWithMessage("Exception for seeking on default radio tuner")
.that(thrown).hasMessageThat().contains("Seeking is not supported");
}
@Test
public void getDynamicProgramList_forRadioTuner_returnsNull() {
assertWithMessage("Dynamic program list obtained from default radio tuner")
@@ -143,29 +155,45 @@ public final class DefaultRadioTunerTest {
@Test
public void isConfigFlagSet_forRadioTuner_throwsException() {
assertThrows(UnsupportedOperationException.class, () -> {
DEFAULT_RADIO_TUNER.isConfigFlagSet(/* flag= */ 1);
});
UnsupportedOperationException thrown = assertThrows(
UnsupportedOperationException.class, () -> {
DEFAULT_RADIO_TUNER.isConfigFlagSet(/* flag= */ 1);
});
assertWithMessage("Exception for isConfigFlagSet on default radio tuner")
.that(thrown).hasMessageThat().contains("isConfigFlagSet is not supported");
}
@Test
public void setConfigFlag_forRadioTuner_throwsException() {
assertThrows(UnsupportedOperationException.class, () -> {
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
() -> {
DEFAULT_RADIO_TUNER.setConfigFlag(/* flag= */ 1, /* value= */ false);
});
assertWithMessage("Exception for setting config flag on default radio tuner")
.that(thrown).hasMessageThat().contains("Setting config flag is not supported");
}
@Test
public void setParameters_forRadioTuner_throwsException() {
assertThrows(UnsupportedOperationException.class, () -> {
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
() -> {
DEFAULT_RADIO_TUNER.setParameters(Map.of("testKey", "testValue"));
});
assertWithMessage("Exception for setting parameters from default radio tuner")
.that(thrown).hasMessageThat().contains("Setting parameters is not supported");
}
@Test
public void getParameters_forRadioTuner_throwsException() {
assertThrows(UnsupportedOperationException.class, () -> {
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
() -> {
DEFAULT_RADIO_TUNER.getParameters(List.of("testKey"));
});
assertWithMessage("Exception for getting parameters from default radio tuner")
.that(thrown).hasMessageThat().contains("Getting parameters is not supported");
}
}

View File

@@ -55,7 +55,6 @@ public final class TunerAdapterTest {
private static final int AM_LOWER_LIMIT_KHZ = 150;
private static final RadioManager.BandConfig TEST_BAND_CONFIG = createBandConfig();
private static final ProgramSelector.Identifier FM_IDENTIFIER =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 94300);
@@ -169,16 +168,31 @@ public final class TunerAdapterTest {
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramInfoChanged(FM_PROGRAM_INFO);
}
@Test
public void scan_forTunerAdapter_succeeds() throws Exception {
doAnswer(invocation -> {
mTunerCallback.onCurrentProgramInfoChanged(FM_PROGRAM_INFO);
return RadioManager.STATUS_OK;
}).when(mTunerMock).seek(anyBoolean(), anyBoolean());
int scanStatus = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, /* skipSubChannel= */ false);
verify(mTunerMock).seek(/* directionDown= */ true, /* skipSubChannel= */ false);
assertWithMessage("Status for scaning")
.that(scanStatus).isEqualTo(RadioManager.STATUS_OK);
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramInfoChanged(FM_PROGRAM_INFO);
}
@Test
public void seek_forTunerAdapter_succeeds() throws Exception {
doAnswer(invocation -> {
mTunerCallback.onCurrentProgramInfoChanged(FM_PROGRAM_INFO);
return RadioManager.STATUS_OK;
}).when(mTunerMock).scan(anyBoolean(), anyBoolean());
}).when(mTunerMock).seek(anyBoolean(), anyBoolean());
int scanStatus = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, /* skipSubChannel= */ false);
verify(mTunerMock).scan(/* directionDown= */ true, /* skipSubChannel= */ false);
verify(mTunerMock).seek(/* directionDown= */ true, /* skipSubChannel= */ false);
assertWithMessage("Status for seeking")
.that(scanStatus).isEqualTo(RadioManager.STATUS_OK);
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramInfoChanged(FM_PROGRAM_INFO);
@@ -187,13 +201,14 @@ public final class TunerAdapterTest {
@Test
public void seek_forTunerAdapter_invokesOnErrorWhenTimeout() throws Exception {
doAnswer(invocation -> {
mTunerCallback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
mTunerCallback.onTuneFailed(RadioManager.STATUS_TIMED_OUT, FM_SELECTOR);
return RadioManager.STATUS_OK;
}).when(mTunerMock).scan(anyBoolean(), anyBoolean());
}).when(mTunerMock).seek(anyBoolean(), anyBoolean());
mRadioTuner.scan(RadioTuner.DIRECTION_UP, /* skipSubChannel*/ true);
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onError(RadioTuner.ERROR_SCAN_TIMEOUT);
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onTuneFailed(
RadioManager.STATUS_TIMED_OUT, FM_SELECTOR);
}
@Test
@@ -414,6 +429,17 @@ public final class TunerAdapterTest {
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramListChanged();
}
@Test
public void onConfigFlagUpdated_forTunerCallbackAdapter() throws Exception {
int configFlag = RadioManager.CONFIG_RDS_AF;
boolean configFlagValue = true;
mTunerCallback.onConfigFlagUpdated(configFlag, configFlagValue);
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS))
.onConfigFlagUpdated(configFlag, configFlagValue);
}
@Test
public void onParametersUpdated_forTunerCallbackAdapter() throws Exception {
Map<String, String> parametersExpected = Map.of("ParameterKeyMock", "ParameterValueMock");

View File

@@ -377,28 +377,28 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void scan_withDirectionUp() throws Exception {
public void seek_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[2];
ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq);
RadioManager.ProgramInfo scanUpInfo = AidlTestUtils.makeProgramInfo(
RadioManager.ProgramInfo seekUpInfo = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ false)),
SIGNAL_QUALITY);
openAidlClients(/* numClients= */ 1);
mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo(
ConversionUtils.programSelectorToHalProgramSelector(initialSel), SIGNAL_QUALITY);
mTunerSessions[0].scan(/* directionDown= */ false, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ false, /* skipSubChannel= */ false);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onCurrentProgramInfoChanged(scanUpInfo);
.onCurrentProgramInfoChanged(seekUpInfo);
}
@Test
public void scan_callsOnTuneFailedWhenTimeout() throws Exception {
public void seek_callsOnTuneFailedWhenTimeout() throws Exception {
int numSessions = 2;
openAidlClients(numSessions);
mTunerSessions[0].scan(/* directionDown= */ false, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ false, /* skipSubChannel= */ false);
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT)
@@ -407,19 +407,19 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void scan_withDirectionDown() throws Exception {
public void seek_withDirectionDown() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[2];
ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq);
RadioManager.ProgramInfo scanUpInfo = AidlTestUtils.makeProgramInfo(
RadioManager.ProgramInfo seekUpInfo = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ true)),
SIGNAL_QUALITY);
openAidlClients(/* numClients= */ 1);
mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo(
ConversionUtils.programSelectorToHalProgramSelector(initialSel), SIGNAL_QUALITY);
mTunerSessions[0].scan(/* directionDown= */ true, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onCurrentProgramInfoChanged(scanUpInfo);
.onCurrentProgramInfoChanged(seekUpInfo);
}
@Test
@@ -585,7 +585,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void onConfigFlagUpdated_forTunerCallback() throws Exception {
public void onAntennaStateChange_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
@@ -597,6 +597,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
}
@Test
public void onConfigFlagUpdated_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
int flag = UNSUPPORTED_CONFIG_FLAG + 1;
boolean configFlagValue = true;
mHalTunerCallback.onConfigFlagUpdated(flag, configFlagValue);
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT)
.onConfigFlagUpdated(flag, configFlagValue);
}
}
@Test
public void onParametersUpdated_forTunerCallback() throws Exception {
int numSessions = 3;

View File

@@ -384,28 +384,28 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void scan_withDirectionUp() throws Exception {
public void seek_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[2];
ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
RadioManager.ProgramInfo scanUpInfo = TestUtils.makeProgramInfo(
RadioManager.ProgramInfo seekUpInfo = TestUtils.makeProgramInfo(
TestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ false)),
SIGNAL_QUALITY);
openAidlClients(/* numClients= */ 1);
mHalCurrentInfo = TestUtils.makeHalProgramInfo(
Convert.programSelectorToHal(initialSel), SIGNAL_QUALITY);
mTunerSessions[0].scan(/* directionDown= */ false, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ false, /* skipSubChannel= */ false);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onCurrentProgramInfoChanged(scanUpInfo);
.onCurrentProgramInfoChanged(seekUpInfo);
}
@Test
public void scan_callsOnTuneFailedWhenTimeout() throws Exception {
public void seek_callsOnTuneFailedWhenTimeout() throws Exception {
int numSessions = 2;
openAidlClients(numSessions);
mTunerSessions[0].scan(/* directionDown= */ false, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ false, /* skipSubChannel= */ false);
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT)
@@ -414,19 +414,19 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void scan_withDirectionDown() throws Exception {
public void seek_withDirectionDown() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[2];
ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
RadioManager.ProgramInfo scanUpInfo = TestUtils.makeProgramInfo(
RadioManager.ProgramInfo seekUpInfo = TestUtils.makeProgramInfo(
TestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ true)),
SIGNAL_QUALITY);
openAidlClients(/* numClients= */ 1);
mHalCurrentInfo = TestUtils.makeHalProgramInfo(
Convert.programSelectorToHal(initialSel), SIGNAL_QUALITY);
mTunerSessions[0].scan(/* directionDown= */ true, /* skipSubChannel= */ false);
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onCurrentProgramInfoChanged(scanUpInfo);
.onCurrentProgramInfoChanged(seekUpInfo);
}
@Test

View File

@@ -143,6 +143,7 @@ final class ConversionUtils {
case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE:
case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID:
case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY:
case ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT:
return ProgramSelector.PROGRAM_TYPE_DAB;
case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID:
case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY:

View File

@@ -147,8 +147,9 @@ final class RadioModule {
@Override
public void onConfigFlagUpdated(int flag, boolean value) {
fireLater(() -> {
// TODO(b/243853343): implement config flag update method in
// android.hardware.radio.ITunerCallback
synchronized (mLock) {
fanoutAidlCallbackLocked(cb -> cb.onConfigFlagUpdated(flag, value));
}
});
}

View File

@@ -178,8 +178,8 @@ final class TunerSession extends ITuner.Stub {
}
@Override
public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException {
mLogger.logRadioEvent("Scan with direction %s, skipSubChannel? %s",
public void seek(boolean directionDown, boolean skipSubChannel) throws RemoteException {
mLogger.logRadioEvent("Seek with direction %s, skipSubChannel? %s",
directionDown ? "down" : "up", skipSubChannel ? "yes" : "no");
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
Slogf.w(TAG, "Cannot scan on AIDL HAL client from non-current user");
@@ -232,8 +232,7 @@ final class TunerSession extends ITuner.Stub {
@Override
public void cancelAnnouncement() {
// TODO(b/244485175): deperacte cancelAnnouncement
Slogf.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in AIDL");
Slogf.w(TAG, "Announcements control doesn't involve cancelling at the HAL level in AIDL");
}
@Override
@@ -244,7 +243,7 @@ final class TunerSession extends ITuner.Stub {
@Override
public boolean startBackgroundScan() {
Slogf.i(TAG, "Explicit background scan trigger is not supported with HAL AIDL");
Slogf.w(TAG, "Explicit background scan trigger is not supported with HAL AIDL");
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
Slogf.w(TAG, "Cannot start background scan on AIDL HAL client from non-current user");
return false;

View File

@@ -189,9 +189,9 @@ class Tuner extends ITuner.Stub {
}
@Override
public void scan(boolean directionDown, boolean skipSubChannel) {
public void seek(boolean directionDown, boolean skipSubChannel) {
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
Slogf.w(TAG, "Cannot scan on HAL 1.x client from non-current user");
Slogf.w(TAG, "Cannot seek on HAL 1.x client from non-current user");
return;
}
synchronized (mLock) {

View File

@@ -173,9 +173,14 @@ class TunerCallback implements ITunerCallback {
dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
}
@Override
public void onConfigFlagUpdated(int flag, boolean value) {
Slog.w(TAG, "Not applicable for HAL 1.x");
}
@Override
public void onParametersUpdated(Map<String, String> parameters) {
Slog.e(TAG, "Not applicable for HAL 1.x");
Slog.w(TAG, "Not applicable for HAL 1.x");
}
@Override

View File

@@ -130,6 +130,7 @@ class Convert {
case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE:
case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID:
case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY:
case ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT:
return ProgramSelector.PROGRAM_TYPE_DAB;
case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID:
case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY:

View File

@@ -171,8 +171,8 @@ class TunerSession extends ITuner.Stub {
}
@Override
public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException {
mEventLogger.logRadioEvent("Scan with direction %s, skipSubChannel? %s",
public void seek(boolean directionDown, boolean skipSubChannel) throws RemoteException {
mEventLogger.logRadioEvent("Seek with direction %s, skipSubChannel? %s",
directionDown ? "down" : "up", skipSubChannel ? "yes" : "no");
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
Slogf.w(TAG, "Cannot scan on HAL 2.0 client from non-current user");
@@ -214,7 +214,7 @@ class TunerSession extends ITuner.Stub {
@Override
public void cancelAnnouncement() {
Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in HAL 2.0");
Slog.w(TAG, "Announcements control doesn't involve cancelling at the HAL level in HAL 2.0");
}
@Override
@@ -225,7 +225,7 @@ class TunerSession extends ITuner.Stub {
@Override
public boolean startBackgroundScan() {
Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.0");
Slog.w(TAG, "Explicit background scan trigger is not supported with HAL 2.0");
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
Slogf.w(TAG,
"Cannot start background scan on HAL 2.0 client from non-current user");