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 android.hardware.radio; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.graphics.Bitmap; 22import android.os.RemoteException; 23import android.util.Log; 24 25import java.util.List; 26import java.util.Map; 27import java.util.Objects; 28 29/** 30 * Implements the RadioTuner interface by forwarding calls to radio service. 31 */ 32class TunerAdapter extends RadioTuner { 33 private static final String TAG = "BroadcastRadio.TunerAdapter"; 34 35 @NonNull private final ITuner mTuner; 36 @NonNull private final TunerCallbackAdapter mCallback; 37 private boolean mIsClosed = false; 38 39 private @RadioManager.Band int mBand; 40 41 private ProgramList mLegacyListProxy; 42 private Map<String, String> mLegacyListFilter; 43 44 TunerAdapter(@NonNull ITuner tuner, @NonNull TunerCallbackAdapter callback, 45 @RadioManager.Band int band) { 46 mTuner = Objects.requireNonNull(tuner); 47 mCallback = Objects.requireNonNull(callback); 48 mBand = band; 49 } 50 51 @Override 52 public void close() { 53 synchronized (mTuner) { 54 if (mIsClosed) { 55 Log.v(TAG, "Tuner is already closed"); 56 return; 57 } 58 mIsClosed = true; 59 if (mLegacyListProxy != null) { 60 mLegacyListProxy.close(); 61 mLegacyListProxy = null; 62 } 63 mCallback.close(); 64 } 65 try { 66 mTuner.close(); 67 } catch (RemoteException e) { 68 Log.e(TAG, "Exception trying to close tuner", e); 69 } 70 } 71 72 @Override 73 public int setConfiguration(RadioManager.BandConfig config) { 74 if (config == null) return RadioManager.STATUS_BAD_VALUE; 75 try { 76 mTuner.setConfiguration(config); 77 mBand = config.getType(); 78 return RadioManager.STATUS_OK; 79 } catch (IllegalArgumentException e) { 80 Log.e(TAG, "Can't set configuration", e); 81 return RadioManager.STATUS_BAD_VALUE; 82 } catch (RemoteException e) { 83 Log.e(TAG, "service died", e); 84 return RadioManager.STATUS_DEAD_OBJECT; 85 } 86 } 87 88 @Override 89 public int getConfiguration(RadioManager.BandConfig[] config) { 90 if (config == null || config.length != 1) { 91 throw new IllegalArgumentException("The argument must be an array of length 1"); 92 } 93 try { 94 config[0] = mTuner.getConfiguration(); 95 return RadioManager.STATUS_OK; 96 } catch (RemoteException e) { 97 Log.e(TAG, "service died", e); 98 return RadioManager.STATUS_DEAD_OBJECT; 99 } 100 } 101 102 @Override 103 public int setMute(boolean mute) { 104 try { 105 mTuner.setMuted(mute); 106 } catch (IllegalStateException e) { 107 Log.e(TAG, "Can't set muted", e); 108 return RadioManager.STATUS_ERROR; 109 } catch (RemoteException e) { 110 Log.e(TAG, "service died", e); 111 return RadioManager.STATUS_DEAD_OBJECT; 112 } 113 return RadioManager.STATUS_OK; 114 } 115 116 @Override 117 public boolean getMute() { 118 try { 119 return mTuner.isMuted(); 120 } catch (RemoteException e) { 121 Log.e(TAG, "service died", e); 122 return true; 123 } 124 } 125 126 @Override 127 public int step(int direction, boolean skipSubChannel) { 128 try { 129 mTuner.step(direction == RadioTuner.DIRECTION_DOWN, skipSubChannel); 130 } catch (IllegalStateException e) { 131 Log.e(TAG, "Can't step", e); 132 return RadioManager.STATUS_INVALID_OPERATION; 133 } catch (RemoteException e) { 134 Log.e(TAG, "service died", e); 135 return RadioManager.STATUS_DEAD_OBJECT; 136 } 137 return RadioManager.STATUS_OK; 138 } 139 140 @Override 141 public int scan(int direction, boolean skipSubChannel) { 142 try { 143 mTuner.scan(direction == RadioTuner.DIRECTION_DOWN, skipSubChannel); 144 } catch (IllegalStateException e) { 145 Log.e(TAG, "Can't scan", e); 146 return RadioManager.STATUS_INVALID_OPERATION; 147 } catch (RemoteException e) { 148 Log.e(TAG, "service died", e); 149 return RadioManager.STATUS_DEAD_OBJECT; 150 } 151 return RadioManager.STATUS_OK; 152 } 153 154 @Override 155 public int tune(int channel, int subChannel) { 156 try { 157 mTuner.tune(ProgramSelector.createAmFmSelector(mBand, channel, subChannel)); 158 } catch (IllegalStateException e) { 159 Log.e(TAG, "Can't tune", e); 160 return RadioManager.STATUS_INVALID_OPERATION; 161 } catch (IllegalArgumentException e) { 162 Log.e(TAG, "Can't tune", e); 163 return RadioManager.STATUS_BAD_VALUE; 164 } catch (RemoteException e) { 165 Log.e(TAG, "service died", e); 166 return RadioManager.STATUS_DEAD_OBJECT; 167 } 168 return RadioManager.STATUS_OK; 169 } 170 171 @Override 172 public void tune(@NonNull ProgramSelector selector) { 173 try { 174 mTuner.tune(selector); 175 } catch (RemoteException e) { 176 throw new RuntimeException("service died", e); 177 } 178 } 179 180 @Override 181 public int cancel() { 182 try { 183 mTuner.cancel(); 184 } catch (IllegalStateException e) { 185 Log.e(TAG, "Can't cancel", e); 186 return RadioManager.STATUS_INVALID_OPERATION; 187 } catch (RemoteException e) { 188 Log.e(TAG, "service died", e); 189 return RadioManager.STATUS_DEAD_OBJECT; 190 } 191 return RadioManager.STATUS_OK; 192 } 193 194 @Override 195 public void cancelAnnouncement() { 196 try { 197 mTuner.cancelAnnouncement(); 198 } catch (RemoteException e) { 199 throw new RuntimeException("service died", e); 200 } 201 } 202 203 @Override 204 public int getProgramInformation(RadioManager.ProgramInfo[] info) { 205 if (info == null || info.length != 1) { 206 Log.e(TAG, "The argument must be an array of length 1"); 207 return RadioManager.STATUS_BAD_VALUE; 208 } 209 210 RadioManager.ProgramInfo current = mCallback.getCurrentProgramInformation(); 211 if (current == null) { 212 Log.w(TAG, "Didn't get program info yet"); 213 return RadioManager.STATUS_INVALID_OPERATION; 214 } 215 info[0] = current; 216 return RadioManager.STATUS_OK; 217 } 218 219 @Override 220 public @Nullable Bitmap getMetadataImage(int id) { 221 try { 222 return mTuner.getImage(id); 223 } catch (RemoteException e) { 224 throw new RuntimeException("service died", e); 225 } 226 } 227 228 @Override 229 public boolean startBackgroundScan() { 230 try { 231 return mTuner.startBackgroundScan(); 232 } catch (RemoteException e) { 233 throw new RuntimeException("service died", e); 234 } 235 } 236 237 @Override 238 public @NonNull List<RadioManager.ProgramInfo> 239 getProgramList(@Nullable Map<String, String> vendorFilter) { 240 synchronized (mTuner) { 241 if (mLegacyListProxy == null || !Objects.equals(mLegacyListFilter, vendorFilter)) { 242 Log.i(TAG, "Program list filter has changed, requesting new list"); 243 mLegacyListProxy = new ProgramList(); 244 mLegacyListFilter = vendorFilter; 245 246 mCallback.clearLastCompleteList(); 247 mCallback.setProgramListObserver(mLegacyListProxy, () -> { }); 248 try { 249 mTuner.startProgramListUpdates(new ProgramList.Filter(vendorFilter)); 250 } catch (RemoteException ex) { 251 throw new RuntimeException("service died", ex); 252 } 253 } 254 255 List<RadioManager.ProgramInfo> list = mCallback.getLastCompleteList(); 256 if (list == null) throw new IllegalStateException("Program list is not ready yet"); 257 return list; 258 } 259 } 260 261 @Override 262 public @Nullable ProgramList getDynamicProgramList(@Nullable ProgramList.Filter filter) { 263 synchronized (mTuner) { 264 if (mLegacyListProxy != null) { 265 mLegacyListProxy.close(); 266 mLegacyListProxy = null; 267 } 268 mLegacyListFilter = null; 269 270 ProgramList list = new ProgramList(); 271 mCallback.setProgramListObserver(list, () -> { 272 try { 273 mTuner.stopProgramListUpdates(); 274 } catch (RemoteException ex) { 275 Log.e(TAG, "Couldn't stop program list updates", ex); 276 } 277 }); 278 279 try { 280 mTuner.startProgramListUpdates(filter); 281 } catch (UnsupportedOperationException ex) { 282 Log.i(TAG, "Program list is not supported with this hardware"); 283 return null; 284 } catch (RemoteException ex) { 285 mCallback.setProgramListObserver(null, () -> { }); 286 throw new RuntimeException("service died", ex); 287 } 288 289 return list; 290 } 291 } 292 293 @Override 294 public boolean isAnalogForced() { 295 try { 296 return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG); 297 } catch (UnsupportedOperationException ex) { 298 throw new IllegalStateException(ex); 299 } 300 } 301 302 @Override 303 public void setAnalogForced(boolean isForced) { 304 try { 305 setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced); 306 } catch (UnsupportedOperationException ex) { 307 throw new IllegalStateException(ex); 308 } 309 } 310 311 @Override 312 public boolean isConfigFlagSupported(@RadioManager.ConfigFlag int flag) { 313 try { 314 return mTuner.isConfigFlagSupported(flag); 315 } catch (RemoteException e) { 316 throw new RuntimeException("service died", e); 317 } 318 } 319 320 @Override 321 public boolean isConfigFlagSet(@RadioManager.ConfigFlag int flag) { 322 try { 323 return mTuner.isConfigFlagSet(flag); 324 } catch (RemoteException e) { 325 throw new RuntimeException("service died", e); 326 } 327 } 328 329 @Override 330 public void setConfigFlag(@RadioManager.ConfigFlag int flag, boolean value) { 331 try { 332 mTuner.setConfigFlag(flag, value); 333 } catch (RemoteException e) { 334 throw new RuntimeException("service died", e); 335 } 336 } 337 338 @Override 339 public @NonNull Map<String, String> setParameters(@NonNull Map<String, String> parameters) { 340 try { 341 return mTuner.setParameters(Objects.requireNonNull(parameters)); 342 } catch (RemoteException e) { 343 throw new RuntimeException("service died", e); 344 } 345 } 346 347 @Override 348 public @NonNull Map<String, String> getParameters(@NonNull List<String> keys) { 349 try { 350 return mTuner.getParameters(Objects.requireNonNull(keys)); 351 } catch (RemoteException e) { 352 throw new RuntimeException("service died", e); 353 } 354 } 355 356 @Override 357 public boolean isAntennaConnected() { 358 return mCallback.isAntennaConnected(); 359 } 360 361 @Override 362 public boolean hasControl() { 363 try { 364 // don't rely on mIsClosed, as tuner might get closed internally 365 return !mTuner.isClosed(); 366 } catch (RemoteException e) { 367 return false; 368 } 369 } 370} 371