blob: 04c0e5788e7b9c5cfea8e3f1d65e084638ed575e [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 Wasilczyk3b4465e2018-01-14 21:47:44 -080023import android.hardware.radio.ProgramSelector;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070024import android.hardware.radio.RadioManager;
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -070025import android.hardware.radio.RadioMetadata;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070026import android.hardware.radio.RadioTuner;
27import android.os.IBinder;
28import android.os.RemoteException;
29import android.util.Slog;
30
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000031import java.util.List;
32import java.util.Map;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080033import java.util.Objects;
34import java.util.Set;
35import java.util.concurrent.atomic.AtomicReference;
36import java.util.stream.Collectors;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000037
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070038class TunerCallback implements ITunerCallback {
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070039 private static final String TAG = "BroadcastRadioService.TunerCallback";
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070040
41 /**
42 * This field is used by native code, do not access or modify.
43 */
44 private final long mNativeContext;
45
46 @NonNull private final Tuner mTuner;
47 @NonNull private final ITunerCallback mClientCallback;
48
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080049 private final AtomicReference<ProgramList.Filter> mProgramListFilter = new AtomicReference<>();
50
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070051 TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) {
52 mTuner = tuner;
53 mClientCallback = clientCallback;
54 mNativeContext = nativeInit(tuner, halRev);
55 }
56
57 @Override
58 protected void finalize() throws Throwable {
59 nativeFinalize(mNativeContext);
60 super.finalize();
61 }
62
63 private native long nativeInit(@NonNull Tuner tuner, int halRev);
64 private native void nativeFinalize(long nativeContext);
65 private native void nativeDetach(long nativeContext);
66
67 public void detach() {
68 nativeDetach(mNativeContext);
69 }
70
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -070071 private interface RunnableThrowingRemoteException {
72 void run() throws RemoteException;
73 }
74
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
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070083 // called from native side
84 private void handleHwFailure() {
85 onError(RadioTuner.ERROR_HARDWARE_FAILURE);
86 mTuner.close();
87 }
88
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080089 void startProgramListUpdates(@NonNull ProgramList.Filter filter) {
90 mProgramListFilter.set(Objects.requireNonNull(filter));
91 sendProgramListUpdate();
92 }
93
94 void stopProgramListUpdates() {
95 mProgramListFilter.set(null);
96 }
97
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070098 @Override
99 public void onError(int status) {
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700100 dispatch(() -> mClientCallback.onError(status));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700101 }
102
103 @Override
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800104 public void onTuneFailed(int result, ProgramSelector selector) {
105 Slog.e(TAG, "Not applicable for HAL 1.x");
106 }
107
108 @Override
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700109 public void onConfigurationChanged(RadioManager.BandConfig config) {
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700110 dispatch(() -> mClientCallback.onConfigurationChanged(config));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700111 }
112
113 @Override
Tomasz Wasilczyk162d14a2017-08-03 18:10:45 -0700114 public void onCurrentProgramInfoChanged(RadioManager.ProgramInfo info) {
115 dispatch(() -> mClientCallback.onCurrentProgramInfoChanged(info));
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700116 }
117
118 @Override
119 public void onTrafficAnnouncement(boolean active) {
120 dispatch(() -> mClientCallback.onTrafficAnnouncement(active));
121 }
122
123 @Override
124 public void onEmergencyAnnouncement(boolean active) {
125 dispatch(() -> mClientCallback.onEmergencyAnnouncement(active));
126 }
127
128 @Override
129 public void onAntennaState(boolean connected) {
130 dispatch(() -> mClientCallback.onAntennaState(connected));
131 }
132
133 @Override
134 public void onBackgroundScanAvailabilityChange(boolean isAvailable) {
135 dispatch(() -> mClientCallback.onBackgroundScanAvailabilityChange(isAvailable));
136 }
137
138 @Override
139 public void onBackgroundScanComplete() {
140 dispatch(() -> mClientCallback.onBackgroundScanComplete());
141 }
142
143 @Override
144 public void onProgramListChanged() {
145 dispatch(() -> mClientCallback.onProgramListChanged());
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800146 sendProgramListUpdate();
147 }
148
149 private void sendProgramListUpdate() {
150 ProgramList.Filter filter = mProgramListFilter.get();
151 if (filter == null) return;
152
153 List<RadioManager.ProgramInfo> modified;
154 try {
155 modified = mTuner.getProgramList(filter.getVendorFilter());
156 } catch (IllegalStateException ex) {
157 Slog.d(TAG, "Program list not ready yet");
158 return;
159 }
160 Set<RadioManager.ProgramInfo> modifiedSet = modified.stream().collect(Collectors.toSet());
161 ProgramList.Chunk chunk = new ProgramList.Chunk(true, true, modifiedSet, null);
162 dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
163 }
164
165 @Override
166 public void onProgramListUpdated(ProgramList.Chunk chunk) {
167 dispatch(() -> mClientCallback.onProgramListUpdated(chunk));
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700168 }
169
170 @Override
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000171 public void onParametersUpdated(Map parameters) {
172 dispatch(() -> mClientCallback.onParametersUpdated(parameters));
173 }
174
175 @Override
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700176 public IBinder asBinder() {
177 throw new RuntimeException("Not a binder");
178 }
179}