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