blob: 18f56ed5847509b3fa09fa6bd2ec156888ee94d3 [file] [log] [blame]
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -07001/**
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
Tomasz Wasilczykdf013262017-12-13 11:47:20 -080017package com.android.server.broadcastradio.hal1;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070018
19import android.annotation.NonNull;
20import android.hardware.radio.ITuner;
21import android.hardware.radio.ITunerCallback;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080022import android.hardware.radio.ProgramList;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070023import android.hardware.radio.RadioManager;
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -070024import android.hardware.radio.RadioMetadata;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070025import android.hardware.radio.RadioTuner;
26import android.os.IBinder;
27import android.os.RemoteException;
28import android.util.Slog;
29
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000030import java.util.List;
31import java.util.Map;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080032import java.util.Objects;
33import java.util.Set;
34import java.util.concurrent.atomic.AtomicReference;
35import java.util.stream.Collectors;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000036
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070037class TunerCallback implements ITunerCallback {
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070038 private static final String TAG = "BroadcastRadioService.TunerCallback";
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070039
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
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080048 private final AtomicReference<ProgramList.Filter> mProgramListFilter = new AtomicReference<>();
49
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070050 TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) {
51 mTuner = tuner;
52 mClientCallback = clientCallback;
53 mNativeContext = nativeInit(tuner, halRev);
54 }
55
56 @Override
57 protected void finalize() throws Throwable {
58 nativeFinalize(mNativeContext);
59 super.finalize();
60 }
61
62 private native long nativeInit(@NonNull Tuner tuner, int halRev);
63 private native void nativeFinalize(long nativeContext);
64 private native void nativeDetach(long nativeContext);
65
66 public void detach() {
67 nativeDetach(mNativeContext);
68 }
69
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -070070 private interface RunnableThrowingRemoteException {
71 void run() throws RemoteException;
72 }
73
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
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070082 // called from native side
83 private void handleHwFailure() {
84 onError(RadioTuner.ERROR_HARDWARE_FAILURE);
85 mTuner.close();
86 }
87
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080088 void startProgramListUpdates(@NonNull ProgramList.Filter filter) {
89 mProgramListFilter.set(Objects.requireNonNull(filter));
90 sendProgramListUpdate();
91 }
92
93 void stopProgramListUpdates() {
94 mProgramListFilter.set(null);
95 }
96
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070097 @Override
98 public void onError(int status) {
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -070099 dispatch(() -> mClientCallback.onError(status));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700100 }
101
102 @Override
103 public void onConfigurationChanged(RadioManager.BandConfig config) {
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700104 dispatch(() -> mClientCallback.onConfigurationChanged(config));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700105 }
106
107 @Override
Tomasz Wasilczyk162d14a2017-08-03 18:10:45 -0700108 public void onCurrentProgramInfoChanged(RadioManager.ProgramInfo info) {
109 dispatch(() -> mClientCallback.onCurrentProgramInfoChanged(info));
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700110 }
111
112 @Override
113 public void onTrafficAnnouncement(boolean active) {
114 dispatch(() -> mClientCallback.onTrafficAnnouncement(active));
115 }
116
117 @Override
118 public void onEmergencyAnnouncement(boolean active) {
119 dispatch(() -> mClientCallback.onEmergencyAnnouncement(active));
120 }
121
122 @Override
123 public void onAntennaState(boolean connected) {
124 dispatch(() -> mClientCallback.onAntennaState(connected));
125 }
126
127 @Override
128 public void onBackgroundScanAvailabilityChange(boolean isAvailable) {
129 dispatch(() -> mClientCallback.onBackgroundScanAvailabilityChange(isAvailable));
130 }
131
132 @Override
133 public void onBackgroundScanComplete() {
134 dispatch(() -> mClientCallback.onBackgroundScanComplete());
135 }
136
137 @Override
138 public void onProgramListChanged() {
139 dispatch(() -> mClientCallback.onProgramListChanged());
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800140 sendProgramListUpdate();
141 }
142
143 private void sendProgramListUpdate() {
144 ProgramList.Filter filter = mProgramListFilter.get();
145 if (filter == null) return;
146
147 List<RadioManager.ProgramInfo> modified;
148 try {
149 modified = mTuner.getProgramList(filter.getVendorFilter());
150 } catch (IllegalStateException ex) {
151 Slog.d(TAG, "Program list not ready yet");
152 return;
153 }
154 Set<RadioManager.ProgramInfo> modifiedSet = modified.stream().collect(Collectors.toSet());
155 ProgramList.Chunk chunk = new ProgramList.Chunk(true, true, modifiedSet, null);
156 dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
157 }
158
159 @Override
160 public void onProgramListUpdated(ProgramList.Chunk chunk) {
161 dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700162 }
163
164 @Override
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000165 public void onParametersUpdated(Map parameters) {
166 dispatch(() -> mClientCallback.onParametersUpdated(parameters));
167 }
168
169 @Override
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700170 public IBinder asBinder() {
171 throw new RuntimeException("Not a binder");
172 }
173}