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