1 /*
2  * Copyright 2024 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.android.server.ranging;
18 
19 import static java.lang.Math.min;
20 
21 import com.google.common.collect.ImmutableList;
22 
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.util.BitSet;
26 import java.util.List;
27 
28 /**
29  * Utilities for {@link com.android.ranging}.
30  */
31 public class RangingUtils {
32     /**
33      * A basic synchronized state machine.
34      * @param <E> enum representing the different states of the machine.
35      */
36     public static class StateMachine<E extends Enum<E>> {
37         private E mState;
38 
StateMachine(E start)39         public StateMachine(E start) {
40             mState = start;
41         }
42 
43         /** Gets the current state */
getState()44         public synchronized E getState() {
45             return mState;
46         }
47 
48         /** Sets the current state */
setState(E state)49         public synchronized void setState(E state) {
50             mState = state;
51         }
52 
53         /**
54          * Sets the current state.
55          * @return true if the state was successfully changed, false if the current state is
56          * already {@code state}.
57          */
changeStateTo(E state)58         public synchronized boolean changeStateTo(E state) {
59             if (mState == state) {
60                 return false;
61             }
62             setState(state);
63             return true;
64         }
65 
66         /**
67          * If the current state is {@code from}, sets it to {@code to}.
68          * @return true if the current state is {@code from}, false otherwise.
69          */
transition(E from, E to)70         public synchronized boolean transition(E from, E to) {
71             if (mState != from) {
72                 return false;
73             }
74             mState = to;
75             return true;
76         }
77 
78         @Override
toString()79         public String toString() {
80             return "StateMachine{ "
81                     + mState
82                     + "}";
83         }
84     }
85 
86     public static class Conversions {
87         /**
88          * Converts a list of integers to a byte array representing a bitmap of the integers. Given
89          * integers are first shifted by the shift param amount before being placed into the bitmap
90          * (e.g int x results in bit at pos "x - shift" being set).
91          */
intListToByteArrayBitmap( List<Integer> list, int expectedSizeBytes, int shift)92         public static byte[] intListToByteArrayBitmap(
93                 List<Integer> list, int expectedSizeBytes, int shift) {
94             BitSet bitSet = new BitSet(expectedSizeBytes * 8);
95             for (int i : list) {
96                 bitSet.set(i - shift);
97             }
98             byte[] byteArray = new byte[expectedSizeBytes];
99             System.arraycopy(bitSet.toByteArray(), 0, byteArray, 0,
100                     min(expectedSizeBytes, bitSet.toByteArray().length));
101             return byteArray;
102         }
103 
104         /**
105          * Converts a byte array representing a bitmap of integers to a list of integers. The
106          * resulting integers are shifted by the shift param amount (e.g bit set at pos x results
107          * to "x + shift" int in the final list).
108          */
byteArrayToIntList(byte[] byteArray, int shift)109         public static ImmutableList<Integer> byteArrayToIntList(byte[] byteArray, int shift) {
110             ImmutableList.Builder<Integer> list = ImmutableList.builder();
111             BitSet bitSet = BitSet.valueOf(byteArray);
112             for (int i = 0; i < bitSet.length(); i++) {
113                 if (bitSet.get(i)) {
114                     list.add(i + shift);
115                 }
116             }
117             return list.build();
118         }
119 
120         /** Converts an int to a byte array of a given size, using little endianness. */
intToByteArray(int value, int expectedSizeBytes)121         public static byte[] intToByteArray(int value, int expectedSizeBytes) {
122             ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
123             buffer.putInt(value).rewind();
124             byte[] byteArray = new byte[expectedSizeBytes];
125             buffer.get(byteArray, 0, min(expectedSizeBytes, 4));
126             return byteArray;
127         }
128 
129         /** Converts the given byte array to an integer using little endianness. */
byteArrayToInt(byte[] byteArray)130         public static int byteArrayToInt(byte[] byteArray) {
131             ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
132             buffer.put(byteArray).rewind();
133             return buffer.getInt();
134         }
135     }
136 }
137