blob: 56668ac00527e14d0021961bc0a1b2ec618fedd1 [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 Wasilczyk749e3dc2017-07-28 13:20:41 -070019import android.Manifest;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070020import android.annotation.IntDef;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -070021import android.annotation.NonNull;
Tomasz Wasilczyk749e3dc2017-07-28 13:20:41 -070022import android.annotation.RequiresPermission;
Eric Laurent2035ac82015-03-05 15:18:44 -080023import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.SystemService;
Eric Laurent2035ac82015-03-05 15:18:44 -080025import android.content.Context;
26import android.os.Handler;
27import android.os.Parcel;
28import android.os.Parcelable;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070029import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.os.ServiceManager.ServiceNotFoundException;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -070032import android.text.TextUtils;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -070033import android.util.Log;
34
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070035import java.lang.annotation.Retention;
36import java.lang.annotation.RetentionPolicy;
Eric Laurent2035ac82015-03-05 15:18:44 -080037import java.util.Arrays;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -070038import java.util.HashMap;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -070039import java.util.List;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -070040import java.util.Map;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080041import java.util.Objects;
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -070042import java.util.Set;
43import java.util.stream.Collectors;
Eric Laurent2035ac82015-03-05 15:18:44 -080044
45/**
46 * The RadioManager class allows to control a broadcast radio tuner present on the device.
47 * It provides data structures and methods to query for available radio modules, list their
48 * properties and open an interface to control tuning operations and receive callbacks when
49 * asynchronous operations complete or events occur.
50 * @hide
51 */
52@SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060053@SystemService(Context.RADIO_SERVICE)
Eric Laurent2035ac82015-03-05 15:18:44 -080054public class RadioManager {
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070055 private static final String TAG = "BroadcastRadio.manager";
Eric Laurent2035ac82015-03-05 15:18:44 -080056
57 /** Method return status: successful operation */
58 public static final int STATUS_OK = 0;
59 /** Method return status: unspecified error */
60 public static final int STATUS_ERROR = Integer.MIN_VALUE;
61 /** Method return status: permission denied */
62 public static final int STATUS_PERMISSION_DENIED = -1;
63 /** Method return status: initialization failure */
64 public static final int STATUS_NO_INIT = -19;
65 /** Method return status: invalid argument provided */
66 public static final int STATUS_BAD_VALUE = -22;
67 /** Method return status: cannot reach service */
68 public static final int STATUS_DEAD_OBJECT = -32;
69 /** Method return status: invalid or out of sequence operation */
70 public static final int STATUS_INVALID_OPERATION = -38;
71 /** Method return status: time out before operation completion */
72 public static final int STATUS_TIMED_OUT = -110;
73
74
75 // keep in sync with radio_class_t in /system/core/incluse/system/radio.h
76 /** Radio module class supporting FM (including HD radio) and AM */
77 public static final int CLASS_AM_FM = 0;
78 /** Radio module class supporting satellite radio */
79 public static final int CLASS_SAT = 1;
80 /** Radio module class supporting Digital terrestrial radio */
81 public static final int CLASS_DT = 2;
82
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070083 public static final int BAND_INVALID = -1;
Eric Laurent2035ac82015-03-05 15:18:44 -080084 /** AM radio band (LW/MW/SW).
85 * @see BandDescriptor */
86 public static final int BAND_AM = 0;
87 /** FM radio band.
88 * @see BandDescriptor */
89 public static final int BAND_FM = 1;
90 /** FM HD radio or DRM band.
91 * @see BandDescriptor */
92 public static final int BAND_FM_HD = 2;
93 /** AM HD radio or DRM band.
94 * @see BandDescriptor */
95 public static final int BAND_AM_HD = 3;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070096 @IntDef(prefix = { "BAND_" }, value = {
97 BAND_INVALID,
98 BAND_AM,
99 BAND_FM,
100 BAND_AM_HD,
101 BAND_FM_HD,
102 })
103 @Retention(RetentionPolicy.SOURCE)
104 public @interface Band {}
Eric Laurent2035ac82015-03-05 15:18:44 -0800105
106 // keep in sync with radio_region_t in /system/core/incluse/system/radio.h
107 /** Africa, Europe.
108 * @see BandDescriptor */
109 public static final int REGION_ITU_1 = 0;
110 /** Americas.
111 * @see BandDescriptor */
112 public static final int REGION_ITU_2 = 1;
113 /** Russia.
114 * @see BandDescriptor */
115 public static final int REGION_OIRT = 2;
116 /** Japan.
117 * @see BandDescriptor */
118 public static final int REGION_JAPAN = 3;
119 /** Korea.
120 * @see BandDescriptor */
121 public static final int REGION_KOREA = 4;
122
Tomasz Wasilczykce40fe92018-01-04 20:52:39 -0800123 /**
124 * Forces mono audio stream reception.
125 *
126 * Analog broadcasts can recover poor reception conditions by jointing
127 * stereo channels into one. Mainly for, but not limited to AM/FM.
128 */
129 public static final int CONFIG_FORCE_MONO = 1;
130 /**
131 * Forces the analog playback for the supporting radio technology.
132 *
133 * User may disable digital playback for FM HD Radio or hybrid FM/DAB with
134 * this option. This is purely user choice, ie. does not reflect digital-
135 * analog handover state managed from the HAL implementation side.
136 *
137 * Some radio technologies may not support this, ie. DAB.
138 */
139 public static final int CONFIG_FORCE_ANALOG = 2;
140 /**
141 * Forces the digital playback for the supporting radio technology.
142 *
143 * User may disable digital-analog handover that happens with poor
144 * reception conditions. With digital forced, the radio will remain silent
145 * instead of switching to analog channel if it's available. This is purely
146 * user choice, it does not reflect the actual state of handover.
147 */
148 public static final int CONFIG_FORCE_DIGITAL = 3;
149 /**
150 * RDS Alternative Frequencies.
151 *
152 * If set and the currently tuned RDS station broadcasts on multiple
153 * channels, radio tuner automatically switches to the best available
154 * alternative.
155 */
156 public static final int CONFIG_RDS_AF = 4;
157 /**
158 * RDS region-specific program lock-down.
159 *
160 * Allows user to lock to the current region as they move into the
161 * other region.
162 */
163 public static final int CONFIG_RDS_REG = 5;
164 /** Enables DAB-DAB hard- and implicit-linking (the same content). */
165 public static final int CONFIG_DAB_DAB_LINKING = 6;
166 /** Enables DAB-FM hard- and implicit-linking (the same content). */
167 public static final int CONFIG_DAB_FM_LINKING = 7;
168 /** Enables DAB-DAB soft-linking (related content). */
169 public static final int CONFIG_DAB_DAB_SOFT_LINKING = 8;
170 /** Enables DAB-FM soft-linking (related content). */
171 public static final int CONFIG_DAB_FM_SOFT_LINKING = 9;
172
173 /** @hide */
174 @IntDef(prefix = { "CONFIG_" }, value = {
175 CONFIG_FORCE_MONO,
176 CONFIG_FORCE_ANALOG,
177 CONFIG_FORCE_DIGITAL,
178 CONFIG_RDS_AF,
179 CONFIG_RDS_REG,
180 CONFIG_DAB_DAB_LINKING,
181 CONFIG_DAB_FM_LINKING,
182 CONFIG_DAB_DAB_SOFT_LINKING,
183 CONFIG_DAB_FM_SOFT_LINKING,
184 })
185 @Retention(RetentionPolicy.SOURCE)
186 public @interface ConfigFlag {}
187
Eric Laurent2035ac82015-03-05 15:18:44 -0800188 /*****************************************************************************
189 * Lists properties, options and radio bands supported by a given broadcast radio module.
190 * Each module has a unique ID used to address it when calling RadioManager APIs.
191 * Module properties are returned by {@link #listModules(List <ModuleProperties>)} method.
192 ****************************************************************************/
193 public static class ModuleProperties implements Parcelable {
194
195 private final int mId;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700196 @NonNull private final String mServiceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800197 private final int mClassId;
198 private final String mImplementor;
199 private final String mProduct;
200 private final String mVersion;
201 private final String mSerial;
202 private final int mNumTuners;
203 private final int mNumAudioSources;
204 private final boolean mIsCaptureSupported;
205 private final BandDescriptor[] mBands;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700206 private final boolean mIsBgScanSupported;
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700207 private final Set<Integer> mSupportedProgramTypes;
208 private final Set<Integer> mSupportedIdentifierTypes;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700209 @NonNull private final Map<String, String> mVendorInfo;
Eric Laurent2035ac82015-03-05 15:18:44 -0800210
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -0800211 /** @hide */
212 public ModuleProperties(int id, String serviceName, int classId, String implementor,
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700213 String product, String version, String serial, int numTuners, int numAudioSources,
214 boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700215 @ProgramSelector.ProgramType int[] supportedProgramTypes,
216 @ProgramSelector.IdentifierType int[] supportedIdentifierTypes,
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700217 Map<String, String> vendorInfo) {
Eric Laurent2035ac82015-03-05 15:18:44 -0800218 mId = id;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700219 mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800220 mClassId = classId;
221 mImplementor = implementor;
222 mProduct = product;
223 mVersion = version;
224 mSerial = serial;
225 mNumTuners = numTuners;
226 mNumAudioSources = numAudioSources;
227 mIsCaptureSupported = isCaptureSupported;
228 mBands = bands;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700229 mIsBgScanSupported = isBgScanSupported;
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700230 mSupportedProgramTypes = arrayToSet(supportedProgramTypes);
231 mSupportedIdentifierTypes = arrayToSet(supportedIdentifierTypes);
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700232 mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
Eric Laurent2035ac82015-03-05 15:18:44 -0800233 }
234
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700235 private static Set<Integer> arrayToSet(int[] arr) {
236 return Arrays.stream(arr).boxed().collect(Collectors.toSet());
237 }
238
239 private static int[] setToArray(Set<Integer> set) {
240 return set.stream().mapToInt(Integer::intValue).toArray();
241 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800242
243 /** Unique module identifier provided by the native service.
244 * For use with {@link #openTuner(int, BandConfig, boolean, Callback, Handler)}.
245 * @return the radio module unique identifier.
246 */
247 public int getId() {
248 return mId;
249 }
250
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700251 /**
252 * Module service (driver) name as registered with HIDL.
253 * @return the module service name.
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700254 */
255 public @NonNull String getServiceName() {
256 return mServiceName;
257 }
258
Eric Laurent2035ac82015-03-05 15:18:44 -0800259 /** Module class identifier: {@link #CLASS_AM_FM}, {@link #CLASS_SAT}, {@link #CLASS_DT}
260 * @return the radio module class identifier.
261 */
262 public int getClassId() {
263 return mClassId;
264 }
265
266 /** Human readable broadcast radio module implementor
267 * @return the name of the radio module implementator.
268 */
269 public String getImplementor() {
270 return mImplementor;
271 }
272
273 /** Human readable broadcast radio module product name
274 * @return the radio module product name.
275 */
276 public String getProduct() {
277 return mProduct;
278 }
279
280 /** Human readable broadcast radio module version number
281 * @return the radio module version.
282 */
283 public String getVersion() {
284 return mVersion;
285 }
286
287 /** Radio module serial number.
288 * Can be used for subscription services.
289 * @return the radio module serial number.
290 */
291 public String getSerial() {
292 return mSerial;
293 }
294
295 /** Number of tuners available.
296 * This is the number of tuners that can be open simultaneously.
297 * @return the number of tuners supported.
298 */
299 public int getNumTuners() {
300 return mNumTuners;
301 }
302
303 /** Number tuner audio sources available. Must be less or equal to getNumTuners().
304 * When more than one tuner is supported, one is usually for playback and has one
305 * associated audio source and the other is for pre scanning and building a
306 * program list.
307 * @return the number of audio sources available.
308 */
309 public int getNumAudioSources() {
310 return mNumAudioSources;
311 }
312
313 /** {@code true} if audio capture is possible from radio tuner output.
314 * This indicates if routing to audio devices not connected to the same HAL as the FM radio
315 * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented.
316 * @return {@code true} if audio capture is possible, {@code false} otherwise.
317 */
318 public boolean isCaptureSupported() {
319 return mIsCaptureSupported;
320 }
321
Tomasz Wasilczyke597ce12017-03-24 13:50:53 -0700322 /**
323 * {@code true} if the module supports background scanning. At the given time it may not
324 * be available though, see {@link RadioTuner#startBackgroundScan()}.
325 *
326 * @return {@code true} if background scanning is supported (not necessary available
327 * at a given time), {@code false} otherwise.
Tomasz Wasilczyke597ce12017-03-24 13:50:53 -0700328 */
329 public boolean isBackgroundScanningSupported() {
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700330 return mIsBgScanSupported;
331 }
332
333 /**
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700334 * Checks, if a given program type is supported by this tuner.
335 *
336 * If a program type is supported by radio module, it means it can tune
337 * to ProgramSelector of a given type.
338 *
339 * @return {@code true} if a given program type is supported.
340 */
341 public boolean isProgramTypeSupported(@ProgramSelector.ProgramType int type) {
342 return mSupportedProgramTypes.contains(type);
343 }
344
345 /**
346 * Checks, if a given program identifier is supported by this tuner.
347 *
348 * If an identifier is supported by radio module, it means it can use it for
349 * tuning to ProgramSelector with either primary or secondary Identifier of
350 * a given type.
351 *
352 * @return {@code true} if a given program type is supported.
353 */
354 public boolean isProgramIdentifierSupported(@ProgramSelector.IdentifierType int type) {
355 return mSupportedIdentifierTypes.contains(type);
356 }
357
358 /**
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700359 * A map of vendor-specific opaque strings, passed from HAL without changes.
360 * Format of these strings can vary across vendors.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700361 *
362 * It may be used for extra features, that's not supported by a platform,
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700363 * for example: preset-slots=6; ultra-hd-capable=false.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700364 *
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700365 * Keys must be prefixed with unique vendor Java-style namespace,
366 * eg. 'com.somecompany.parameter1'.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700367 */
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700368 public @NonNull Map<String, String> getVendorInfo() {
369 return mVendorInfo;
Tomasz Wasilczyke597ce12017-03-24 13:50:53 -0700370 }
371
Eric Laurent2035ac82015-03-05 15:18:44 -0800372 /** List of descriptors for all bands supported by this module.
373 * @return an array of {@link BandDescriptor}.
374 */
375 public BandDescriptor[] getBands() {
376 return mBands;
377 }
378
379 private ModuleProperties(Parcel in) {
380 mId = in.readInt();
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700381 String serviceName = in.readString();
382 mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
Eric Laurent2035ac82015-03-05 15:18:44 -0800383 mClassId = in.readInt();
384 mImplementor = in.readString();
385 mProduct = in.readString();
386 mVersion = in.readString();
387 mSerial = in.readString();
388 mNumTuners = in.readInt();
389 mNumAudioSources = in.readInt();
390 mIsCaptureSupported = in.readInt() == 1;
391 Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader());
392 mBands = new BandDescriptor[tmp.length];
393 for (int i = 0; i < tmp.length; i++) {
394 mBands[i] = (BandDescriptor) tmp[i];
395 }
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700396 mIsBgScanSupported = in.readInt() == 1;
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700397 mSupportedProgramTypes = arrayToSet(in.createIntArray());
398 mSupportedIdentifierTypes = arrayToSet(in.createIntArray());
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800399 mVendorInfo = Utils.readStringMap(in);
Eric Laurent2035ac82015-03-05 15:18:44 -0800400 }
401
402 public static final Parcelable.Creator<ModuleProperties> CREATOR
403 = new Parcelable.Creator<ModuleProperties>() {
404 public ModuleProperties createFromParcel(Parcel in) {
405 return new ModuleProperties(in);
406 }
407
408 public ModuleProperties[] newArray(int size) {
409 return new ModuleProperties[size];
410 }
411 };
412
413 @Override
414 public void writeToParcel(Parcel dest, int flags) {
415 dest.writeInt(mId);
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700416 dest.writeString(mServiceName);
Eric Laurent2035ac82015-03-05 15:18:44 -0800417 dest.writeInt(mClassId);
418 dest.writeString(mImplementor);
419 dest.writeString(mProduct);
420 dest.writeString(mVersion);
421 dest.writeString(mSerial);
422 dest.writeInt(mNumTuners);
423 dest.writeInt(mNumAudioSources);
424 dest.writeInt(mIsCaptureSupported ? 1 : 0);
425 dest.writeParcelableArray(mBands, flags);
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700426 dest.writeInt(mIsBgScanSupported ? 1 : 0);
Tomasz Wasilczyk54587ce2017-07-16 15:15:40 -0700427 dest.writeIntArray(setToArray(mSupportedProgramTypes));
428 dest.writeIntArray(setToArray(mSupportedIdentifierTypes));
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800429 Utils.writeStringMap(dest, mVendorInfo);
Eric Laurent2035ac82015-03-05 15:18:44 -0800430 }
431
432 @Override
433 public int describeContents() {
434 return 0;
435 }
436
437 @Override
438 public String toString() {
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700439 return "ModuleProperties [mId=" + mId
440 + ", mServiceName=" + mServiceName + ", mClassId=" + mClassId
Eric Laurent2035ac82015-03-05 15:18:44 -0800441 + ", mImplementor=" + mImplementor + ", mProduct=" + mProduct
442 + ", mVersion=" + mVersion + ", mSerial=" + mSerial
443 + ", mNumTuners=" + mNumTuners
444 + ", mNumAudioSources=" + mNumAudioSources
445 + ", mIsCaptureSupported=" + mIsCaptureSupported
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700446 + ", mIsBgScanSupported=" + mIsBgScanSupported
Eric Laurent2035ac82015-03-05 15:18:44 -0800447 + ", mBands=" + Arrays.toString(mBands) + "]";
448 }
449
450 @Override
451 public int hashCode() {
452 final int prime = 31;
453 int result = 1;
454 result = prime * result + mId;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700455 result = prime * result + mServiceName.hashCode();
Eric Laurent2035ac82015-03-05 15:18:44 -0800456 result = prime * result + mClassId;
457 result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
458 result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
459 result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
460 result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
461 result = prime * result + mNumTuners;
462 result = prime * result + mNumAudioSources;
463 result = prime * result + (mIsCaptureSupported ? 1 : 0);
464 result = prime * result + Arrays.hashCode(mBands);
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700465 result = prime * result + (mIsBgScanSupported ? 1 : 0);
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700466 result = prime * result + mVendorInfo.hashCode();
Eric Laurent2035ac82015-03-05 15:18:44 -0800467 return result;
468 }
469
470 @Override
471 public boolean equals(Object obj) {
472 if (this == obj)
473 return true;
474 if (!(obj instanceof ModuleProperties))
475 return false;
476 ModuleProperties other = (ModuleProperties) obj;
477 if (mId != other.getId())
478 return false;
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -0700479 if (!TextUtils.equals(mServiceName, other.mServiceName)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800480 if (mClassId != other.getClassId())
481 return false;
482 if (mImplementor == null) {
483 if (other.getImplementor() != null)
484 return false;
485 } else if (!mImplementor.equals(other.getImplementor()))
486 return false;
487 if (mProduct == null) {
488 if (other.getProduct() != null)
489 return false;
490 } else if (!mProduct.equals(other.getProduct()))
491 return false;
492 if (mVersion == null) {
493 if (other.getVersion() != null)
494 return false;
495 } else if (!mVersion.equals(other.getVersion()))
496 return false;
497 if (mSerial == null) {
498 if (other.getSerial() != null)
499 return false;
500 } else if (!mSerial.equals(other.getSerial()))
501 return false;
502 if (mNumTuners != other.getNumTuners())
503 return false;
504 if (mNumAudioSources != other.getNumAudioSources())
505 return false;
506 if (mIsCaptureSupported != other.isCaptureSupported())
507 return false;
508 if (!Arrays.equals(mBands, other.getBands()))
509 return false;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -0700510 if (mIsBgScanSupported != other.isBackgroundScanningSupported())
511 return false;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700512 if (!mVendorInfo.equals(other.mVendorInfo)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800513 return true;
514 }
515 }
516
517 /** Radio band descriptor: an element in ModuleProperties bands array.
518 * It is either an instance of {@link FmBandDescriptor} or {@link AmBandDescriptor} */
519 public static class BandDescriptor implements Parcelable {
520
521 private final int mRegion;
522 private final int mType;
523 private final int mLowerLimit;
524 private final int mUpperLimit;
525 private final int mSpacing;
526
527 BandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700528 if (type != BAND_AM && type != BAND_FM && type != BAND_FM_HD && type != BAND_AM_HD) {
529 throw new IllegalArgumentException("Unsupported band: " + type);
530 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800531 mRegion = region;
532 mType = type;
533 mLowerLimit = lowerLimit;
534 mUpperLimit = upperLimit;
535 mSpacing = spacing;
536 }
537
538 /** Region this band applies to. E.g. {@link #REGION_ITU_1}
539 * @return the region this band is associated to.
540 */
541 public int getRegion() {
542 return mRegion;
543 }
544 /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
545 * <ul>
546 * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
547 * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
548 * </ul>
549 * @return the band type.
550 */
551 public int getType() {
552 return mType;
553 }
Tomasz Wasilczyk2880b9a2017-06-28 14:28:47 -0700554
555 /**
556 * Checks if the band is either AM or AM_HD.
557 *
558 * @return {@code true}, if band is AM or AM_HD.
559 */
560 public boolean isAmBand() {
561 return mType == BAND_AM || mType == BAND_AM_HD;
562 }
563
564 /**
565 * Checks if the band is either FM or FM_HD.
566 *
567 * @return {@code true}, if band is FM or FM_HD.
568 */
569 public boolean isFmBand() {
570 return mType == BAND_FM || mType == BAND_FM_HD;
571 }
572
Eric Laurent2035ac82015-03-05 15:18:44 -0800573 /** Lower band limit expressed in units according to band type.
574 * Currently all defined band types express channels as frequency in kHz
575 * @return the lower band limit.
576 */
577 public int getLowerLimit() {
578 return mLowerLimit;
579 }
580 /** Upper band limit expressed in units according to band type.
581 * Currently all defined band types express channels as frequency in kHz
582 * @return the upper band limit.
583 */
584 public int getUpperLimit() {
585 return mUpperLimit;
586 }
587 /** Channel spacing in units according to band type.
588 * Currently all defined band types express channels as frequency in kHz
589 * @return the channel spacing.
590 */
591 public int getSpacing() {
592 return mSpacing;
593 }
594
595 private BandDescriptor(Parcel in) {
596 mRegion = in.readInt();
597 mType = in.readInt();
598 mLowerLimit = in.readInt();
599 mUpperLimit = in.readInt();
600 mSpacing = in.readInt();
601 }
602
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700603 private static int lookupTypeFromParcel(Parcel in) {
604 int pos = in.dataPosition();
605 in.readInt(); // skip region
606 int type = in.readInt();
607 in.setDataPosition(pos);
608 return type;
609 }
610
Eric Laurent2035ac82015-03-05 15:18:44 -0800611 public static final Parcelable.Creator<BandDescriptor> CREATOR
612 = new Parcelable.Creator<BandDescriptor>() {
613 public BandDescriptor createFromParcel(Parcel in) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700614 int type = lookupTypeFromParcel(in);
615 switch (type) {
616 case BAND_FM:
617 case BAND_FM_HD:
618 return new FmBandDescriptor(in);
619 case BAND_AM:
620 case BAND_AM_HD:
621 return new AmBandDescriptor(in);
622 default:
623 throw new IllegalArgumentException("Unsupported band: " + type);
624 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800625 }
626
627 public BandDescriptor[] newArray(int size) {
628 return new BandDescriptor[size];
629 }
630 };
631
632 @Override
633 public void writeToParcel(Parcel dest, int flags) {
634 dest.writeInt(mRegion);
635 dest.writeInt(mType);
636 dest.writeInt(mLowerLimit);
637 dest.writeInt(mUpperLimit);
638 dest.writeInt(mSpacing);
639 }
640
641 @Override
642 public int describeContents() {
643 return 0;
644 }
645
646 @Override
647 public String toString() {
648 return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
649 + mLowerLimit + ", mUpperLimit=" + mUpperLimit + ", mSpacing=" + mSpacing + "]";
650 }
651
652 @Override
653 public int hashCode() {
654 final int prime = 31;
655 int result = 1;
656 result = prime * result + mRegion;
657 result = prime * result + mType;
658 result = prime * result + mLowerLimit;
659 result = prime * result + mUpperLimit;
660 result = prime * result + mSpacing;
661 return result;
662 }
663
664 @Override
665 public boolean equals(Object obj) {
666 if (this == obj)
667 return true;
668 if (!(obj instanceof BandDescriptor))
669 return false;
670 BandDescriptor other = (BandDescriptor) obj;
671 if (mRegion != other.getRegion())
672 return false;
673 if (mType != other.getType())
674 return false;
675 if (mLowerLimit != other.getLowerLimit())
676 return false;
677 if (mUpperLimit != other.getUpperLimit())
678 return false;
679 if (mSpacing != other.getSpacing())
680 return false;
681 return true;
682 }
683 }
684
685 /** FM band descriptor
686 * @see #BAND_FM
687 * @see #BAND_FM_HD */
688 public static class FmBandDescriptor extends BandDescriptor {
689 private final boolean mStereo;
690 private final boolean mRds;
691 private final boolean mTa;
692 private final boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700693 private final boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -0800694
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800695 /** @hide */
696 public FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700697 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
Eric Laurent2035ac82015-03-05 15:18:44 -0800698 super(region, type, lowerLimit, upperLimit, spacing);
699 mStereo = stereo;
700 mRds = rds;
701 mTa = ta;
702 mAf = af;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700703 mEa = ea;
Eric Laurent2035ac82015-03-05 15:18:44 -0800704 }
705
706 /** Stereo is supported
707 * @return {@code true} if stereo is supported, {@code false} otherwise.
708 */
709 public boolean isStereoSupported() {
710 return mStereo;
711 }
712 /** RDS or RBDS(if region is ITU2) is supported
713 * @return {@code true} if RDS or RBDS is supported, {@code false} otherwise.
714 */
715 public boolean isRdsSupported() {
716 return mRds;
717 }
718 /** Traffic announcement is supported
719 * @return {@code true} if TA is supported, {@code false} otherwise.
720 */
721 public boolean isTaSupported() {
722 return mTa;
723 }
724 /** Alternate Frequency Switching is supported
725 * @return {@code true} if AF switching is supported, {@code false} otherwise.
726 */
727 public boolean isAfSupported() {
728 return mAf;
729 }
730
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700731 /** Emergency Announcement is supported
732 * @return {@code true} if Emergency annoucement is supported, {@code false} otherwise.
733 */
734 public boolean isEaSupported() {
735 return mEa;
736 }
737
Eric Laurent2035ac82015-03-05 15:18:44 -0800738 /* Parcelable implementation */
739 private FmBandDescriptor(Parcel in) {
740 super(in);
741 mStereo = in.readByte() == 1;
742 mRds = in.readByte() == 1;
743 mTa = in.readByte() == 1;
744 mAf = in.readByte() == 1;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700745 mEa = in.readByte() == 1;
Eric Laurent2035ac82015-03-05 15:18:44 -0800746 }
747
748 public static final Parcelable.Creator<FmBandDescriptor> CREATOR
749 = new Parcelable.Creator<FmBandDescriptor>() {
750 public FmBandDescriptor createFromParcel(Parcel in) {
751 return new FmBandDescriptor(in);
752 }
753
754 public FmBandDescriptor[] newArray(int size) {
755 return new FmBandDescriptor[size];
756 }
757 };
758
759 @Override
760 public void writeToParcel(Parcel dest, int flags) {
761 super.writeToParcel(dest, flags);
762 dest.writeByte((byte) (mStereo ? 1 : 0));
763 dest.writeByte((byte) (mRds ? 1 : 0));
764 dest.writeByte((byte) (mTa ? 1 : 0));
765 dest.writeByte((byte) (mAf ? 1 : 0));
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700766 dest.writeByte((byte) (mEa ? 1 : 0));
Eric Laurent2035ac82015-03-05 15:18:44 -0800767 }
768
769 @Override
770 public int describeContents() {
771 return 0;
772 }
773
774 @Override
775 public String toString() {
776 return "FmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700777 + ", mRds=" + mRds + ", mTa=" + mTa + ", mAf=" + mAf +
778 ", mEa =" + mEa + "]";
Eric Laurent2035ac82015-03-05 15:18:44 -0800779 }
780
781 @Override
782 public int hashCode() {
783 final int prime = 31;
784 int result = super.hashCode();
785 result = prime * result + (mStereo ? 1 : 0);
786 result = prime * result + (mRds ? 1 : 0);
787 result = prime * result + (mTa ? 1 : 0);
788 result = prime * result + (mAf ? 1 : 0);
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700789 result = prime * result + (mEa ? 1 : 0);
Eric Laurent2035ac82015-03-05 15:18:44 -0800790 return result;
791 }
792
793 @Override
794 public boolean equals(Object obj) {
795 if (this == obj)
796 return true;
797 if (!super.equals(obj))
798 return false;
799 if (!(obj instanceof FmBandDescriptor))
800 return false;
801 FmBandDescriptor other = (FmBandDescriptor) obj;
802 if (mStereo != other.isStereoSupported())
803 return false;
804 if (mRds != other.isRdsSupported())
805 return false;
806 if (mTa != other.isTaSupported())
807 return false;
808 if (mAf != other.isAfSupported())
809 return false;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -0700810 if (mEa != other.isEaSupported())
811 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -0800812 return true;
813 }
814 }
815
816 /** AM band descriptor.
817 * @see #BAND_AM */
818 public static class AmBandDescriptor extends BandDescriptor {
819
820 private final boolean mStereo;
821
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800822 /** @hide */
823 public AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
Eric Laurent2035ac82015-03-05 15:18:44 -0800824 boolean stereo) {
825 super(region, type, lowerLimit, upperLimit, spacing);
826 mStereo = stereo;
827 }
828
829 /** Stereo is supported
830 * @return {@code true} if stereo is supported, {@code false} otherwise.
831 */
832 public boolean isStereoSupported() {
833 return mStereo;
834 }
835
836 private AmBandDescriptor(Parcel in) {
837 super(in);
838 mStereo = in.readByte() == 1;
839 }
840
841 public static final Parcelable.Creator<AmBandDescriptor> CREATOR
842 = new Parcelable.Creator<AmBandDescriptor>() {
843 public AmBandDescriptor createFromParcel(Parcel in) {
844 return new AmBandDescriptor(in);
845 }
846
847 public AmBandDescriptor[] newArray(int size) {
848 return new AmBandDescriptor[size];
849 }
850 };
851
852 @Override
853 public void writeToParcel(Parcel dest, int flags) {
854 super.writeToParcel(dest, flags);
855 dest.writeByte((byte) (mStereo ? 1 : 0));
856 }
857
858 @Override
859 public int describeContents() {
860 return 0;
861 }
862
863 @Override
864 public String toString() {
865 return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
866 }
867
868 @Override
869 public int hashCode() {
870 final int prime = 31;
871 int result = super.hashCode();
872 result = prime * result + (mStereo ? 1 : 0);
873 return result;
874 }
875
876 @Override
877 public boolean equals(Object obj) {
878 if (this == obj)
879 return true;
880 if (!super.equals(obj))
881 return false;
882 if (!(obj instanceof AmBandDescriptor))
883 return false;
884 AmBandDescriptor other = (AmBandDescriptor) obj;
885 if (mStereo != other.isStereoSupported())
886 return false;
887 return true;
888 }
889 }
890
891
892 /** Radio band configuration. */
893 public static class BandConfig implements Parcelable {
894
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800895 @NonNull final BandDescriptor mDescriptor;
Eric Laurent2035ac82015-03-05 15:18:44 -0800896
897 BandConfig(BandDescriptor descriptor) {
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800898 mDescriptor = Objects.requireNonNull(descriptor);
Eric Laurent2035ac82015-03-05 15:18:44 -0800899 }
900
901 BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
902 mDescriptor = new BandDescriptor(region, type, lowerLimit, upperLimit, spacing);
903 }
904
905 private BandConfig(Parcel in) {
906 mDescriptor = new BandDescriptor(in);
907 }
908
909 BandDescriptor getDescriptor() {
910 return mDescriptor;
911 }
912
913 /** Region this band applies to. E.g. {@link #REGION_ITU_1}
914 * @return the region associated with this band.
915 */
916 public int getRegion() {
917 return mDescriptor.getRegion();
918 }
919 /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
920 * <ul>
921 * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
922 * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
923 * </ul>
924 * @return the band type.
925 */
926 public int getType() {
927 return mDescriptor.getType();
928 }
929 /** Lower band limit expressed in units according to band type.
930 * Currently all defined band types express channels as frequency in kHz
931 * @return the lower band limit.
932 */
933 public int getLowerLimit() {
934 return mDescriptor.getLowerLimit();
935 }
936 /** Upper band limit expressed in units according to band type.
937 * Currently all defined band types express channels as frequency in kHz
938 * @return the upper band limit.
939 */
940 public int getUpperLimit() {
941 return mDescriptor.getUpperLimit();
942 }
943 /** Channel spacing in units according to band type.
944 * Currently all defined band types express channels as frequency in kHz
945 * @return the channel spacing.
946 */
947 public int getSpacing() {
948 return mDescriptor.getSpacing();
949 }
950
951
952 public static final Parcelable.Creator<BandConfig> CREATOR
953 = new Parcelable.Creator<BandConfig>() {
954 public BandConfig createFromParcel(Parcel in) {
Tomasz Wasilczykf24ecf72017-04-24 13:32:32 -0700955 int type = BandDescriptor.lookupTypeFromParcel(in);
956 switch (type) {
957 case BAND_FM:
958 case BAND_FM_HD:
959 return new FmBandConfig(in);
960 case BAND_AM:
961 case BAND_AM_HD:
962 return new AmBandConfig(in);
963 default:
964 throw new IllegalArgumentException("Unsupported band: " + type);
965 }
Eric Laurent2035ac82015-03-05 15:18:44 -0800966 }
967
968 public BandConfig[] newArray(int size) {
969 return new BandConfig[size];
970 }
971 };
972
973 @Override
974 public void writeToParcel(Parcel dest, int flags) {
975 mDescriptor.writeToParcel(dest, flags);
976 }
977
978 @Override
979 public int describeContents() {
980 return 0;
981 }
982
983 @Override
984 public String toString() {
985 return "BandConfig [ " + mDescriptor.toString() + "]";
986 }
987
988 @Override
989 public int hashCode() {
990 final int prime = 31;
991 int result = 1;
992 result = prime * result + mDescriptor.hashCode();
993 return result;
994 }
995
996 @Override
997 public boolean equals(Object obj) {
998 if (this == obj)
999 return true;
1000 if (!(obj instanceof BandConfig))
1001 return false;
1002 BandConfig other = (BandConfig) obj;
Tomasz Wasilczykdd767062017-04-28 08:19:34 -07001003 BandDescriptor otherDesc = other.getDescriptor();
1004 if ((mDescriptor == null) != (otherDesc == null)) return false;
1005 if (mDescriptor != null && !mDescriptor.equals(otherDesc)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001006 return true;
1007 }
1008 }
1009
1010 /** FM band configuration.
1011 * @see #BAND_FM
1012 * @see #BAND_FM_HD */
1013 public static class FmBandConfig extends BandConfig {
1014 private final boolean mStereo;
1015 private final boolean mRds;
1016 private final boolean mTa;
1017 private final boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001018 private final boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -08001019
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -08001020 /** @hide */
1021 public FmBandConfig(FmBandDescriptor descriptor) {
Eric Laurent2035ac82015-03-05 15:18:44 -08001022 super((BandDescriptor)descriptor);
1023 mStereo = descriptor.isStereoSupported();
1024 mRds = descriptor.isRdsSupported();
1025 mTa = descriptor.isTaSupported();
1026 mAf = descriptor.isAfSupported();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001027 mEa = descriptor.isEaSupported();
Eric Laurent2035ac82015-03-05 15:18:44 -08001028 }
1029
1030 FmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001031 boolean stereo, boolean rds, boolean ta, boolean af, boolean ea) {
Eric Laurent2035ac82015-03-05 15:18:44 -08001032 super(region, type, lowerLimit, upperLimit, spacing);
1033 mStereo = stereo;
1034 mRds = rds;
1035 mTa = ta;
1036 mAf = af;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001037 mEa = ea;
Eric Laurent2035ac82015-03-05 15:18:44 -08001038 }
1039
1040 /** Get stereo enable state
1041 * @return the enable state.
1042 */
1043 public boolean getStereo() {
1044 return mStereo;
1045 }
1046
1047 /** Get RDS or RBDS(if region is ITU2) enable state
1048 * @return the enable state.
1049 */
1050 public boolean getRds() {
1051 return mRds;
1052 }
1053
1054 /** Get Traffic announcement enable state
1055 * @return the enable state.
1056 */
1057 public boolean getTa() {
1058 return mTa;
1059 }
1060
1061 /** Get Alternate Frequency Switching enable state
1062 * @return the enable state.
1063 */
1064 public boolean getAf() {
1065 return mAf;
1066 }
1067
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001068 /**
1069 * Get Emergency announcement enable state
1070 * @return the enable state.
1071 */
1072 public boolean getEa() {
1073 return mEa;
1074 }
1075
Eric Laurent2035ac82015-03-05 15:18:44 -08001076 private FmBandConfig(Parcel in) {
1077 super(in);
1078 mStereo = in.readByte() == 1;
1079 mRds = in.readByte() == 1;
1080 mTa = in.readByte() == 1;
1081 mAf = in.readByte() == 1;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001082 mEa = in.readByte() == 1;
Eric Laurent2035ac82015-03-05 15:18:44 -08001083 }
1084
1085 public static final Parcelable.Creator<FmBandConfig> CREATOR
1086 = new Parcelable.Creator<FmBandConfig>() {
1087 public FmBandConfig createFromParcel(Parcel in) {
1088 return new FmBandConfig(in);
1089 }
1090
1091 public FmBandConfig[] newArray(int size) {
1092 return new FmBandConfig[size];
1093 }
1094 };
1095
1096 @Override
1097 public void writeToParcel(Parcel dest, int flags) {
1098 super.writeToParcel(dest, flags);
1099 dest.writeByte((byte) (mStereo ? 1 : 0));
1100 dest.writeByte((byte) (mRds ? 1 : 0));
1101 dest.writeByte((byte) (mTa ? 1 : 0));
1102 dest.writeByte((byte) (mAf ? 1 : 0));
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001103 dest.writeByte((byte) (mEa ? 1 : 0));
Eric Laurent2035ac82015-03-05 15:18:44 -08001104 }
1105
1106 @Override
1107 public int describeContents() {
1108 return 0;
1109 }
1110
1111 @Override
1112 public String toString() {
1113 return "FmBandConfig [" + super.toString()
1114 + ", mStereo=" + mStereo + ", mRds=" + mRds + ", mTa=" + mTa
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001115 + ", mAf=" + mAf + ", mEa =" + mEa + "]";
Eric Laurent2035ac82015-03-05 15:18:44 -08001116 }
1117
1118 @Override
1119 public int hashCode() {
1120 final int prime = 31;
1121 int result = super.hashCode();
1122 result = prime * result + (mStereo ? 1 : 0);
1123 result = prime * result + (mRds ? 1 : 0);
1124 result = prime * result + (mTa ? 1 : 0);
1125 result = prime * result + (mAf ? 1 : 0);
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001126 result = prime * result + (mEa ? 1 : 0);
Eric Laurent2035ac82015-03-05 15:18:44 -08001127 return result;
1128 }
1129
1130 @Override
1131 public boolean equals(Object obj) {
1132 if (this == obj)
1133 return true;
1134 if (!super.equals(obj))
1135 return false;
1136 if (!(obj instanceof FmBandConfig))
1137 return false;
1138 FmBandConfig other = (FmBandConfig) obj;
1139 if (mStereo != other.mStereo)
1140 return false;
1141 if (mRds != other.mRds)
1142 return false;
1143 if (mTa != other.mTa)
1144 return false;
1145 if (mAf != other.mAf)
1146 return false;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001147 if (mEa != other.mEa)
1148 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001149 return true;
1150 }
1151
1152 /**
1153 * Builder class for {@link FmBandConfig} objects.
1154 */
1155 public static class Builder {
1156 private final BandDescriptor mDescriptor;
1157 private boolean mStereo;
1158 private boolean mRds;
1159 private boolean mTa;
1160 private boolean mAf;
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001161 private boolean mEa;
Eric Laurent2035ac82015-03-05 15:18:44 -08001162
1163 /**
1164 * Constructs a new Builder with the defaults from an {@link FmBandDescriptor} .
1165 * @param descriptor the FmBandDescriptor defaults are read from .
1166 */
1167 public Builder(FmBandDescriptor descriptor) {
1168 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
1169 descriptor.getLowerLimit(), descriptor.getUpperLimit(),
1170 descriptor.getSpacing());
1171 mStereo = descriptor.isStereoSupported();
1172 mRds = descriptor.isRdsSupported();
1173 mTa = descriptor.isTaSupported();
1174 mAf = descriptor.isAfSupported();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001175 mEa = descriptor.isEaSupported();
Eric Laurent2035ac82015-03-05 15:18:44 -08001176 }
1177
1178 /**
1179 * Constructs a new Builder from a given {@link FmBandConfig}
1180 * @param config the FmBandConfig object whose data will be reused in the new Builder.
1181 */
1182 public Builder(FmBandConfig config) {
1183 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
1184 config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
1185 mStereo = config.getStereo();
1186 mRds = config.getRds();
1187 mTa = config.getTa();
1188 mAf = config.getAf();
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001189 mEa = config.getEa();
Eric Laurent2035ac82015-03-05 15:18:44 -08001190 }
1191
1192 /**
1193 * Combines all of the parameters that have been set and return a new
1194 * {@link FmBandConfig} object.
1195 * @return a new {@link FmBandConfig} object
1196 */
1197 public FmBandConfig build() {
1198 FmBandConfig config = new FmBandConfig(mDescriptor.getRegion(),
1199 mDescriptor.getType(), mDescriptor.getLowerLimit(),
1200 mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001201 mStereo, mRds, mTa, mAf, mEa);
Eric Laurent2035ac82015-03-05 15:18:44 -08001202 return config;
1203 }
1204
1205 /** Set stereo enable state
1206 * @param state The new enable state.
1207 * @return the same Builder instance.
1208 */
1209 public Builder setStereo(boolean state) {
1210 mStereo = state;
1211 return this;
1212 }
1213
1214 /** Set RDS or RBDS(if region is ITU2) enable state
1215 * @param state The new enable state.
1216 * @return the same Builder instance.
1217 */
1218 public Builder setRds(boolean state) {
1219 mRds = state;
1220 return this;
1221 }
1222
1223 /** Set Traffic announcement enable state
1224 * @param state The new enable state.
1225 * @return the same Builder instance.
1226 */
1227 public Builder setTa(boolean state) {
1228 mTa = state;
1229 return this;
1230 }
1231
1232 /** Set Alternate Frequency Switching enable state
1233 * @param state The new enable state.
1234 * @return the same Builder instance.
1235 */
1236 public Builder setAf(boolean state) {
1237 mAf = state;
1238 return this;
1239 }
Sanket Agarwal7058e4c2015-10-08 14:14:20 -07001240
1241 /** Set Emergency Announcement enable state
1242 * @param state The new enable state.
1243 * @return the same Builder instance.
1244 */
1245 public Builder setEa(boolean state) {
1246 mEa = state;
1247 return this;
1248 }
Eric Laurent2035ac82015-03-05 15:18:44 -08001249 };
1250 }
1251
1252 /** AM band configuration.
1253 * @see #BAND_AM */
1254 public static class AmBandConfig extends BandConfig {
1255 private final boolean mStereo;
1256
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -08001257 /** @hide */
1258 public AmBandConfig(AmBandDescriptor descriptor) {
Eric Laurent2035ac82015-03-05 15:18:44 -08001259 super((BandDescriptor)descriptor);
1260 mStereo = descriptor.isStereoSupported();
1261 }
1262
1263 AmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
1264 boolean stereo) {
1265 super(region, type, lowerLimit, upperLimit, spacing);
1266 mStereo = stereo;
1267 }
1268
1269 /** Get stereo enable state
1270 * @return the enable state.
1271 */
1272 public boolean getStereo() {
1273 return mStereo;
1274 }
1275
1276 private AmBandConfig(Parcel in) {
1277 super(in);
1278 mStereo = in.readByte() == 1;
1279 }
1280
1281 public static final Parcelable.Creator<AmBandConfig> CREATOR
1282 = new Parcelable.Creator<AmBandConfig>() {
1283 public AmBandConfig createFromParcel(Parcel in) {
1284 return new AmBandConfig(in);
1285 }
1286
1287 public AmBandConfig[] newArray(int size) {
1288 return new AmBandConfig[size];
1289 }
1290 };
1291
1292 @Override
1293 public void writeToParcel(Parcel dest, int flags) {
1294 super.writeToParcel(dest, flags);
1295 dest.writeByte((byte) (mStereo ? 1 : 0));
1296 }
1297
1298 @Override
1299 public int describeContents() {
1300 return 0;
1301 }
1302
1303 @Override
1304 public String toString() {
1305 return "AmBandConfig [" + super.toString()
1306 + ", mStereo=" + mStereo + "]";
1307 }
1308
1309 @Override
1310 public int hashCode() {
1311 final int prime = 31;
1312 int result = super.hashCode();
1313 result = prime * result + (mStereo ? 1 : 0);
1314 return result;
1315 }
1316
1317 @Override
1318 public boolean equals(Object obj) {
1319 if (this == obj)
1320 return true;
1321 if (!super.equals(obj))
1322 return false;
1323 if (!(obj instanceof AmBandConfig))
1324 return false;
1325 AmBandConfig other = (AmBandConfig) obj;
1326 if (mStereo != other.getStereo())
1327 return false;
1328 return true;
1329 }
1330
1331 /**
1332 * Builder class for {@link AmBandConfig} objects.
1333 */
1334 public static class Builder {
1335 private final BandDescriptor mDescriptor;
1336 private boolean mStereo;
1337
1338 /**
1339 * Constructs a new Builder with the defaults from an {@link AmBandDescriptor} .
1340 * @param descriptor the FmBandDescriptor defaults are read from .
1341 */
1342 public Builder(AmBandDescriptor descriptor) {
1343 mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
1344 descriptor.getLowerLimit(), descriptor.getUpperLimit(),
1345 descriptor.getSpacing());
1346 mStereo = descriptor.isStereoSupported();
1347 }
1348
1349 /**
1350 * Constructs a new Builder from a given {@link AmBandConfig}
1351 * @param config the FmBandConfig object whose data will be reused in the new Builder.
1352 */
1353 public Builder(AmBandConfig config) {
1354 mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
1355 config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
1356 mStereo = config.getStereo();
1357 }
1358
1359 /**
1360 * Combines all of the parameters that have been set and return a new
1361 * {@link AmBandConfig} object.
1362 * @return a new {@link AmBandConfig} object
1363 */
1364 public AmBandConfig build() {
1365 AmBandConfig config = new AmBandConfig(mDescriptor.getRegion(),
1366 mDescriptor.getType(), mDescriptor.getLowerLimit(),
1367 mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
1368 mStereo);
1369 return config;
1370 }
1371
1372 /** Set stereo enable state
1373 * @param state The new enable state.
1374 * @return the same Builder instance.
1375 */
1376 public Builder setStereo(boolean state) {
1377 mStereo = state;
1378 return this;
1379 }
1380 };
1381 }
1382
1383 /** Radio program information returned by
1384 * {@link RadioTuner#getProgramInformation(RadioManager.ProgramInfo[])} */
1385 public static class ProgramInfo implements Parcelable {
1386
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001387 // sourced from hardware/interfaces/broadcastradio/1.1/types.hal
Tomasz Wasilczykc4cd8232017-07-14 10:46:15 -07001388 private static final int FLAG_LIVE = 1 << 0;
1389 private static final int FLAG_MUTED = 1 << 1;
1390 private static final int FLAG_TRAFFIC_PROGRAM = 1 << 2;
1391 private static final int FLAG_TRAFFIC_ANNOUNCEMENT = 1 << 3;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001392
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001393 @NonNull private final ProgramSelector mSelector;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -08001394 private final boolean mTuned; // TODO(b/69958777): replace with mFlags
Eric Laurent2035ac82015-03-05 15:18:44 -08001395 private final boolean mStereo;
1396 private final boolean mDigital;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001397 private final int mFlags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001398 private final int mSignalStrength;
1399 private final RadioMetadata mMetadata;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001400 @NonNull private final Map<String, String> mVendorInfo;
Eric Laurent2035ac82015-03-05 15:18:44 -08001401
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -08001402 /** @hide */
1403 public ProgramInfo(@NonNull ProgramSelector selector, boolean tuned, boolean stereo,
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001404 boolean digital, int signalStrength, RadioMetadata metadata, int flags,
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001405 Map<String, String> vendorInfo) {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001406 mSelector = selector;
Eric Laurent2035ac82015-03-05 15:18:44 -08001407 mTuned = tuned;
1408 mStereo = stereo;
1409 mDigital = digital;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001410 mFlags = flags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001411 mSignalStrength = signalStrength;
1412 mMetadata = metadata;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001413 mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
Eric Laurent2035ac82015-03-05 15:18:44 -08001414 }
1415
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001416 /**
1417 * Program selector, necessary for tuning to a program.
1418 *
1419 * @return the program selector.
1420 */
1421 public @NonNull ProgramSelector getSelector() {
1422 return mSelector;
1423 }
1424
Eric Laurent2035ac82015-03-05 15:18:44 -08001425 /** Main channel expressed in units according to band type.
1426 * Currently all defined band types express channels as frequency in kHz
1427 * @return the program channel
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001428 * @deprecated Use {@link getSelector()} instead.
Eric Laurent2035ac82015-03-05 15:18:44 -08001429 */
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001430 @Deprecated
Eric Laurent2035ac82015-03-05 15:18:44 -08001431 public int getChannel() {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001432 try {
1433 return (int) mSelector.getFirstId(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY);
1434 } catch (IllegalArgumentException ex) {
1435 Log.w(TAG, "Not an AM/FM program");
1436 return 0;
1437 }
Eric Laurent2035ac82015-03-05 15:18:44 -08001438 }
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001439
Eric Laurent2035ac82015-03-05 15:18:44 -08001440 /** Sub channel ID. E.g 1 for HD radio HD1
1441 * @return the program sub channel
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001442 * @deprecated Use {@link getSelector()} instead.
Eric Laurent2035ac82015-03-05 15:18:44 -08001443 */
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001444 @Deprecated
Eric Laurent2035ac82015-03-05 15:18:44 -08001445 public int getSubChannel() {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001446 try {
1447 return (int) mSelector.getFirstId(
1448 ProgramSelector.IDENTIFIER_TYPE_HD_SUBCHANNEL) + 1;
1449 } catch (IllegalArgumentException ex) {
1450 // this is a normal behavior for analog AM/FM selector
1451 return 0;
1452 }
Eric Laurent2035ac82015-03-05 15:18:44 -08001453 }
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001454
Eric Laurent2035ac82015-03-05 15:18:44 -08001455 /** {@code true} if the tuner is currently tuned on a valid station
1456 * @return {@code true} if currently tuned, {@code false} otherwise.
1457 */
1458 public boolean isTuned() {
1459 return mTuned;
1460 }
1461 /** {@code true} if the received program is stereo
1462 * @return {@code true} if stereo, {@code false} otherwise.
1463 */
1464 public boolean isStereo() {
1465 return mStereo;
1466 }
1467 /** {@code true} if the received program is digital (e.g HD radio)
1468 * @return {@code true} if digital, {@code false} otherwise.
1469 */
1470 public boolean isDigital() {
1471 return mDigital;
1472 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001473
1474 /**
1475 * {@code true} if the program is currently playing live stream.
1476 * This may result in a slightly altered reception parameters,
1477 * usually targetted at reduced latency.
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001478 */
1479 public boolean isLive() {
1480 return (mFlags & FLAG_LIVE) != 0;
1481 }
1482
1483 /**
1484 * {@code true} if radio stream is not playing, ie. due to bad reception
1485 * conditions or buffering. In this state volume knob MAY be disabled to
1486 * prevent user increasing volume too much.
1487 * It does NOT mean the user has muted audio.
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001488 */
1489 public boolean isMuted() {
1490 return (mFlags & FLAG_MUTED) != 0;
1491 }
1492
Tomasz Wasilczykc4cd8232017-07-14 10:46:15 -07001493 /**
1494 * {@code true} if radio station transmits traffic information
1495 * regularily.
1496 */
1497 public boolean isTrafficProgram() {
1498 return (mFlags & FLAG_TRAFFIC_PROGRAM) != 0;
1499 }
1500
1501 /**
1502 * {@code true} if radio station transmits traffic information
1503 * at the very moment.
1504 */
1505 public boolean isTrafficAnnouncementActive() {
1506 return (mFlags & FLAG_TRAFFIC_ANNOUNCEMENT) != 0;
1507 }
1508
Eric Laurent2035ac82015-03-05 15:18:44 -08001509 /** Signal strength indicator from 0 (no signal) to 100 (excellent)
1510 * @return the signal strength indication.
1511 */
1512 public int getSignalStrength() {
1513 return mSignalStrength;
1514 }
1515 /** Metadata currently received from this station.
1516 * null if no metadata have been received
1517 * @return current meta data received from this program.
1518 */
1519 public RadioMetadata getMetadata() {
1520 return mMetadata;
1521 }
1522
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001523 /**
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001524 * A map of vendor-specific opaque strings, passed from HAL without changes.
1525 * Format of these strings can vary across vendors.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001526 *
1527 * It may be used for extra features, that's not supported by a platform,
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001528 * for example: paid-service=true; bitrate=320kbps.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001529 *
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001530 * Keys must be prefixed with unique vendor Java-style namespace,
1531 * eg. 'com.somecompany.parameter1'.
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001532 */
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001533 public @NonNull Map<String, String> getVendorInfo() {
1534 return mVendorInfo;
Tomasz Wasilczyk6849aa82017-03-29 11:59:23 -07001535 }
1536
Eric Laurent2035ac82015-03-05 15:18:44 -08001537 private ProgramInfo(Parcel in) {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001538 mSelector = in.readParcelable(null);
Eric Laurent2035ac82015-03-05 15:18:44 -08001539 mTuned = in.readByte() == 1;
1540 mStereo = in.readByte() == 1;
1541 mDigital = in.readByte() == 1;
1542 mSignalStrength = in.readInt();
1543 if (in.readByte() == 1) {
1544 mMetadata = RadioMetadata.CREATOR.createFromParcel(in);
1545 } else {
1546 mMetadata = null;
1547 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001548 mFlags = in.readInt();
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -08001549 mVendorInfo = Utils.readStringMap(in);
Eric Laurent2035ac82015-03-05 15:18:44 -08001550 }
1551
1552 public static final Parcelable.Creator<ProgramInfo> CREATOR
1553 = new Parcelable.Creator<ProgramInfo>() {
1554 public ProgramInfo createFromParcel(Parcel in) {
1555 return new ProgramInfo(in);
1556 }
1557
1558 public ProgramInfo[] newArray(int size) {
1559 return new ProgramInfo[size];
1560 }
1561 };
1562
1563 @Override
1564 public void writeToParcel(Parcel dest, int flags) {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001565 dest.writeParcelable(mSelector, 0);
Eric Laurent2035ac82015-03-05 15:18:44 -08001566 dest.writeByte((byte)(mTuned ? 1 : 0));
1567 dest.writeByte((byte)(mStereo ? 1 : 0));
1568 dest.writeByte((byte)(mDigital ? 1 : 0));
1569 dest.writeInt(mSignalStrength);
1570 if (mMetadata == null) {
1571 dest.writeByte((byte)0);
1572 } else {
1573 dest.writeByte((byte)1);
1574 mMetadata.writeToParcel(dest, flags);
1575 }
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001576 dest.writeInt(mFlags);
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -08001577 Utils.writeStringMap(dest, mVendorInfo);
Eric Laurent2035ac82015-03-05 15:18:44 -08001578 }
1579
1580 @Override
1581 public int describeContents() {
1582 return 0;
1583 }
1584
1585 @Override
1586 public String toString() {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001587 return "ProgramInfo [mSelector=" + mSelector
Eric Laurent2035ac82015-03-05 15:18:44 -08001588 + ", mTuned=" + mTuned + ", mStereo=" + mStereo + ", mDigital=" + mDigital
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001589 + ", mFlags=" + mFlags + ", mSignalStrength=" + mSignalStrength
Eric Laurent2035ac82015-03-05 15:18:44 -08001590 + ((mMetadata == null) ? "" : (", mMetadata=" + mMetadata.toString()))
1591 + "]";
1592 }
1593
1594 @Override
1595 public int hashCode() {
1596 final int prime = 31;
1597 int result = 1;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001598 result = prime * result + mSelector.hashCode();
Eric Laurent2035ac82015-03-05 15:18:44 -08001599 result = prime * result + (mTuned ? 1 : 0);
1600 result = prime * result + (mStereo ? 1 : 0);
1601 result = prime * result + (mDigital ? 1 : 0);
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001602 result = prime * result + mFlags;
Eric Laurent2035ac82015-03-05 15:18:44 -08001603 result = prime * result + mSignalStrength;
1604 result = prime * result + ((mMetadata == null) ? 0 : mMetadata.hashCode());
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001605 result = prime * result + mVendorInfo.hashCode();
Eric Laurent2035ac82015-03-05 15:18:44 -08001606 return result;
1607 }
1608
1609 @Override
1610 public boolean equals(Object obj) {
1611 if (this == obj)
1612 return true;
1613 if (!(obj instanceof ProgramInfo))
1614 return false;
1615 ProgramInfo other = (ProgramInfo) obj;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -07001616 if (!mSelector.equals(other.getSelector())) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001617 if (mTuned != other.isTuned())
1618 return false;
1619 if (mStereo != other.isStereo())
1620 return false;
1621 if (mDigital != other.isDigital())
1622 return false;
Tomasz Wasilczyk5fb600b2017-03-24 14:55:08 -07001623 if (mFlags != other.mFlags)
1624 return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001625 if (mSignalStrength != other.getSignalStrength())
1626 return false;
1627 if (mMetadata == null) {
1628 if (other.getMetadata() != null)
1629 return false;
1630 } else if (!mMetadata.equals(other.getMetadata()))
1631 return false;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -07001632 if (!mVendorInfo.equals(other.mVendorInfo)) return false;
Eric Laurent2035ac82015-03-05 15:18:44 -08001633 return true;
1634 }
1635 }
1636
1637
1638 /**
1639 * Returns a list of descriptors for all broadcast radio modules present on the device.
1640 * @param modules An List of {@link ModuleProperties} where the list will be returned.
1641 * @return
1642 * <ul>
1643 * <li>{@link #STATUS_OK} in case of success, </li>
1644 * <li>{@link #STATUS_ERROR} in case of unspecified error, </li>
1645 * <li>{@link #STATUS_NO_INIT} if the native service cannot be reached, </li>
1646 * <li>{@link #STATUS_BAD_VALUE} if modules is null, </li>
1647 * <li>{@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails, </li>
1648 * </ul>
1649 */
Tomasz Wasilczyk749e3dc2017-07-28 13:20:41 -07001650 @RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -07001651 public int listModules(List<ModuleProperties> modules) {
1652 if (modules == null) {
1653 Log.e(TAG, "the output list must not be empty");
1654 return STATUS_BAD_VALUE;
1655 }
1656
Tomasz Wasilczyk14752372017-06-21 11:58:21 -07001657 Log.d(TAG, "Listing available tuners...");
Tomasz Wasilczykd15c9df2017-06-13 10:10:36 -07001658 List<ModuleProperties> returnedList;
1659 try {
1660 returnedList = mService.listModules();
1661 } catch (RemoteException e) {
1662 Log.e(TAG, "Failed listing available tuners", e);
1663 return STATUS_DEAD_OBJECT;
1664 }
1665
1666 if (returnedList == null) {
1667 Log.e(TAG, "Returned list was a null");
1668 return STATUS_ERROR;
1669 }
1670
1671 modules.addAll(returnedList);
1672 return STATUS_OK;
1673 }
1674
1675 private native int nativeListModules(List<ModuleProperties> modules);
Eric Laurent2035ac82015-03-05 15:18:44 -08001676
1677 /**
1678 * Open an interface to control a tuner on a given broadcast radio module.
1679 * Optionally selects and applies the configuration passed as "config" argument.
1680 * @param moduleId radio module identifier {@link ModuleProperties#getId()}. Mandatory.
1681 * @param config desired band and configuration to apply when enabling the hardware module.
1682 * optional, can be null.
1683 * @param withAudio {@code true} to request a tuner with an audio source.
1684 * This tuner is intended for live listening or recording or a radio program.
1685 * If {@code false}, the tuner can only be used to retrieve program informations.
1686 * @param callback {@link RadioTuner.Callback} interface. Mandatory.
1687 * @param handler the Handler on which the callbacks will be received.
1688 * Can be null if default handler is OK.
1689 * @return a valid {@link RadioTuner} interface in case of success or null in case of error.
1690 */
Tomasz Wasilczyk749e3dc2017-07-28 13:20:41 -07001691 @RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
Eric Laurent2035ac82015-03-05 15:18:44 -08001692 public RadioTuner openTuner(int moduleId, BandConfig config, boolean withAudio,
1693 RadioTuner.Callback callback, Handler handler) {
1694 if (callback == null) {
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001695 throw new IllegalArgumentException("callback must not be empty");
Eric Laurent2035ac82015-03-05 15:18:44 -08001696 }
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001697
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001698 Log.d(TAG, "Opening tuner " + moduleId + "...");
Tomasz Wasilczyk21348172017-04-20 14:02:42 -07001699
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001700 ITuner tuner;
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -07001701 TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler);
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001702 try {
1703 tuner = mService.openTuner(moduleId, config, withAudio, halCallback);
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -08001704 } catch (RemoteException | IllegalArgumentException ex) {
1705 Log.e(TAG, "Failed to open tuner", ex);
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001706 return null;
Eric Laurent2035ac82015-03-05 15:18:44 -08001707 }
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001708 if (tuner == null) {
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001709 Log.e(TAG, "Failed to open tuner");
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001710 return null;
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001711 }
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -08001712 return new TunerAdapter(tuner, halCallback,
1713 config != null ? config.getType() : BAND_INVALID);
Eric Laurent2035ac82015-03-05 15:18:44 -08001714 }
1715
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001716 @NonNull private final Context mContext;
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001717 @NonNull private final IRadioService mService;
Eric Laurent2035ac82015-03-05 15:18:44 -08001718
1719 /**
1720 * @hide
1721 */
Tomasz Wasilczyk347192e2017-04-04 11:13:44 -07001722 public RadioManager(@NonNull Context context) throws ServiceNotFoundException {
Eric Laurent2035ac82015-03-05 15:18:44 -08001723 mContext = context;
Tomasz Wasilczyk9b595f32017-06-21 11:14:19 -07001724 mService = IRadioService.Stub.asInterface(
1725 ServiceManager.getServiceOrThrow(Context.RADIO_SERVICE));
Eric Laurent2035ac82015-03-05 15:18:44 -08001726 }
1727}