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
17package android.hardware.radio;
18
19import android.annotation.SystemApi;
20import android.annotation.SystemService;
21import android.content.Context;
22import android.os.Handler;
23import android.os.Parcel;
24import android.os.Parcelable;
25import java.util.List;
26import 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)
37public 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