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