Convert.java revision f58305d137f07071238239dfa0a144cfefc2831c
1/** 2 * Copyright (C) 2017 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 com.android.server.broadcastradio.hal2; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.hardware.broadcastradio.V2_0.AmFmBandRange; 22import android.hardware.broadcastradio.V2_0.AmFmRegionConfig; 23import android.hardware.broadcastradio.V2_0.Properties; 24import android.hardware.broadcastradio.V2_0.Result; 25import android.hardware.broadcastradio.V2_0.VendorKeyValue; 26import android.hardware.radio.ProgramSelector; 27import android.hardware.radio.RadioManager; 28import android.os.ParcelableException; 29import android.util.Slog; 30 31import java.util.ArrayList; 32import java.util.Collections; 33import java.util.HashMap; 34import java.util.HashSet; 35import java.util.List; 36import java.util.Map; 37import java.util.Objects; 38import java.util.Set; 39 40class Convert { 41 private static final String TAG = "BcRadio2Srv.convert"; 42 43 static void throwOnError(String action, int result) { 44 switch (result) { 45 case Result.OK: 46 return; 47 case Result.UNKNOWN_ERROR: 48 throw new ParcelableException(new RuntimeException(action + ": UNKNOWN_ERROR")); 49 case Result.INTERNAL_ERROR: 50 throw new ParcelableException(new RuntimeException(action + ": INTERNAL_ERROR")); 51 case Result.INVALID_ARGUMENTS: 52 throw new IllegalArgumentException(action + ": INVALID_ARGUMENTS"); 53 case Result.INVALID_STATE: 54 throw new IllegalStateException(action + ": INVALID_STATE"); 55 case Result.NOT_SUPPORTED: 56 throw new UnsupportedOperationException(action + ": NOT_SUPPORTED"); 57 case Result.TIMEOUT: 58 throw new ParcelableException(new RuntimeException(action + ": TIMEOUT")); 59 default: 60 throw new ParcelableException(new RuntimeException( 61 action + ": unknown error (" + result + ")")); 62 } 63 } 64 65 private static @NonNull Map<String, String> 66 vendorInfoFromHal(@Nullable List<VendorKeyValue> info) { 67 if (info == null) return Collections.emptyMap(); 68 69 Map<String, String> map = new HashMap<>(); 70 for (VendorKeyValue kvp : info) { 71 if (kvp.key == null || kvp.value == null) { 72 Slog.w(TAG, "VendorKeyValue contains null pointers"); 73 continue; 74 } 75 map.put(kvp.key, kvp.value); 76 } 77 78 return map; 79 } 80 81 private static @NonNull int[] 82 identifierTypesToProgramTypes(@NonNull int[] idTypes) { 83 Set<Integer> pTypes = new HashSet<>(); 84 85 for (int idType : idTypes) { 86 switch (idType) { 87 case ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY: 88 case ProgramSelector.IDENTIFIER_TYPE_RDS_PI: 89 // TODO(b/69958423): verify AM/FM with region info 90 pTypes.add(ProgramSelector.PROGRAM_TYPE_AM); 91 pTypes.add(ProgramSelector.PROGRAM_TYPE_FM); 92 break; 93 case ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT: 94 // TODO(b/69958423): verify AM/FM with region info 95 pTypes.add(ProgramSelector.PROGRAM_TYPE_AM_HD); 96 pTypes.add(ProgramSelector.PROGRAM_TYPE_FM_HD); 97 break; 98 case ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC: 99 case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE: 100 case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID: 101 case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY: 102 pTypes.add(ProgramSelector.PROGRAM_TYPE_DAB); 103 break; 104 case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID: 105 case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY: 106 pTypes.add(ProgramSelector.PROGRAM_TYPE_DRMO); 107 break; 108 case ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID: 109 case ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL: 110 pTypes.add(ProgramSelector.PROGRAM_TYPE_SXM); 111 break; 112 default: 113 break; 114 } 115 if (idType >= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_START 116 && idType <= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_END) { 117 pTypes.add(idType); 118 } 119 } 120 121 return pTypes.stream().mapToInt(Integer::intValue).toArray(); 122 } 123 124 private static @NonNull RadioManager.BandDescriptor[] 125 amfmConfigToBands(@Nullable AmFmRegionConfig config) { 126 if (config == null) return new RadioManager.BandDescriptor[0]; 127 128 int len = config.ranges.size(); 129 List<RadioManager.BandDescriptor> bands = new ArrayList<>(len); 130 131 // Just a dummy value. 132 int region = RadioManager.REGION_ITU_1; 133 134 for (AmFmBandRange range : config.ranges) { 135 FrequencyBand bandType = Utils.getBand(range.lowerBound); 136 if (bandType == FrequencyBand.UNKNOWN) { 137 Slog.e(TAG, "Unknown frequency band at " + range.lowerBound + "kHz"); 138 continue; 139 } 140 if (bandType == FrequencyBand.FM) { 141 bands.add(new RadioManager.FmBandDescriptor(region, RadioManager.BAND_FM, 142 range.lowerBound, range.upperBound, range.spacing, 143 144 // TODO(b/69958777): stereo, rds, ta, af, ea 145 true, true, true, true, true 146 )); 147 } else { // AM 148 bands.add(new RadioManager.AmBandDescriptor(region, RadioManager.BAND_AM, 149 range.lowerBound, range.upperBound, range.spacing, 150 151 // TODO(b/69958777): stereo 152 true 153 )); 154 } 155 } 156 157 return bands.toArray(new RadioManager.BandDescriptor[bands.size()]); 158 } 159 160 static @NonNull RadioManager.ModuleProperties 161 propertiesFromHal(int id, @NonNull String serviceName, @NonNull Properties prop, 162 @Nullable AmFmRegionConfig amfmConfig) { 163 Objects.requireNonNull(serviceName); 164 Objects.requireNonNull(prop); 165 166 int[] supportedIdentifierTypes = prop.supportedIdentifierTypes.stream(). 167 mapToInt(Integer::intValue).toArray(); 168 int[] supportedProgramTypes = identifierTypesToProgramTypes(supportedIdentifierTypes); 169 170 return new RadioManager.ModuleProperties( 171 id, 172 serviceName, 173 174 // There is no Class concept in HAL 2.0. 175 RadioManager.CLASS_AM_FM, 176 177 prop.maker, 178 prop.product, 179 prop.version, 180 prop.serial, 181 182 /* HAL 2.0 only supports single tuner and audio source per 183 * HAL implementation instance. */ 184 1, // numTuners 185 1, // numAudioSources 186 false, // isCaptureSupported 187 188 amfmConfigToBands(amfmConfig), 189 true, // isBgScanSupported is deprecated 190 supportedProgramTypes, 191 supportedIdentifierTypes, 192 vendorInfoFromHal(prop.vendorInfo)); 193 } 194} 195