blob: 7437c40351db37eb47ff8eebd76cc5c69edfa3e8 [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 Wasilczyk436128f2018-01-08 16:46:09 -080056 void setProgramListObserver(@Nullable ProgramList programList,
57 @NonNull ProgramList.OnCloseListener closeListener) {
58 Objects.requireNonNull(closeListener);
59 synchronized (mLock) {
60 if (mProgramList != null) {
61 Log.w(TAG, "Previous program list observer wasn't properly closed, closing it...");
62 mProgramList.close();
63 }
64 mProgramList = programList;
65 if (programList == null) return;
66 programList.setOnCloseListener(() -> {
67 synchronized (mLock) {
68 if (mProgramList != programList) return;
69 mProgramList = null;
70 mLastCompleteList = null;
71 closeListener.onClose();
72 }
73 });
74 programList.addOnCompleteListener(() -> {
75 synchronized (mLock) {
76 if (mProgramList != programList) return;
77 mLastCompleteList = programList.toList();
78 if (mDelayedCompleteCallback) {
79 Log.d(TAG, "Sending delayed onBackgroundScanComplete callback");
80 sendBackgroundScanCompleteLocked();
81 }
82 }
83 });
84 }
85 }
86
87 @Nullable List<RadioManager.ProgramInfo> getLastCompleteList() {
88 synchronized (mLock) {
89 return mLastCompleteList;
90 }
91 }
92
93 void clearLastCompleteList() {
94 synchronized (mLock) {
95 mLastCompleteList = null;
96 }
97 }
98
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080099 @Nullable RadioManager.ProgramInfo getCurrentProgramInformation() {
100 synchronized (mLock) {
101 return mCurrentProgramInfo;
102 }
103 }
104
105 boolean isAntennaConnected() {
106 return mIsAntennaConnected;
107 }
108
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700109 @Override
110 public void onError(int status) {
111 mHandler.post(() -> mCallback.onError(status));
112 }
113
114 @Override
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800115 public void onTuneFailed(int status, @Nullable ProgramSelector selector) {
116 mHandler.post(() -> mCallback.onTuneFailed(status, selector));
117
118 int errorCode;
119 switch (status) {
120 case RadioManager.STATUS_PERMISSION_DENIED:
121 case RadioManager.STATUS_DEAD_OBJECT:
122 errorCode = RadioTuner.ERROR_SERVER_DIED;
123 break;
124 case RadioManager.STATUS_ERROR:
125 case RadioManager.STATUS_NO_INIT:
126 case RadioManager.STATUS_BAD_VALUE:
127 case RadioManager.STATUS_INVALID_OPERATION:
128 Log.i(TAG, "Got an error with no mapping to the legacy API (" + status
129 + "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT");
130 // fall through
131 case RadioManager.STATUS_TIMED_OUT:
132 default:
133 errorCode = RadioTuner.ERROR_SCAN_TIMEOUT;
134 }
135 mHandler.post(() -> mCallback.onError(errorCode));
136 }
137
138 @Override
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700139 public void onConfigurationChanged(RadioManager.BandConfig config) {
140 mHandler.post(() -> mCallback.onConfigurationChanged(config));
141 }
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700142
143 @Override
Tomasz Wasilczyk162d14a2017-08-03 18:10:45 -0700144 public void onCurrentProgramInfoChanged(RadioManager.ProgramInfo info) {
145 if (info == null) {
146 Log.e(TAG, "ProgramInfo must not be null");
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -0700147 return;
148 }
149
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800150 synchronized (mLock) {
151 mCurrentProgramInfo = info;
152 }
153
Tomasz Wasilczyk24250ef2017-07-13 15:59:08 -0700154 mHandler.post(() -> {
155 mCallback.onProgramInfoChanged(info);
156
157 RadioMetadata metadata = info.getMetadata();
158 if (metadata != null) mCallback.onMetadataChanged(metadata);
159 });
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700160 }
161
162 @Override
163 public void onTrafficAnnouncement(boolean active) {
164 mHandler.post(() -> mCallback.onTrafficAnnouncement(active));
165 }
166
167 @Override
168 public void onEmergencyAnnouncement(boolean active) {
169 mHandler.post(() -> mCallback.onEmergencyAnnouncement(active));
170 }
171
172 @Override
173 public void onAntennaState(boolean connected) {
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800174 mIsAntennaConnected = connected;
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700175 mHandler.post(() -> mCallback.onAntennaState(connected));
176 }
177
178 @Override
179 public void onBackgroundScanAvailabilityChange(boolean isAvailable) {
180 mHandler.post(() -> mCallback.onBackgroundScanAvailabilityChange(isAvailable));
181 }
182
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800183 private void sendBackgroundScanCompleteLocked() {
184 mDelayedCompleteCallback = false;
185 mHandler.post(() -> mCallback.onBackgroundScanComplete());
186 }
187
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700188 @Override
189 public void onBackgroundScanComplete() {
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800190 synchronized (mLock) {
191 if (mLastCompleteList == null) {
192 Log.i(TAG, "Got onBackgroundScanComplete callback, but the "
193 + "program list didn't get through yet. Delaying it...");
194 mDelayedCompleteCallback = true;
195 return;
196 }
197 sendBackgroundScanCompleteLocked();
198 }
Tomasz Wasilczykc9a1ac72017-05-17 21:29:28 -0700199 }
200
201 @Override
202 public void onProgramListChanged() {
203 mHandler.post(() -> mCallback.onProgramListChanged());
204 }
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000205
206 @Override
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -0800207 public void onProgramListUpdated(ProgramList.Chunk chunk) {
208 synchronized (mLock) {
209 if (mProgramList == null) return;
210 mProgramList.apply(Objects.requireNonNull(chunk));
211 }
212 }
213
214 @Override
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000215 public void onParametersUpdated(Map parameters) {
216 mHandler.post(() -> mCallback.onParametersUpdated(parameters));
217 }
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700218}