1 /* 2 * Copyright 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.uwb; 18 19 import android.Manifest.permission; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SuppressLint; 25 import android.annotation.SystemApi; 26 import android.annotation.SystemService; 27 import android.content.Context; 28 import android.os.CancellationSignal; 29 import android.os.IBinder; 30 import android.os.PersistableBundle; 31 import android.os.RemoteException; 32 import android.os.ServiceManager; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.concurrent.Executor; 37 38 /** 39 * This class provides a way to perform Ultra Wideband (UWB) operations such as querying the 40 * device's capabilities and determining the distance and angle between the local device and a 41 * remote device. 42 * 43 * <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>. 44 * 45 * @hide 46 */ 47 @SystemApi 48 @SystemService(Context.UWB_SERVICE) 49 public final class UwbManager { 50 private static final String SERVICE_NAME = Context.UWB_SERVICE; 51 52 private final Context mContext; 53 private final IUwbAdapter mUwbAdapter; 54 private final AdapterStateListener mAdapterStateListener; 55 private final RangingManager mRangingManager; 56 57 /** 58 * Interface for receiving UWB adapter state changes 59 */ 60 public interface AdapterStateCallback { 61 /** 62 * @hide 63 */ 64 @Retention(RetentionPolicy.SOURCE) 65 @IntDef(value = { 66 STATE_CHANGED_REASON_SESSION_STARTED, 67 STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED, 68 STATE_CHANGED_REASON_SYSTEM_POLICY, 69 STATE_CHANGED_REASON_SYSTEM_BOOT, 70 STATE_CHANGED_REASON_ERROR_UNKNOWN}) 71 @interface StateChangedReason {} 72 73 /** 74 * @hide 75 */ 76 @Retention(RetentionPolicy.SOURCE) 77 @IntDef(value = { 78 STATE_ENABLED_INACTIVE, 79 STATE_ENABLED_ACTIVE, 80 STATE_DISABLED}) 81 @interface State {} 82 83 /** 84 * Indicates that the state change was due to opening of first UWB session 85 */ 86 int STATE_CHANGED_REASON_SESSION_STARTED = 0; 87 88 /** 89 * Indicates that the state change was due to closure of all UWB sessions 90 */ 91 int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; 92 93 /** 94 * Indicates that the state change was due to changes in system policy 95 */ 96 int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; 97 98 /** 99 * Indicates that the current state is due to a system boot 100 */ 101 int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; 102 103 /** 104 * Indicates that the state change was due to some unknown error 105 */ 106 int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; 107 108 /** 109 * Indicates that UWB is disabled on device 110 */ 111 int STATE_DISABLED = 0; 112 /** 113 * Indicates that UWB is enabled on device but has no active ranging sessions 114 */ 115 int STATE_ENABLED_INACTIVE = 1; 116 117 /** 118 * Indicates that UWB is enabled and has active ranging session 119 */ 120 int STATE_ENABLED_ACTIVE = 2; 121 122 /** 123 * Invoked when underlying UWB adapter's state is changed 124 * <p>Invoked with the adapter's current state after registering an 125 * {@link AdapterStateCallback} using 126 * {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}. 127 * 128 * <p>Possible reasons for the state to change are 129 * {@link #STATE_CHANGED_REASON_SESSION_STARTED}, 130 * {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED}, 131 * {@link #STATE_CHANGED_REASON_SYSTEM_POLICY}, 132 * {@link #STATE_CHANGED_REASON_SYSTEM_BOOT}, 133 * {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}. 134 * 135 * <p>Possible values for the UWB state are 136 * {@link #STATE_ENABLED_INACTIVE}, 137 * {@link #STATE_ENABLED_ACTIVE}, 138 * {@link #STATE_DISABLED}. 139 * 140 * @param state the UWB state; inactive, active or disabled 141 * @param reason the reason for the state change 142 */ onStateChanged(@tate int state, @StateChangedReason int reason)143 void onStateChanged(@State int state, @StateChangedReason int reason); 144 } 145 146 /** 147 * Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance. 148 * 149 * @param ctx Context of the client. 150 * @param adapter an instance of an {@link android.uwb.IUwbAdapter} 151 */ UwbManager(@onNull Context ctx, @NonNull IUwbAdapter adapter)152 private UwbManager(@NonNull Context ctx, @NonNull IUwbAdapter adapter) { 153 mContext = ctx; 154 mUwbAdapter = adapter; 155 mAdapterStateListener = new AdapterStateListener(adapter); 156 mRangingManager = new RangingManager(adapter); 157 } 158 159 /** 160 * @hide 161 */ getInstance(@onNull Context ctx)162 public static UwbManager getInstance(@NonNull Context ctx) { 163 IBinder b = ServiceManager.getService(SERVICE_NAME); 164 if (b == null) { 165 return null; 166 } 167 168 IUwbAdapter adapter = IUwbAdapter.Stub.asInterface(b); 169 if (adapter == null) { 170 return null; 171 } 172 173 return new UwbManager(ctx, adapter); 174 } 175 176 /** 177 * Register an {@link AdapterStateCallback} to listen for UWB adapter state changes 178 * <p>The provided callback will be invoked by the given {@link Executor}. 179 * 180 * <p>When first registering a callback, the callbacks's 181 * {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate 182 * the current state of the underlying UWB adapter with the most recent 183 * {@link AdapterStateCallback.StateChangedReason} that caused the change. 184 * 185 * @param executor an {@link Executor} to execute given callback 186 * @param callback user implementation of the {@link AdapterStateCallback} 187 */ 188 @RequiresPermission(permission.UWB_PRIVILEGED) registerAdapterStateCallback(@onNull @allbackExecutor Executor executor, @NonNull AdapterStateCallback callback)189 public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor, 190 @NonNull AdapterStateCallback callback) { 191 mAdapterStateListener.register(executor, callback); 192 } 193 194 /** 195 * Unregister the specified {@link AdapterStateCallback} 196 * <p>The same {@link AdapterStateCallback} object used when calling 197 * {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used. 198 * 199 * <p>Callbacks are automatically unregistered when application process goes away 200 * 201 * @param callback user implementation of the {@link AdapterStateCallback} 202 */ 203 @RequiresPermission(permission.UWB_PRIVILEGED) unregisterAdapterStateCallback(@onNull AdapterStateCallback callback)204 public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) { 205 mAdapterStateListener.unregister(callback); 206 } 207 208 /** 209 * Get a {@link PersistableBundle} with the supported UWB protocols and parameters. 210 * <p>The {@link PersistableBundle} should be parsed using a support library 211 * 212 * <p>Android reserves the '^android.*' namespace</p> 213 * 214 * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters 215 */ 216 @NonNull 217 @RequiresPermission(permission.UWB_PRIVILEGED) getSpecificationInfo()218 public PersistableBundle getSpecificationInfo() { 219 try { 220 return mUwbAdapter.getSpecificationInfo(); 221 } catch (RemoteException e) { 222 throw e.rethrowFromSystemServer(); 223 } 224 } 225 226 /** 227 * Get the timestamp resolution for events in nanoseconds 228 * <p>This value defines the maximum error of all timestamps for events reported to 229 * {@link RangingSession.Callback}. 230 * 231 * @return the timestamp resolution in nanoseconds 232 */ 233 @SuppressLint("MethodNameUnits") 234 @RequiresPermission(permission.UWB_PRIVILEGED) elapsedRealtimeResolutionNanos()235 public long elapsedRealtimeResolutionNanos() { 236 try { 237 return mUwbAdapter.getTimestampResolutionNanos(); 238 } catch (RemoteException e) { 239 throw e.rethrowFromSystemServer(); 240 } 241 } 242 243 /** 244 * Open a {@link RangingSession} with the given parameters 245 * <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a 246 * {@link RangingSession} object used to control ranging when the session is successfully 247 * opened. 248 * 249 * <p>If a session cannot be opened, then 250 * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} will be invoked with the 251 * appropriate {@link RangingSession.Callback.Reason}. 252 * 253 * <p>An open {@link RangingSession} will be automatically closed if client application process 254 * dies. 255 * 256 * <p>A UWB support library must be used in order to construct the {@code parameter} 257 * {@link PersistableBundle}. 258 * 259 * @param parameters the parameters that define the ranging session 260 * @param executor {@link Executor} to run callbacks 261 * @param callbacks {@link RangingSession.Callback} to associate with the 262 * {@link RangingSession} that is being opened. 263 * 264 * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a 265 * {@link RangingSession} that has been requested through {@link #openRangingSession} 266 * but has not yet been made available by 267 * {@link RangingSession.Callback#onOpened(RangingSession)}. 268 */ 269 @NonNull 270 @RequiresPermission(allOf = { 271 permission.UWB_PRIVILEGED, 272 permission.UWB_RANGING 273 }) openRangingSession(@onNull PersistableBundle parameters, @NonNull @CallbackExecutor Executor executor, @NonNull RangingSession.Callback callbacks)274 public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters, 275 @NonNull @CallbackExecutor Executor executor, 276 @NonNull RangingSession.Callback callbacks) { 277 return mRangingManager.openSession( 278 mContext.getAttributionSource(), parameters, executor, callbacks); 279 } 280 281 /** 282 * Returns the current enabled/disabled state for UWB. 283 * 284 * Possible values are: 285 * AdapterStateCallback#STATE_DISABLED 286 * AdapterStateCallback#STATE_ENABLED_INACTIVE 287 * AdapterStateCallback#STATE_ENABLED_ACTIVE 288 * 289 * @return value representing current enabled/disabled state for UWB. 290 * @hide 291 */ getAdapterState()292 public @AdapterStateCallback.State int getAdapterState() { 293 return mAdapterStateListener.getAdapterState(); 294 } 295 296 /** 297 * Disables or enables UWB for a user 298 * 299 * @param enabled value representing intent to disable or enable UWB. If true any subsequent 300 * calls to IUwbAdapter#openRanging will be allowed. If false, all active ranging sessions will 301 * be closed and subsequent calls to IUwbAdapter#openRanging will be disallowed. 302 * 303 * @hide 304 */ setUwbEnabled(boolean enabled)305 public void setUwbEnabled(boolean enabled) { 306 mAdapterStateListener.setEnabled(enabled); 307 } 308 } 309