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