blob: 8ed646af2b8882bfa1a556060d9f11e5cfd58660 [file] [log] [blame]
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -08001/**
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 com.android.server.broadcastradio.hal2;
18
19import android.annotation.NonNull;
20import android.graphics.Bitmap;
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080021import android.hardware.broadcastradio.V2_0.ConfigFlag;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080022import android.hardware.broadcastradio.V2_0.ITunerSession;
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080023import android.hardware.broadcastradio.V2_0.Result;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080024import android.hardware.radio.ITuner;
25import android.hardware.radio.ProgramSelector;
26import android.hardware.radio.RadioManager;
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080027import android.media.AudioSystem;
28import android.os.RemoteException;
29import android.util.MutableBoolean;
30import android.util.MutableInt;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080031import android.util.Slog;
32
33import java.util.List;
34import java.util.Map;
35import java.util.Objects;
36
37class TunerSession extends ITuner.Stub {
38 private static final String TAG = "BcRadio2Srv.session";
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080039 private static final String kAudioDeviceName = "Radio tuner source";
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080040
41 private final Object mLock = new Object();
42
43 private final ITunerSession mHwSession;
44 private final TunerCallback mCallback;
45 private boolean mIsClosed = false;
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080046 private boolean mIsAudioConnected = false;
47 private boolean mIsMuted = false;
48
49 // necessary only for older APIs compatibility
50 private RadioManager.BandConfig mDummyConfig = null;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080051
52 TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) {
53 mHwSession = Objects.requireNonNull(hwSession);
54 mCallback = Objects.requireNonNull(callback);
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080055 notifyAudioServiceLocked(true);
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080056 }
57
58 @Override
59 public void close() {
60 synchronized (mLock) {
61 if (mIsClosed) return;
62 mIsClosed = true;
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080063 notifyAudioServiceLocked(false);
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080064 }
65 }
66
67 @Override
68 public boolean isClosed() {
69 return mIsClosed;
70 }
71
72 private void checkNotClosedLocked() {
73 if (mIsClosed) {
74 throw new IllegalStateException("Tuner is closed, no further operations are allowed");
75 }
76 }
77
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080078 private void notifyAudioServiceLocked(boolean connected) {
79 if (mIsAudioConnected == connected) return;
80
81 Slog.d(TAG, "Notifying AudioService about new state: " + connected);
82 int ret = AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_FM_TUNER,
83 connected ? AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
84 null, kAudioDeviceName);
85
86 if (ret == AudioSystem.AUDIO_STATUS_OK) {
87 mIsAudioConnected = connected;
88 } else {
89 Slog.e(TAG, "Failed to notify AudioService about new state: " + connected);
90 }
91 }
92
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080093 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -080094 public void setConfiguration(RadioManager.BandConfig config) {
95 synchronized (mLock) {
96 checkNotClosedLocked();
97 mDummyConfig = Objects.requireNonNull(config);
98 Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x");
99 TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config));
100 }
101 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800102
103 @Override
104 public RadioManager.BandConfig getConfiguration() {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800105 synchronized (mLock) {
106 checkNotClosedLocked();
107 return mDummyConfig;
108 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800109 }
110
111 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800112 public void setMuted(boolean mute) {
113 synchronized (mLock) {
114 checkNotClosedLocked();
115 if (mIsMuted == mute) return;
116 mIsMuted = mute;
117 notifyAudioServiceLocked(!mute);
118 }
119 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800120
121 @Override
122 public boolean isMuted() {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800123 synchronized (mLock) {
124 checkNotClosedLocked();
125 return mIsMuted;
126 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800127 }
128
129 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800130 public void step(boolean directionDown, boolean skipSubChannel) {
131 synchronized (mLock) {
132 checkNotClosedLocked();
133 }
134 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800135
136 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800137 public void scan(boolean directionDown, boolean skipSubChannel) {
138 synchronized (mLock) {
139 checkNotClosedLocked();
140 }
141 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800142
143 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800144 public void tune(ProgramSelector selector) {
145 synchronized (mLock) {
146 checkNotClosedLocked();
147 }
148 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800149
150 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800151 public void cancel() {
152 synchronized (mLock) {
153 checkNotClosedLocked();
154 }
155 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800156
157 @Override
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800158 public void cancelAnnouncement() {
159 synchronized (mLock) {
160 checkNotClosedLocked();
161 }
162 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800163
164 @Override
165 public RadioManager.ProgramInfo getProgramInformation() {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800166 synchronized (mLock) {
167 checkNotClosedLocked();
168 return null;
169 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800170 }
171
172 @Override
173 public Bitmap getImage(int id) {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800174 synchronized (mLock) {
175 checkNotClosedLocked();
176 return null;
177 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800178 }
179
180 @Override
181 public boolean startBackgroundScan() {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800182 Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x");
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800183 return false;
184 }
185
186 @Override
187 public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800188 synchronized (mLock) {
189 checkNotClosedLocked();
190 return null;
191 }
192 }
193
Tomasz Wasilczykce40fe92018-01-04 20:52:39 -0800194 @Override
195 public boolean isConfigFlagSupported(int flag) {
196 try {
197 isConfigFlagSet(flag);
198 return true;
199 } catch (IllegalStateException ex) {
200 return true;
201 } catch (UnsupportedOperationException ex) {
202 return false;
203 }
204 }
205
206 @Override
207 public boolean isConfigFlagSet(int flag) {
208 Slog.v(TAG, "isConfigFlagSet " + ConfigFlag.toString(flag));
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800209 synchronized (mLock) {
210 checkNotClosedLocked();
211
212 MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
213 MutableBoolean flagState = new MutableBoolean(false);
214 try {
215 mHwSession.getConfigFlag(flag, (int result, boolean value) -> {
216 halResult.value = result;
217 flagState.value = value;
218 });
219 } catch (RemoteException ex) {
Tomasz Wasilczykce40fe92018-01-04 20:52:39 -0800220 throw new RuntimeException("Failed to check flag " + ConfigFlag.toString(flag), ex);
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800221 }
Tomasz Wasilczykce40fe92018-01-04 20:52:39 -0800222 Convert.throwOnError("isConfigFlagSet", halResult.value);
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800223
224 return flagState.value;
225 }
226 }
227
Tomasz Wasilczykce40fe92018-01-04 20:52:39 -0800228 @Override
229 public void setConfigFlag(int flag, boolean value) {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800230 Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
231 synchronized (mLock) {
232 checkNotClosedLocked();
233
234 int halResult;
235 try {
236 halResult = mHwSession.setConfigFlag(flag, value);
237 } catch (RemoteException ex) {
238 throw new RuntimeException("Failed to set flag " + ConfigFlag.toString(flag), ex);
239 }
240 Convert.throwOnError("setConfigFlag", halResult);
241 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800242 }
243
244 @Override
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800245 public Map setParameters(Map parameters) {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800246 synchronized (mLock) {
247 checkNotClosedLocked();
248 return null;
249 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800250 }
251
252 @Override
253 public Map getParameters(List<String> keys) {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800254 synchronized (mLock) {
255 checkNotClosedLocked();
256 return null;
257 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800258 }
259
260 @Override
261 public boolean isAntennaConnected() {
Tomasz Wasilczykca98cde2018-01-04 12:26:40 -0800262 synchronized (mLock) {
263 checkNotClosedLocked();
264 return true;
265 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -0800266 }
267}