1 /*
2  * Copyright (C) 2023 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 package com.android.server.remoteauth.ranging;
17 
18 import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UNKNOWN;
19 
20 import android.annotation.NonNull;
21 
22 import androidx.annotation.IntDef;
23 
24 import com.android.internal.util.Preconditions;
25 import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 
30 /**
31  * The set of parameters to create a ranging session.
32  *
33  * <p>Required parameters must be provided, else {@link Builder} will throw an exception. The
34  * optional parameters only need to be provided if the functionality is necessary to the session,
35  * see the setter functions of the {@link Builder} for detailed info of each parameter.
36  */
37 public class SessionParameters {
38 
39     /** Ranging device role. */
40     @Retention(RetentionPolicy.SOURCE)
41     @IntDef(
42             value = {
43                 DEVICE_ROLE_UNKNOWN,
44                 DEVICE_ROLE_INITIATOR,
45                 DEVICE_ROLE_RESPONDER,
46             })
47     public @interface DeviceRole {}
48 
49     /** Unknown device role. */
50     public static final int DEVICE_ROLE_UNKNOWN = 0x0;
51 
52     /** Device that initiates the ranging. */
53     public static final int DEVICE_ROLE_INITIATOR = 0x1;
54 
55     /** Device that responds to ranging. */
56     public static final int DEVICE_ROLE_RESPONDER = 0x2;
57 
58     /* Required parameters */
59     private final String mDeviceId;
60     @RangingMethod private final int mRangingMethod;
61     @DeviceRole private final int mDeviceRole;
62 
63     /* Optional parameters */
64     private final float mLowerProximityBoundaryM;
65     private final float mUpperProximityBoundaryM;
66     private final boolean mAutoDeriveParams;
67     private final byte[] mBaseKey;
68     private final byte[] mSyncData;
69 
getDeviceId()70     public String getDeviceId() {
71         return mDeviceId;
72     }
73 
74     @RangingMethod
getRangingMethod()75     public int getRangingMethod() {
76         return mRangingMethod;
77     }
78 
79     @DeviceRole
getDeviceRole()80     public int getDeviceRole() {
81         return mDeviceRole;
82     }
83 
getLowerProximityBoundaryM()84     public float getLowerProximityBoundaryM() {
85         return mLowerProximityBoundaryM;
86     }
87 
getUpperProximityBoundaryM()88     public float getUpperProximityBoundaryM() {
89         return mUpperProximityBoundaryM;
90     }
91 
getAutoDeriveParams()92     public boolean getAutoDeriveParams() {
93         return mAutoDeriveParams;
94     }
95 
getBaseKey()96     public byte[] getBaseKey() {
97         return mBaseKey;
98     }
99 
getSyncData()100     public byte[] getSyncData() {
101         return mSyncData;
102     }
103 
SessionParameters( String deviceId, @RangingMethod int rangingMethod, @DeviceRole int deviceRole, float lowerProximityBoundaryM, float upperProximityBoundaryM, boolean autoDeriveParams, byte[] baseKey, byte[] syncData)104     private SessionParameters(
105             String deviceId,
106             @RangingMethod int rangingMethod,
107             @DeviceRole int deviceRole,
108             float lowerProximityBoundaryM,
109             float upperProximityBoundaryM,
110             boolean autoDeriveParams,
111             byte[] baseKey,
112             byte[] syncData) {
113         mDeviceId = deviceId;
114         mRangingMethod = rangingMethod;
115         mDeviceRole = deviceRole;
116         mLowerProximityBoundaryM = lowerProximityBoundaryM;
117         mUpperProximityBoundaryM = upperProximityBoundaryM;
118         mAutoDeriveParams = autoDeriveParams;
119         mBaseKey = baseKey;
120         mSyncData = syncData;
121     }
122 
123     /** Builder class for {@link SessionParameters}. */
124     public static final class Builder {
125         private String mDeviceId = new String("");
126         @RangingMethod private int mRangingMethod = RANGING_METHOD_UNKNOWN;
127         @DeviceRole private int mDeviceRole = DEVICE_ROLE_UNKNOWN;
128         private float mLowerProximityBoundaryM;
129         private float mUpperProximityBoundaryM;
130         private boolean mAutoDeriveParams = false;
131         private byte[] mBaseKey = new byte[] {};
132         private byte[] mSyncData = new byte[] {};
133 
134         /**
135          * Sets the device id.
136          *
137          * <p>This is used as the identity included in the {@link SessionInfo} for all {@link
138          * RangingCallback}s.
139          */
setDeviceId(@onNull String deviceId)140         public Builder setDeviceId(@NonNull String deviceId) {
141             mDeviceId = deviceId;
142             return this;
143         }
144 
145         /**
146          * Sets the {@link RangingMethod} to be used for the {@link RangingSession}.
147          *
148          * <p>Note: The ranging method should be ones in the list return by {@link
149          * RangingCapabilities#getSupportedRangingMethods};
150          */
setRangingMethod(@angingMethod int rangingMethod)151         public Builder setRangingMethod(@RangingMethod int rangingMethod) {
152             mRangingMethod = rangingMethod;
153             return this;
154         }
155 
156         /** Sets the {@link DeviceRole} to be used for the {@link RangingSession}. */
setDeviceRole(@eviceRole int deviceRole)157         public Builder setDeviceRole(@DeviceRole int deviceRole) {
158             mDeviceRole = deviceRole;
159             return this;
160         }
161 
162         /**
163          * Sets the lower proximity boundary in meters, must be greater than or equals to zero.
164          *
165          * <p>This value is used to compute the {@link ProximityState} = {@link
166          * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
167          * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
168          */
setLowerProximityBoundaryM(float lowerProximityBoundaryM)169         public Builder setLowerProximityBoundaryM(float lowerProximityBoundaryM) {
170             mLowerProximityBoundaryM = lowerProximityBoundaryM;
171             return this;
172         }
173 
174         /**
175          * Sets the upper proximity boundary in meters, must be greater than or equals to
176          * lowerProximityBoundaryM.
177          *
178          * <p>This value is used to compute the {@link ProximityState} = {@link
179          * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
180          * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
181          */
setUpperProximityBoundaryM(float upperProximityBoundaryM)182         public Builder setUpperProximityBoundaryM(float upperProximityBoundaryM) {
183             mUpperProximityBoundaryM = upperProximityBoundaryM;
184             return this;
185         }
186 
187         /**
188          * Sets the auto derive ranging parameters flag. Defaults to false.
189          *
190          * <p>This enables the {@link RangingSession} to automatically derive all possible {@link
191          * RangingParameters} at each {@link RangingSession#start} using the provided {@link
192          * #setBaseKey} and {@link #setSyncData}, which shall be securely shared between the ranging
193          * devices out of band.
194          */
setAutoDeriveParams(boolean autoDeriveParams)195         public Builder setAutoDeriveParams(boolean autoDeriveParams) {
196             mAutoDeriveParams = autoDeriveParams;
197             return this;
198         }
199 
200         /**
201          * Sets the base key. Only required if {@link #setAutoDeriveParams} is set to true.
202          *
203          * @param baseKey baseKey must be 16 or 32 bytes.
204          * @throws NullPointerException if baseKey is null
205          */
setBaseKey(@onNull byte[] baseKey)206         public Builder setBaseKey(@NonNull byte[] baseKey) {
207             Preconditions.checkNotNull(baseKey);
208             mBaseKey = baseKey;
209             return this;
210         }
211 
212         /**
213          * Sets the sync data. Only required if {@link #setAutoDeriveParams} is set to true.
214          *
215          * @param syncData syncData must be 16 bytes.
216          * @throws NullPointerException if syncData is null
217          */
setSyncData(@onNull byte[] syncData)218         public Builder setSyncData(@NonNull byte[] syncData) {
219             Preconditions.checkNotNull(syncData);
220             mSyncData = syncData;
221             return this;
222         }
223 
224         /**
225          * Builds {@link SessionParameters}.
226          *
227          * @throws IllegalArgumentException if any parameter is invalid.
228          */
build()229         public SessionParameters build() {
230             Preconditions.checkArgument(!mDeviceId.isEmpty(), "deviceId must not be empty.");
231             Preconditions.checkArgument(
232                     mRangingMethod != RANGING_METHOD_UNKNOWN, "Unknown rangingMethod");
233             Preconditions.checkArgument(mDeviceRole != DEVICE_ROLE_UNKNOWN, "Unknown deviceRole");
234             Preconditions.checkArgument(
235                     mLowerProximityBoundaryM >= 0,
236                     "Negative lowerProximityBoundaryM: " + mLowerProximityBoundaryM);
237             Preconditions.checkArgument(
238                     mLowerProximityBoundaryM <= mUpperProximityBoundaryM,
239                     "lowerProximityBoundaryM is greater than upperProximityBoundaryM: "
240                             + mLowerProximityBoundaryM
241                             + " > "
242                             + mUpperProximityBoundaryM);
243             // If mAutoDeriveParams is false, mBaseKey and mSyncData will not be used.
244             if (mAutoDeriveParams) {
245                 Preconditions.checkArgument(
246                         mBaseKey.length == 16 || mBaseKey.length == 32,
247                         "Invalid baseKey length: " + mBaseKey.length);
248                 Preconditions.checkArgument(
249                         mSyncData.length == 16, "Invalid syncData length: " + mSyncData.length);
250             }
251 
252             return new SessionParameters(
253                     mDeviceId,
254                     mRangingMethod,
255                     mDeviceRole,
256                     mLowerProximityBoundaryM,
257                     mUpperProximityBoundaryM,
258                     mAutoDeriveParams,
259                     mBaseKey,
260                     mSyncData);
261         }
262     }
263 }
264