1 /* 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 17 package android.car.vms; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.car.Car; 24 import android.car.CarManagerBase; 25 import android.car.annotation.AddedInOrBefore; 26 import android.car.annotation.RequiredFeature; 27 import android.car.vms.VmsClientManager.VmsClientCallback; 28 29 import com.android.internal.annotations.GuardedBy; 30 31 import java.util.Objects; 32 import java.util.Set; 33 import java.util.concurrent.CountDownLatch; 34 import java.util.concurrent.Executor; 35 import java.util.concurrent.TimeUnit; 36 37 /** 38 * API implementation for use by Vehicle Map Service subscribers. 39 * 40 * Supports a single client callback that can subscribe and unsubscribe to different data layers. 41 * {@link #setVmsSubscriberClientCallback} must be called before any subscription operations. 42 * 43 * @deprecated Use {@link VmsClientManager} instead 44 * @hide 45 */ 46 @RequiredFeature(Car.VMS_SUBSCRIBER_SERVICE) 47 @Deprecated 48 @SystemApi 49 public final class VmsSubscriberManager extends CarManagerBase { 50 private static final long CLIENT_READY_TIMEOUT_MS = 500; 51 private static final byte[] DEFAULT_PUBLISHER_INFO = new byte[0]; 52 53 /** 54 * Callback interface for Vehicle Map Service subscribers. 55 */ 56 public interface VmsSubscriberClientCallback { 57 /** 58 * Called when a data packet is received. 59 * 60 * @param layer subscribed layer that packet was received for 61 * @param payload data packet that was received 62 */ 63 @AddedInOrBefore(majorVersion = 33) onVmsMessageReceived(@onNull VmsLayer layer, byte[] payload)64 void onVmsMessageReceived(@NonNull VmsLayer layer, byte[] payload); 65 66 /** 67 * Called when set of available data layers changes. 68 * 69 * @param availableLayers set of available data layers 70 */ 71 @AddedInOrBefore(majorVersion = 33) onLayersAvailabilityChanged(@onNull VmsAvailableLayers availableLayers)72 void onLayersAvailabilityChanged(@NonNull VmsAvailableLayers availableLayers); 73 } 74 75 private final VmsClientManager mClientManager; 76 77 private final Object mLock = new Object(); 78 79 @GuardedBy("mLock") 80 private @Nullable VmsClient mClient; 81 82 @GuardedBy("mLock") 83 private @Nullable VmsClientCallback mClientCallback; 84 85 private final VmsSubscriptionHelper mSubscriptionHelper = 86 new VmsSubscriptionHelper(this::setSubscriptions); 87 88 /** 89 * @hide 90 */ 91 @AddedInOrBefore(majorVersion = 33) wrap(Car car, @Nullable VmsClientManager clientManager)92 public static VmsSubscriberManager wrap(Car car, @Nullable VmsClientManager clientManager) { 93 if (clientManager == null) { 94 return null; 95 } 96 return new VmsSubscriberManager(car, clientManager); 97 } 98 VmsSubscriberManager(Car car, VmsClientManager clientManager)99 private VmsSubscriberManager(Car car, VmsClientManager clientManager) { 100 super(car); 101 mClientManager = clientManager; 102 } 103 104 /** 105 * Sets the subscriber client's callback, for receiving layer availability and data events. 106 * 107 * @param executor {@link Executor} to handle the callbacks 108 * @param clientCallback subscriber callback that will handle events 109 * @throws IllegalStateException if the client callback was already set 110 */ 111 @AddedInOrBefore(majorVersion = 33) setVmsSubscriberClientCallback( @onNull @allbackExecutor Executor executor, @NonNull VmsSubscriberClientCallback clientCallback)112 public void setVmsSubscriberClientCallback( 113 @NonNull @CallbackExecutor Executor executor, 114 @NonNull VmsSubscriberClientCallback clientCallback) { 115 Objects.requireNonNull(clientCallback, "clientCallback cannot be null"); 116 Objects.requireNonNull(executor, "executor cannot be null"); 117 CountDownLatch clientReady; 118 synchronized (mLock) { 119 if (mClientCallback != null) { 120 throw new IllegalStateException("Client callback is already configured."); 121 } 122 clientReady = new CountDownLatch(1); 123 mClientCallback = new SubscriberCallbackWrapper(clientCallback, clientReady); 124 // Register callback with broker service 125 mClientManager.registerVmsClientCallback(executor, mClientCallback, 126 /* legacyClient= */ true); 127 } 128 129 try { 130 // Wait for VmsClient to be available 131 if (!clientReady.await(CLIENT_READY_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 132 clearVmsSubscriberClientCallback(); 133 throw new IllegalStateException("Subscriber client is not ready"); 134 } 135 } catch (InterruptedException e) { 136 clearVmsSubscriberClientCallback(); 137 Thread.currentThread().interrupt(); 138 throw new IllegalStateException("Interrupted while waiting for subscriber client", e); 139 } 140 } 141 142 /** 143 * Clears the subscriber client's callback. 144 */ 145 @AddedInOrBefore(majorVersion = 33) clearVmsSubscriberClientCallback()146 public void clearVmsSubscriberClientCallback() { 147 synchronized (mLock) { 148 mClientManager.unregisterVmsClientCallback(mClientCallback); 149 mClient = null; 150 mClientCallback = null; 151 } 152 } 153 154 /** 155 * Gets a publisher's self-reported description information. 156 * 157 * @param publisherId publisher ID to retrieve information for 158 * @return serialized publisher information, in a vendor-specific format 159 */ 160 @NonNull 161 @AddedInOrBefore(majorVersion = 33) getPublisherInfo(int publisherId)162 public byte[] getPublisherInfo(int publisherId) { 163 byte[] publisherInfo = getVmsClient().getProviderDescription(publisherId); 164 return publisherInfo != null ? publisherInfo : DEFAULT_PUBLISHER_INFO; 165 } 166 167 /** 168 * Gets all layers available for subscription. 169 * 170 * @return available layers 171 */ 172 @NonNull 173 @AddedInOrBefore(majorVersion = 33) getAvailableLayers()174 public VmsAvailableLayers getAvailableLayers() { 175 return getVmsClient().getAvailableLayers(); 176 } 177 178 /** 179 * Subscribes to data packets for a specific layer. 180 * 181 * @param layer layer to subscribe to 182 * @throws IllegalStateException if the client callback was not set via 183 * {@link #setVmsSubscriberClientCallback}. 184 */ 185 @AddedInOrBefore(majorVersion = 33) subscribe(@onNull VmsLayer layer)186 public void subscribe(@NonNull VmsLayer layer) { 187 mSubscriptionHelper.subscribe(layer); 188 } 189 190 /** 191 * Subscribes to data packets for a specific layer from a specific publisher. 192 * 193 * @param layer layer to subscribe to 194 * @param publisherId a publisher of the layer 195 * @throws IllegalStateException if the client callback was not set via 196 * {@link #setVmsSubscriberClientCallback}. 197 */ 198 @AddedInOrBefore(majorVersion = 33) subscribe(@onNull VmsLayer layer, int publisherId)199 public void subscribe(@NonNull VmsLayer layer, int publisherId) { 200 mSubscriptionHelper.subscribe(layer, publisherId); 201 } 202 203 /** 204 * Start monitoring all messages for all layers, regardless of subscriptions. 205 */ 206 @AddedInOrBefore(majorVersion = 33) startMonitoring()207 public void startMonitoring() { 208 getVmsClient().setMonitoringEnabled(true); 209 } 210 211 /** 212 * Unsubscribes from data packets for a specific layer. 213 * 214 * @param layer layer to unsubscribe from 215 * @throws IllegalStateException if the client callback was not set via 216 * {@link #setVmsSubscriberClientCallback}. 217 */ 218 @AddedInOrBefore(majorVersion = 33) unsubscribe(@onNull VmsLayer layer)219 public void unsubscribe(@NonNull VmsLayer layer) { 220 mSubscriptionHelper.unsubscribe(layer); 221 } 222 223 /** 224 * Unsubscribes from data packets for a specific layer from a specific publisher. 225 * 226 * @param layer layer to unsubscribe from 227 * @param publisherId a publisher of the layer 228 * @throws IllegalStateException if the client callback was not set via 229 * {@link #setVmsSubscriberClientCallback}. 230 */ 231 @AddedInOrBefore(majorVersion = 33) unsubscribe(@onNull VmsLayer layer, int publisherId)232 public void unsubscribe(@NonNull VmsLayer layer, int publisherId) { 233 mSubscriptionHelper.unsubscribe(layer, publisherId); 234 } 235 236 /** 237 * Stop monitoring. Only receive messages for layers which have been subscribed to." 238 */ 239 @AddedInOrBefore(majorVersion = 33) stopMonitoring()240 public void stopMonitoring() { 241 getVmsClient().setMonitoringEnabled(false); 242 } 243 244 /** 245 * @hide 246 */ 247 @Override 248 @AddedInOrBefore(majorVersion = 33) onCarDisconnected()249 public void onCarDisconnected() {} 250 setSubscriptions(Set<VmsAssociatedLayer> subscriptions)251 private void setSubscriptions(Set<VmsAssociatedLayer> subscriptions) { 252 getVmsClient().setSubscriptions(subscriptions); 253 } 254 getVmsClient()255 private VmsClient getVmsClient() { 256 synchronized (mLock) { 257 if (mClient == null) { 258 throw new IllegalStateException("VMS client connection is not ready"); 259 } 260 return mClient; 261 } 262 } 263 264 private final class SubscriberCallbackWrapper implements VmsClientCallback { 265 private final VmsSubscriberClientCallback mCallback; 266 private final CountDownLatch mClientReady; 267 SubscriberCallbackWrapper(VmsSubscriberClientCallback callback, CountDownLatch clientReady)268 SubscriberCallbackWrapper(VmsSubscriberClientCallback callback, 269 CountDownLatch clientReady) { 270 mCallback = callback; 271 mClientReady = clientReady; 272 } 273 274 @Override onClientConnected(VmsClient client)275 public void onClientConnected(VmsClient client) { 276 synchronized (mLock) { 277 mClient = client; 278 } 279 mClientReady.countDown(); 280 } 281 282 @Override onSubscriptionStateChanged(VmsSubscriptionState subscriptionState)283 public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) { 284 // Ignored 285 } 286 287 @Override onLayerAvailabilityChanged(VmsAvailableLayers availableLayers)288 public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) { 289 mCallback.onLayersAvailabilityChanged(availableLayers); 290 } 291 292 @Override onPacketReceived(int providerId, VmsLayer layer, byte[] packet)293 public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) { 294 mCallback.onVmsMessageReceived(layer, packet); 295 } 296 } 297 } 298