• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.NonNull;
20 import android.car.annotation.AddedInOrBefore;
21 import android.util.ArrayMap;
22 import android.util.ArraySet;
23 import android.util.SparseBooleanArray;
24 
25 import com.android.internal.annotations.GuardedBy;
26 
27 import java.util.Collections;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.Set;
31 import java.util.function.Consumer;
32 import java.util.stream.Collectors;
33 import java.util.stream.Stream;
34 
35 /**
36  * Internal utility for computing subscription updates.
37  *
38  * @hide
39  */
40 public final class VmsSubscriptionHelper {
41     private final Consumer<Set<VmsAssociatedLayer>> mUpdateHandler;
42 
43     private final Object mLock = new Object();
44 
45     @GuardedBy("mLock")
46     private final Set<VmsLayer> mLayerSubscriptions = new ArraySet<>();
47 
48     @GuardedBy("mLock")
49     private final Map<VmsLayer, SparseBooleanArray> mPublisherSubscriptions = new ArrayMap<>();
50 
51     @GuardedBy("mLock")
52     private boolean mPendingUpdate;
53 
54     /**
55      * Constructor for subscription helper.
56      *
57      * @param updateHandler Consumer of subscription updates.
58      */
VmsSubscriptionHelper(@onNull Consumer<Set<VmsAssociatedLayer>> updateHandler)59     public VmsSubscriptionHelper(@NonNull Consumer<Set<VmsAssociatedLayer>> updateHandler) {
60         mUpdateHandler = Objects.requireNonNull(updateHandler, "updateHandler cannot be null");
61     }
62 
63     /**
64      * Adds a subscription to a layer.
65      */
66     @AddedInOrBefore(majorVersion = 33)
subscribe(@onNull VmsLayer layer)67     public void subscribe(@NonNull VmsLayer layer) {
68         Objects.requireNonNull(layer, "layer cannot be null");
69         synchronized (mLock) {
70             if (mLayerSubscriptions.add(layer)) {
71                 mPendingUpdate = true;
72             }
73             publishSubscriptionUpdate();
74         }
75     }
76 
77     /**
78      * Adds a subscription to a specific provider of a layer.
79      */
80     @AddedInOrBefore(majorVersion = 33)
subscribe(@onNull VmsLayer layer, int providerId)81     public void subscribe(@NonNull VmsLayer layer, int providerId) {
82         Objects.requireNonNull(layer, "layer cannot be null");
83         synchronized (mLock) {
84             SparseBooleanArray providerIds = mPublisherSubscriptions.computeIfAbsent(layer,
85                     ignored -> new SparseBooleanArray());
86             if (!providerIds.get(providerId)) {
87                 providerIds.put(providerId, true);
88                 mPendingUpdate = true;
89             }
90             publishSubscriptionUpdate();
91         }
92     }
93 
94     /**
95      * Removes a subscription to a layer.
96      */
97     @AddedInOrBefore(majorVersion = 33)
unsubscribe(@onNull VmsLayer layer)98     public void unsubscribe(@NonNull VmsLayer layer) {
99         Objects.requireNonNull(layer, "layer cannot be null");
100         synchronized (mLock) {
101             if (mLayerSubscriptions.remove(layer)) {
102                 mPendingUpdate = true;
103             }
104             publishSubscriptionUpdate();
105         }
106     }
107 
108     /**
109      * Removes a subscription to the specific provider of a layer.
110      */
111     @AddedInOrBefore(majorVersion = 33)
unsubscribe(@onNull VmsLayer layer, int providerId)112     public void unsubscribe(@NonNull VmsLayer layer, int providerId) {
113         Objects.requireNonNull(layer, "layer cannot be null");
114         synchronized (mLock) {
115             SparseBooleanArray providerIds = mPublisherSubscriptions.get(layer);
116             if (providerIds != null && providerIds.get(providerId)) {
117                 providerIds.delete(providerId);
118                 if (providerIds.size() == 0) {
119                     mPublisherSubscriptions.remove(layer);
120                 }
121                 mPendingUpdate = true;
122             }
123             publishSubscriptionUpdate();
124         }
125     }
126 
127     /**
128      * Gets the current set of subscriptions.
129      */
130     @NonNull
131     @AddedInOrBefore(majorVersion = 33)
getSubscriptions()132     public Set<VmsAssociatedLayer> getSubscriptions() {
133         return Stream.concat(
134                 mLayerSubscriptions.stream().map(
135                         layer -> new VmsAssociatedLayer(layer, Collections.emptySet())),
136                 mPublisherSubscriptions.entrySet().stream()
137                         .filter(entry -> !mLayerSubscriptions.contains(entry.getKey()))
138                         .map(VmsSubscriptionHelper::toAssociatedLayer))
139                 .collect(Collectors.toSet());
140     }
141 
publishSubscriptionUpdate()142     private void publishSubscriptionUpdate() {
143         synchronized (mLock) {
144             if (mPendingUpdate) {
145                 mUpdateHandler.accept(getSubscriptions());
146             }
147             mPendingUpdate = false;
148         }
149     }
150 
toAssociatedLayer( Map.Entry<VmsLayer, SparseBooleanArray> entry)151     private static VmsAssociatedLayer toAssociatedLayer(
152             Map.Entry<VmsLayer, SparseBooleanArray> entry) {
153         SparseBooleanArray providerIdArray = entry.getValue();
154         Set<Integer> providerIds = new ArraySet<>(providerIdArray.size());
155         for (int i = 0; i < providerIdArray.size(); i++) {
156             providerIds.add(providerIdArray.keyAt(i));
157         }
158         return new VmsAssociatedLayer(entry.getKey(), providerIds);
159     }
160 }
161