blob: 50f032d659b70d86f23fd1b1266578665d3a33dd [file] [log] [blame]
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -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.annotation.Nullable;
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080021import android.graphics.Bitmap;
22import android.graphics.BitmapFactory;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080023import android.hardware.radio.ITuner;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080024import android.hardware.radio.RadioManager;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080025import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -080026import android.hardware.broadcastradio.V2_0.Announcement;
27import android.hardware.broadcastradio.V2_0.IAnnouncementListener;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080028import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -080029import android.hardware.broadcastradio.V2_0.ICloseHandle;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080030import android.hardware.broadcastradio.V2_0.ITunerSession;
31import android.hardware.broadcastradio.V2_0.Result;
32import android.os.ParcelableException;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080033import android.os.RemoteException;
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080034import android.util.MutableInt;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080035import android.util.Slog;
36
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -080037import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.List;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080040import java.util.Objects;
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -080041import java.util.stream.Collectors;
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080042
43class RadioModule {
44 private static final String TAG = "BcRadio2Srv.module";
45
46 @NonNull private final IBroadcastRadio mService;
47 @NonNull public final RadioManager.ModuleProperties mProperties;
48
49 private RadioModule(@NonNull IBroadcastRadio service,
50 @NonNull RadioManager.ModuleProperties properties) {
51 mProperties = Objects.requireNonNull(properties);
52 mService = Objects.requireNonNull(service);
53 }
54
55 public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
56 try {
57 IBroadcastRadio service = IBroadcastRadio.getService();
58 if (service == null) return null;
59
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080060 Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
61 service.getAmFmRegionConfig(false, (int result, AmFmRegionConfig config) -> {
62 if (result == Result.OK) amfmConfig.value = config;
63 });
64
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080065 RadioManager.ModuleProperties prop =
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080066 Convert.propertiesFromHal(idx, fqName, service.getProperties(), amfmConfig.value);
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -080067
68 return new RadioModule(service, prop);
69 } catch (RemoteException ex) {
70 Slog.e(TAG, "failed to load module " + fqName, ex);
71 return null;
72 }
73 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080074
Tomasz Wasilczyk436128f2018-01-08 16:46:09 -080075 public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb)
76 throws RemoteException {
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080077 TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb));
78 Mutable<ITunerSession> hwSession = new Mutable<>();
79 MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
80
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080081 synchronized (mService) {
82 mService.openSession(cb, (result, session) -> {
83 hwSession.value = session;
84 halResult.value = result;
85 });
86 }
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080087
88 Convert.throwOnError("openSession", halResult.value);
89 Objects.requireNonNull(hwSession.value);
90
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -080091 return new TunerSession(this, hwSession.value, cb);
Tomasz Wasilczykf58305d2017-12-28 14:03:15 -080092 }
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -080093
94 public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
95 @NonNull android.hardware.radio.IAnnouncementListener listener) throws RemoteException {
96 ArrayList<Byte> enabledList = new ArrayList<>();
97 for (int type : enabledTypes) {
98 enabledList.add((byte)type);
99 }
100
101 MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
102 Mutable<ICloseHandle> hwCloseHandle = new Mutable<>();
103 IAnnouncementListener hwListener = new IAnnouncementListener.Stub() {
104 public void onListUpdated(ArrayList<Announcement> hwAnnouncements)
105 throws RemoteException {
106 listener.onListUpdated(hwAnnouncements.stream().
107 map(a -> Convert.announcementFromHal(a)).collect(Collectors.toList()));
108 }
109 };
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800110
111 synchronized (mService) {
112 mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
113 halResult.value = result;
114 hwCloseHandle.value = closeHnd;
115 });
116 }
Tomasz Wasilczykf151a7b2018-01-11 16:03:46 -0800117 Convert.throwOnError("addAnnouncementListener", halResult.value);
118
119 return new android.hardware.radio.ICloseHandle.Stub() {
120 public void close() {
121 try {
122 hwCloseHandle.value.close();
123 } catch (RemoteException ex) {
124 Slog.e(TAG, "Failed closing announcement listener", ex);
125 }
126 }
127 };
128 }
Tomasz Wasilczyk3b4465e2018-01-14 21:47:44 -0800129
130 Bitmap getImage(int id) {
131 if (id == 0) throw new IllegalArgumentException("Image ID is missing");
132
133 byte[] rawImage;
134 synchronized (mService) {
135 List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
136 rawImage = new byte[rawList.size()];
137 for (int i = 0; i < rawList.size(); i++) {
138 rawImage[i] = rawList.get(i);
139 }
140 }
141
142 if (rawImage == null || rawImage.length == 0) return null;
143
144 return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
145 }
Tomasz Wasilczykd65b3ca2017-12-13 08:26:25 -0800146}