• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 com.google.uwb.support.ccc;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.os.Build.VERSION_CODES;
22 import android.os.PersistableBundle;
23 import android.uwb.UwbManager;
24 
25 import androidx.annotation.IntRange;
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.RequiresApi;
29 
30 import com.google.uwb.support.base.RequiredParam;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * Defines parameters for CCC capability reports
38  *
39  * <p>This is returned as a bundle from the service API {@link UwbManager#getSpecificationInfo}.
40  */
41 @RequiresApi(VERSION_CODES.LOLLIPOP)
42 public class CccSpecificationParams extends CccParams {
43     private static final int BUNDLE_VERSION_1 = 1;
44     private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1;
45 
46     private final List<CccProtocolVersion> mProtocolVersions;
47     @UwbConfig private final List<Integer> mUwbConfigs;
48     private final List<CccPulseShapeCombo> mPulseShapeCombos;
49     private final int mRanMultiplier;
50     @ChapsPerSlot private final List<Integer> mChapsPerSlot;
51     @SyncCodeIndex private final List<Integer> mSyncCodes;
52     @Channel private final List<Integer> mChannels;
53     @HoppingConfigMode private final List<Integer> mHoppingConfigModes;
54     @HoppingSequence private final List<Integer> mHoppingSequences;
55 
56     private static final String KEY_PROTOCOL_VERSIONS = "protocol_versions";
57     private static final String KEY_UWB_CONFIGS = "uwb_configs";
58     private static final String KEY_PULSE_SHAPE_COMBOS = "pulse_shape_combos";
59     private static final String KEY_RAN_MULTIPLIER = "ran_multiplier";
60     private static final String KEY_CHAPS_PER_SLOTS = "chaps_per_slots";
61     private static final String KEY_SYNC_CODES = "sync_codes";
62     private static final String KEY_CHANNELS = "channels";
63     private static final String KEY_HOPPING_CONFIGS = "hopping_config_modes";
64     private static final String KEY_HOPPING_SEQUENCES = "hopping_sequences";
65 
CccSpecificationParams( List<CccProtocolVersion> protocolVersions, @UwbConfig List<Integer> uwbConfigs, List<CccPulseShapeCombo> pulseShapeCombos, int ranMultiplier, @ChapsPerSlot List<Integer> chapsPerSlot, @SyncCodeIndex List<Integer> syncCodes, @Channel List<Integer> channels, @HoppingConfigMode List<Integer> hoppingConfigModes, @HoppingSequence List<Integer> hoppingSequences)66     private CccSpecificationParams(
67             List<CccProtocolVersion> protocolVersions,
68             @UwbConfig List<Integer> uwbConfigs,
69             List<CccPulseShapeCombo> pulseShapeCombos,
70             int ranMultiplier,
71             @ChapsPerSlot List<Integer> chapsPerSlot,
72             @SyncCodeIndex List<Integer> syncCodes,
73             @Channel List<Integer> channels,
74             @HoppingConfigMode List<Integer> hoppingConfigModes,
75             @HoppingSequence List<Integer> hoppingSequences) {
76         mProtocolVersions = protocolVersions;
77         mUwbConfigs = uwbConfigs;
78         mPulseShapeCombos = pulseShapeCombos;
79         mRanMultiplier = ranMultiplier;
80         mChapsPerSlot = chapsPerSlot;
81         mSyncCodes = syncCodes;
82         mChannels = channels;
83         mHoppingConfigModes = hoppingConfigModes;
84         mHoppingSequences = hoppingSequences;
85     }
86 
87     @Override
getBundleVersion()88     protected int getBundleVersion() {
89         return BUNDLE_VERSION_CURRENT;
90     }
91 
92     @Override
toBundle()93     public PersistableBundle toBundle() {
94         PersistableBundle bundle = super.toBundle();
95         String[] protocols = new String[mProtocolVersions.size()];
96         for (int i = 0; i < protocols.length; i++) {
97             protocols[i] = mProtocolVersions.get(i).toString();
98         }
99         String[] pulseShapeCombos = new String[mPulseShapeCombos.size()];
100         for (int i = 0; i < pulseShapeCombos.length; i++) {
101             pulseShapeCombos[i] = mPulseShapeCombos.get(i).toString();
102         }
103         bundle.putStringArray(KEY_PROTOCOL_VERSIONS, protocols);
104         bundle.putIntArray(KEY_UWB_CONFIGS, toIntArray(mUwbConfigs));
105         bundle.putStringArray(KEY_PULSE_SHAPE_COMBOS, pulseShapeCombos);
106         bundle.putInt(KEY_RAN_MULTIPLIER, mRanMultiplier);
107         bundle.putIntArray(KEY_CHAPS_PER_SLOTS, toIntArray(mChapsPerSlot));
108         bundle.putIntArray(KEY_SYNC_CODES, toIntArray(mSyncCodes));
109         bundle.putIntArray(KEY_CHANNELS, toIntArray(mChannels));
110         bundle.putIntArray(KEY_HOPPING_CONFIGS, toIntArray(mHoppingConfigModes));
111         bundle.putIntArray(KEY_HOPPING_SEQUENCES, toIntArray(mHoppingSequences));
112         return bundle;
113     }
114 
fromBundle(PersistableBundle bundle)115     public static CccSpecificationParams fromBundle(PersistableBundle bundle) {
116         if (!isCorrectProtocol(bundle)) {
117             throw new IllegalArgumentException("Invalid protocol");
118         }
119 
120         switch (getBundleVersion(bundle)) {
121             case BUNDLE_VERSION_1:
122                 return parseVersion1(bundle);
123 
124             default:
125                 throw new IllegalArgumentException("Invalid bundle version");
126         }
127     }
128 
parseVersion1(PersistableBundle bundle)129     private static CccSpecificationParams parseVersion1(PersistableBundle bundle) {
130         CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder();
131         String[] protocolStrings = checkNotNull(bundle.getStringArray(KEY_PROTOCOL_VERSIONS));
132         for (String protocol : protocolStrings) {
133             builder.addProtocolVersion(CccProtocolVersion.fromString(protocol));
134         }
135 
136         for (int config : checkNotNull(bundle.getIntArray(KEY_UWB_CONFIGS))) {
137             builder.addUwbConfig(config);
138         }
139 
140         String[] pulseShapeComboStrings =
141                 checkNotNull(bundle.getStringArray(KEY_PULSE_SHAPE_COMBOS));
142         for (String pulseShapeCombo : pulseShapeComboStrings) {
143             builder.addPulseShapeCombo(CccPulseShapeCombo.fromString(pulseShapeCombo));
144         }
145 
146         builder.setRanMultiplier(bundle.getInt(KEY_RAN_MULTIPLIER));
147 
148         for (int chapsPerSlot : checkNotNull(bundle.getIntArray(KEY_CHAPS_PER_SLOTS))) {
149             builder.addChapsPerSlot(chapsPerSlot);
150         }
151 
152         for (int syncCode : checkNotNull(bundle.getIntArray(KEY_SYNC_CODES))) {
153             builder.addSyncCode(syncCode);
154         }
155 
156         for (int channel : checkNotNull(bundle.getIntArray(KEY_CHANNELS))) {
157             builder.addChannel(channel);
158         }
159 
160         for (int hoppingConfig : checkNotNull(bundle.getIntArray(KEY_HOPPING_CONFIGS))) {
161             builder.addHoppingConfigMode(hoppingConfig);
162         }
163 
164         for (int hoppingSequence : checkNotNull(bundle.getIntArray(KEY_HOPPING_SEQUENCES))) {
165             builder.addHoppingSequence(hoppingSequence);
166         }
167 
168         return builder.build();
169     }
170 
toIntArray(List<Integer> data)171     private int[] toIntArray(List<Integer> data) {
172         int[] res = new int[data.size()];
173         for (int i = 0; i < data.size(); i++) {
174             res[i] = data.get(i);
175         }
176         return res;
177     }
178 
getProtocolVersions()179     public List<CccProtocolVersion> getProtocolVersions() {
180         return mProtocolVersions;
181     }
182 
183     @UwbConfig
getUwbConfigs()184     public List<Integer> getUwbConfigs() {
185         return mUwbConfigs;
186     }
187 
getPulseShapeCombos()188     public List<CccPulseShapeCombo> getPulseShapeCombos() {
189         return mPulseShapeCombos;
190     }
191 
192     @IntRange(from = 0, to = 255)
getRanMultiplier()193     public int getRanMultiplier() {
194         return mRanMultiplier;
195     }
196 
197     @ChapsPerSlot
getChapsPerSlot()198     public List<Integer> getChapsPerSlot() {
199         return mChapsPerSlot;
200     }
201 
202     @SyncCodeIndex
getSyncCodes()203     public List<Integer> getSyncCodes() {
204         return mSyncCodes;
205     }
206 
207     @Channel
getChannels()208     public List<Integer> getChannels() {
209         return mChannels;
210     }
211 
212     @HoppingSequence
getHoppingSequences()213     public List<Integer> getHoppingSequences() {
214         return mHoppingSequences;
215     }
216 
217     @HoppingConfigMode
getHoppingConfigModes()218     public List<Integer> getHoppingConfigModes() {
219         return mHoppingConfigModes;
220     }
221 
222     @Override
equals(@ullable Object other)223     public boolean equals(@Nullable Object other) {
224         if (other instanceof CccSpecificationParams) {
225             CccSpecificationParams otherSpecificationParams = (CccSpecificationParams) other;
226             return otherSpecificationParams.mProtocolVersions.equals(mProtocolVersions)
227                 && otherSpecificationParams.mPulseShapeCombos.equals(mPulseShapeCombos)
228                 && otherSpecificationParams.mUwbConfigs.equals(mUwbConfigs)
229                 && otherSpecificationParams.mRanMultiplier == mRanMultiplier
230                 && otherSpecificationParams.mChapsPerSlot.equals(mChapsPerSlot)
231                 && otherSpecificationParams.mSyncCodes.equals(mSyncCodes)
232                 && otherSpecificationParams.mChannels.equals(mChannels)
233                 && otherSpecificationParams.mHoppingConfigModes.equals(mHoppingConfigModes)
234                 && otherSpecificationParams.mHoppingSequences.equals(mHoppingSequences);
235         }
236         return false;
237     }
238 
239     @Override
hashCode()240     public int hashCode() {
241         return Arrays.hashCode(
242             new int[] {
243                 mProtocolVersions.hashCode(),
244                 mPulseShapeCombos.hashCode(),
245                 mUwbConfigs.hashCode(),
246                 mRanMultiplier,
247                 mChapsPerSlot.hashCode(),
248                 mSyncCodes.hashCode(),
249                 mChannels.hashCode(),
250                 mHoppingConfigModes.hashCode(),
251                 mHoppingSequences.hashCode()
252             });
253     }
254 
255     /** Builder */
256     public static class Builder {
257         private List<CccProtocolVersion> mProtocolVersions = new ArrayList<>();
258         @UwbConfig private List<Integer> mUwbConfigs = new ArrayList<>();
259         private List<CccPulseShapeCombo> mPulseShapeCombos = new ArrayList<>();
260         private RequiredParam<Integer> mRanMultiplier = new RequiredParam<>();
261         @ChapsPerSlot private List<Integer> mChapsPerSlot = new ArrayList<>();
262         @SyncCodeIndex private List<Integer> mSyncCodes = new ArrayList<>();
263         @Channel private List<Integer> mChannels = new ArrayList<>();
264         @HoppingSequence private List<Integer> mHoppingSequences = new ArrayList<>();
265         @HoppingConfigMode private List<Integer> mHoppingConfigModes = new ArrayList<>();
266 
addProtocolVersion(@onNull CccProtocolVersion version)267         public Builder addProtocolVersion(@NonNull CccProtocolVersion version) {
268             mProtocolVersions.add(version);
269             return this;
270         }
271 
addUwbConfig(@wbConfig int uwbConfig)272         public Builder addUwbConfig(@UwbConfig int uwbConfig) {
273             mUwbConfigs.add(uwbConfig);
274             return this;
275         }
276 
addPulseShapeCombo(CccPulseShapeCombo pulseShapeCombo)277         public Builder addPulseShapeCombo(CccPulseShapeCombo pulseShapeCombo) {
278             mPulseShapeCombos.add(pulseShapeCombo);
279             return this;
280         }
281 
setRanMultiplier(int ranMultiplier)282         public Builder setRanMultiplier(int ranMultiplier) {
283             if (ranMultiplier < 0 || ranMultiplier > 255) {
284                 throw new IllegalArgumentException("Invalid RAN Multiplier");
285             }
286             mRanMultiplier.set(ranMultiplier);
287             return this;
288         }
289 
addChapsPerSlot(@hapsPerSlot int chapsPerSlot)290         public Builder addChapsPerSlot(@ChapsPerSlot int chapsPerSlot) {
291             mChapsPerSlot.add(chapsPerSlot);
292             return this;
293         }
294 
addSyncCode(@yncCodeIndex int syncCode)295         public Builder addSyncCode(@SyncCodeIndex int syncCode) {
296             mSyncCodes.add(syncCode);
297             return this;
298         }
299 
addChannel(@hannel int channel)300         public Builder addChannel(@Channel int channel) {
301             mChannels.add(channel);
302             return this;
303         }
304 
addHoppingConfigMode(@oppingConfigMode int hoppingConfigMode)305         public Builder addHoppingConfigMode(@HoppingConfigMode int hoppingConfigMode) {
306             mHoppingConfigModes.add(hoppingConfigMode);
307             return this;
308         }
309 
addHoppingSequence(@oppingSequence int hoppingSequence)310         public Builder addHoppingSequence(@HoppingSequence int hoppingSequence) {
311             mHoppingSequences.add(hoppingSequence);
312             return this;
313         }
314 
build()315         public CccSpecificationParams build() {
316             if (mProtocolVersions.size() == 0) {
317                 throw new IllegalStateException("No protocol versions set");
318             }
319 
320             if (mUwbConfigs.size() == 0) {
321                 throw new IllegalStateException("No UWB Configs set");
322             }
323 
324             if (mPulseShapeCombos.size() == 0) {
325                 throw new IllegalStateException("No Pulse Shape Combos set");
326             }
327 
328             if (mChapsPerSlot.size() == 0) {
329                 throw new IllegalStateException("No Slot Durations set");
330             }
331 
332             if (mSyncCodes.size() == 0) {
333                 throw new IllegalStateException("No Sync Codes set");
334             }
335 
336             if (mChannels.size() == 0) {
337                 throw new IllegalStateException("No channels set");
338             }
339 
340             if (mHoppingConfigModes.size() == 0) {
341                 throw new IllegalStateException("No hopping config modes set");
342             }
343 
344             if (mHoppingSequences.size() == 0) {
345                 throw new IllegalStateException("No hopping sequences set");
346             }
347 
348             return new CccSpecificationParams(
349                     mProtocolVersions,
350                     mUwbConfigs,
351                     mPulseShapeCombos,
352                     mRanMultiplier.get(),
353                     mChapsPerSlot,
354                     mSyncCodes,
355                     mChannels,
356                     mHoppingConfigModes,
357                     mHoppingSequences);
358         }
359     }
360 }
361