Home | History | Annotate | Download | only in hal2
      1 /**
      2  * Copyright (C) 2018 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.hal2;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.hardware.radio.Announcement;
     22 import android.hardware.radio.IAnnouncementListener;
     23 import android.hardware.radio.ICloseHandle;
     24 import android.os.IBinder;
     25 import android.os.RemoteException;
     26 import android.util.Slog;
     27 
     28 import com.android.internal.annotations.GuardedBy;
     29 
     30 import java.util.ArrayList;
     31 import java.util.Collection;
     32 import java.util.List;
     33 import java.util.Objects;
     34 
     35 public class AnnouncementAggregator extends ICloseHandle.Stub {
     36     private static final String TAG = "BcRadio2Srv.AnnAggr";
     37 
     38     private final Object mLock = new Object();
     39     @NonNull private final IAnnouncementListener mListener;
     40     private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient();
     41 
     42     @GuardedBy("mLock")
     43     private final Collection<ModuleWatcher> mModuleWatchers = new ArrayList<>();
     44 
     45     @GuardedBy("mLock")
     46     private boolean mIsClosed = false;
     47 
     48     public AnnouncementAggregator(@NonNull IAnnouncementListener listener) {
     49         mListener = Objects.requireNonNull(listener);
     50         try {
     51             listener.asBinder().linkToDeath(mDeathRecipient, 0);
     52         } catch (RemoteException ex) {
     53             ex.rethrowFromSystemServer();
     54         }
     55     }
     56 
     57     private class ModuleWatcher extends IAnnouncementListener.Stub {
     58         private @Nullable ICloseHandle mCloseHandle;
     59         public @NonNull List<Announcement> currentList = new ArrayList<>();
     60 
     61         public void onListUpdated(List<Announcement> active) {
     62             currentList = Objects.requireNonNull(active);
     63             AnnouncementAggregator.this.onListUpdated();
     64         }
     65 
     66         public void setCloseHandle(@NonNull ICloseHandle closeHandle) {
     67             mCloseHandle = Objects.requireNonNull(closeHandle);
     68         }
     69 
     70         public void close() throws RemoteException {
     71             if (mCloseHandle != null) mCloseHandle.close();
     72         }
     73     }
     74 
     75     private class DeathRecipient implements IBinder.DeathRecipient {
     76         public void binderDied() {
     77             try {
     78                 close();
     79             } catch (RemoteException ex) {}
     80         }
     81     }
     82 
     83     private void onListUpdated() {
     84         synchronized (mLock) {
     85             if (mIsClosed) {
     86                 Slog.e(TAG, "Announcement aggregator is closed, it shouldn't receive callbacks");
     87                 return;
     88             }
     89             List<Announcement> combined = new ArrayList<>();
     90             for (ModuleWatcher watcher : mModuleWatchers) {
     91                 combined.addAll(watcher.currentList);
     92             }
     93             TunerCallback.dispatch(() -> mListener.onListUpdated(combined));
     94         }
     95     }
     96 
     97     public void watchModule(@NonNull RadioModule module, @NonNull int[] enabledTypes) {
     98         synchronized (mLock) {
     99             if (mIsClosed) throw new IllegalStateException();
    100 
    101             ModuleWatcher watcher = new ModuleWatcher();
    102             ICloseHandle closeHandle;
    103             try {
    104                 closeHandle = module.addAnnouncementListener(enabledTypes, watcher);
    105             } catch (RemoteException ex) {
    106                 Slog.e(TAG, "Failed to add announcement listener", ex);
    107                 return;
    108             }
    109             watcher.setCloseHandle(closeHandle);
    110             mModuleWatchers.add(watcher);
    111         }
    112     }
    113 
    114     @Override
    115     public void close() throws RemoteException {
    116         synchronized (mLock) {
    117             if (mIsClosed) return;
    118             mIsClosed = true;
    119 
    120             mListener.asBinder().unlinkToDeath(mDeathRecipient, 0);
    121 
    122             for (ModuleWatcher watcher : mModuleWatchers) {
    123                 watcher.close();
    124             }
    125             mModuleWatchers.clear();
    126         }
    127     }
    128 }
    129