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