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 
ModuleProperties(int id, int classId, String implementor, String product, String version, String serial, int numTuners, int numAudioSources, boolean isCaptureSupported, BandDescriptor[] bands)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          */
getId()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          */
getClassId()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          */
getImplementor()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          */
getProduct()155         public String getProduct() {
156             return mProduct;
157         }
158 
159         /** Human readable broadcast radio module version number
160          * @return the radio module version.
161          */
getVersion()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          */
getSerial()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          */
getNumTuners()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          */
getNumAudioSources()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          */
isCaptureSupported()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          */
getBands()204         public BandDescriptor[] getBands() {
205             return mBands;
206         }
207 
ModuleProperties(Parcel in)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
writeToParcel(Parcel dest, int flags)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
describeContents()251         public int describeContents() {
252             return 0;
253         }
254 
255         @Override
toString()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
hashCode()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
equals(Object obj)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 
BandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing)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          */
getRegion()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          */
getType()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          */
getLowerLimit()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          */
getUpperLimit()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          */
getSpacing()378         public int getSpacing() {
379             return mSpacing;
380         }
381 
BandDescriptor(Parcel in)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
writeToParcel(Parcel dest, int flags)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
describeContents()411         public int describeContents() {
412             return 0;
413         }
414 
415         @Override
toString()416         public String toString() {
417             return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
418                     + mLowerLimit + ", mUpperLimit=" + mUpperLimit + ", mSpacing=" + mSpacing + "]";
419         }
420 
421         @Override
hashCode()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
equals(Object obj)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 
FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing, boolean stereo, boolean rds, boolean ta, boolean af, boolean ea)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          */
isStereoSupported()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          */
isRdsSupported()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          */
isTaSupported()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          */
isAfSupported()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          */
isEaSupported()502         public boolean isEaSupported() {
503             return mEa;
504         }
505 
506         /* Parcelable implementation */
FmBandDescriptor(Parcel in)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
writeToParcel(Parcel dest, int flags)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
describeContents()538         public int describeContents() {
539             return 0;
540         }
541 
542         @Override
toString()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
hashCode()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
equals(Object obj)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 
AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing, boolean stereo)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          */
isStereoSupported()599         public boolean isStereoSupported() {
600             return mStereo;
601         }
602 
AmBandDescriptor(Parcel in)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
writeToParcel(Parcel dest, int flags)620         public void writeToParcel(Parcel dest, int flags) {
621             super.writeToParcel(dest, flags);
622             dest.writeByte((byte) (mStereo ? 1 : 0));
623         }
624 
625         @Override
describeContents()626         public int describeContents() {
627             return 0;
628         }
629 
630         @Override
toString()631         public String toString() {
632             return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
633         }
634 
635         @Override
hashCode()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
equals(Object obj)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 
BandConfig(BandDescriptor descriptor)664         BandConfig(BandDescriptor descriptor) {
665             mDescriptor = descriptor;
666         }
667 
BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing)668         BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
669             mDescriptor = new BandDescriptor(region, type, lowerLimit, upperLimit, spacing);
670         }
671 
BandConfig(Parcel in)672         private BandConfig(Parcel in) {
673             mDescriptor = new BandDescriptor(in);
674         }
675 
getDescriptor()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          */
getRegion()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          */
getType()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          */
getLowerLimit()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          */
getUpperLimit()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          */
getSpacing()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
writeToParcel(Parcel dest, int flags)731         public void writeToParcel(Parcel dest, int flags) {
732             mDescriptor.writeToParcel(dest, flags);
733         }
734 
735         @Override
describeContents()736         public int describeContents() {
737             return 0;
738         }
739 
740         @Override
toString()741         public String toString() {
742             return "BandConfig [ " + mDescriptor.toString() + "]";
743         }
744 
745         @Override
hashCode()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
equals(Object obj)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 
FmBandConfig(FmBandDescriptor descriptor)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 
FmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing, boolean stereo, boolean rds, boolean ta, boolean af, boolean ea)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          */
getStereo()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          */
getRds()805         public boolean getRds() {
806             return mRds;
807         }
808 
809         /** Get Traffic announcement enable state
810          * @return the enable state.
811          */
getTa()812         public boolean getTa() {
813             return mTa;
814         }
815 
816         /** Get Alternate Frequency Switching enable state
817          * @return the enable state.
818          */
getAf()819         public boolean getAf() {
820             return mAf;
821         }
822 
823         /**
824          * Get Emergency announcement enable state
825          * @return the enable state.
826          */
getEa()827         public boolean getEa() {
828             return mEa;
829         }
830 
FmBandConfig(Parcel in)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
writeToParcel(Parcel dest, int flags)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
describeContents()862         public int describeContents() {
863             return 0;
864         }
865 
866         @Override
toString()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
hashCode()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
equals(Object obj)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              */
Builder(FmBandDescriptor descriptor)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              */
Builder(FmBandConfig config)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              */
build()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              */
setStereo(boolean state)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              */
setRds(boolean state)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              */
setTa(boolean state)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              */
setAf(boolean state)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              */
setEa(boolean state)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 
AmBandConfig(AmBandDescriptor descriptor)1012         AmBandConfig(AmBandDescriptor descriptor) {
1013             super((BandDescriptor)descriptor);
1014             mStereo = descriptor.isStereoSupported();
1015         }
1016 
AmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing, boolean stereo)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          */
getStereo()1026         public boolean getStereo() {
1027             return mStereo;
1028         }
1029 
AmBandConfig(Parcel in)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
writeToParcel(Parcel dest, int flags)1047         public void writeToParcel(Parcel dest, int flags) {
1048             super.writeToParcel(dest, flags);
1049             dest.writeByte((byte) (mStereo ? 1 : 0));
1050         }
1051 
1052         @Override
describeContents()1053         public int describeContents() {
1054             return 0;
1055         }
1056 
1057         @Override
toString()1058         public String toString() {
1059             return "AmBandConfig [" + super.toString()
1060                     + ", mStereo=" + mStereo + "]";
1061         }
1062 
1063         @Override
hashCode()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
equals(Object obj)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              */
Builder(AmBandDescriptor descriptor)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              */
Builder(AmBandConfig config)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              */
build()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              */
setStereo(boolean state)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 
ProgramInfo(int channel, int subChannel, boolean tuned, boolean stereo, boolean digital, int signalStrength, RadioMetadata metadata)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          */
getChannel()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          */
getSubChannel()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          */
isTuned()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          */
isStereo()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          */
isDigital()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          */
getSignalStrength()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          */
getMetadata()1201         public RadioMetadata getMetadata() {
1202             return mMetadata;
1203         }
1204 
ProgramInfo(Parcel in)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
writeToParcel(Parcel dest, int flags)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
describeContents()1247         public int describeContents() {
1248             return 0;
1249         }
1250 
1251         @Override
toString()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
hashCode()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
equals(Object obj)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      */
listModules(List <ModuleProperties> modules)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      */
openTuner(int moduleId, BandConfig config, boolean withAudio, RadioTuner.Callback callback, Handler handler)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      */
RadioManager(Context context)1350     public RadioManager(Context context) {
1351         mContext = context;
1352     }
1353 }
1354