Merge changes from topic "broadcast-radio-api-u"
* changes: Implement explicit result conversion for radio HAL Add SDK version checking in AIDL radio HAL client Update RadioTuner APIs for AIDL HAL migration
This commit is contained in:
committed by
Android (Google) Code Review
commit
68cfa17232
@@ -5274,11 +5274,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
|
||||
@@ -5315,7 +5316,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 {
|
||||
@@ -5530,30 +5531,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
|
||||
@@ -5563,6 +5565,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 {
|
||||
@@ -5570,6 +5580,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);
|
||||
|
||||
@@ -31,7 +31,7 @@ interface IRadioService {
|
||||
List<RadioManager.ModuleProperties> listModules();
|
||||
|
||||
ITuner openTuner(int moduleId, in RadioManager.BandConfig bandConfig, boolean withAudio,
|
||||
in ITunerCallback callback);
|
||||
in ITunerCallback callback, int targetSdkVersion);
|
||||
|
||||
ICloseHandle addAnnouncementListener(in int[] enabledTypes,
|
||||
in IAnnouncementListener listener);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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");
|
||||
@@ -1776,7 +1796,7 @@ public class RadioManager {
|
||||
ITuner tuner;
|
||||
TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler);
|
||||
try {
|
||||
tuner = mService.openTuner(moduleId, config, withAudio, halCallback);
|
||||
tuner = mService.openTuner(moduleId, config, withAudio, halCallback, mTargetSdkVersion);
|
||||
} catch (RemoteException | IllegalArgumentException | IllegalStateException ex) {
|
||||
Log.e(TAG, "Failed to open tuner", ex);
|
||||
return null;
|
||||
@@ -1853,6 +1873,7 @@ public class RadioManager {
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final IRadioService mService;
|
||||
private final int mTargetSdkVersion;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -1869,5 +1890,6 @@ public class RadioManager {
|
||||
public RadioManager(Context context, IRadioService service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -54,6 +56,8 @@ import java.util.concurrent.Executor;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class ProgramListTest {
|
||||
|
||||
public final Context mContext = InstrumentationRegistry.getContext();
|
||||
|
||||
private static final int CREATOR_ARRAY_SIZE = 3;
|
||||
private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 500);
|
||||
|
||||
@@ -109,8 +113,6 @@ public final class ProgramListTest {
|
||||
@Mock
|
||||
private IRadioService mRadioServiceMock;
|
||||
@Mock
|
||||
private Context mContextMock;
|
||||
@Mock
|
||||
private ITuner mTunerMock;
|
||||
@Mock
|
||||
private RadioTuner.Callback mTunerCallbackMock;
|
||||
@@ -477,7 +479,7 @@ public final class ProgramListTest {
|
||||
}
|
||||
|
||||
private void createRadioTuner() throws Exception {
|
||||
RadioManager radioManager = new RadioManager(mContextMock, mRadioServiceMock);
|
||||
RadioManager radioManager = new RadioManager(mContext, mRadioServiceMock);
|
||||
RadioManager.BandConfig band = new RadioManager.FmBandConfig(
|
||||
new RadioManager.FmBandDescriptor(RadioManager.REGION_ITU_1, RadioManager.BAND_FM,
|
||||
/* lowerLimit= */ 87500, /* upperLimit= */ 108000, /* spacing= */ 200,
|
||||
@@ -487,7 +489,7 @@ public final class ProgramListTest {
|
||||
doAnswer(invocation -> {
|
||||
mTunerCallback = (ITunerCallback) invocation.getArguments()[3];
|
||||
return mTunerMock;
|
||||
}).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any());
|
||||
}).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt());
|
||||
|
||||
mRadioTuner = radioManager.openTuner(/* moduleId= */ 0, band,
|
||||
/* withAudio= */ true, mTunerCallbackMock, /* handler= */ null);
|
||||
|
||||
@@ -18,14 +18,16 @@ package android.hardware.radio.tests.unittests;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.hardware.radio.Announcement;
|
||||
import android.hardware.radio.IAnnouncementListener;
|
||||
import android.hardware.radio.ICloseHandle;
|
||||
@@ -34,6 +36,7 @@ import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioMetadata;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
@@ -53,6 +56,8 @@ import java.util.Set;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class RadioManagerTest {
|
||||
|
||||
private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
|
||||
private static final int REGION = RadioManager.REGION_ITU_2;
|
||||
private static final int FM_LOWER_LIMIT = 87500;
|
||||
private static final int FM_UPPER_LIMIT = 108000;
|
||||
@@ -126,6 +131,7 @@ public final class RadioManagerTest {
|
||||
/* vendorInfo= */ new ArrayMap<>()));
|
||||
|
||||
private RadioManager mRadioManager;
|
||||
private final ApplicationInfo mApplicationInfo = new ApplicationInfo();
|
||||
|
||||
@Mock
|
||||
private IRadioService mRadioServiceMock;
|
||||
@@ -1008,7 +1014,8 @@ public final class RadioManagerTest {
|
||||
mRadioManager.openTuner(moduleId, FM_BAND_CONFIG, withAudio, mCallbackMock,
|
||||
/* handler= */ null);
|
||||
|
||||
verify(mRadioServiceMock).openTuner(eq(moduleId), eq(FM_BAND_CONFIG), eq(withAudio), any());
|
||||
verify(mRadioServiceMock).openTuner(eq(moduleId), eq(FM_BAND_CONFIG), eq(withAudio), any(),
|
||||
anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1103,6 +1110,8 @@ public final class RadioManagerTest {
|
||||
}
|
||||
|
||||
private void createRadioManager() throws RemoteException {
|
||||
mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION;
|
||||
when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo);
|
||||
when(mRadioServiceMock.listModules()).thenReturn(Arrays.asList(AMFM_PROPERTIES));
|
||||
when(mRadioServiceMock.addAnnouncementListener(any(), any())).thenReturn(mCloseHandleMock);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.hardware.radio.IRadioService;
|
||||
import android.hardware.radio.ITuner;
|
||||
@@ -35,6 +36,7 @@ import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioMetadata;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.Build;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -51,11 +53,12 @@ import java.util.Map;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class TunerAdapterTest {
|
||||
|
||||
private static final int TEST_TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
|
||||
private static final int CALLBACK_TIMEOUT_MS = 30_000;
|
||||
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);
|
||||
@@ -66,6 +69,7 @@ public final class TunerAdapterTest {
|
||||
|
||||
private RadioTuner mRadioTuner;
|
||||
private ITunerCallback mTunerCallback;
|
||||
private final ApplicationInfo mApplicationInfo = new ApplicationInfo();
|
||||
|
||||
@Mock
|
||||
private IRadioService mRadioServiceMock;
|
||||
@@ -78,12 +82,14 @@ public final class TunerAdapterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION;
|
||||
when(mContextMock.getApplicationInfo()).thenReturn(mApplicationInfo);
|
||||
RadioManager radioManager = new RadioManager(mContextMock, mRadioServiceMock);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
mTunerCallback = (ITunerCallback) invocation.getArguments()[3];
|
||||
return mTunerMock;
|
||||
}).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any());
|
||||
}).when(mRadioServiceMock).openTuner(anyInt(), any(), anyBoolean(), any(), anyInt());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
ProgramSelector program = (ProgramSelector) invocation.getArguments()[0];
|
||||
@@ -92,7 +98,7 @@ public final class TunerAdapterTest {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (program.getPrimaryId().getValue() < AM_LOWER_LIMIT_KHZ) {
|
||||
mTunerCallback.onTuneFailed(RadioManager.STATUS_BAD_VALUE, program);
|
||||
mTunerCallback.onTuneFailed(RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS, program);
|
||||
} else {
|
||||
mTunerCallback.onCurrentProgramInfoChanged(FM_PROGRAM_INFO);
|
||||
}
|
||||
@@ -169,16 +175,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 +208,14 @@ public final class TunerAdapterTest {
|
||||
@Test
|
||||
public void seek_forTunerAdapter_invokesOnErrorWhenTimeout() throws Exception {
|
||||
doAnswer(invocation -> {
|
||||
mTunerCallback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
|
||||
mTunerCallback.onTuneFailed(RadioTuner.TUNER_RESULT_TIMEOUT, 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(
|
||||
RadioTuner.TUNER_RESULT_TIMEOUT, FM_SELECTOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -224,7 +246,7 @@ public final class TunerAdapterTest {
|
||||
mRadioTuner.tune(invalidSelector);
|
||||
|
||||
verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS))
|
||||
.onTuneFailed(RadioManager.STATUS_BAD_VALUE, invalidSelector);
|
||||
.onTuneFailed(RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS, invalidSelector);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -414,6 +436,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");
|
||||
|
||||
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -33,6 +34,7 @@ import android.hardware.radio.ICloseHandle;
|
||||
import android.hardware.radio.ITuner;
|
||||
import android.hardware.radio.ITunerCallback;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
|
||||
@@ -55,6 +57,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas
|
||||
"android.hardware.broadcastradio.IBroadcastRadio/amfm";
|
||||
private static final String DAB_SERVICE_NAME =
|
||||
"android.hardware.broadcastradio.IBroadcastRadio/dab";
|
||||
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
|
||||
private IRadioServiceAidlImpl mAidlImpl;
|
||||
|
||||
@@ -82,7 +85,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas
|
||||
doNothing().when(mServiceMock).enforcePolicyAccess();
|
||||
|
||||
when(mHalMock.listModules()).thenReturn(List.of(mModuleMock));
|
||||
when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any()))
|
||||
when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any(), eq(TARGET_SDK_VERSION)))
|
||||
.thenReturn(mTunerMock);
|
||||
when(mHalMock.addAnnouncementListener(any(), any())).thenReturn(mICloseHandle);
|
||||
|
||||
@@ -114,7 +117,7 @@ public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCas
|
||||
@Test
|
||||
public void openTuner_forAidlImpl() throws Exception {
|
||||
ITuner tuner = mAidlImpl.openTuner(/* moduleId= */ 0, mBandConfigMock,
|
||||
/* withAudio= */ true, mTunerCallbackMock);
|
||||
/* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION);
|
||||
|
||||
assertWithMessage("Tuner opened in AIDL HAL")
|
||||
.that(tuner).isEqualTo(mTunerMock);
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.hardware.radio.ICloseHandle;
|
||||
import android.hardware.radio.ITuner;
|
||||
import android.hardware.radio.ITunerCallback;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.os.Build;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -49,6 +50,7 @@ public final class IRadioServiceHidlImplTest {
|
||||
|
||||
private static final int HAL1_MODULE_ID = 0;
|
||||
private static final int[] ENABLE_TYPES = new int[]{Announcement.TYPE_TRAFFIC};
|
||||
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
|
||||
private IRadioServiceHidlImpl mHidlImpl;
|
||||
|
||||
@@ -103,7 +105,7 @@ public final class IRadioServiceHidlImplTest {
|
||||
@Test
|
||||
public void openTuner_withHal1ModuleId_forHidlImpl() throws Exception {
|
||||
ITuner tuner = mHidlImpl.openTuner(HAL1_MODULE_ID, mBandConfigMock,
|
||||
/* withAudio= */ true, mTunerCallbackMock);
|
||||
/* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION);
|
||||
|
||||
assertWithMessage("Tuner opened in HAL 1")
|
||||
.that(tuner).isEqualTo(mHal1TunerMock);
|
||||
@@ -112,7 +114,7 @@ public final class IRadioServiceHidlImplTest {
|
||||
@Test
|
||||
public void openTuner_withHal2ModuleId_forHidlImpl() throws Exception {
|
||||
ITuner tuner = mHidlImpl.openTuner(HAL1_MODULE_ID + 1, mBandConfigMock,
|
||||
/* withAudio= */ true, mTunerCallbackMock);
|
||||
/* withAudio= */ true, mTunerCallbackMock, TARGET_SDK_VERSION);
|
||||
|
||||
assertWithMessage("Tuner opened in HAL 2")
|
||||
.that(tuner).isEqualTo(mHal2TunerMock);
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.hardware.radio.ITuner;
|
||||
import android.hardware.radio.ITunerCallback;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.IServiceCallback;
|
||||
import android.os.RemoteException;
|
||||
@@ -54,6 +55,8 @@ import java.util.Arrays;
|
||||
|
||||
public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTestCase {
|
||||
|
||||
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
|
||||
private static final int FM_RADIO_MODULE_ID = 0;
|
||||
private static final int DAB_RADIO_MODULE_ID = 1;
|
||||
private static final ArrayList<String> SERVICE_LIST =
|
||||
@@ -137,7 +140,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes
|
||||
createBroadcastRadioService();
|
||||
|
||||
ITuner session = mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID,
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock);
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock,
|
||||
TARGET_SDK_VERSION);
|
||||
|
||||
assertWithMessage("Session opened in FM radio module")
|
||||
.that(session).isEqualTo(mFmTunerSessionMock);
|
||||
@@ -148,7 +152,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes
|
||||
createBroadcastRadioService();
|
||||
|
||||
ITuner session = mBroadcastRadioService.openSession(DAB_RADIO_MODULE_ID + 1,
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock);
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock,
|
||||
TARGET_SDK_VERSION);
|
||||
|
||||
assertWithMessage("Session opened with id not found").that(session).isNull();
|
||||
}
|
||||
@@ -160,7 +165,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes
|
||||
|
||||
IllegalStateException thrown = assertThrows(IllegalStateException.class,
|
||||
() -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID,
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock));
|
||||
/* legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock,
|
||||
TARGET_SDK_VERSION));
|
||||
|
||||
assertWithMessage("Exception for opening session by non-current user")
|
||||
.that(thrown).hasMessageThat().contains("Cannot open session for non-current user");
|
||||
@@ -228,7 +234,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes
|
||||
return null;
|
||||
}).when(mFmBinderMock).linkToDeath(any(), anyInt());
|
||||
|
||||
when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock)))
|
||||
when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock), eq(TARGET_SDK_VERSION)))
|
||||
.thenReturn(mFmTunerSessionMock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.broadcastradio.aidl;
|
||||
|
||||
import android.hardware.broadcastradio.Result;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
|
||||
import com.google.common.truth.Expect;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public final class ConversionUtilsResultTest {
|
||||
|
||||
private final int mHalResult;
|
||||
private final int mTunerResult;
|
||||
|
||||
@Rule
|
||||
public final Expect expect = Expect.create();
|
||||
|
||||
public ConversionUtilsResultTest(int halResult, int tunerResult) {
|
||||
this.mHalResult = halResult;
|
||||
this.mTunerResult = tunerResult;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static List<Object[]> inputParameters() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{Result.OK, RadioTuner.TUNER_RESULT_OK},
|
||||
{Result.INTERNAL_ERROR, RadioTuner.TUNER_RESULT_INTERNAL_ERROR},
|
||||
{Result.INVALID_ARGUMENTS, RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS},
|
||||
{Result.INVALID_STATE, RadioTuner.TUNER_RESULT_INVALID_STATE},
|
||||
{Result.NOT_SUPPORTED, RadioTuner.TUNER_RESULT_NOT_SUPPORTED},
|
||||
{Result.TIMEOUT, RadioTuner.TUNER_RESULT_TIMEOUT},
|
||||
{Result.UNKNOWN_ERROR, RadioTuner.TUNER_RESULT_UNKNOWN_ERROR}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void halResultToTunerResult() {
|
||||
expect.withMessage("Tuner result converted from AIDL HAL result %s", mHalResult)
|
||||
.that(ConversionUtils.halResultToTunerResult(mHalResult))
|
||||
.isEqualTo(mTunerResult);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import android.hardware.broadcastradio.VendorKeyValue;
|
||||
import android.hardware.radio.Announcement;
|
||||
import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.os.Build;
|
||||
|
||||
import com.google.common.truth.Expect;
|
||||
|
||||
@@ -68,6 +69,18 @@ public final class ConversionUtilsTest {
|
||||
@Rule
|
||||
public final Expect expect = Expect.create();
|
||||
|
||||
@Test
|
||||
public void isAtLeastU_withTSdkVersion_returnsFalse() {
|
||||
expect.withMessage("Target SDK version of T")
|
||||
.that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.TIRAMISU)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAtLeastU_withCurrentSdkVersion_returnsTrue() {
|
||||
expect.withMessage("Target SDK version of U")
|
||||
.that(ConversionUtils.isAtLeastU(Build.VERSION_CODES.CUR_DEVELOPMENT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesFromHalProperties_idsMatch() {
|
||||
expect.withMessage("Properties id")
|
||||
|
||||
@@ -42,6 +42,7 @@ import android.hardware.radio.ProgramList;
|
||||
import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.Build;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -65,6 +66,7 @@ import java.util.Map;
|
||||
*/
|
||||
public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
|
||||
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
private static final VerificationWithTimeout CALLBACK_TIMEOUT =
|
||||
timeout(/* millis= */ 200);
|
||||
private static final int SIGNAL_QUALITY = 1;
|
||||
@@ -298,6 +300,18 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tune_withLowerSdkVersion() throws Exception {
|
||||
openAidlClients(/* numClients= */ 1, Build.VERSION_CODES.TIRAMISU);
|
||||
ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
|
||||
RadioManager.ProgramInfo tuneInfo =
|
||||
AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
|
||||
|
||||
mTunerSessions[0].tune(initialSel);
|
||||
|
||||
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tune_withMultipleSessions() throws Exception {
|
||||
int numSessions = 3;
|
||||
@@ -377,49 +391,49 @@ 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)
|
||||
.onTuneFailed(eq(Result.TIMEOUT), any());
|
||||
.onTuneFailed(eq(RadioTuner.TUNER_RESULT_TIMEOUT), any());
|
||||
}
|
||||
}
|
||||
|
||||
@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 +599,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 +611,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;
|
||||
@@ -612,13 +641,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
.onParametersUpdated(parametersExpected);
|
||||
}
|
||||
}
|
||||
|
||||
private void openAidlClients(int numClients) throws Exception {
|
||||
openAidlClients(numClients, TARGET_SDK_VERSION);
|
||||
}
|
||||
|
||||
private void openAidlClients(int numClients, int targetSdkVersion) throws Exception {
|
||||
mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
|
||||
mTunerSessions = new TunerSession[numClients];
|
||||
for (int index = 0; index < numClients; index++) {
|
||||
mAidlTunerCallbackMocks[index] = mock(android.hardware.radio.ITunerCallback.class);
|
||||
mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index]);
|
||||
mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index],
|
||||
targetSdkVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.broadcastradio.hal2;
|
||||
|
||||
import android.hardware.broadcastradio.V2_0.Result;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
|
||||
import com.google.common.truth.Expect;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public final class ConvertResultTest {
|
||||
|
||||
private final int mHalResult;
|
||||
private final int mTunerResult;
|
||||
|
||||
@Rule
|
||||
public final Expect expect = Expect.create();
|
||||
|
||||
public ConvertResultTest(int halResult, int tunerResult) {
|
||||
this.mHalResult = halResult;
|
||||
this.mTunerResult = tunerResult;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static List<Object[]> inputParameters() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{Result.OK, RadioTuner.TUNER_RESULT_OK},
|
||||
{Result.INTERNAL_ERROR, RadioTuner.TUNER_RESULT_INTERNAL_ERROR},
|
||||
{Result.INVALID_ARGUMENTS, RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS},
|
||||
{Result.INVALID_STATE, RadioTuner.TUNER_RESULT_INVALID_STATE},
|
||||
{Result.NOT_SUPPORTED, RadioTuner.TUNER_RESULT_NOT_SUPPORTED},
|
||||
{Result.TIMEOUT, RadioTuner.TUNER_RESULT_TIMEOUT},
|
||||
{Result.UNKNOWN_ERROR, RadioTuner.TUNER_RESULT_UNKNOWN_ERROR}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void halResultToTunerResult() {
|
||||
expect.withMessage("Tuner result converted from HAL 2.0 result %s",
|
||||
Result.toString(mHalResult))
|
||||
.that(Convert.halResultToTunerResult(mHalResult))
|
||||
.isEqualTo(mTunerResult);
|
||||
}
|
||||
}
|
||||
@@ -384,49 +384,49 @@ 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)
|
||||
.onTuneFailed(eq(Result.TIMEOUT), any());
|
||||
.onTuneFailed(eq(RadioTuner.TUNER_RESULT_TIMEOUT), any());
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@@ -86,7 +86,8 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub {
|
||||
|
||||
@Override
|
||||
public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
|
||||
boolean withAudio, ITunerCallback callback) throws RemoteException {
|
||||
boolean withAudio, ITunerCallback callback, int targetSdkVersion)
|
||||
throws RemoteException {
|
||||
if (isDebugEnabled()) {
|
||||
Slogf.d(TAG, "Opening module %d", moduleId);
|
||||
}
|
||||
@@ -94,7 +95,7 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("Callback must not be null");
|
||||
}
|
||||
return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback);
|
||||
return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback, targetSdkVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -92,7 +92,8 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub {
|
||||
|
||||
@Override
|
||||
public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
|
||||
boolean withAudio, ITunerCallback callback) throws RemoteException {
|
||||
boolean withAudio, ITunerCallback callback, int targetSdkVersion)
|
||||
throws RemoteException {
|
||||
if (isDebugEnabled()) {
|
||||
Slog.d(TAG, "Opening module " + moduleId);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,8 @@ public final class BroadcastRadioServiceImpl {
|
||||
*/
|
||||
@Nullable
|
||||
public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig,
|
||||
boolean withAudio, ITunerCallback callback) throws RemoteException {
|
||||
boolean withAudio, ITunerCallback callback, int targetSdkVersion)
|
||||
throws RemoteException {
|
||||
if (DEBUG) {
|
||||
Slogf.d(TAG, "Open AIDL radio session");
|
||||
}
|
||||
@@ -222,7 +223,7 @@ public final class BroadcastRadioServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
TunerSession tunerSession = radioModule.openSession(callback);
|
||||
TunerSession tunerSession = radioModule.openSession(callback, targetSdkVersion);
|
||||
if (legacyConfig != null) {
|
||||
tunerSession.setConfiguration(legacyConfig);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import android.hardware.radio.ProgramList;
|
||||
import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioMetadata;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.util.ArrayMap;
|
||||
@@ -62,6 +64,11 @@ final class ConversionUtils {
|
||||
throw new UnsupportedOperationException("ConversionUtils class is noninstantiable");
|
||||
}
|
||||
|
||||
static boolean isAtLeastU(int targetSdkVersion) {
|
||||
// TODO(b/261770108): Use version code for U.
|
||||
return targetSdkVersion >= Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
}
|
||||
|
||||
static RuntimeException throwOnError(RuntimeException halException, String action) {
|
||||
if (!(halException instanceof ServiceSpecificException)) {
|
||||
return new ParcelableException(new RuntimeException(
|
||||
@@ -89,6 +96,27 @@ final class ConversionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@RadioTuner.TunerResultType
|
||||
static int halResultToTunerResult(int result) {
|
||||
switch (result) {
|
||||
case Result.OK:
|
||||
return RadioTuner.TUNER_RESULT_OK;
|
||||
case Result.INTERNAL_ERROR:
|
||||
return RadioTuner.TUNER_RESULT_INTERNAL_ERROR;
|
||||
case Result.INVALID_ARGUMENTS:
|
||||
return RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS;
|
||||
case Result.INVALID_STATE:
|
||||
return RadioTuner.TUNER_RESULT_INVALID_STATE;
|
||||
case Result.NOT_SUPPORTED:
|
||||
return RadioTuner.TUNER_RESULT_NOT_SUPPORTED;
|
||||
case Result.TIMEOUT:
|
||||
return RadioTuner.TUNER_RESULT_TIMEOUT;
|
||||
case Result.UNKNOWN_ERROR:
|
||||
default:
|
||||
return RadioTuner.TUNER_RESULT_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static VendorKeyValue[] vendorInfoToHalVendorKeyValues(@Nullable Map<String, String> info) {
|
||||
if (info == null) {
|
||||
return new VendorKeyValue[]{};
|
||||
@@ -143,6 +171,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:
|
||||
@@ -471,6 +500,60 @@ final class ConversionUtils {
|
||||
return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed);
|
||||
}
|
||||
|
||||
private static boolean isNewIdentifierInU(ProgramSelector.Identifier id) {
|
||||
return id.getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT;
|
||||
}
|
||||
|
||||
static boolean programSelectorMeetsSdkVersionRequirement(ProgramSelector sel,
|
||||
int targetSdkVersion) {
|
||||
if (isAtLeastU(targetSdkVersion)) {
|
||||
return true;
|
||||
}
|
||||
if (sel.getPrimaryId().getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT) {
|
||||
return false;
|
||||
}
|
||||
ProgramSelector.Identifier[] secondaryIds = sel.getSecondaryIds();
|
||||
for (int i = 0; i < secondaryIds.length; i++) {
|
||||
if (isNewIdentifierInU(secondaryIds[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean programInfoMeetsSdkVersionRequirement(RadioManager.ProgramInfo info,
|
||||
int targetSdkVersion) {
|
||||
if (isAtLeastU(targetSdkVersion)) {
|
||||
return true;
|
||||
}
|
||||
if (!programSelectorMeetsSdkVersionRequirement(info.getSelector(), targetSdkVersion)) {
|
||||
return false;
|
||||
}
|
||||
if (isNewIdentifierInU(info.getLogicallyTunedTo())
|
||||
|| isNewIdentifierInU(info.getPhysicallyTunedTo())) {
|
||||
return false;
|
||||
}
|
||||
Iterator<ProgramSelector.Identifier> relatedContentIt = info.getRelatedContent().iterator();
|
||||
while (relatedContentIt.hasNext()) {
|
||||
if (isNewIdentifierInU(relatedContentIt.next())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static ProgramList.Chunk convertChunkToTargetSdkVersion(ProgramList.Chunk chunk,
|
||||
int targetSdkVersion) {
|
||||
if (isAtLeastU(targetSdkVersion)) {
|
||||
return chunk;
|
||||
}
|
||||
Set<RadioManager.ProgramInfo> modified = chunk.getModified();
|
||||
modified.removeIf(info -> !programInfoMeetsSdkVersionRequirement(info, targetSdkVersion));
|
||||
Set<ProgramSelector.Identifier> removed = chunk.getRemoved();
|
||||
removed.removeIf(id -> isNewIdentifierInU(id));
|
||||
return new ProgramList.Chunk(chunk.isPurge(), chunk.isComplete(), modified, removed);
|
||||
}
|
||||
|
||||
public static android.hardware.radio.Announcement announcementFromHalAnnouncement(
|
||||
Announcement hwAnnouncement) {
|
||||
return new android.hardware.radio.Announcement(
|
||||
|
||||
@@ -100,7 +100,16 @@ final class RadioModule {
|
||||
synchronized (mLock) {
|
||||
android.hardware.radio.ProgramSelector csel =
|
||||
ConversionUtils.programSelectorFromHalProgramSelector(programSelector);
|
||||
fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
|
||||
int tunerResult = ConversionUtils.halResultToTunerResult(result);
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> {
|
||||
if (csel != null && !ConversionUtils
|
||||
.programSelectorMeetsSdkVersionRequirement(csel, sdkVersion)) {
|
||||
Slogf.e(TAG, "onTuneFailed: cannot send program selector "
|
||||
+ "requiring higher target SDK version");
|
||||
return;
|
||||
}
|
||||
cb.onTuneFailed(tunerResult, csel);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -112,7 +121,13 @@ final class RadioModule {
|
||||
mCurrentProgramInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo);
|
||||
RadioManager.ProgramInfo currentProgramInfo = mCurrentProgramInfo;
|
||||
fanoutAidlCallbackLocked(cb -> {
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> {
|
||||
if (!ConversionUtils.programInfoMeetsSdkVersionRequirement(
|
||||
currentProgramInfo, sdkVersion)) {
|
||||
Slogf.e(TAG, "onCurrentProgramInfoChanged: cannot send "
|
||||
+ "program info requiring higher target SDK version");
|
||||
return;
|
||||
}
|
||||
cb.onCurrentProgramInfoChanged(currentProgramInfo);
|
||||
});
|
||||
}
|
||||
@@ -139,7 +154,7 @@ final class RadioModule {
|
||||
fireLater(() -> {
|
||||
synchronized (mLock) {
|
||||
mAntennaConnected = connected;
|
||||
fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> cb.onAntennaState(connected));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -147,8 +162,11 @@ 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, sdkVersion) -> {
|
||||
cb.onConfigFlagUpdated(flag, value);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -158,7 +176,9 @@ final class RadioModule {
|
||||
synchronized (mLock) {
|
||||
Map<String, String> cparam =
|
||||
ConversionUtils.vendorInfoFromHalVendorKeyValues(parameters);
|
||||
fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> {
|
||||
cb.onParametersUpdated(cparam);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -222,14 +242,14 @@ final class RadioModule {
|
||||
mService.setTunerCallback(mHalTunerCallback);
|
||||
}
|
||||
|
||||
TunerSession openSession(android.hardware.radio.ITunerCallback userCb)
|
||||
TunerSession openSession(android.hardware.radio.ITunerCallback userCb, int targetSdkVersion)
|
||||
throws RemoteException {
|
||||
mLogger.logRadioEvent("Open TunerSession");
|
||||
TunerSession tunerSession;
|
||||
Boolean antennaConnected;
|
||||
RadioManager.ProgramInfo currentProgramInfo;
|
||||
synchronized (mLock) {
|
||||
tunerSession = new TunerSession(this, mService, userCb);
|
||||
tunerSession = new TunerSession(this, mService, userCb, targetSdkVersion);
|
||||
mAidlTunerSessions.add(tunerSession);
|
||||
antennaConnected = mAntennaConnected;
|
||||
currentProgramInfo = mCurrentProgramInfo;
|
||||
@@ -382,7 +402,8 @@ final class RadioModule {
|
||||
}
|
||||
|
||||
interface AidlCallbackRunnable {
|
||||
void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
|
||||
void run(android.hardware.radio.ITunerCallback callback, int targetSdkVersion)
|
||||
throws RemoteException;
|
||||
}
|
||||
|
||||
// Invokes runnable with each TunerSession currently open.
|
||||
@@ -399,7 +420,8 @@ final class RadioModule {
|
||||
List<TunerSession> deadSessions = null;
|
||||
for (int i = 0; i < mAidlTunerSessions.size(); i++) {
|
||||
try {
|
||||
runnable.run(mAidlTunerSessions.valueAt(i).mCallback);
|
||||
runnable.run(mAidlTunerSessions.valueAt(i).mCallback,
|
||||
mAidlTunerSessions.valueAt(i).getTargetSdkVersion());
|
||||
} catch (DeadObjectException ex) {
|
||||
// The other side died without calling close(), so just purge it from our records.
|
||||
Slogf.e(TAG, "Removing dead TunerSession");
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.graphics.Bitmap;
|
||||
import android.hardware.broadcastradio.ConfigFlag;
|
||||
import android.hardware.broadcastradio.IBroadcastRadio;
|
||||
import android.hardware.radio.ITuner;
|
||||
import android.hardware.radio.ITunerCallback;
|
||||
import android.hardware.radio.ProgramList;
|
||||
import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
@@ -47,6 +46,7 @@ final class TunerSession extends ITuner.Stub {
|
||||
private final RadioLogger mLogger;
|
||||
private final RadioModule mModule;
|
||||
final android.hardware.radio.ITunerCallback mCallback;
|
||||
private final int mTargetSdkVersion;
|
||||
private final IBroadcastRadio mService;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -61,10 +61,11 @@ final class TunerSession extends ITuner.Stub {
|
||||
private RadioManager.BandConfig mPlaceHolderConfig;
|
||||
|
||||
TunerSession(RadioModule radioModule, IBroadcastRadio service,
|
||||
android.hardware.radio.ITunerCallback callback) {
|
||||
android.hardware.radio.ITunerCallback callback, int targetSdkVersion) {
|
||||
mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null");
|
||||
mService = Objects.requireNonNull(service, "service cannot be null");
|
||||
mCallback = Objects.requireNonNull(callback, "callback cannot be null");
|
||||
mTargetSdkVersion = targetSdkVersion;
|
||||
mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ final class TunerSession extends ITuner.Stub {
|
||||
mPlaceHolderConfig = Objects.requireNonNull(config, "config cannot be null");
|
||||
}
|
||||
Slogf.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL AIDL");
|
||||
mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
|
||||
mModule.fanoutAidlCallback((cb, sdkVersion) -> cb.onConfigurationChanged(config));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,8 +179,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 +233,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,12 +244,14 @@ 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;
|
||||
}
|
||||
mModule.fanoutAidlCallback(ITunerCallback::onBackgroundScanComplete);
|
||||
mModule.fanoutAidlCallback((cb, sdkVersion) -> {
|
||||
cb.onBackgroundScanComplete();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -277,6 +279,10 @@ final class TunerSession extends ITuner.Stub {
|
||||
mModule.onTunerSessionProgramListFilterChanged(this);
|
||||
}
|
||||
|
||||
int getTargetSdkVersion() {
|
||||
return mTargetSdkVersion;
|
||||
}
|
||||
|
||||
ProgramList.Filter getProgramListFilter() {
|
||||
synchronized (mLock) {
|
||||
return mProgramInfoCache == null ? null : mProgramInfoCache.getFilter();
|
||||
@@ -312,7 +318,14 @@ final class TunerSession extends ITuner.Stub {
|
||||
}
|
||||
for (int i = 0; i < chunks.size(); i++) {
|
||||
try {
|
||||
mCallback.onProgramListUpdated(chunks.get(i));
|
||||
if (!ConversionUtils.isAtLeastU(getTargetSdkVersion())) {
|
||||
ProgramList.Chunk downgradedChunk =
|
||||
ConversionUtils.convertChunkToTargetSdkVersion(chunks.get(i),
|
||||
getTargetSdkVersion());
|
||||
mCallback.onProgramListUpdated(downgradedChunk);
|
||||
} else {
|
||||
mCallback.onProgramListUpdated(chunks.get(i));
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
Slogf.w(TAG, ex, "mCallback.onProgramListUpdated() failed");
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -169,7 +169,7 @@ public final class BroadcastRadioService {
|
||||
}
|
||||
|
||||
public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig,
|
||||
boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException {
|
||||
boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException {
|
||||
Slog.v(TAG, "Open HIDL 2.0 session with module id " + moduleId);
|
||||
if (!RadioServiceUserController.isCurrentOrSystemUser()) {
|
||||
Slogf.e(TAG, "Cannot open tuner on HAL 2.0 client for non-current user");
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.hardware.radio.ProgramList;
|
||||
import android.hardware.radio.ProgramSelector;
|
||||
import android.hardware.radio.RadioManager;
|
||||
import android.hardware.radio.RadioMetadata;
|
||||
import android.hardware.radio.RadioTuner;
|
||||
import android.os.ParcelableException;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -81,6 +82,27 @@ class Convert {
|
||||
}
|
||||
}
|
||||
|
||||
@RadioTuner.TunerResultType
|
||||
static int halResultToTunerResult(int result) {
|
||||
switch (result) {
|
||||
case Result.OK:
|
||||
return RadioTuner.TUNER_RESULT_OK;
|
||||
case Result.INTERNAL_ERROR:
|
||||
return RadioTuner.TUNER_RESULT_INTERNAL_ERROR;
|
||||
case Result.INVALID_ARGUMENTS:
|
||||
return RadioTuner.TUNER_RESULT_INVALID_ARGUMENTS;
|
||||
case Result.INVALID_STATE:
|
||||
return RadioTuner.TUNER_RESULT_INVALID_STATE;
|
||||
case Result.NOT_SUPPORTED:
|
||||
return RadioTuner.TUNER_RESULT_NOT_SUPPORTED;
|
||||
case Result.TIMEOUT:
|
||||
return RadioTuner.TUNER_RESULT_TIMEOUT;
|
||||
case Result.UNKNOWN_ERROR:
|
||||
default:
|
||||
return RadioTuner.TUNER_RESULT_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static @NonNull ArrayList<VendorKeyValue>
|
||||
vendorInfoToHal(@Nullable Map<String, String> info) {
|
||||
if (info == null) return new ArrayList<>();
|
||||
@@ -130,6 +152,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:
|
||||
|
||||
@@ -87,8 +87,9 @@ final class RadioModule {
|
||||
fireLater(() -> {
|
||||
android.hardware.radio.ProgramSelector csel =
|
||||
Convert.programSelectorFromHal(programSelector);
|
||||
int tunerResult = Convert.halResultToTunerResult(result);
|
||||
synchronized (mLock) {
|
||||
fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
|
||||
fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(tunerResult, csel));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user