blob: 434cf51bbefcc10ff54f0eddeb3b7036e89bbf66 [file] [log] [blame]
Eric Laurent2035ac82015-03-05 15:18:44 -08001/**
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
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -070019import android.annotation.NonNull;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070020import android.annotation.Nullable;
Eric Laurent2035ac82015-03-05 15:18:44 -080021import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060022import android.annotation.SystemService;
Eric Laurent2035ac82015-03-05 15:18:44 -080023import android.content.Context;
24import android.os.Handler;
25import android.os.Parcel;
26import android.os.Parcelable;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070027import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.os.ServiceManager.ServiceNotFoundException;
30import android.os.SystemProperties;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -070031import android.text.TextUtils;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070032import android.util.Log;
33
Eric Laurent2035ac82015-03-05 15:18:44 -080034import java.util.Arrays;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -070035import java.util.List;
Eric Laurent2035ac82015-03-05 15:18:44 -080036
37/**
38 * The RadioManager class allows to control a broadcast radio tuner present on the device.
39 * It provides data structures and methods to query for available radio modules, list their
40 * properties and open an interface to control tuning operations and receive callbacks when
41 * asynchronous operations complete or events occur.
42 * @hide
43 */
44@SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060045@SystemService(Context.RADIO_SERVICE)
Eric Laurent2035ac82015-03-05 15:18:44 -080046public class RadioManager {
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070047 private static final String TAG = "RadioManager";
Eric Laurent2035ac82015-03-05 15:18:44 -080048
49 /** Method return status: successful operation */
50 public static final int STATUS_OK = 0;
51 /** Method return status: unspecified error */
52 public static final int STATUS_ERROR = Integer.MIN_VALUE;
53 /** Method return status: permission denied */
54 public static final int STATUS_PERMISSION_DENIED = -1;
55 /** Method return status: initialization failure */
56 public static final int STATUS_NO_INIT = -19;
57 /** Method return status: invalid argument provided */
58 public static final int STATUS_BAD_VALUE = -22;
59 /** Method return status: cannot reach service */
60 public static final int STATUS_DEAD_OBJECT = -32;
61 /** Method return status: invalid or out of sequence operation */
62 public static final int STATUS_INVALID_OPERATION = -38;
63 /** Method return status: time out before operation completion */
64 public static final int STATUS_TIMED_OUT = -110;
65
66
67 // keep in sync with radio_class_t in /system/core/incluse/system/radio.h
68 /** Radio module class supporting FM (including HD radio) and AM */
69 public static final int CLASS_AM_FM = 0;
70 /** Radio module class supporting satellite radio */
71 public static final int CLASS_SAT = 1;
72 /** Radio module class supporting Digital terrestrial radio */
73 public static final int CLASS_DT = 2;
74
75 // keep in sync with radio_band_t in /system/core/incluse/system/radio.h
76 /** AM radio band (LW/MW/SW).
77 * @see BandDescriptor */
78 public static final int BAND_AM = 0;
79 /** FM radio band.
80 * @see BandDescriptor */
81 public static final int BAND_FM = 1;
82 /** FM HD radio or DRM band.
83 * @see BandDescriptor */
84 public static final int BAND_FM_HD = 2;
85 /** AM HD radio or DRM band.
86 * @see BandDescriptor */
87 public static final int BAND_AM_HD = 3;
88
89 // keep in sync with radio_region_t in /system/core/incluse/system/radio.h
90 /** Africa, Europe.
91 * @see BandDescriptor */
92 public static final int REGION_ITU_1 = 0;
93 /** Americas.
94 * @see BandDescriptor */
95 public static final int REGION_ITU_2 = 1;
96 /** Russia.
97 * @see BandDescriptor */
98 public static final int REGION_OIRT = 2;
99 /** Japan.
100 * @see BandDescriptor */
101 public static final int REGION_JAPAN = 3;
102 /** Korea.
103 * @see BandDescriptor */
104 public static final int REGION_KOREA = 4;
105
106 /*****************************************************************************
107 * Lists properties, options and radio bands supported by a given broadcast radio module.
108 * Each module has a unique ID used to address it when calling RadioManager APIs.
109 * Module properties are returned by {@link #listModules(List <ModuleProperties>)} method.
110 ****************************************************************************/
111 public static class ModuleProperties implements Parcelable {
112
113 private final int mId;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700114 @NonNull private final String mServiceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800115 private final int mClassId;
116 private final String mImplementor;
117 private final String mProduct;
118 private final String mVersion;
119 private final String mSerial;
120 private final int mNumTuners;
121 private final int mNumAudioSources;
122 private final boolean mIsCaptureSupported;
123 private final BandDescriptor[] mBands;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700124 private final boolean mIsBgScanSupported;
125 private final String mVendorExension;
Eric Laurent2035ac82015-03-05 15:18:44 -0800126
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700127 ModuleProperties(int id, String serviceName, int classId, String implementor,
128 String product, String version, String serial, int numTuners, int numAudioSources,
129 boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
130 String vendorExension) {
Eric Laurent2035ac82015-03-05 15:18:44 -0800131 mId = id;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700132 mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800133 mClassId = classId;
134 mImplementor = implementor;
135 mProduct = product;
136 mVersion = version;
137 mSerial = serial;
138 mNumTuners = numTuners;
139 mNumAudioSources = numAudioSources;
140 mIsCaptureSupported = isCaptureSupported;
141 mBands = bands;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700142 mIsBgScanSupported = isBgScanSupported;
143 mVendorExension = vendorExension;
Eric Laurent2035ac82015-03-05 15:18:44 -0800144 }
145
146
147 /** Unique module identifier provided by the native service.
148 * For use with {@link #openTuner(int, BandConfig, boolean, Callback, Handler)}.
149 * @return the radio module unique identifier.
150 */
151 public int getId() {
152 return mId;
153 }
154
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700155 /**
156 * Module service (driver) name as registered with HIDL.
157 * @return the module service name.
158 *
159 * @hide FutureFeature
160 */
161 public @NonNull String getServiceName() {
162 return mServiceName;
163 }
164
Eric Laurent2035ac82015-03-05 15:18:44 -0800165 /** Module class identifier: {@link #CLASS_AM_FM}, {@link #CLASS_SAT}, {@link #CLASS_DT}
166 * @return the radio module class identifier.
167 */
168 public int getClassId() {
169 return mClassId;
170 }
171
172 /** Human readable broadcast radio module implementor
173 * @return the name of the radio module implementator.
174 */
175 public String getImplementor() {
176 return mImplementor;
177 }
178
179 /** Human readable broadcast radio module product name
180 * @return the radio module product name.
181 */
182 public String getProduct() {
183 return mProduct;
184 }
185
186 /** Human readable broadcast radio module version number
187 * @return the radio module version.
188 */
189 public String getVersion() {
190 return mVersion;
191 }
192
193 /** Radio module serial number.
194 * Can be used for subscription services.
195 * @return the radio module serial number.
196 */
197 public String getSerial() {
198 return mSerial;
199 }
200
201 /** Number of tuners available.
202 * This is the number of tuners that can be open simultaneously.
203 * @return the number of tuners supported.
204 */
205 public int getNumTuners() {
206 return mNumTuners;
207 }
208
209 /** Number tuner audio sources available. Must be less or equal to getNumTuners().
210 * When more than one tuner is supported, one is usually for playback and has one
211 * associated audio source and the other is for pre scanning and building a
212 * program list.
213 * @return the number of audio sources available.
214 */
215 public int getNumAudioSources() {
216 return mNumAudioSources;
217 }
218
219 /** {@code true} if audio capture is possible from radio tuner output.
220 * This indicates if routing to audio devices not connected to the same HAL as the FM radio
221 * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented.
222 * @return {@code true} if audio capture is possible, {@code false} otherwise.
223 */
224 public boolean isCaptureSupported() {
225 return mIsCaptureSupported;
226 }
227
Tomasz Wasilczyke597ce12017-03-24 13:50:53 -0700228 /**
229 * {@code true} if the module supports background scanning. At the given time it may not
230 * be available though, see {@link RadioTuner#startBackgroundScan()}.
231 *
232 * @return {@code true} if background scanning is supported (not necessary available
233 * at a given time), {@code false} otherwise.
234 *
235 * @hide FutureFeature
236 */
237 public boolean isBackgroundScanningSupported() {
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700238 return mIsBgScanSupported;
239 }
240
241 /**
242 * Opaque vendor-specific string, passed from HAL without changes.
243 * Format of this string can vary across vendors.
244 *
245 * It may be used for extra features, that's not supported by a platform,
246 * for example: "preset-slots=6;ultra-hd-capable=false".
247 *
248 * Client application MUST verify vendor/product name from the
249 * ModuleProperties class before doing any interpretation of this value.
250 *
251 * @hide FutureFeature
252 */
253 public @NonNull String getVendorExension() {
254 return mVendorExension == null ? "" : mVendorExension;
Tomasz Wasilczyke597ce12017-03-24 13:50:53 -0700255 }
256
Eric Laurent2035ac82015-03-05 15:18:44 -0800257 /** List of descriptors for all bands supported by this module.
258 * @return an array of {@link BandDescriptor}.
259 */
260 public BandDescriptor[] getBands() {
261 return mBands;
262 }
263
264 private ModuleProperties(Parcel in) {
265 mId = in.readInt();
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700266 String serviceName = in.readString();
267 mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800268 mClassId = in.readInt();
269 mImplementor = in.readString();
270 mProduct = in.readString();
271 mVersion = in.readString();
272 mSerial = in.readString();
273 mNumTuners = in.readInt();
274 mNumAudioSources = in.readInt();
275 mIsCaptureSupported = in.readInt() == 1;
276 Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader());
277 mBands = new BandDescriptor[tmp.length];
278 for (int i = 0; i < tmp.length; i++) {
279 mBands[i] = (BandDescriptor) tmp[i];
280 }
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700281 mIsBgScanSupported = in.readInt() == 1;
282 mVendorExension = in.readString();
Eric Laurent2035ac82015-03-05 15:18:44 -0800283 }
284
285 public static final Parcelable.Creator<ModuleProperties> CREATOR
286 = new Parcelable.Creator<ModuleProperties>() {
287 public ModuleProperties createFromParcel(Parcel in) {
288 return new ModuleProperties(in);
289 }
290
291 public ModuleProperties[] newArray(int size) {
292 return new ModuleProperties[size];
293 }
294 };
295
296 @Override
297 public void writeToParcel(Parcel dest, int flags) {
298 dest.writeInt(mId);
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700299 dest.writeString(mServiceName);
Eric Laurent2035ac82015-03-05 15:18:44 -0800300 dest.writeInt(mClassId);
301 dest.writeString(mImplementor);
302 dest.writeString(mProduct);
303 dest.writeString(mVersion);
304 dest.writeString(mSerial);
305 dest.writeInt(mNumTuners);
306 dest.writeInt(mNumAudioSources);
307 dest.writeInt(mIsCaptureSupported ? 1 : 0);
308 dest.writeParcelableArray(mBands, flags);
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700309 dest.writeInt(mIsBgScanSupported ? 1 : 0);
310 dest.writeString(mVendorExension);
Eric Laurent2035ac82015-03-05 15:18:44 -0800311 }
312
313 @Override
314 public int describeContents() {
315 return 0;
316 }
317
318 @Override
319 public String toString() {
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700320 return "ModuleProperties [mId=" + mId
321 + ", mServiceName=" + mServiceName + ", mClassId=" + mClassId
Eric Laurent2035ac82015-03-05 15:18:44 -0800322 + ", mImplementor=" + mImplementor + ", mProduct=" + mProduct
323 + ", mVersion=" + mVersion + ", mSerial=" + mSerial
324 + ", mNumTuners=" + mNumTuners
325 + ", mNumAudioSources=" + mNumAudioSources
326 + ", mIsCaptureSupported=" + mIsCaptureSupported
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700327 + ", mIsBgScanSupported=" + mIsBgScanSupported
Eric Laurent2035ac82015-03-05 15:18:44 -0800328 + ", mBands=" + Arrays.toString(mBands) + "]";
329 }
330
331 @Override
332 public int hashCode() {
333 final int prime = 31;
334 int result = 1;
335 result = prime * result + mId;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700336 result = prime * result + mServiceName.hashCode();
Eric Laurent2035ac82015-03-05 15:18:44 -0800337 result = prime * result + mClassId;
338 result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
339 result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
340 result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
341 result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
342 result = prime * result + mNumTuners;
343 result = prime * result + mNumAudioSources;
344 result = prime * result + (mIsCaptureSupported ? 1 : 0);
345 result = prime * result + Arrays.hashCode(mBands);
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700346 result = prime * result + (mIsBgScanSupported ? 1 : 0);
347 result = prime * result + ((mVendorExension == null) ? 0 : mVendorExension.hashCode());
Eric Laurent2035ac82015-03-05 15:18:44 -0800348 return result;
349 }
350
351 @Override
352 public boolean equals(Object obj) {
353 if (this == obj)
354 return true;
355 if (!(obj instanceof ModuleProperties))
356 return false;
357 ModuleProperties other = (ModuleProperties) obj;
358 if (mId != other.getId())
359 return false;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700360 if (!TextUtils.equals(mServiceName, other.mServiceName)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800361 if (mClassId != other.getClassId())
362 return false;
363 if (mImplementor == null) {
364 if (other.getImplementor() != null)
365 return false;
366 } else if (!mImplementor.equals(other.getImplementor()))
367 return false;
368 if (mProduct == null) {
369 if (other.getProduct() != null)
370 return false;
371 } else if (!mProduct.equals(other.getProduct()))
372 return false;
373 if (mVersion == null) {
374 if (other.getVersion() != null)
375 return false;
376 } else if (!mVersion.equals(other.getVersion()))
377 return false;
378 if (mSerial == null) {
379 if (other.getSerial() != null)
380 return false;
381 } else if (!mSerial.equals(other.getSerial()))
382 return false;
383 if (mNumTuners != other.getNumTuners())
384 return false;
385 if (mNumAudioSources != other.getNumAudioSources())
386 return false;
387 if (mIsCaptureSupported != other.isCaptureSupported())
388 return false;
389 if (!Arrays.equals(mBands, other.getBands()))
390 return false;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700391 if (mIsBgScanSupported != other.isBackgroundScanningSupported())
392 return false;
393 if (!TextUtils.equals(mVendorExension, other.mVendorExension))
394 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800395 return true;
396 }
397 }
398
399 /** Radio band descriptor: an element in ModuleProperties bands array.
400 * It is either an instance of {@link FmBandDescriptor} or {@link AmBandDescriptor} */
401 public static class BandDescriptor implements Parcelable {
402
403 private final int mRegion;
404 private final int mType;
405 private final int mLowerLimit;
406 private final int mUpperLimit;
407 private final int mSpacing;
408
409 BandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700410 if (type != BAND_AM && type != BAND_FM && type != BAND_FM_HD && type != BAND_AM_HD) {
411 throw new IllegalArgumentException("Unsupported band: " + type);
412 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800413 mRegion = region;
414 mType = type;
415 mLowerLimit = lowerLimit;
416 mUpperLimit = upperLimit;
417 mSpacing = spacing;
418 }
419
420 /** Region this band applies to. E.g. {@link #REGION_ITU_1}
421 * @return the region this band is associated to.
422 */
423 public int getRegion() {
424 return mRegion;
425 }
426 /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
427 * <ul>
428 * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
429 * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
430 * </ul>
431 * @return the band type.
432 */
433 public int getType() {
434 return mType;
435 }
436 /** Lower band limit expressed in units according to band type.
437 * Currently all defined band types express channels as frequency in kHz
438 * @return the lower band limit.
439 */
440 public int getLowerLimit() {
441 return mLowerLimit;
442 }
443 /** Upper band limit expressed in units according to band type.
444 * Currently all defined band types express channels as frequency in kHz
445 * @return the upper band limit.
446 */
447 public int getUpperLimit() {
448 return mUpperLimit;
449 }
450 /** Channel spacing in units according to band type.
451 * Currently all defined band types express channels as frequency in kHz
452 * @return the channel spacing.
453 */
454 public int getSpacing() {
455 return mSpacing;
456 }
457
458 private BandDescriptor(Parcel in) {
459 mRegion = in.readInt();
460 mType = in.readInt();
461 mLowerLimit = in.readInt();
462 mUpperLimit = in.readInt();
463 mSpacing = in.readInt();
464 }
465
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700466 private static int lookupTypeFromParcel(Parcel in) {
467 int pos = in.dataPosition();
468 in.readInt(); // skip region
469 int type = in.readInt();
470 in.setDataPosition(pos);
471 return type;
472 }
473
Eric Laurent2035ac82015-03-05 15:18:44 -0800474 public static final Parcelable.Creator<BandDescriptor> CREATOR
475 = new Parcelable.Creator<BandDescriptor>() {
476 public BandDescriptor createFromParcel(Parcel in) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700477 int type = lookupTypeFromParcel(in);
478 switch (type) {
479 case BAND_FM:
480 case BAND_FM_HD:
481 return new FmBandDescriptor(in);
482 case BAND_AM:
483 case BAND_AM_HD:
484 return new AmBandDescriptor(in);
485 default:
486 throw new IllegalArgumentException("Unsupported band: " + type);
487 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800488 }
489
490 public BandDescriptor[] newArray(int size) {
491 return new BandDescriptor[size];
492 }
493 };
494
495 @Override
496 public void writeToParcel(Parcel dest, int flags) {
497 dest.writeInt(mRegion);
498 dest.writeInt(mType);
499 dest.writeInt(mLowerLimit);
500 dest.writeInt(mUpperLimit);
501 dest.writeInt(mSpacing);
502 }
503
504 @Override
505 public int describeContents() {
506 return 0;
507 }
508
509 @Override
510 public String toString() {
511 return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
512 + mLowerLimit + ", mUpperLimit=" + mUpperLimit + ", mSpacing=" + mSpacing + "]";
513 }
514
515 @Override
516 public int hashCode() {
517 final int prime = 31;
518 int result = 1;
519 result = prime * result + mRegion;
520 result = prime * result + mType;
521 result = prime * result + mLowerLimit;
522 result = prime * result + mUpperLimit;
523 result = prime * result + mSpacing;
524 return result;
525 }
526
527 @Override
528 public boolean equals(Object obj) {
529 if (this == obj)
530 return true;
531 if (!(obj instanceof BandDescriptor))
532 return false;
533 BandDescriptor other = (BandDescriptor) obj;
534 if (mRegion != other.getRegion())
535 return false;
536 if (mType != other.getType())
537 return false;
538 if (mLowerLimit != other.getLowerLimit())
539 return false;
540 if (mUpperLimit != other.getUpperLimit())
541 return false;
542 if (mSpacing != other.getSpacing())
543 return false;
544 return true;
545 }
546 }
547
548 /** FM band descriptor
549 * @see #BAND_FM
550 * @see #BAND_FM_HD */
551 public static class FmBandDescriptor extends BandDescriptor {
552 private final boolean mStereo;
553 private final boolean mRds;
554 private final boolean mTa;
555 private final boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700556 private final boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -0800557
558 FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700559 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
Eric Laurent2035ac82015-03-05 15:18:44 -0800560 super(region, type, lowerLimit, upperLimit, spacing);
561 mStereo = stereo;
562 mRds = rds;
563 mTa = ta;
564 mAf = af;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700565 mEa = ea;
Eric Laurent2035ac82015-03-05 15:18:44 -0800566 }
567
568 /** Stereo is supported
569 * @return {@code true} if stereo is supported, {@code false} otherwise.
570 */
571 public boolean isStereoSupported() {
572 return mStereo;
573 }
574 /** RDS or RBDS(if region is ITU2) is supported
575 * @return {@code true} if RDS or RBDS is supported, {@code false} otherwise.
576 */
577 public boolean isRdsSupported() {
578 return mRds;
579 }
580 /** Traffic announcement is supported
581 * @return {@code true} if TA is supported, {@code false} otherwise.
582 */
583 public boolean isTaSupported() {
584 return mTa;
585 }
586 /** Alternate Frequency Switching is supported
587 * @return {@code true} if AF switching is supported, {@code false} otherwise.
588 */
589 public boolean isAfSupported() {
590 return mAf;
591 }
592
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700593 /** Emergency Announcement is supported
594 * @return {@code true} if Emergency annoucement is supported, {@code false} otherwise.
595 */
596 public boolean isEaSupported() {
597 return mEa;
598 }
599
Eric Laurent2035ac82015-03-05 15:18:44 -0800600 /* Parcelable implementation */
601 private FmBandDescriptor(Parcel in) {
602 super(in);
603 mStereo = in.readByte() == 1;
604 mRds = in.readByte() == 1;
605 mTa = in.readByte() == 1;
606 mAf = in.readByte() == 1;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700607 mEa = in.readByte() == 1;
Eric Laurent2035ac82015-03-05 15:18:44 -0800608 }
609
610 public static final Parcelable.Creator<FmBandDescriptor> CREATOR
611 = new Parcelable.Creator<FmBandDescriptor>() {
612 public FmBandDescriptor createFromParcel(Parcel in) {
613 return new FmBandDescriptor(in);
614 }
615
616 public FmBandDescriptor[] newArray(int size) {
617 return new FmBandDescriptor[size];
618 }
619 };
620
621 @Override
622 public void writeToParcel(Parcel dest, int flags) {
623 super.writeToParcel(dest, flags);
624 dest.writeByte((byte) (mStereo ? 1 : 0));
625 dest.writeByte((byte) (mRds ? 1 : 0));
626 dest.writeByte((byte) (mTa ? 1 : 0));
627 dest.writeByte((byte) (mAf ? 1 : 0));
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700628 dest.writeByte((byte) (mEa ? 1 : 0));
Eric Laurent2035ac82015-03-05 15:18:44 -0800629 }
630
631 @Override
632 public int describeContents() {
633 return 0;
634 }
635
636 @Override
637 public String toString() {
638 return "FmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700639 + ", mRds=" + mRds + ", mTa=" + mTa + ", mAf=" + mAf +
640 ", mEa =" + mEa + "]";
Eric Laurent2035ac82015-03-05 15:18:44 -0800641 }
642
643 @Override
644 public int hashCode() {
645 final int prime = 31;
646 int result = super.hashCode();
647 result = prime * result + (mStereo ? 1 : 0);
648 result = prime * result + (mRds ? 1 : 0);
649 result = prime * result + (mTa ? 1 : 0);
650 result = prime * result + (mAf ? 1 : 0);
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700651 result = prime * result + (mEa ? 1 : 0);
Eric Laurent2035ac82015-03-05 15:18:44 -0800652 return result;
653 }
654
655 @Override
656 public boolean equals(Object obj) {
657 if (this == obj)
658 return true;
659 if (!super.equals(obj))
660 return false;
661 if (!(obj instanceof FmBandDescriptor))
662 return false;
663 FmBandDescriptor other = (FmBandDescriptor) obj;
664 if (mStereo != other.isStereoSupported())
665 return false;
666 if (mRds != other.isRdsSupported())
667 return false;
668 if (mTa != other.isTaSupported())
669 return false;
670 if (mAf != other.isAfSupported())
671 return false;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700672 if (mEa != other.isEaSupported())
673 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800674 return true;
675 }
676 }
677
678 /** AM band descriptor.
679 * @see #BAND_AM */
680 public static class AmBandDescriptor extends BandDescriptor {
681
682 private final boolean mStereo;
683
684 AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
685 boolean stereo) {
686 super(region, type, lowerLimit, upperLimit, spacing);
687 mStereo = stereo;
688 }
689
690 /** Stereo is supported
691 * @return {@code true} if stereo is supported, {@code false} otherwise.
692 */
693 public boolean isStereoSupported() {
694 return mStereo;
695 }
696
697 private AmBandDescriptor(Parcel in) {
698 super(in);
699 mStereo = in.readByte() == 1;
700 }
701
702 public static final Parcelable.Creator<AmBandDescriptor> CREATOR
703 = new Parcelable.Creator<AmBandDescriptor>() {
704 public AmBandDescriptor createFromParcel(Parcel in) {
705 return new AmBandDescriptor(in);
706 }
707
708 public AmBandDescriptor[] newArray(int size) {
709 return new AmBandDescriptor[size];
710 }
711 };
712
713 @Override
714 public void writeToParcel(Parcel dest, int flags) {
715 super.writeToParcel(dest, flags);
716 dest.writeByte((byte) (mStereo ? 1 : 0));
717 }
718
719 @Override
720 public int describeContents() {
721 return 0;
722 }
723
724 @Override
725 public String toString() {
726 return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
727 }
728
729 @Override
730 public int hashCode() {
731 final int prime = 31;
732 int result = super.hashCode();
733 result = prime * result + (mStereo ? 1 : 0);
734 return result;
735 }
736
737 @Override
738 public boolean equals(Object obj) {
739 if (this == obj)
740 return true;
741 if (!super.equals(obj))
742 return false;
743 if (!(obj instanceof AmBandDescriptor))
744 return false;
745 AmBandDescriptor other = (AmBandDescriptor) obj;
746 if (mStereo != other.isStereoSupported())
747 return false;
748 return true;
749 }
750 }
751
752
753 /** Radio band configuration. */
754 public static class BandConfig implements Parcelable {
755
756 final BandDescriptor mDescriptor;
757
758 BandConfig(BandDescriptor descriptor) {
759 mDescriptor = descriptor;
760 }
761
762 BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
763 mDescriptor = new BandDescriptor(region, type, lowerLimit, upperLimit, spacing);
764 }
765
766 private BandConfig(Parcel in) {
767 mDescriptor = new BandDescriptor(in);
768 }
769
770 BandDescriptor getDescriptor() {
771 return mDescriptor;
772 }
773
774 /** Region this band applies to. E.g. {@link #REGION_ITU_1}
775 * @return the region associated with this band.
776 */
777 public int getRegion() {
778 return mDescriptor.getRegion();
779 }
780 /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
781 * <ul>
782 * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
783 * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
784 * </ul>
785 * @return the band type.
786 */
787 public int getType() {
788 return mDescriptor.getType();
789 }
790 /** Lower band limit expressed in units according to band type.
791 * Currently all defined band types express channels as frequency in kHz
792 * @return the lower band limit.
793 */
794 public int getLowerLimit() {
795 return mDescriptor.getLowerLimit();
796 }
797 /** Upper band limit expressed in units according to band type.
798 * Currently all defined band types express channels as frequency in kHz
799 * @return the upper band limit.
800 */
801 public int getUpperLimit() {
802 return mDescriptor.getUpperLimit();
803 }
804 /** Channel spacing in units according to band type.
805 * Currently all defined band types express channels as frequency in kHz
806 * @return the channel spacing.
807 */
808 public int getSpacing() {
809 return mDescriptor.getSpacing();
810 }
811
812
813 public static final Parcelable.Creator<BandConfig> CREATOR
814 = new Parcelable.Creator<BandConfig>() {
815 public BandConfig createFromParcel(Parcel in) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700816 int type = BandDescriptor.lookupTypeFromParcel(in);
817 switch (type) {
818 case BAND_FM:
819 case BAND_FM_HD:
820 return new FmBandConfig(in);
821 case BAND_AM:
822 case BAND_AM_HD:
823 return new AmBandConfig(in);
824 default:
825 throw new IllegalArgumentException("Unsupported band: " + type);
826 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800827 }
828
829 public BandConfig[] newArray(int size) {
830 return new BandConfig[size];
831 }
832 };
833
834 @Override
835 public void writeToParcel(Parcel dest, int flags) {
836 mDescriptor.writeToParcel(dest, flags);
837 }
838
839 @Override
840 public int describeContents() {
841 return 0;
842 }
843
844 @Override
845 public String toString() {
846 return "BandConfig [ " + mDescriptor.toString() + "]";
847 }
848
849 @Override
850 public int hashCode() {
851 final int prime = 31;
852 int result = 1;
853 result = prime * result + mDescriptor.hashCode();
854 return result;
855 }
856
857 @Override
858 public boolean equals(Object obj) {
859 if (this == obj)
860 return true;
861 if (!(obj instanceof BandConfig))
862 return false;
863 BandConfig other = (BandConfig) obj;
Tomasz Wasilczykdd767062017-04-28 08:19:34 -0700864 BandDescriptor otherDesc = other.getDescriptor();
865 if ((mDescriptor == null) != (otherDesc == null)) return false;
866 if (mDescriptor != null && !mDescriptor.equals(otherDesc)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800867 return true;
868 }
869 }
870
871 /** FM band configuration.
872 * @see #BAND_FM
873 * @see #BAND_FM_HD */
874 public static class FmBandConfig extends BandConfig {
875 private final boolean mStereo;
876 private final boolean mRds;
877 private final boolean mTa;
878 private final boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700879 private final boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -0800880
881 FmBandConfig(FmBandDescriptor descriptor) {
882 super((BandDescriptor)descriptor);
883 mStereo = descriptor.isStereoSupported();
884 mRds = descriptor.isRdsSupported();
885 mTa = descriptor.isTaSupported();
886 mAf = descriptor.isAfSupported();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700887 mEa = descriptor.isEaSupported();
Eric Laurent2035ac82015-03-05 15:18:44 -0800888 }
889
890 FmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700891 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
Eric Laurent2035ac82015-03-05 15:18:44 -0800892 super(region, type, lowerLimit, upperLimit, spacing);
893 mStereo = stereo;
894 mRds = rds;
895 mTa = ta;
896 mAf = af;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700897 mEa = ea;
Eric Laurent2035ac82015-03-05 15:18:44 -0800898 }
899
900 /** Get stereo enable state
901 * @return the enable state.
902 */
903 public boolean getStereo() {
904 return mStereo;
905 }
906
907 /** Get RDS or RBDS(if region is ITU2) enable state
908 * @return the enable state.
909 */
910 public boolean getRds() {
911 return mRds;
912 }
913
914 /** Get Traffic announcement enable state
915 * @return the enable state.
916 */
917 public boolean getTa() {
918 return mTa;
919 }
920
921 /** Get Alternate Frequency Switching enable state
922 * @return the enable state.
923 */
924 public boolean getAf() {
925 return mAf;
926 }
927
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700928 /**
929 * Get Emergency announcement enable state
930 * @return the enable state.
931 */
932 public boolean getEa() {
933 return mEa;
934 }
935
Eric Laurent2035ac82015-03-05 15:18:44 -0800936 private FmBandConfig(Parcel in) {
937 super(in);
938 mStereo = in.readByte() == 1;
939 mRds = in.readByte() == 1;
940 mTa = in.readByte() == 1;
941 mAf = in.readByte() == 1;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700942 mEa = in.readByte() == 1;
Eric Laurent2035ac82015-03-05 15:18:44 -0800943 }
944
945 public static final Parcelable.Creator<FmBandConfig> CREATOR
946 = new Parcelable.Creator<FmBandConfig>() {
947 public FmBandConfig createFromParcel(Parcel in) {
948 return new FmBandConfig(in);
949 }
950
951 public FmBandConfig[] newArray(int size) {
952 return new FmBandConfig[size];
953 }
954 };
955
956 @Override
957 public void writeToParcel(Parcel dest, int flags) {
958 super.writeToParcel(dest, flags);
959 dest.writeByte((byte) (mStereo ? 1 : 0));
960 dest.writeByte((byte) (mRds ? 1 : 0));
961 dest.writeByte((byte) (mTa ? 1 : 0));
962 dest.writeByte((byte) (mAf ? 1 : 0));
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700963 dest.writeByte((byte) (mEa ? 1 : 0));
Eric Laurent2035ac82015-03-05 15:18:44 -0800964 }
965
966 @Override
967 public int describeContents() {
968 return 0;
969 }
970
971 @Override
972 public String toString() {
973 return "FmBandConfig [" + super.toString()
974 + ", mStereo=" + mStereo + ", mRds=" + mRds + ", mTa=" + mTa
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700975 + ", mAf=" + mAf + ", mEa =" + mEa + "]";
Eric Laurent2035ac82015-03-05 15:18:44 -0800976 }
977
978 @Override
979 public int hashCode() {
980 final int prime = 31;
981 int result = super.hashCode();
982 result = prime * result + (mStereo ? 1 : 0);
983 result = prime * result + (mRds ? 1 : 0);
984 result = prime * result + (mTa ? 1 : 0);
985 result = prime * result + (mAf ? 1 : 0);
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700986 result = prime * result + (mEa ? 1 : 0);
Eric Laurent2035ac82015-03-05 15:18:44 -0800987 return result;
988 }
989
990 @Override
991 public boolean equals(Object obj) {
992 if (this == obj)
993 return true;
994 if (!super.equals(obj))
995 return false;
996 if (!(obj instanceof FmBandConfig))
997 return false;
998 FmBandConfig other = (FmBandConfig) obj;
999 if (mStereo != other.mStereo)
1000 return false;
1001 if (mRds != other.mRds)
1002 return false;
1003 if (mTa != other.mTa)
1004 return false;
1005 if (mAf != other.mAf)
1006 return false;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001007 if (mEa != other.mEa)
1008 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001009 return true;
1010 }
1011
1012 /**
1013 * Builder class for {@link FmBandConfig} objects.
1014 */
1015 public static class Builder {
1016 private final BandDescriptor mDescriptor;
1017 private boolean mStereo;
1018 private boolean mRds;
1019 private boolean mTa;
1020 private boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001021 private boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -08001022
1023 /**
1024 * Constructs a new Builder with the defaults from an {@link FmBandDescriptor} .
1025 * @param descriptor the FmBandDescriptor defaults are read from .
1026 */
1027 public Builder(FmBandDescriptor descriptor) {
1028 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
1029 descriptor.getLowerLimit(), descriptor.getUpperLimit(),
1030 descriptor.getSpacing());
1031 mStereo = descriptor.isStereoSupported();
1032 mRds = descriptor.isRdsSupported();
1033 mTa = descriptor.isTaSupported();
1034 mAf = descriptor.isAfSupported();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001035 mEa = descriptor.isEaSupported();
Eric Laurent2035ac82015-03-05 15:18:44 -08001036 }
1037
1038 /**
1039 * Constructs a new Builder from a given {@link FmBandConfig}
1040 * @param config the FmBandConfig object whose data will be reused in the new Builder.
1041 */
1042 public Builder(FmBandConfig config) {
1043 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
1044 config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
1045 mStereo = config.getStereo();
1046 mRds = config.getRds();
1047 mTa = config.getTa();
1048 mAf = config.getAf();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001049 mEa = config.getEa();
Eric Laurent2035ac82015-03-05 15:18:44 -08001050 }
1051
1052 /**
1053 * Combines all of the parameters that have been set and return a new
1054 * {@link FmBandConfig} object.
1055 * @return a new {@link FmBandConfig} object
1056 */
1057 public FmBandConfig build() {
1058 FmBandConfig config = new FmBandConfig(mDescriptor.getRegion(),
1059 mDescriptor.getType(), mDescriptor.getLowerLimit(),
1060 mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001061 mStereo, mRds, mTa, mAf, mEa);
Eric Laurent2035ac82015-03-05 15:18:44 -08001062 return config;
1063 }
1064
1065 /** Set stereo enable state
1066 * @param state The new enable state.
1067 * @return the same Builder instance.
1068 */
1069 public Builder setStereo(boolean state) {
1070 mStereo = state;
1071 return this;
1072 }
1073
1074 /** Set RDS or RBDS(if region is ITU2) enable state
1075 * @param state The new enable state.
1076 * @return the same Builder instance.
1077 */
1078 public Builder setRds(boolean state) {
1079 mRds = state;
1080 return this;
1081 }
1082
1083 /** Set Traffic announcement enable state
1084 * @param state The new enable state.
1085 * @return the same Builder instance.
1086 */
1087 public Builder setTa(boolean state) {
1088 mTa = state;
1089 return this;
1090 }
1091
1092 /** Set Alternate Frequency Switching enable state
1093 * @param state The new enable state.
1094 * @return the same Builder instance.
1095 */
1096 public Builder setAf(boolean state) {
1097 mAf = state;
1098 return this;
1099 }
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001100
1101 /** Set Emergency Announcement enable state
1102 * @param state The new enable state.
1103 * @return the same Builder instance.
1104 */
1105 public Builder setEa(boolean state) {
1106 mEa = state;
1107 return this;
1108 }
Eric Laurent2035ac82015-03-05 15:18:44 -08001109 };
1110 }
1111
1112 /** AM band configuration.
1113 * @see #BAND_AM */
1114 public static class AmBandConfig extends BandConfig {
1115 private final boolean mStereo;
1116
1117 AmBandConfig(AmBandDescriptor descriptor) {
1118 super((BandDescriptor)descriptor);
1119 mStereo = descriptor.isStereoSupported();
1120 }
1121
1122 AmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
1123 boolean stereo) {
1124 super(region, type, lowerLimit, upperLimit, spacing);
1125 mStereo = stereo;
1126 }
1127
1128 /** Get stereo enable state
1129 * @return the enable state.
1130 */
1131 public boolean getStereo() {
1132 return mStereo;
1133 }
1134
1135 private AmBandConfig(Parcel in) {
1136 super(in);
1137 mStereo = in.readByte() == 1;
1138 }
1139
1140 public static final Parcelable.Creator<AmBandConfig> CREATOR
1141 = new Parcelable.Creator<AmBandConfig>() {
1142 public AmBandConfig createFromParcel(Parcel in) {
1143 return new AmBandConfig(in);
1144 }
1145
1146 public AmBandConfig[] newArray(int size) {
1147 return new AmBandConfig[size];
1148 }
1149 };
1150
1151 @Override
1152 public void writeToParcel(Parcel dest, int flags) {
1153 super.writeToParcel(dest, flags);
1154 dest.writeByte((byte) (mStereo ? 1 : 0));
1155 }
1156
1157 @Override
1158 public int describeContents() {
1159 return 0;
1160 }
1161
1162 @Override
1163 public String toString() {
1164 return "AmBandConfig [" + super.toString()
1165 + ", mStereo=" + mStereo + "]";
1166 }
1167
1168 @Override
1169 public int hashCode() {
1170 final int prime = 31;
1171 int result = super.hashCode();
1172 result = prime * result + (mStereo ? 1 : 0);
1173 return result;
1174 }
1175
1176 @Override
1177 public boolean equals(Object obj) {
1178 if (this == obj)
1179 return true;
1180 if (!super.equals(obj))
1181 return false;
1182 if (!(obj instanceof AmBandConfig))
1183 return false;
1184 AmBandConfig other = (AmBandConfig) obj;
1185 if (mStereo != other.getStereo())
1186 return false;
1187 return true;
1188 }
1189
1190 /**
1191 * Builder class for {@link AmBandConfig} objects.
1192 */
1193 public static class Builder {
1194 private final BandDescriptor mDescriptor;
1195 private boolean mStereo;
1196
1197 /**
1198 * Constructs a new Builder with the defaults from an {@link AmBandDescriptor} .
1199 * @param descriptor the FmBandDescriptor defaults are read from .
1200 */
1201 public Builder(AmBandDescriptor descriptor) {
1202 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
1203 descriptor.getLowerLimit(), descriptor.getUpperLimit(),
1204 descriptor.getSpacing());
1205 mStereo = descriptor.isStereoSupported();
1206 }
1207
1208 /**
1209 * Constructs a new Builder from a given {@link AmBandConfig}
1210 * @param config the FmBandConfig object whose data will be reused in the new Builder.
1211 */
1212 public Builder(AmBandConfig config) {
1213 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
1214 config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
1215 mStereo = config.getStereo();
1216 }
1217
1218 /**
1219 * Combines all of the parameters that have been set and return a new
1220 * {@link AmBandConfig} object.
1221 * @return a new {@link AmBandConfig} object
1222 */
1223 public AmBandConfig build() {
1224 AmBandConfig config = new AmBandConfig(mDescriptor.getRegion(),
1225 mDescriptor.getType(), mDescriptor.getLowerLimit(),
1226 mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
1227 mStereo);
1228 return config;
1229 }
1230
1231 /** Set stereo enable state
1232 * @param state The new enable state.
1233 * @return the same Builder instance.
1234 */
1235 public Builder setStereo(boolean state) {
1236 mStereo = state;
1237 return this;
1238 }
1239 };
1240 }
1241
1242 /** Radio program information returned by
1243 * {@link RadioTuner#getProgramInformation(RadioManager.ProgramInfo[])} */
1244 public static class ProgramInfo implements Parcelable {
1245
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001246 // sourced from hardware/interfaces/broadcastradio/1.1/types.hal
1247 private final static int FLAG_LIVE = 1 << 0;
1248 private final static int FLAG_MUTED = 1 << 1;
1249
Eric Laurent2035ac82015-03-05 15:18:44 -08001250 private final int mChannel;
1251 private final int mSubChannel;
1252 private final boolean mTuned;
1253 private final boolean mStereo;
1254 private final boolean mDigital;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001255 private final int mFlags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001256 private final int mSignalStrength;
1257 private final RadioMetadata mMetadata;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001258 private final String mVendorExension;
Eric Laurent2035ac82015-03-05 15:18:44 -08001259
1260 ProgramInfo(int channel, int subChannel, boolean tuned, boolean stereo,
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001261 boolean digital, int signalStrength, RadioMetadata metadata, int flags,
1262 String vendorExension) {
Eric Laurent2035ac82015-03-05 15:18:44 -08001263 mChannel = channel;
1264 mSubChannel = subChannel;
1265 mTuned = tuned;
1266 mStereo = stereo;
1267 mDigital = digital;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001268 mFlags = flags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001269 mSignalStrength = signalStrength;
1270 mMetadata = metadata;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001271 mVendorExension = vendorExension;
Eric Laurent2035ac82015-03-05 15:18:44 -08001272 }
1273
1274 /** Main channel expressed in units according to band type.
1275 * Currently all defined band types express channels as frequency in kHz
1276 * @return the program channel
1277 */
1278 public int getChannel() {
1279 return mChannel;
1280 }
1281 /** Sub channel ID. E.g 1 for HD radio HD1
1282 * @return the program sub channel
1283 */
1284 public int getSubChannel() {
1285 return mSubChannel;
1286 }
1287 /** {@code true} if the tuner is currently tuned on a valid station
1288 * @return {@code true} if currently tuned, {@code false} otherwise.
1289 */
1290 public boolean isTuned() {
1291 return mTuned;
1292 }
1293 /** {@code true} if the received program is stereo
1294 * @return {@code true} if stereo, {@code false} otherwise.
1295 */
1296 public boolean isStereo() {
1297 return mStereo;
1298 }
1299 /** {@code true} if the received program is digital (e.g HD radio)
1300 * @return {@code true} if digital, {@code false} otherwise.
1301 */
1302 public boolean isDigital() {
1303 return mDigital;
1304 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001305
1306 /**
1307 * {@code true} if the program is currently playing live stream.
1308 * This may result in a slightly altered reception parameters,
1309 * usually targetted at reduced latency.
1310 *
1311 * @hide FutureFeature
1312 */
1313 public boolean isLive() {
1314 return (mFlags & FLAG_LIVE) != 0;
1315 }
1316
1317 /**
1318 * {@code true} if radio stream is not playing, ie. due to bad reception
1319 * conditions or buffering. In this state volume knob MAY be disabled to
1320 * prevent user increasing volume too much.
1321 * It does NOT mean the user has muted audio.
1322 *
1323 * @hide FutureFeature
1324 */
1325 public boolean isMuted() {
1326 return (mFlags & FLAG_MUTED) != 0;
1327 }
1328
Eric Laurent2035ac82015-03-05 15:18:44 -08001329 /** Signal strength indicator from 0 (no signal) to 100 (excellent)
1330 * @return the signal strength indication.
1331 */
1332 public int getSignalStrength() {
1333 return mSignalStrength;
1334 }
1335 /** Metadata currently received from this station.
1336 * null if no metadata have been received
1337 * @return current meta data received from this program.
1338 */
1339 public RadioMetadata getMetadata() {
1340 return mMetadata;
1341 }
1342
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001343 /**
1344 * Opaque vendor-specific string, passed from HAL without changes.
1345 * Format of this string can vary across vendors.
1346 *
1347 * It may be used for extra features, that's not supported by a platform,
1348 * for example: "paid-service=true;bitrate=320kbps".
1349 *
1350 * Client application MUST verify vendor/product name from the
1351 * ModuleProperties class before doing any interpretation of this value.
1352 *
1353 * @hide FutureFeature
1354 */
1355 public @NonNull String getVendorExension() {
1356 return mVendorExension == null ? "" : mVendorExension;
1357 }
1358
Eric Laurent2035ac82015-03-05 15:18:44 -08001359 private ProgramInfo(Parcel in) {
1360 mChannel = in.readInt();
1361 mSubChannel = in.readInt();
1362 mTuned = in.readByte() == 1;
1363 mStereo = in.readByte() == 1;
1364 mDigital = in.readByte() == 1;
1365 mSignalStrength = in.readInt();
1366 if (in.readByte() == 1) {
1367 mMetadata = RadioMetadata.CREATOR.createFromParcel(in);
1368 } else {
1369 mMetadata = null;
1370 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001371 mFlags = in.readInt();
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001372 mVendorExension = in.readString();
Eric Laurent2035ac82015-03-05 15:18:44 -08001373 }
1374
1375 public static final Parcelable.Creator<ProgramInfo> CREATOR
1376 = new Parcelable.Creator<ProgramInfo>() {
1377 public ProgramInfo createFromParcel(Parcel in) {
1378 return new ProgramInfo(in);
1379 }
1380
1381 public ProgramInfo[] newArray(int size) {
1382 return new ProgramInfo[size];
1383 }
1384 };
1385
1386 @Override
1387 public void writeToParcel(Parcel dest, int flags) {
1388 dest.writeInt(mChannel);
1389 dest.writeInt(mSubChannel);
1390 dest.writeByte((byte)(mTuned ? 1 : 0));
1391 dest.writeByte((byte)(mStereo ? 1 : 0));
1392 dest.writeByte((byte)(mDigital ? 1 : 0));
1393 dest.writeInt(mSignalStrength);
1394 if (mMetadata == null) {
1395 dest.writeByte((byte)0);
1396 } else {
1397 dest.writeByte((byte)1);
1398 mMetadata.writeToParcel(dest, flags);
1399 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001400 dest.writeInt(mFlags);
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001401 dest.writeString(mVendorExension);
Eric Laurent2035ac82015-03-05 15:18:44 -08001402 }
1403
1404 @Override
1405 public int describeContents() {
1406 return 0;
1407 }
1408
1409 @Override
1410 public String toString() {
1411 return "ProgramInfo [mChannel=" + mChannel + ", mSubChannel=" + mSubChannel
1412 + ", mTuned=" + mTuned + ", mStereo=" + mStereo + ", mDigital=" + mDigital
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001413 + ", mFlags=" + mFlags + ", mSignalStrength=" + mSignalStrength
Eric Laurent2035ac82015-03-05 15:18:44 -08001414 + ((mMetadata == null) ? "" : (", mMetadata=" + mMetadata.toString()))
1415 + "]";
1416 }
1417
1418 @Override
1419 public int hashCode() {
1420 final int prime = 31;
1421 int result = 1;
1422 result = prime * result + mChannel;
1423 result = prime * result + mSubChannel;
1424 result = prime * result + (mTuned ? 1 : 0);
1425 result = prime * result + (mStereo ? 1 : 0);
1426 result = prime * result + (mDigital ? 1 : 0);
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001427 result = prime * result + mFlags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001428 result = prime * result + mSignalStrength;
1429 result = prime * result + ((mMetadata == null) ? 0 : mMetadata.hashCode());
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001430 result = prime * result + ((mVendorExension == null) ? 0 : mVendorExension.hashCode());
Eric Laurent2035ac82015-03-05 15:18:44 -08001431 return result;
1432 }
1433
1434 @Override
1435 public boolean equals(Object obj) {
1436 if (this == obj)
1437 return true;
1438 if (!(obj instanceof ProgramInfo))
1439 return false;
1440 ProgramInfo other = (ProgramInfo) obj;
1441 if (mChannel != other.getChannel())
1442 return false;
1443 if (mSubChannel != other.getSubChannel())
1444 return false;
1445 if (mTuned != other.isTuned())
1446 return false;
1447 if (mStereo != other.isStereo())
1448 return false;
1449 if (mDigital != other.isDigital())
1450 return false;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001451 if (mFlags != other.mFlags)
1452 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001453 if (mSignalStrength != other.getSignalStrength())
1454 return false;
1455 if (mMetadata == null) {
1456 if (other.getMetadata() != null)
1457 return false;
1458 } else if (!mMetadata.equals(other.getMetadata()))
1459 return false;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001460 if (!TextUtils.equals(mVendorExension, other.mVendorExension))
1461 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001462 return true;
1463 }
1464 }
1465
1466
1467 /**
1468 * Returns a list of descriptors for all broadcast radio modules present on the device.
1469 * @param modules An List of {@link ModuleProperties} where the list will be returned.
1470 * @return
1471 * <ul>
1472 * <li>{@link #STATUS_OK} in case of success, </li>
1473 * <li>{@link #STATUS_ERROR} in case of unspecified error, </li>
1474 * <li>{@link #STATUS_NO_INIT} if the native service cannot be reached, </li>
1475 * <li>{@link #STATUS_BAD_VALUE} if modules is null, </li>
1476 * <li>{@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails, </li>
1477 * </ul>
1478 */
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -07001479 public int listModules(List<ModuleProperties> modules) {
1480 if (modules == null) {
1481 Log.e(TAG, "the output list must not be empty");
1482 return STATUS_BAD_VALUE;
1483 }
1484
1485 if (mService == null) {
1486 return nativeListModules(modules);
1487 }
1488
1489 Log.v(TAG, "Listing available tuners...");
1490 List<ModuleProperties> returnedList;
1491 try {
1492 returnedList = mService.listModules();
1493 } catch (RemoteException e) {
1494 Log.e(TAG, "Failed listing available tuners", e);
1495 return STATUS_DEAD_OBJECT;
1496 }
1497
1498 if (returnedList == null) {
1499 Log.e(TAG, "Returned list was a null");
1500 return STATUS_ERROR;
1501 }
1502
1503 modules.addAll(returnedList);
1504 return STATUS_OK;
1505 }
1506
1507 private native int nativeListModules(List<ModuleProperties> modules);
Eric Laurent2035ac82015-03-05 15:18:44 -08001508
1509 /**
1510 * Open an interface to control a tuner on a given broadcast radio module.
1511 * Optionally selects and applies the configuration passed as "config" argument.
1512 * @param moduleId radio module identifier {@link ModuleProperties#getId()}. Mandatory.
1513 * @param config desired band and configuration to apply when enabling the hardware module.
1514 * optional, can be null.
1515 * @param withAudio {@code true} to request a tuner with an audio source.
1516 * This tuner is intended for live listening or recording or a radio program.
1517 * If {@code false}, the tuner can only be used to retrieve program informations.
1518 * @param callback {@link RadioTuner.Callback} interface. Mandatory.
1519 * @param handler the Handler on which the callbacks will be received.
1520 * Can be null if default handler is OK.
1521 * @return a valid {@link RadioTuner} interface in case of success or null in case of error.
1522 */
1523 public RadioTuner openTuner(int moduleId, BandConfig config, boolean withAudio,
1524 RadioTuner.Callback callback, Handler handler) {
1525 if (callback == null) {
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001526 throw new IllegalArgumentException("callback must not be empty");
Eric Laurent2035ac82015-03-05 15:18:44 -08001527 }
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001528
1529 if (mService != null) {
Tomasz Wasilczyk21348172017-04-20 14:02:42 -07001530 Log.d(TAG, "Opening tuner...");
1531
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001532 ITuner tuner;
Tomasz Wasilczyk21348172017-04-20 14:02:42 -07001533 ITunerCallback halCallback = new TunerCallbackAdapter(callback, handler);
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001534 try {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -07001535 tuner = mService.openTuner(moduleId, config, withAudio, halCallback);
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001536 } catch (RemoteException e) {
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -07001537 Log.e(TAG, "Failed to open tuner", e);
1538 return null;
Eric Laurent2035ac82015-03-05 15:18:44 -08001539 }
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -07001540 if (tuner == null) {
1541 Log.e(TAG, "Failed to open tuner");
1542 return null;
1543 }
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001544 return new TunerAdapter(tuner);
Eric Laurent2035ac82015-03-05 15:18:44 -08001545 }
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001546
1547 RadioModule module = new RadioModule(moduleId, config, withAudio, callback, handler);
1548 if (!module.initCheck()) {
1549 Log.e(TAG, "Failed to open tuner");
1550 module = null;
1551 }
1552
Eric Laurent2035ac82015-03-05 15:18:44 -08001553 return (RadioTuner)module;
1554 }
1555
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001556 @NonNull private final Context mContext;
1557 // TODO(b/36863239): NonNull when transitioned from native service
1558 @Nullable private final IRadioService mService;
Eric Laurent2035ac82015-03-05 15:18:44 -08001559
1560 /**
1561 * @hide
1562 */
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001563 public RadioManager(@NonNull Context context) throws ServiceNotFoundException {
Eric Laurent2035ac82015-03-05 15:18:44 -08001564 mContext = context;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001565
1566 boolean isServiceJava = SystemProperties.getBoolean("config.enable_java_radio", false);
1567 mService = isServiceJava ? IRadioService.Stub.asInterface(
1568 ServiceManager.getServiceOrThrow(Context.RADIO_SERVICE)) : null;
Eric Laurent2035ac82015-03-05 15:18:44 -08001569 }
1570}