Home | History | Annotate | Download | only in radio
      1 /**
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware.radio;
     18 
     19 import android.annotation.SystemApi;
     20 import android.annotation.SystemService;
     21 import android.content.Context;
     22 import android.os.Handler;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import java.util.List;
     26 import java.util.Arrays;
     27 
     28 /**
     29  * The RadioManager class allows to control a broadcast radio tuner present on the device.
     30  * It provides data structures and methods to query for available radio modules, list their
     31  * properties and open an interface to control tuning operations and receive callbacks when
     32  * asynchronous operations complete or events occur.
     33  * @hide
     34  */
     35 @SystemApi
     36 @SystemService(Context.RADIO_SERVICE)
     37 public class RadioManager {
     38 
     39     /** Method return status: successful operation */
     40     public static final int STATUS_OK = 0;
     41     /** Method return status: unspecified error */
     42     public static final int STATUS_ERROR = Integer.MIN_VALUE;
     43     /** Method return status: permission denied */
     44     public static final int STATUS_PERMISSION_DENIED = -1;
     45     /** Method return status: initialization failure */
     46     public static final int STATUS_NO_INIT = -19;
     47     /** Method return status: invalid argument provided */
     48     public static final int STATUS_BAD_VALUE = -22;
     49     /** Method return status: cannot reach service */
     50     public static final int STATUS_DEAD_OBJECT = -32;
     51     /** Method return status: invalid or out of sequence operation */
     52     public static final int STATUS_INVALID_OPERATION = -38;
     53     /** Method return status: time out before operation completion */
     54     public static final int STATUS_TIMED_OUT = -110;
     55 
     56 
     57     // keep in sync with radio_class_t in /system/core/incluse/system/radio.h
     58     /** Radio module class supporting FM (including HD radio) and AM */
     59     public static final int CLASS_AM_FM = 0;
     60     /** Radio module class supporting satellite radio */
     61     public static final int CLASS_SAT = 1;
     62     /** Radio module class supporting Digital terrestrial radio */
     63     public static final int CLASS_DT = 2;
     64 
     65     // keep in sync with radio_band_t in /system/core/incluse/system/radio.h
     66     /** AM radio band (LW/MW/SW).
     67      * @see BandDescriptor */
     68     public static final int BAND_AM = 0;
     69     /** FM radio band.
     70      * @see BandDescriptor */
     71     public static final int BAND_FM = 1;
     72     /** FM HD radio or DRM  band.
     73      * @see BandDescriptor */
     74     public static final int BAND_FM_HD = 2;
     75     /** AM HD radio or DRM band.
     76      * @see BandDescriptor */
     77     public static final int BAND_AM_HD = 3;
     78 
     79     // keep in sync with radio_region_t in /system/core/incluse/system/radio.h
     80     /** Africa, Europe.
     81      * @see BandDescriptor */
     82     public static final int REGION_ITU_1  = 0;
     83     /** Americas.
     84      * @see BandDescriptor */
     85     public static final int REGION_ITU_2  = 1;
     86     /** Russia.
     87      * @see BandDescriptor */
     88     public static final int REGION_OIRT   = 2;
     89     /** Japan.
     90      * @see BandDescriptor */
     91     public static final int REGION_JAPAN  = 3;
     92     /** Korea.
     93      * @see BandDescriptor */
     94     public static final int REGION_KOREA  = 4;
     95 
     96     /*****************************************************************************
     97      * Lists properties, options and radio bands supported by a given broadcast radio module.
     98      * Each module has a unique ID used to address it when calling RadioManager APIs.
     99      * Module properties are returned by {@link #listModules(List <ModuleProperties>)} method.
    100      ****************************************************************************/
    101     public static class ModuleProperties implements Parcelable {
    102 
    103         private final int mId;
    104         private final int mClassId;
    105         private final String mImplementor;
    106         private final String mProduct;
    107         private final String mVersion;
    108         private final String mSerial;
    109         private final int mNumTuners;
    110         private final int mNumAudioSources;
    111         private final boolean mIsCaptureSupported;
    112         private final BandDescriptor[] mBands;
    113 
    114         ModuleProperties(int id, int classId, String implementor, String product, String version,
    115                 String serial, int numTuners, int numAudioSources, boolean isCaptureSupported,
    116                 BandDescriptor[] bands) {
    117             mId = id;
    118             mClassId = classId;
    119             mImplementor = implementor;
    120             mProduct = product;
    121             mVersion = version;
    122             mSerial = serial;
    123             mNumTuners = numTuners;
    124             mNumAudioSources = numAudioSources;
    125             mIsCaptureSupported = isCaptureSupported;
    126             mBands = bands;
    127         }
    128 
    129 
    130         /** Unique module identifier provided by the native service.
    131          * For use with {@link #openTuner(int, BandConfig, boolean, Callback, Handler)}.
    132          * @return the radio module unique identifier.
    133          */
    134         public int getId() {
    135             return mId;
    136         }
    137 
    138         /** Module class identifier: {@link #CLASS_AM_FM}, {@link #CLASS_SAT}, {@link #CLASS_DT}
    139          * @return the radio module class identifier.
    140          */
    141         public int getClassId() {
    142             return mClassId;
    143         }
    144 
    145         /** Human readable broadcast radio module implementor
    146          * @return the name of the radio module implementator.
    147          */
    148         public String getImplementor() {
    149             return mImplementor;
    150         }
    151 
    152         /** Human readable broadcast radio module product name
    153          * @return the radio module product name.
    154          */
    155         public String getProduct() {
    156             return mProduct;
    157         }
    158 
    159         /** Human readable broadcast radio module version number
    160          * @return the radio module version.
    161          */
    162         public String getVersion() {
    163             return mVersion;
    164         }
    165 
    166         /** Radio module serial number.
    167          * Can be used for subscription services.
    168          * @return the radio module serial number.
    169          */
    170         public String getSerial() {
    171             return mSerial;
    172         }
    173 
    174         /** Number of tuners available.
    175          * This is the number of tuners that can be open simultaneously.
    176          * @return the number of tuners supported.
    177          */
    178         public int getNumTuners() {
    179             return mNumTuners;
    180         }
    181 
    182         /** Number tuner audio sources available. Must be less or equal to getNumTuners().
    183          * When more than one tuner is supported, one is usually for playback and has one
    184          * associated audio source and the other is for pre scanning and building a
    185          * program list.
    186          * @return the number of audio sources available.
    187          */
    188         public int getNumAudioSources() {
    189             return mNumAudioSources;
    190         }
    191 
    192         /** {@code true} if audio capture is possible from radio tuner output.
    193          * This indicates if routing to audio devices not connected to the same HAL as the FM radio
    194          * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented.
    195          * @return {@code true} if audio capture is possible, {@code false} otherwise.
    196          */
    197         public boolean isCaptureSupported() {
    198             return mIsCaptureSupported;
    199         }
    200 
    201         /** List of descriptors for all bands supported by this module.
    202          * @return an array of {@link BandDescriptor}.
    203          */
    204         public BandDescriptor[] getBands() {
    205             return mBands;
    206         }
    207 
    208         private ModuleProperties(Parcel in) {
    209             mId = in.readInt();
    210             mClassId = in.readInt();
    211             mImplementor = in.readString();
    212             mProduct = in.readString();
    213             mVersion = in.readString();
    214             mSerial = in.readString();
    215             mNumTuners = in.readInt();
    216             mNumAudioSources = in.readInt();
    217             mIsCaptureSupported = in.readInt() == 1;
    218             Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader());
    219             mBands = new BandDescriptor[tmp.length];
    220             for (int i = 0; i < tmp.length; i++) {
    221                 mBands[i] = (BandDescriptor) tmp[i];
    222             }
    223         }
    224 
    225         public static final Parcelable.Creator<ModuleProperties> CREATOR
    226                 = new Parcelable.Creator<ModuleProperties>() {
    227             public ModuleProperties createFromParcel(Parcel in) {
    228                 return new ModuleProperties(in);
    229             }
    230 
    231             public ModuleProperties[] newArray(int size) {
    232                 return new ModuleProperties[size];
    233             }
    234         };
    235 
    236         @Override
    237         public void writeToParcel(Parcel dest, int flags) {
    238             dest.writeInt(mId);
    239             dest.writeInt(mClassId);
    240             dest.writeString(mImplementor);
    241             dest.writeString(mProduct);
    242             dest.writeString(mVersion);
    243             dest.writeString(mSerial);
    244             dest.writeInt(mNumTuners);
    245             dest.writeInt(mNumAudioSources);
    246             dest.writeInt(mIsCaptureSupported ? 1 : 0);
    247             dest.writeParcelableArray(mBands, flags);
    248         }
    249 
    250         @Override
    251         public int describeContents() {
    252             return 0;
    253         }
    254 
    255         @Override
    256         public String toString() {
    257             return "ModuleProperties [mId=" + mId + ", mClassId=" + mClassId
    258                     + ", mImplementor=" + mImplementor + ", mProduct=" + mProduct
    259                     + ", mVersion=" + mVersion + ", mSerial=" + mSerial
    260                     + ", mNumTuners=" + mNumTuners
    261                     + ", mNumAudioSources=" + mNumAudioSources
    262                     + ", mIsCaptureSupported=" + mIsCaptureSupported
    263                     + ", mBands=" + Arrays.toString(mBands) + "]";
    264         }
    265 
    266         @Override
    267         public int hashCode() {
    268             final int prime = 31;
    269             int result = 1;
    270             result = prime * result + mId;
    271             result = prime * result + mClassId;
    272             result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
    273             result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
    274             result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
    275             result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
    276             result = prime * result + mNumTuners;
    277             result = prime * result + mNumAudioSources;
    278             result = prime * result + (mIsCaptureSupported ? 1 : 0);
    279             result = prime * result + Arrays.hashCode(mBands);
    280             return result;
    281         }
    282 
    283         @Override
    284         public boolean equals(Object obj) {
    285             if (this == obj)
    286                 return true;
    287             if (!(obj instanceof ModuleProperties))
    288                 return false;
    289             ModuleProperties other = (ModuleProperties) obj;
    290             if (mId != other.getId())
    291                 return false;
    292             if (mClassId != other.getClassId())
    293                 return false;
    294             if (mImplementor == null) {
    295                 if (other.getImplementor() != null)
    296                     return false;
    297             } else if (!mImplementor.equals(other.getImplementor()))
    298                 return false;
    299             if (mProduct == null) {
    300                 if (other.getProduct() != null)
    301                     return false;
    302             } else if (!mProduct.equals(other.getProduct()))
    303                 return false;
    304             if (mVersion == null) {
    305                 if (other.getVersion() != null)
    306                     return false;
    307             } else if (!mVersion.equals(other.getVersion()))
    308                 return false;
    309             if (mSerial == null) {
    310                 if (other.getSerial() != null)
    311                     return false;
    312             } else if (!mSerial.equals(other.getSerial()))
    313                 return false;
    314             if (mNumTuners != other.getNumTuners())
    315                 return false;
    316             if (mNumAudioSources != other.getNumAudioSources())
    317                 return false;
    318             if (mIsCaptureSupported != other.isCaptureSupported())
    319                 return false;
    320             if (!Arrays.equals(mBands, other.getBands()))
    321                 return false;
    322             return true;
    323         }
    324     }
    325 
    326     /** Radio band descriptor: an element in ModuleProperties bands array.
    327      * It is either an instance of {@link FmBandDescriptor} or {@link AmBandDescriptor} */
    328     public static class BandDescriptor implements Parcelable {
    329 
    330         private final int mRegion;
    331         private final int mType;
    332         private final int mLowerLimit;
    333         private final int mUpperLimit;
    334         private final int mSpacing;
    335 
    336         BandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing) {
    337             mRegion = region;
    338             mType = type;
    339             mLowerLimit = lowerLimit;
    340             mUpperLimit = upperLimit;
    341             mSpacing = spacing;
    342         }
    343 
    344         /** Region this band applies to. E.g. {@link #REGION_ITU_1}
    345          * @return the region this band is associated to.
    346          */
    347         public int getRegion() {
    348             return mRegion;
    349         }
    350         /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
    351          * <ul>
    352          *  <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
    353          *  <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
    354          * </ul>
    355          * @return the band type.
    356          */
    357         public int getType() {
    358             return mType;
    359         }
    360         /** Lower band limit expressed in units according to band type.
    361          * Currently all defined band types express channels as frequency in kHz
    362          * @return the lower band limit.
    363          */
    364         public int getLowerLimit() {
    365             return mLowerLimit;
    366         }
    367         /** Upper band limit expressed in units according to band type.
    368          * Currently all defined band types express channels as frequency in kHz
    369          * @return the upper band limit.
    370          */
    371         public int getUpperLimit() {
    372             return mUpperLimit;
    373         }
    374         /** Channel spacing in units according to band type.
    375          * Currently all defined band types express channels as frequency in kHz
    376          * @return the channel spacing.
    377          */
    378         public int getSpacing() {
    379             return mSpacing;
    380         }
    381 
    382         private BandDescriptor(Parcel in) {
    383             mRegion = in.readInt();
    384             mType = in.readInt();
    385             mLowerLimit = in.readInt();
    386             mUpperLimit = in.readInt();
    387             mSpacing = in.readInt();
    388         }
    389 
    390         public static final Parcelable.Creator<BandDescriptor> CREATOR
    391                 = new Parcelable.Creator<BandDescriptor>() {
    392             public BandDescriptor createFromParcel(Parcel in) {
    393                 return new BandDescriptor(in);
    394             }
    395 
    396             public BandDescriptor[] newArray(int size) {
    397                 return new BandDescriptor[size];
    398             }
    399         };
    400 
    401         @Override
    402         public void writeToParcel(Parcel dest, int flags) {
    403             dest.writeInt(mRegion);
    404             dest.writeInt(mType);
    405             dest.writeInt(mLowerLimit);
    406             dest.writeInt(mUpperLimit);
    407             dest.writeInt(mSpacing);
    408         }
    409 
    410         @Override
    411         public int describeContents() {
    412             return 0;
    413         }
    414 
    415         @Override
    416         public String toString() {
    417             return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
    418                     + mLowerLimit + ", mUpperLimit=" + mUpperLimit + ", mSpacing=" + mSpacing + "]";
    419         }
    420 
    421         @Override
    422         public int hashCode() {
    423             final int prime = 31;
    424             int result = 1;
    425             result = prime * result + mRegion;
    426             result = prime * result + mType;
    427             result = prime * result + mLowerLimit;
    428             result = prime * result + mUpperLimit;
    429             result = prime * result + mSpacing;
    430             return result;
    431         }
    432 
    433         @Override
    434         public boolean equals(Object obj) {
    435             if (this == obj)
    436                 return true;
    437             if (!(obj instanceof BandDescriptor))
    438                 return false;
    439             BandDescriptor other = (BandDescriptor) obj;
    440             if (mRegion != other.getRegion())
    441                 return false;
    442             if (mType != other.getType())
    443                 return false;
    444             if (mLowerLimit != other.getLowerLimit())
    445                 return false;
    446             if (mUpperLimit != other.getUpperLimit())
    447                 return false;
    448             if (mSpacing != other.getSpacing())
    449                 return false;
    450             return true;
    451         }
    452     }
    453 
    454     /** FM band descriptor
    455      * @see #BAND_FM
    456      * @see #BAND_FM_HD */
    457     public static class FmBandDescriptor extends BandDescriptor {
    458         private final boolean mStereo;
    459         private final boolean mRds;
    460         private final boolean mTa;
    461         private final boolean mAf;
    462         private final boolean mEa;
    463 
    464         FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
    465                 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
    466             super(region, type, lowerLimit, upperLimit, spacing);
    467             mStereo = stereo;
    468             mRds = rds;
    469             mTa = ta;
    470             mAf = af;
    471             mEa = ea;
    472         }
    473 
    474         /** Stereo is supported
    475          * @return {@code true} if stereo is supported, {@code false} otherwise.
    476          */
    477         public boolean isStereoSupported() {
    478             return mStereo;
    479         }
    480         /** RDS or RBDS(if region is ITU2) is supported
    481          * @return {@code true} if RDS or RBDS is supported, {@code false} otherwise.
    482          */
    483         public boolean isRdsSupported() {
    484             return mRds;
    485         }
    486         /** Traffic announcement is supported
    487          * @return {@code true} if TA is supported, {@code false} otherwise.
    488          */
    489         public boolean isTaSupported() {
    490             return mTa;
    491         }
    492         /** Alternate Frequency Switching is supported
    493          * @return {@code true} if AF switching is supported, {@code false} otherwise.
    494          */
    495         public boolean isAfSupported() {
    496             return mAf;
    497         }
    498 
    499         /** Emergency Announcement is supported
    500          * @return {@code true} if Emergency annoucement is supported, {@code false} otherwise.
    501          */
    502         public boolean isEaSupported() {
    503             return mEa;
    504         }
    505 
    506         /* Parcelable implementation */
    507         private FmBandDescriptor(Parcel in) {
    508             super(in);
    509             mStereo = in.readByte() == 1;
    510             mRds = in.readByte() == 1;
    511             mTa = in.readByte() == 1;
    512             mAf = in.readByte() == 1;
    513             mEa = in.readByte() == 1;
    514         }
    515 
    516         public static final Parcelable.Creator<FmBandDescriptor> CREATOR
    517                 = new Parcelable.Creator<FmBandDescriptor>() {
    518             public FmBandDescriptor createFromParcel(Parcel in) {
    519                 return new FmBandDescriptor(in);
    520             }
    521 
    522             public FmBandDescriptor[] newArray(int size) {
    523                 return new FmBandDescriptor[size];
    524             }
    525         };
    526 
    527         @Override
    528         public void writeToParcel(Parcel dest, int flags) {
    529             super.writeToParcel(dest, flags);
    530             dest.writeByte((byte) (mStereo ? 1 : 0));
    531             dest.writeByte((byte) (mRds ? 1 : 0));
    532             dest.writeByte((byte) (mTa ? 1 : 0));
    533             dest.writeByte((byte) (mAf ? 1 : 0));
    534             dest.writeByte((byte) (mEa ? 1 : 0));
    535         }
    536 
    537         @Override
    538         public int describeContents() {
    539             return 0;
    540         }
    541 
    542         @Override
    543         public String toString() {
    544             return "FmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo
    545                     + ", mRds=" + mRds + ", mTa=" + mTa + ", mAf=" + mAf +
    546                     ", mEa =" + mEa + "]";
    547         }
    548 
    549         @Override
    550         public int hashCode() {
    551             final int prime = 31;
    552             int result = super.hashCode();
    553             result = prime * result + (mStereo ? 1 : 0);
    554             result = prime * result + (mRds ? 1 : 0);
    555             result = prime * result + (mTa ? 1 : 0);
    556             result = prime * result + (mAf ? 1 : 0);
    557             result = prime * result + (mEa ? 1 : 0);
    558             return result;
    559         }
    560 
    561         @Override
    562         public boolean equals(Object obj) {
    563             if (this == obj)
    564                 return true;
    565             if (!super.equals(obj))
    566                 return false;
    567             if (!(obj instanceof FmBandDescriptor))
    568                 return false;
    569             FmBandDescriptor other = (FmBandDescriptor) obj;
    570             if (mStereo != other.isStereoSupported())
    571                 return false;
    572             if (mRds != other.isRdsSupported())
    573                 return false;
    574             if (mTa != other.isTaSupported())
    575                 return false;
    576             if (mAf != other.isAfSupported())
    577                 return false;
    578             if (mEa != other.isEaSupported())
    579                 return false;
    580             return true;
    581         }
    582     }
    583 
    584     /** AM band descriptor.
    585      * @see #BAND_AM */
    586     public static class AmBandDescriptor extends BandDescriptor {
    587 
    588         private final boolean mStereo;
    589 
    590         AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
    591                 boolean stereo) {
    592             super(region, type, lowerLimit, upperLimit, spacing);
    593             mStereo = stereo;
    594         }
    595 
    596         /** Stereo is supported
    597          *  @return {@code true} if stereo is supported, {@code false} otherwise.
    598          */
    599         public boolean isStereoSupported() {
    600             return mStereo;
    601         }
    602 
    603         private AmBandDescriptor(Parcel in) {
    604             super(in);
    605             mStereo = in.readByte() == 1;
    606         }
    607 
    608         public static final Parcelable.Creator<AmBandDescriptor> CREATOR
    609                 = new Parcelable.Creator<AmBandDescriptor>() {
    610             public AmBandDescriptor createFromParcel(Parcel in) {
    611                 return new AmBandDescriptor(in);
    612             }
    613 
    614             public AmBandDescriptor[] newArray(int size) {
    615                 return new AmBandDescriptor[size];
    616             }
    617         };
    618 
    619         @Override
    620         public void writeToParcel(Parcel dest, int flags) {
    621             super.writeToParcel(dest, flags);
    622             dest.writeByte((byte) (mStereo ? 1 : 0));
    623         }
    624 
    625         @Override
    626         public int describeContents() {
    627             return 0;
    628         }
    629 
    630         @Override
    631         public String toString() {
    632             return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
    633         }
    634 
    635         @Override
    636         public int hashCode() {
    637             final int prime = 31;
    638             int result = super.hashCode();
    639             result = prime * result + (mStereo ? 1 : 0);
    640             return result;
    641         }
    642 
    643         @Override
    644         public boolean equals(Object obj) {
    645             if (this == obj)
    646                 return true;
    647             if (!super.equals(obj))
    648                 return false;
    649             if (!(obj instanceof AmBandDescriptor))
    650                 return false;
    651             AmBandDescriptor other = (AmBandDescriptor) obj;
    652             if (mStereo != other.isStereoSupported())
    653                 return false;
    654             return true;
    655         }
    656     }
    657 
    658 
    659     /** Radio band configuration. */
    660     public static class BandConfig implements Parcelable {
    661 
    662         final BandDescriptor mDescriptor;
    663 
    664         BandConfig(BandDescriptor descriptor) {
    665             mDescriptor = descriptor;
    666         }
    667 
    668         BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
    669             mDescriptor = new BandDescriptor(region, type, lowerLimit, upperLimit, spacing);
    670         }
    671 
    672         private BandConfig(Parcel in) {
    673             mDescriptor = new BandDescriptor(in);
    674         }
    675 
    676         BandDescriptor getDescriptor() {
    677             return mDescriptor;
    678         }
    679 
    680         /** Region this band applies to. E.g. {@link #REGION_ITU_1}
    681          *  @return the region associated with this band.
    682          */
    683         public int getRegion() {
    684             return mDescriptor.getRegion();
    685         }
    686         /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
    687          * <ul>
    688          *  <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
    689          *  <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
    690          * </ul>
    691          *  @return the band type.
    692          */
    693         public int getType() {
    694             return mDescriptor.getType();
    695         }
    696         /** Lower band limit expressed in units according to band type.
    697          * Currently all defined band types express channels as frequency in kHz
    698          *  @return the lower band limit.
    699          */
    700         public int getLowerLimit() {
    701             return mDescriptor.getLowerLimit();
    702         }
    703         /** Upper band limit expressed in units according to band type.
    704          * Currently all defined band types express channels as frequency in kHz
    705          *  @return the upper band limit.
    706          */
    707         public int getUpperLimit() {
    708             return mDescriptor.getUpperLimit();
    709         }
    710         /** Channel spacing in units according to band type.
    711          * Currently all defined band types express channels as frequency in kHz
    712          *  @return the channel spacing.
    713          */
    714         public int getSpacing() {
    715             return mDescriptor.getSpacing();
    716         }
    717 
    718 
    719         public static final Parcelable.Creator<BandConfig> CREATOR
    720                 = new Parcelable.Creator<BandConfig>() {
    721             public BandConfig createFromParcel(Parcel in) {
    722                 return new BandConfig(in);
    723             }
    724 
    725             public BandConfig[] newArray(int size) {
    726                 return new BandConfig[size];
    727             }
    728         };
    729 
    730         @Override
    731         public void writeToParcel(Parcel dest, int flags) {
    732             mDescriptor.writeToParcel(dest, flags);
    733         }
    734 
    735         @Override
    736         public int describeContents() {
    737             return 0;
    738         }
    739 
    740         @Override
    741         public String toString() {
    742             return "BandConfig [ " + mDescriptor.toString() + "]";
    743         }
    744 
    745         @Override
    746         public int hashCode() {
    747             final int prime = 31;
    748             int result = 1;
    749             result = prime * result + mDescriptor.hashCode();
    750             return result;
    751         }
    752 
    753         @Override
    754         public boolean equals(Object obj) {
    755             if (this == obj)
    756                 return true;
    757             if (!(obj instanceof BandConfig))
    758                 return false;
    759             BandConfig other = (BandConfig) obj;
    760             if (mDescriptor != other.getDescriptor())
    761                 return false;
    762             return true;
    763         }
    764     }
    765 
    766     /** FM band configuration.
    767      * @see #BAND_FM
    768      * @see #BAND_FM_HD */
    769     public static class FmBandConfig extends BandConfig {
    770         private final boolean mStereo;
    771         private final boolean mRds;
    772         private final boolean mTa;
    773         private final boolean mAf;
    774         private final boolean mEa;
    775 
    776         FmBandConfig(FmBandDescriptor descriptor) {
    777             super((BandDescriptor)descriptor);
    778             mStereo = descriptor.isStereoSupported();
    779             mRds = descriptor.isRdsSupported();
    780             mTa = descriptor.isTaSupported();
    781             mAf = descriptor.isAfSupported();
    782             mEa = descriptor.isEaSupported();
    783         }
    784 
    785         FmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
    786                 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
    787             super(region, type, lowerLimit, upperLimit, spacing);
    788             mStereo = stereo;
    789             mRds = rds;
    790             mTa = ta;
    791             mAf = af;
    792             mEa = ea;
    793         }
    794 
    795         /** Get stereo enable state
    796          * @return the enable state.
    797          */
    798         public boolean getStereo() {
    799             return mStereo;
    800         }
    801 
    802         /** Get RDS or RBDS(if region is ITU2) enable state
    803          * @return the enable state.
    804          */
    805         public boolean getRds() {
    806             return mRds;
    807         }
    808 
    809         /** Get Traffic announcement enable state
    810          * @return the enable state.
    811          */
    812         public boolean getTa() {
    813             return mTa;
    814         }
    815 
    816         /** Get Alternate Frequency Switching enable state
    817          * @return the enable state.
    818          */
    819         public boolean getAf() {
    820             return mAf;
    821         }
    822 
    823         /**
    824          * Get Emergency announcement enable state
    825          * @return the enable state.
    826          */
    827         public boolean getEa() {
    828             return mEa;
    829         }
    830 
    831         private FmBandConfig(Parcel in) {
    832             super(in);
    833             mStereo = in.readByte() == 1;
    834             mRds = in.readByte() == 1;
    835             mTa = in.readByte() == 1;
    836             mAf = in.readByte() == 1;
    837             mEa = in.readByte() == 1;
    838         }
    839 
    840         public static final Parcelable.Creator<FmBandConfig> CREATOR
    841                 = new Parcelable.Creator<FmBandConfig>() {
    842             public FmBandConfig createFromParcel(Parcel in) {
    843                 return new FmBandConfig(in);
    844             }
    845 
    846             public FmBandConfig[] newArray(int size) {
    847                 return new FmBandConfig[size];
    848             }
    849         };
    850 
    851         @Override
    852         public void writeToParcel(Parcel dest, int flags) {
    853             super.writeToParcel(dest, flags);
    854             dest.writeByte((byte) (mStereo ? 1 : 0));
    855             dest.writeByte((byte) (mRds ? 1 : 0));
    856             dest.writeByte((byte) (mTa ? 1 : 0));
    857             dest.writeByte((byte) (mAf ? 1 : 0));
    858             dest.writeByte((byte) (mEa ? 1 : 0));
    859         }
    860 
    861         @Override
    862         public int describeContents() {
    863             return 0;
    864         }
    865 
    866         @Override
    867         public String toString() {
    868             return "FmBandConfig [" + super.toString()
    869                     + ", mStereo=" + mStereo + ", mRds=" + mRds + ", mTa=" + mTa
    870                     + ", mAf=" + mAf + ", mEa =" + mEa + "]";
    871         }
    872 
    873         @Override
    874         public int hashCode() {
    875             final int prime = 31;
    876             int result = super.hashCode();
    877             result = prime * result + (mStereo ? 1 : 0);
    878             result = prime * result + (mRds ? 1 : 0);
    879             result = prime * result + (mTa ? 1 : 0);
    880             result = prime * result + (mAf ? 1 : 0);
    881             result = prime * result + (mEa ? 1 : 0);
    882             return result;
    883         }
    884 
    885         @Override
    886         public boolean equals(Object obj) {
    887             if (this == obj)
    888                 return true;
    889             if (!super.equals(obj))
    890                 return false;
    891             if (!(obj instanceof FmBandConfig))
    892                 return false;
    893             FmBandConfig other = (FmBandConfig) obj;
    894             if (mStereo != other.mStereo)
    895                 return false;
    896             if (mRds != other.mRds)
    897                 return false;
    898             if (mTa != other.mTa)
    899                 return false;
    900             if (mAf != other.mAf)
    901                 return false;
    902             if (mEa != other.mEa)
    903                 return false;
    904             return true;
    905         }
    906 
    907         /**
    908          * Builder class for {@link FmBandConfig} objects.
    909          */
    910         public static class Builder {
    911             private final BandDescriptor mDescriptor;
    912             private boolean mStereo;
    913             private boolean mRds;
    914             private boolean mTa;
    915             private boolean mAf;
    916             private boolean mEa;
    917 
    918             /**
    919              * Constructs a new Builder with the defaults from an {@link FmBandDescriptor} .
    920              * @param descriptor the FmBandDescriptor defaults are read from .
    921              */
    922             public Builder(FmBandDescriptor descriptor) {
    923                 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
    924                         descriptor.getLowerLimit(), descriptor.getUpperLimit(),
    925                         descriptor.getSpacing());
    926                 mStereo = descriptor.isStereoSupported();
    927                 mRds = descriptor.isRdsSupported();
    928                 mTa = descriptor.isTaSupported();
    929                 mAf = descriptor.isAfSupported();
    930                 mEa = descriptor.isEaSupported();
    931             }
    932 
    933             /**
    934              * Constructs a new Builder from a given {@link FmBandConfig}
    935              * @param config the FmBandConfig object whose data will be reused in the new Builder.
    936              */
    937             public Builder(FmBandConfig config) {
    938                 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
    939                         config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
    940                 mStereo = config.getStereo();
    941                 mRds = config.getRds();
    942                 mTa = config.getTa();
    943                 mAf = config.getAf();
    944                 mEa = config.getEa();
    945             }
    946 
    947             /**
    948              * Combines all of the parameters that have been set and return a new
    949              * {@link FmBandConfig} object.
    950              * @return a new {@link FmBandConfig} object
    951              */
    952             public FmBandConfig build() {
    953                 FmBandConfig config = new FmBandConfig(mDescriptor.getRegion(),
    954                         mDescriptor.getType(), mDescriptor.getLowerLimit(),
    955                         mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
    956                         mStereo, mRds, mTa, mAf, mEa);
    957                 return config;
    958             }
    959 
    960             /** Set stereo enable state
    961              * @param state The new enable state.
    962              * @return the same Builder instance.
    963              */
    964             public Builder setStereo(boolean state) {
    965                 mStereo = state;
    966                 return this;
    967             }
    968 
    969             /** Set RDS or RBDS(if region is ITU2) enable state
    970              * @param state The new enable state.
    971              * @return the same Builder instance.
    972              */
    973             public Builder setRds(boolean state) {
    974                 mRds = state;
    975                 return this;
    976             }
    977 
    978             /** Set Traffic announcement enable state
    979              * @param state The new enable state.
    980              * @return the same Builder instance.
    981              */
    982             public Builder setTa(boolean state) {
    983                 mTa = state;
    984                 return this;
    985             }
    986 
    987             /** Set Alternate Frequency Switching enable state
    988              * @param state The new enable state.
    989              * @return the same Builder instance.
    990              */
    991             public Builder setAf(boolean state) {
    992                 mAf = state;
    993                 return this;
    994             }
    995 
    996             /** Set Emergency Announcement enable state
    997              * @param state The new enable state.
    998              * @return the same Builder instance.
    999              */
   1000             public Builder setEa(boolean state) {
   1001                 mEa = state;
   1002                 return this;
   1003             }
   1004         };
   1005     }
   1006 
   1007     /** AM band configuration.
   1008      * @see #BAND_AM */
   1009     public static class AmBandConfig extends BandConfig {
   1010         private final boolean mStereo;
   1011 
   1012         AmBandConfig(AmBandDescriptor descriptor) {
   1013             super((BandDescriptor)descriptor);
   1014             mStereo = descriptor.isStereoSupported();
   1015         }
   1016 
   1017         AmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
   1018                 boolean stereo) {
   1019             super(region, type, lowerLimit, upperLimit, spacing);
   1020             mStereo = stereo;
   1021         }
   1022 
   1023         /** Get stereo enable state
   1024          * @return the enable state.
   1025          */
   1026         public boolean getStereo() {
   1027             return mStereo;
   1028         }
   1029 
   1030         private AmBandConfig(Parcel in) {
   1031             super(in);
   1032             mStereo = in.readByte() == 1;
   1033         }
   1034 
   1035         public static final Parcelable.Creator<AmBandConfig> CREATOR
   1036                 = new Parcelable.Creator<AmBandConfig>() {
   1037             public AmBandConfig createFromParcel(Parcel in) {
   1038                 return new AmBandConfig(in);
   1039             }
   1040 
   1041             public AmBandConfig[] newArray(int size) {
   1042                 return new AmBandConfig[size];
   1043             }
   1044         };
   1045 
   1046         @Override
   1047         public void writeToParcel(Parcel dest, int flags) {
   1048             super.writeToParcel(dest, flags);
   1049             dest.writeByte((byte) (mStereo ? 1 : 0));
   1050         }
   1051 
   1052         @Override
   1053         public int describeContents() {
   1054             return 0;
   1055         }
   1056 
   1057         @Override
   1058         public String toString() {
   1059             return "AmBandConfig [" + super.toString()
   1060                     + ", mStereo=" + mStereo + "]";
   1061         }
   1062 
   1063         @Override
   1064         public int hashCode() {
   1065             final int prime = 31;
   1066             int result = super.hashCode();
   1067             result = prime * result + (mStereo ? 1 : 0);
   1068             return result;
   1069         }
   1070 
   1071         @Override
   1072         public boolean equals(Object obj) {
   1073             if (this == obj)
   1074                 return true;
   1075             if (!super.equals(obj))
   1076                 return false;
   1077             if (!(obj instanceof AmBandConfig))
   1078                 return false;
   1079             AmBandConfig other = (AmBandConfig) obj;
   1080             if (mStereo != other.getStereo())
   1081                 return false;
   1082             return true;
   1083         }
   1084 
   1085         /**
   1086          * Builder class for {@link AmBandConfig} objects.
   1087          */
   1088         public static class Builder {
   1089             private final BandDescriptor mDescriptor;
   1090             private boolean mStereo;
   1091 
   1092             /**
   1093              * Constructs a new Builder with the defaults from an {@link AmBandDescriptor} .
   1094              * @param descriptor the FmBandDescriptor defaults are read from .
   1095              */
   1096             public Builder(AmBandDescriptor descriptor) {
   1097                 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
   1098                         descriptor.getLowerLimit(), descriptor.getUpperLimit(),
   1099                         descriptor.getSpacing());
   1100                 mStereo = descriptor.isStereoSupported();
   1101             }
   1102 
   1103             /**
   1104              * Constructs a new Builder from a given {@link AmBandConfig}
   1105              * @param config the FmBandConfig object whose data will be reused in the new Builder.
   1106              */
   1107             public Builder(AmBandConfig config) {
   1108                 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
   1109                         config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
   1110                 mStereo = config.getStereo();
   1111             }
   1112 
   1113             /**
   1114              * Combines all of the parameters that have been set and return a new
   1115              * {@link AmBandConfig} object.
   1116              * @return a new {@link AmBandConfig} object
   1117              */
   1118             public AmBandConfig build() {
   1119                 AmBandConfig config = new AmBandConfig(mDescriptor.getRegion(),
   1120                         mDescriptor.getType(), mDescriptor.getLowerLimit(),
   1121                         mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
   1122                         mStereo);
   1123                 return config;
   1124             }
   1125 
   1126             /** Set stereo enable state
   1127              * @param state The new enable state.
   1128              * @return the same Builder instance.
   1129              */
   1130             public Builder setStereo(boolean state) {
   1131                 mStereo = state;
   1132                 return this;
   1133             }
   1134         };
   1135     }
   1136 
   1137     /** Radio program information returned by
   1138      * {@link RadioTuner#getProgramInformation(RadioManager.ProgramInfo[])} */
   1139     public static class ProgramInfo implements Parcelable {
   1140 
   1141         private final int mChannel;
   1142         private final int mSubChannel;
   1143         private final boolean mTuned;
   1144         private final boolean mStereo;
   1145         private final boolean mDigital;
   1146         private final int mSignalStrength;
   1147         private final RadioMetadata mMetadata;
   1148 
   1149         ProgramInfo(int channel, int subChannel, boolean tuned, boolean stereo,
   1150                 boolean digital, int signalStrength, RadioMetadata metadata) {
   1151             mChannel = channel;
   1152             mSubChannel = subChannel;
   1153             mTuned = tuned;
   1154             mStereo = stereo;
   1155             mDigital = digital;
   1156             mSignalStrength = signalStrength;
   1157             mMetadata = metadata;
   1158         }
   1159 
   1160         /** Main channel expressed in units according to band type.
   1161          * Currently all defined band types express channels as frequency in kHz
   1162          * @return the program channel
   1163          */
   1164         public int getChannel() {
   1165             return mChannel;
   1166         }
   1167         /** Sub channel ID. E.g 1 for HD radio HD1
   1168          * @return the program sub channel
   1169          */
   1170         public int getSubChannel() {
   1171             return mSubChannel;
   1172         }
   1173         /** {@code true} if the tuner is currently tuned on a valid station
   1174          * @return {@code true} if currently tuned, {@code false} otherwise.
   1175          */
   1176         public boolean isTuned() {
   1177             return mTuned;
   1178         }
   1179         /** {@code true} if the received program is stereo
   1180          * @return {@code true} if stereo, {@code false} otherwise.
   1181          */
   1182         public boolean isStereo() {
   1183             return mStereo;
   1184         }
   1185         /** {@code true} if the received program is digital (e.g HD radio)
   1186          * @return {@code true} if digital, {@code false} otherwise.
   1187          */
   1188         public boolean isDigital() {
   1189             return mDigital;
   1190         }
   1191         /** Signal strength indicator from 0 (no signal) to 100 (excellent)
   1192          * @return the signal strength indication.
   1193          */
   1194         public int getSignalStrength() {
   1195             return mSignalStrength;
   1196         }
   1197         /** Metadata currently received from this station.
   1198          * null if no metadata have been received
   1199          * @return current meta data received from this program.
   1200          */
   1201         public RadioMetadata getMetadata() {
   1202             return mMetadata;
   1203         }
   1204 
   1205         private ProgramInfo(Parcel in) {
   1206             mChannel = in.readInt();
   1207             mSubChannel = in.readInt();
   1208             mTuned = in.readByte() == 1;
   1209             mStereo = in.readByte() == 1;
   1210             mDigital = in.readByte() == 1;
   1211             mSignalStrength = in.readInt();
   1212             if (in.readByte() == 1) {
   1213                 mMetadata = RadioMetadata.CREATOR.createFromParcel(in);
   1214             } else {
   1215                 mMetadata = null;
   1216             }
   1217         }
   1218 
   1219         public static final Parcelable.Creator<ProgramInfo> CREATOR
   1220                 = new Parcelable.Creator<ProgramInfo>() {
   1221             public ProgramInfo createFromParcel(Parcel in) {
   1222                 return new ProgramInfo(in);
   1223             }
   1224 
   1225             public ProgramInfo[] newArray(int size) {
   1226                 return new ProgramInfo[size];
   1227             }
   1228         };
   1229 
   1230         @Override
   1231         public void writeToParcel(Parcel dest, int flags) {
   1232             dest.writeInt(mChannel);
   1233             dest.writeInt(mSubChannel);
   1234             dest.writeByte((byte)(mTuned ? 1 : 0));
   1235             dest.writeByte((byte)(mStereo ? 1 : 0));
   1236             dest.writeByte((byte)(mDigital ? 1 : 0));
   1237             dest.writeInt(mSignalStrength);
   1238             if (mMetadata == null) {
   1239                 dest.writeByte((byte)0);
   1240             } else {
   1241                 dest.writeByte((byte)1);
   1242                 mMetadata.writeToParcel(dest, flags);
   1243             }
   1244         }
   1245 
   1246         @Override
   1247         public int describeContents() {
   1248             return 0;
   1249         }
   1250 
   1251         @Override
   1252         public String toString() {
   1253             return "ProgramInfo [mChannel=" + mChannel + ", mSubChannel=" + mSubChannel
   1254                     + ", mTuned=" + mTuned + ", mStereo=" + mStereo + ", mDigital=" + mDigital
   1255                     + ", mSignalStrength=" + mSignalStrength
   1256                     + ((mMetadata == null) ? "" : (", mMetadata=" + mMetadata.toString()))
   1257                     + "]";
   1258         }
   1259 
   1260         @Override
   1261         public int hashCode() {
   1262             final int prime = 31;
   1263             int result = 1;
   1264             result = prime * result + mChannel;
   1265             result = prime * result + mSubChannel;
   1266             result = prime * result + (mTuned ? 1 : 0);
   1267             result = prime * result + (mStereo ? 1 : 0);
   1268             result = prime * result + (mDigital ? 1 : 0);
   1269             result = prime * result + mSignalStrength;
   1270             result = prime * result + ((mMetadata == null) ? 0 : mMetadata.hashCode());
   1271             return result;
   1272         }
   1273 
   1274         @Override
   1275         public boolean equals(Object obj) {
   1276             if (this == obj)
   1277                 return true;
   1278             if (!(obj instanceof ProgramInfo))
   1279                 return false;
   1280             ProgramInfo other = (ProgramInfo) obj;
   1281             if (mChannel != other.getChannel())
   1282                 return false;
   1283             if (mSubChannel != other.getSubChannel())
   1284                 return false;
   1285             if (mTuned != other.isTuned())
   1286                 return false;
   1287             if (mStereo != other.isStereo())
   1288                 return false;
   1289             if (mDigital != other.isDigital())
   1290                 return false;
   1291             if (mSignalStrength != other.getSignalStrength())
   1292                 return false;
   1293             if (mMetadata == null) {
   1294                 if (other.getMetadata() != null)
   1295                     return false;
   1296             } else if (!mMetadata.equals(other.getMetadata()))
   1297                 return false;
   1298             return true;
   1299         }
   1300     }
   1301 
   1302 
   1303     /**
   1304      * Returns a list of descriptors for all broadcast radio modules present on the device.
   1305      * @param modules An List of {@link ModuleProperties} where the list will be returned.
   1306      * @return
   1307      * <ul>
   1308      *  <li>{@link #STATUS_OK} in case of success, </li>
   1309      *  <li>{@link #STATUS_ERROR} in case of unspecified error, </li>
   1310      *  <li>{@link #STATUS_NO_INIT} if the native service cannot be reached, </li>
   1311      *  <li>{@link #STATUS_BAD_VALUE} if modules is null, </li>
   1312      *  <li>{@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails, </li>
   1313      * </ul>
   1314      */
   1315     public native int listModules(List <ModuleProperties> modules);
   1316 
   1317     /**
   1318      * Open an interface to control a tuner on a given broadcast radio module.
   1319      * Optionally selects and applies the configuration passed as "config" argument.
   1320      * @param moduleId radio module identifier {@link ModuleProperties#getId()}. Mandatory.
   1321      * @param config desired band and configuration to apply when enabling the hardware module.
   1322      * optional, can be null.
   1323      * @param withAudio {@code true} to request a tuner with an audio source.
   1324      * This tuner is intended for live listening or recording or a radio program.
   1325      * If {@code false}, the tuner can only be used to retrieve program informations.
   1326      * @param callback {@link RadioTuner.Callback} interface. Mandatory.
   1327      * @param handler the Handler on which the callbacks will be received.
   1328      * Can be null if default handler is OK.
   1329      * @return a valid {@link RadioTuner} interface in case of success or null in case of error.
   1330      */
   1331     public RadioTuner openTuner(int moduleId, BandConfig config, boolean withAudio,
   1332             RadioTuner.Callback callback, Handler handler) {
   1333         if (callback == null) {
   1334             return null;
   1335         }
   1336         RadioModule module = new RadioModule(moduleId, config, withAudio, callback, handler);
   1337         if (module != null) {
   1338             if (!module.initCheck()) {
   1339                 module = null;
   1340             }
   1341         }
   1342         return (RadioTuner)module;
   1343     }
   1344 
   1345     private final Context mContext;
   1346 
   1347     /**
   1348      * @hide
   1349      */
   1350     public RadioManager(Context context) {
   1351         mContext = context;
   1352     }
   1353 }
   1354