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