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 17 package com.android.server.broadcastradio.hal1; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.hardware.radio.ITunerCallback; 22 import android.hardware.radio.ProgramList; 23 import android.hardware.radio.ProgramSelector; 24 import android.hardware.radio.RadioManager; 25 import android.hardware.radio.RadioTuner; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.util.Slog; 29 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Set; 33 import java.util.concurrent.atomic.AtomicReference; 34 import java.util.stream.Collectors; 35 36 class TunerCallback implements ITunerCallback { 37 private static final String TAG = "BroadcastRadioService.TunerCallback"; 38 39 /** 40 * This field is used by native code, do not access or modify. 41 */ 42 private final long mNativeContext; 43 44 @NonNull private final Tuner mTuner; 45 @NonNull private final ITunerCallback mClientCallback; 46 47 private final AtomicReference<ProgramList.Filter> mProgramListFilter = new AtomicReference<>(); 48 private boolean mInitialConfigurationDone = false; 49 TunerCallback(@onNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev)50 TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) { 51 mTuner = tuner; 52 mClientCallback = clientCallback; 53 mNativeContext = nativeInit(tuner, halRev); 54 } 55 56 @Override finalize()57 protected void finalize() throws Throwable { 58 nativeFinalize(mNativeContext); 59 super.finalize(); 60 } 61 nativeInit(@onNull Tuner tuner, int halRev)62 private native long nativeInit(@NonNull Tuner tuner, int halRev); nativeFinalize(long nativeContext)63 private native void nativeFinalize(long nativeContext); nativeDetach(long nativeContext)64 private native void nativeDetach(long nativeContext); 65 detach()66 public void detach() { 67 nativeDetach(mNativeContext); 68 } 69 70 private interface RunnableThrowingRemoteException { run()71 void run() throws RemoteException; 72 } 73 dispatch(RunnableThrowingRemoteException func)74 private void dispatch(RunnableThrowingRemoteException func) { 75 try { 76 func.run(); 77 } catch (RemoteException e) { 78 Slog.e(TAG, "client died", e); 79 } 80 } 81 82 // called from native side handleHwFailure()83 private void handleHwFailure() { 84 onError(RadioTuner.ERROR_HARDWARE_FAILURE); 85 mTuner.close(); 86 } 87 startProgramListUpdates(@ullable ProgramList.Filter filter)88 void startProgramListUpdates(@Nullable ProgramList.Filter filter) { 89 if (filter == null) filter = new ProgramList.Filter(); 90 mProgramListFilter.set(filter); 91 sendProgramListUpdate(); 92 } 93 stopProgramListUpdates()94 void stopProgramListUpdates() { 95 mProgramListFilter.set(null); 96 } 97 isInitialConfigurationDone()98 boolean isInitialConfigurationDone() { 99 return mInitialConfigurationDone; 100 } 101 102 @Override onError(int status)103 public void onError(int status) { 104 dispatch(() -> mClientCallback.onError(status)); 105 } 106 107 @Override onTuneFailed(int result, ProgramSelector selector)108 public void onTuneFailed(int result, ProgramSelector selector) { 109 Slog.e(TAG, "Not applicable for HAL 1.x"); 110 } 111 112 @Override onConfigurationChanged(RadioManager.BandConfig config)113 public void onConfigurationChanged(RadioManager.BandConfig config) { 114 mInitialConfigurationDone = true; 115 dispatch(() -> mClientCallback.onConfigurationChanged(config)); 116 } 117 118 @Override onCurrentProgramInfoChanged(RadioManager.ProgramInfo info)119 public void onCurrentProgramInfoChanged(RadioManager.ProgramInfo info) { 120 dispatch(() -> mClientCallback.onCurrentProgramInfoChanged(info)); 121 } 122 123 @Override onTrafficAnnouncement(boolean active)124 public void onTrafficAnnouncement(boolean active) { 125 dispatch(() -> mClientCallback.onTrafficAnnouncement(active)); 126 } 127 128 @Override onEmergencyAnnouncement(boolean active)129 public void onEmergencyAnnouncement(boolean active) { 130 dispatch(() -> mClientCallback.onEmergencyAnnouncement(active)); 131 } 132 133 @Override onAntennaState(boolean connected)134 public void onAntennaState(boolean connected) { 135 dispatch(() -> mClientCallback.onAntennaState(connected)); 136 } 137 138 @Override onBackgroundScanAvailabilityChange(boolean isAvailable)139 public void onBackgroundScanAvailabilityChange(boolean isAvailable) { 140 dispatch(() -> mClientCallback.onBackgroundScanAvailabilityChange(isAvailable)); 141 } 142 143 @Override onBackgroundScanComplete()144 public void onBackgroundScanComplete() { 145 dispatch(() -> mClientCallback.onBackgroundScanComplete()); 146 } 147 148 @Override onProgramListChanged()149 public void onProgramListChanged() { 150 dispatch(() -> mClientCallback.onProgramListChanged()); 151 sendProgramListUpdate(); 152 } 153 sendProgramListUpdate()154 private void sendProgramListUpdate() { 155 ProgramList.Filter filter = mProgramListFilter.get(); 156 if (filter == null) return; 157 158 List<RadioManager.ProgramInfo> modified; 159 try { 160 modified = mTuner.getProgramList(filter.getVendorFilter()); 161 } catch (IllegalStateException ex) { 162 Slog.d(TAG, "Program list not ready yet"); 163 return; 164 } 165 Set<RadioManager.ProgramInfo> modifiedSet = modified.stream().collect(Collectors.toSet()); 166 ProgramList.Chunk chunk = new ProgramList.Chunk(true, true, modifiedSet, null); 167 dispatch(() -> mClientCallback.onProgramListUpdated(chunk)); 168 } 169 170 @Override onProgramListUpdated(ProgramList.Chunk chunk)171 public void onProgramListUpdated(ProgramList.Chunk chunk) { 172 dispatch(() -> mClientCallback.onProgramListUpdated(chunk)); 173 } 174 175 @Override onParametersUpdated(Map<String, String> parameters)176 public void onParametersUpdated(Map<String, String> parameters) { 177 Slog.e(TAG, "Not applicable for HAL 1.x"); 178 } 179 180 @Override asBinder()181 public IBinder asBinder() { 182 throw new RuntimeException("Not a binder"); 183 } 184 } 185