blob: 0fb93e532cd3f1cedbca0261a2aa151cf59c58bf [file] [log] [blame]
Tomasz Wasilczyk21348172017-04-20 14:02:42 -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
17package android.hardware.radio;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.os.Handler;
22import android.os.Looper;
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -070023import android.util.Log;
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070024
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080025import java.util.List;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000026import java.util.Map;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080027import java.util.Objects;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000028
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070029/**
30 * Implements the ITunerCallback interface by forwarding calls to RadioTuner.Callback.
31 */
32class TunerCallbackAdapter extends ITunerCallback.Stub {
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070033 private static final String TAG = "BroadcastRadio.TunerCallbackAdapter";
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -070034
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080035 private final Object mLock = new Object();
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070036 @NonNull private final RadioTuner.Callback mCallback;
37 @NonNull private final Handler mHandler;
38
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080039 @Nullable ProgramList mProgramList;
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080040
41 // cache for deprecated methods
42 boolean mIsAntennaConnected = true;
43 @Nullable List<RadioManager.ProgramInfo> mLastCompleteList;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080044 private boolean mDelayedCompleteCallback = false;
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080045 @Nullable RadioManager.ProgramInfo mCurrentProgramInfo;
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080046
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070047 TunerCallbackAdapter(@NonNull RadioTuner.Callback callback, @Nullable Handler handler) {
48 mCallback = callback;
49 if (handler == null) {
50 mHandler = new Handler(Looper.getMainLooper());
51 } else {
52 mHandler = handler;
53 }
54 }
55
Tomasz Wasilczykd0c78f92018-03-28 17:50:08 -070056 void close() {
57 synchronized (mLock) {
58 if (mProgramList != null) mProgramList.close();
59 }
60 }
61
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080062 void setProgramListObserver(@Nullable ProgramList programList,
63 @NonNull ProgramList.OnCloseListener closeListener) {
64 Objects.requireNonNull(closeListener);
65 synchronized (mLock) {
66 if (mProgramList != null) {
67 Log.w(TAG, "Previous program list observer wasn't properly closed, closing it...");
68 mProgramList.close();
69 }
70 mProgramList = programList;
71 if (programList == null) return;
72 programList.setOnCloseListener(() -> {
73 synchronized (mLock) {
74 if (mProgramList != programList) return;
75 mProgramList = null;
76 mLastCompleteList = null;
77 closeListener.onClose();
78 }
79 });
80 programList.addOnCompleteListener(() -> {
81 synchronized (mLock) {
82 if (mProgramList != programList) return;
83 mLastCompleteList = programList.toList();
84 if (mDelayedCompleteCallback) {
85 Log.d(TAG, "Sending delayed onBackgroundScanComplete callback");
86 sendBackgroundScanCompleteLocked();
87 }
88 }
89 });
90 }
91 }
92
93 @Nullable List<RadioManager.ProgramInfo> getLastCompleteList() {
94 synchronized (mLock) {
95 return mLastCompleteList;
96 }
97 }
98
99 void clearLastCompleteList() {
100 synchronized (mLock) {
101 mLastCompleteList = null;
102 }
103 }
104
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800105 @Nullable RadioManager.ProgramInfo getCurrentProgramInformation() {
106 synchronized (mLock) {
107 return mCurrentProgramInfo;
108 }
109 }
110
111 boolean isAntennaConnected() {
112 return mIsAntennaConnected;
113 }
114
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700115 @Override
116 public void onError(int status) {
117 mHandler.post(() -> mCallback.onError(status));
118 }
119
120 @Override
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800121 public void onTuneFailed(int status, @Nullable ProgramSelector selector) {
122 mHandler.post(() -> mCallback.onTuneFailed(status, selector));
123
124 int errorCode;
125 switch (status) {
126 case RadioManager.STATUS_PERMISSION_DENIED:
127 case RadioManager.STATUS_DEAD_OBJECT:
128 errorCode = RadioTuner.ERROR_SERVER_DIED;
129 break;
130 case RadioManager.STATUS_ERROR:
131 case RadioManager.STATUS_NO_INIT:
132 case RadioManager.STATUS_BAD_VALUE:
133 case RadioManager.STATUS_INVALID_OPERATION:
134 Log.i(TAG, "Got an error with no mapping to the legacy API (" + status
135 + "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT");
136 // fall through
137 case RadioManager.STATUS_TIMED_OUT:
138 default:
139 errorCode = RadioTuner.ERROR_SCAN_TIMEOUT;
140 }
141 mHandler.post(() -> mCallback.onError(errorCode));
142 }
143
144 @Override
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700145 public void onConfigurationChanged(RadioManager.BandConfig config) {
146 mHandler.post(() -> mCallback.onConfigurationChanged(config));
147 }
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700148
149 @Override
Tomasz Wasilczyk162d14a2017-08-03 18:10:45 -0700150 public void onCurrentProgramInfoChanged(RadioManager.ProgramInfo info) {
151 if (info == null) {
152 Log.e(TAG, "ProgramInfo must not be null");
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -0700153 return;
154 }
155
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800156 synchronized (mLock) {
157 mCurrentProgramInfo = info;
158 }
159
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -0700160 mHandler.post(() -> {
161 mCallback.onProgramInfoChanged(info);
162
163 RadioMetadata metadata = info.getMetadata();
164 if (metadata != null) mCallback.onMetadataChanged(metadata);
165 });
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700166 }
167
168 @Override
169 public void onTrafficAnnouncement(boolean active) {
170 mHandler.post(() -> mCallback.onTrafficAnnouncement(active));
171 }
172
173 @Override
174 public void onEmergencyAnnouncement(boolean active) {
175 mHandler.post(() -> mCallback.onEmergencyAnnouncement(active));
176 }
177
178 @Override
179 public void onAntennaState(boolean connected) {
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800180 mIsAntennaConnected = connected;
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700181 mHandler.post(() -> mCallback.onAntennaState(connected));
182 }
183
184 @Override
185 public void onBackgroundScanAvailabilityChange(boolean isAvailable) {
186 mHandler.post(() -> mCallback.onBackgroundScanAvailabilityChange(isAvailable));
187 }
188
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800189 private void sendBackgroundScanCompleteLocked() {
190 mDelayedCompleteCallback = false;
191 mHandler.post(() -> mCallback.onBackgroundScanComplete());
192 }
193
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700194 @Override
195 public void onBackgroundScanComplete() {
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800196 synchronized (mLock) {
197 if (mLastCompleteList == null) {
198 Log.i(TAG, "Got onBackgroundScanComplete callback, but the "
199 + "program list didn't get through yet. Delaying it...");
200 mDelayedCompleteCallback = true;
201 return;
202 }
203 sendBackgroundScanCompleteLocked();
204 }
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700205 }
206
207 @Override
208 public void onProgramListChanged() {
209 mHandler.post(() -> mCallback.onProgramListChanged());
210 }
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000211
212 @Override
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800213 public void onProgramListUpdated(ProgramList.Chunk chunk) {
214 synchronized (mLock) {
215 if (mProgramList == null) return;
216 mProgramList.apply(Objects.requireNonNull(chunk));
217 }
218 }
219
220 @Override
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000221 public void onParametersUpdated(Map parameters) {
222 mHandler.post(() -> mCallback.onParametersUpdated(parameters));
223 }
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700224}