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