• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.trust;
18 
19 import static android.car.Car.PERMISSION_CAR_ENROLL_TRUST;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.bluetooth.BluetoothDevice;
27 import android.car.CarManagerBase;
28 import android.content.Context;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.os.RemoteException;
35 import android.util.Log;
36 
37 import com.android.internal.annotations.GuardedBy;
38 
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.lang.ref.WeakReference;
42 import java.util.List;
43 
44 
45 /**
46  * APIs to help enroll a remote device as a trusted device that can be used to authenticate a user
47  * in the head unit.
48  * <p>
49  * The call sequence to add a new trusted device from the client should be as follows:
50  * <ol>
51  * <li> setEnrollmentCallback()
52  * <li> setBleCallback(bleCallback)
53  * <li> startEnrollmentAdvertising()
54  * <li> wait for onEnrollmentAdvertisingStarted() or
55  * <li> wait for onBleEnrollmentDeviceConnected() and check if the device connected is the right
56  * one.
57  * <li> initiateEnrollmentHandshake()
58  * <li> wait for onAuthStringAvailable() to get the pairing code to display to the user
59  * <li> enrollmentHandshakeAccepted() after user confirms the pairing code
60  * <li> wait for onEscrowTokenAdded()
61  * <li> Authenticate user's credentials by showing the lock screen
62  * <li> activateToken()
63  * <li> wait for onEscrowTokenActiveStateChanged() to add the device as a trusted device and show
64  * in the list
65  * </ol>
66  *
67  * @hide
68  */
69 @SystemApi
70 public final class CarTrustAgentEnrollmentManager implements CarManagerBase {
71     private static final String TAG = "CarTrustEnrollMgr";
72     private static final String KEY_HANDLE = "handle";
73     private static final String KEY_ACTIVE = "active";
74     private static final int MSG_ENROLL_ADVERTISING_STARTED = 0;
75     private static final int MSG_ENROLL_ADVERTISING_FAILED = 1;
76     private static final int MSG_ENROLL_DEVICE_CONNECTED = 2;
77     private static final int MSG_ENROLL_DEVICE_DISCONNECTED = 3;
78     private static final int MSG_ENROLL_HANDSHAKE_FAILURE = 4;
79     private static final int MSG_ENROLL_AUTH_STRING_AVAILABLE = 5;
80     private static final int MSG_ENROLL_TOKEN_ADDED = 6;
81     private static final int MSG_ENROLL_TOKEN_STATE_CHANGED = 7;
82     private static final int MSG_ENROLL_TOKEN_REMOVED = 8;
83 
84     private final Context mContext;
85     private final ICarTrustAgentEnrollment mEnrollmentService;
86     private Object mListenerLock = new Object();
87     @GuardedBy("mListenerLock")
88     private CarTrustAgentEnrollmentCallback mEnrollmentCallback;
89     @GuardedBy("mListenerLock")
90     private CarTrustAgentBleCallback mBleCallback;
91     @GuardedBy("mListenerLock")
92     private final ListenerToEnrollmentService mListenerToEnrollmentService =
93             new ListenerToEnrollmentService(this);
94     private final ListenerToBleService mListenerToBleService = new ListenerToBleService(this);
95     private final EventCallbackHandler mEventCallbackHandler;
96 
97     /**
98      * Enrollment Handshake failed.
99      */
100     public static final int ENROLLMENT_HANDSHAKE_FAILURE = 1;
101     /**
102      * Enrollment of a new device is not allowed.  This happens when either the whole feature is
103      * disabled or just the enrollment is disabled.  Useful when feature needs to be disabled
104      * in a lost/stolen phone scenario.
105      */
106     public static final int ENROLLMENT_NOT_ALLOWED = 2;
107 
108     /** @hide */
109     @Retention(RetentionPolicy.SOURCE)
110     @IntDef({ENROLLMENT_HANDSHAKE_FAILURE,
111             ENROLLMENT_NOT_ALLOWED})
112     public @interface TrustedDeviceEnrollmentError {
113     }
114 
115 
116     /** @hide */
CarTrustAgentEnrollmentManager(IBinder service, Context context, Handler handler)117     public CarTrustAgentEnrollmentManager(IBinder service, Context context, Handler handler) {
118         mContext = context;
119         mEnrollmentService = ICarTrustAgentEnrollment.Stub.asInterface(service);
120         mEventCallbackHandler = new EventCallbackHandler(this, handler.getLooper());
121     }
122 
123     /** @hide */
124     @Override
onCarDisconnected()125     public synchronized void onCarDisconnected() {
126     }
127 
128     /**
129      * Starts broadcasting enrollment UUID on BLE.
130      * Phones can scan and connect for the enrollment process to begin.
131      */
132     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
startEnrollmentAdvertising()133     public void startEnrollmentAdvertising() {
134         try {
135             mEnrollmentService.startEnrollmentAdvertising();
136         } catch (RemoteException e) {
137             throw e.rethrowFromSystemServer();
138         }
139     }
140 
141     /**
142      * Stops Enrollment advertising.
143      */
144     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
stopEnrollmentAdvertising()145     public void stopEnrollmentAdvertising() {
146         try {
147             mEnrollmentService.stopEnrollmentAdvertising();
148         } catch (RemoteException e) {
149             throw e.rethrowFromSystemServer();
150         }
151     }
152 
153     /**
154      * Confirms that the enrollment handshake has been accepted by the user. This should be called
155      * after the user has confirmed the verification code displayed on the UI.
156      *
157      * @param device the remote Bluetooth device that will receive the signal.
158      */
159     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
enrollmentHandshakeAccepted(BluetoothDevice device)160     public void enrollmentHandshakeAccepted(BluetoothDevice device) {
161         try {
162             mEnrollmentService.enrollmentHandshakeAccepted(device);
163         } catch (RemoteException e) {
164             throw e.rethrowFromSystemServer();
165         }
166     }
167 
168     /**
169      * Provides an option to quit enrollment if the pairing code doesn't match for example.
170      */
171     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
terminateEnrollmentHandshake()172     public void terminateEnrollmentHandshake() {
173         try {
174             mEnrollmentService.terminateEnrollmentHandshake();
175         } catch (RemoteException e) {
176             throw e.rethrowFromSystemServer();
177         }
178     }
179 
180     /**
181      * Returns {@code true} if the escrow token associated with the given handle is active.
182      * <p>
183      * When a new escrow token has been added as part of the Trusted device enrollment, the client
184      * will receive {@link CarTrustAgentEnrollmentCallback#onEscrowTokenAdded(long)} and
185      * {@link CarTrustAgentEnrollmentCallback#onEscrowTokenActiveStateChanged(long, boolean)}
186      * callbacks.  This method provides a way to query for the token state at a later point of time.
187      *
188      * @param handle the handle corresponding to the escrow token
189      * @param uid    user id associated with the token
190      * @return true if the token is active, false if not
191      */
192     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
isEscrowTokenActive(long handle, int uid)193     public boolean isEscrowTokenActive(long handle, int uid) {
194         try {
195             return mEnrollmentService.isEscrowTokenActive(handle, uid);
196         } catch (RemoteException e) {
197             throw e.rethrowFromSystemServer();
198         }
199     }
200 
201     /**
202      * Remove the escrow token that is associated with the given handle and uid.
203      *
204      * @param handle the handle associated with the escrow token
205      * @param uid    user id associated with the token
206      */
207     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
removeEscrowToken(long handle, int uid)208     public void removeEscrowToken(long handle, int uid) {
209         try {
210             mEnrollmentService.removeEscrowToken(handle, uid);
211         } catch (RemoteException e) {
212             throw e.rethrowFromSystemServer();
213         }
214     }
215 
216     /**
217      * Remove all of the trusted devices associated with the given user.
218      *
219      * @param uid User id to remove the devices for
220      */
221     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
removeAllTrustedDevices(int uid)222     public void removeAllTrustedDevices(int uid) {
223         try {
224             mEnrollmentService.removeAllTrustedDevices(uid);
225         } catch (RemoteException e) {
226             throw e.rethrowFromSystemServer();
227         }
228     }
229 
230     /**
231      * Enable or Disable Trusted device enrollment.  Once disabled, head unit will not broadcast
232      * for enrollment until enabled back.
233      *
234      * @param isEnabled {@code true} enables enrollment.
235      */
236     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
setTrustedDeviceEnrollmentEnabled(boolean isEnabled)237     public void setTrustedDeviceEnrollmentEnabled(boolean isEnabled) {
238         try {
239             mEnrollmentService.setTrustedDeviceEnrollmentEnabled(isEnabled);
240         } catch (RemoteException e) {
241             throw e.rethrowFromSystemServer();
242         }
243     }
244 
245     /**
246      * Enable or disable Unlocking with a trusted device. Once disabled, head unit will not
247      * broadcast until enabled back.
248      *
249      * @param isEnabled {@code true} enables unlock.
250      */
251     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
setTrustedDeviceUnlockEnabled(boolean isEnabled)252     public void setTrustedDeviceUnlockEnabled(boolean isEnabled) {
253         try {
254             mEnrollmentService.setTrustedDeviceUnlockEnabled(isEnabled);
255         } catch (RemoteException e) {
256             throw e.rethrowFromSystemServer();
257         }
258     }
259 
260     /**
261      * Register for enrollment event callbacks.
262      *
263      * @param callback The callback methods to call, null to unregister
264      */
265     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
setEnrollmentCallback(@ullable CarTrustAgentEnrollmentCallback callback)266     public void setEnrollmentCallback(@Nullable CarTrustAgentEnrollmentCallback callback) {
267         if (callback == null) {
268             unregisterEnrollmentCallback();
269         } else {
270             registerEnrollmentCallback(callback);
271         }
272     }
273 
registerEnrollmentCallback(CarTrustAgentEnrollmentCallback callback)274     private void registerEnrollmentCallback(CarTrustAgentEnrollmentCallback callback) {
275         synchronized (mListenerLock) {
276             if (callback != null && mEnrollmentCallback == null) {
277                 try {
278                     mEnrollmentService.registerEnrollmentCallback(mListenerToEnrollmentService);
279                     mEnrollmentCallback = callback;
280                 } catch (RemoteException e) {
281                     throw e.rethrowFromSystemServer();
282                 }
283             }
284         }
285     }
286 
unregisterEnrollmentCallback()287     private void unregisterEnrollmentCallback() {
288         synchronized (mListenerLock) {
289             if (mEnrollmentCallback != null) {
290                 try {
291                     mEnrollmentService.unregisterEnrollmentCallback(mListenerToEnrollmentService);
292                 } catch (RemoteException e) {
293                     throw e.rethrowFromSystemServer();
294                 }
295                 mEnrollmentCallback = null;
296             }
297         }
298     }
299 
300     /**
301      * Register for general BLE callbacks
302      *
303      * @param callback The callback methods to call, null to unregister
304      */
305     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
setBleCallback(@ullable CarTrustAgentBleCallback callback)306     public void setBleCallback(@Nullable CarTrustAgentBleCallback callback) {
307         if (callback == null) {
308             unregisterBleCallback();
309         } else {
310             registerBleCallback(callback);
311         }
312     }
313 
registerBleCallback(CarTrustAgentBleCallback callback)314     private void registerBleCallback(CarTrustAgentBleCallback callback) {
315         synchronized (mListenerLock) {
316             if (callback != null && mBleCallback == null) {
317                 try {
318                     mEnrollmentService.registerBleCallback(mListenerToBleService);
319                     mBleCallback = callback;
320                 } catch (RemoteException e) {
321                     throw e.rethrowFromSystemServer();
322                 }
323             }
324         }
325     }
326 
unregisterBleCallback()327     private void unregisterBleCallback() {
328         synchronized (mListenerLock) {
329             if (mBleCallback != null) {
330                 try {
331                     mEnrollmentService.unregisterBleCallback(mListenerToBleService);
332                 } catch (RemoteException e) {
333                     throw e.rethrowFromSystemServer();
334                 }
335                 mBleCallback = null;
336             }
337         }
338     }
339 
340     /**
341      * Provides a list that contains information about the enrolled devices for the given user id.
342      * <p>
343      * Each enrollment handle corresponds to a trusted device for the given user.
344      *
345      * @param uid user id.
346      * @return list of the Enrollment handles and user names for the user id.
347      */
348     @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
349     @NonNull
getEnrolledDeviceInfoForUser(int uid)350     public List<TrustedDeviceInfo> getEnrolledDeviceInfoForUser(int uid) {
351         try {
352             return mEnrollmentService.getEnrolledDeviceInfosForUser(uid);
353         } catch (RemoteException e) {
354             throw e.rethrowFromSystemServer();
355         }
356     }
357 
getEventCallbackHandler()358     private Handler getEventCallbackHandler() {
359         return mEventCallbackHandler;
360     }
361 
362     /**
363      * Callback interface for Trusted device enrollment applications to implement.  The applications
364      * get notified on various enrollment state change events.
365      */
366     public interface CarTrustAgentEnrollmentCallback {
367         /**
368          * Communicate about failure/timeouts in the handshake process.  BluetoothDevice will be
369          * null when the returned error code is {@link #ENROLLMENT_NOT_ALLOWED}.
370          *
371          * @param device    the remote device trying to enroll
372          * @param errorCode information on what failed.
373          */
onEnrollmentHandshakeFailure(@ullable BluetoothDevice device, @TrustedDeviceEnrollmentError int errorCode)374         void onEnrollmentHandshakeFailure(@Nullable BluetoothDevice device,
375                 @TrustedDeviceEnrollmentError int errorCode);
376 
377         /**
378          * Present the pairing/authentication string to the user.
379          *
380          * @param device     the remote device trying to enroll
381          * @param authString the authentication string to show to the user to confirm across
382          *                   both devices
383          */
onAuthStringAvailable(BluetoothDevice device, String authString)384         void onAuthStringAvailable(BluetoothDevice device, String authString);
385 
386         /**
387          * Escrow token was received and the Trust Agent framework has generated a corresponding
388          * handle.
389          *
390          * @param handle the handle associated with the escrow token.
391          */
onEscrowTokenAdded(long handle)392         void onEscrowTokenAdded(long handle);
393 
394         /**
395          * Escrow token was removed as a result of a call to {@link #removeEscrowToken(long handle,
396          * int uid)}. The peer device associated with this token is not trusted for authentication
397          * anymore.
398          *
399          * @param handle the handle associated with the escrow token.
400          */
onEscrowTokenRemoved(long handle)401         void onEscrowTokenRemoved(long handle);
402 
403 
404         /**
405          * Escrow token's active state changed.
406          *
407          * @param handle the handle associated with the escrow token
408          * @param active True if token has been activated, false if not.
409          */
onEscrowTokenActiveStateChanged(long handle, boolean active)410         void onEscrowTokenActiveStateChanged(long handle, boolean active);
411     }
412 
413     /**
414      * Callback interface for Trusted device enrollment applications to implement.  The applications
415      * get notified on various BLE state change events that happen during trusted device enrollment.
416      */
417     public interface CarTrustAgentBleCallback {
418         /**
419          * Indicates a remote device connected on BLE.
420          */
onBleEnrollmentDeviceConnected(BluetoothDevice device)421         void onBleEnrollmentDeviceConnected(BluetoothDevice device);
422 
423         /**
424          * Indicates a remote device disconnected on BLE.
425          */
onBleEnrollmentDeviceDisconnected(BluetoothDevice device)426         void onBleEnrollmentDeviceDisconnected(BluetoothDevice device);
427 
428         /**
429          * Indicates that the device is broadcasting for trusted device enrollment on BLE.
430          */
onEnrollmentAdvertisingStarted()431         void onEnrollmentAdvertisingStarted();
432 
433         /**
434          * Indicates a failure in BLE broadcasting for enrollment.
435          */
onEnrollmentAdvertisingFailed()436         void onEnrollmentAdvertisingFailed();
437     }
438 
439     private static final class ListenerToEnrollmentService extends
440             ICarTrustAgentEnrollmentCallback.Stub {
441         private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
442 
ListenerToEnrollmentService(CarTrustAgentEnrollmentManager mgr)443         ListenerToEnrollmentService(CarTrustAgentEnrollmentManager mgr) {
444             mMgr = new WeakReference<>(mgr);
445         }
446 
447         /**
448          * Communicate about failure/timeouts in the handshake process.
449          */
450         @Override
onEnrollmentHandshakeFailure(BluetoothDevice device, @TrustedDeviceEnrollmentError int errorCode)451         public void onEnrollmentHandshakeFailure(BluetoothDevice device,
452                 @TrustedDeviceEnrollmentError int errorCode) {
453             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
454             if (enrollmentManager == null) {
455                 return;
456             }
457             enrollmentManager.getEventCallbackHandler().sendMessage(
458                     enrollmentManager.getEventCallbackHandler().obtainMessage(
459                             MSG_ENROLL_HANDSHAKE_FAILURE, new AuthInfo(device, null, errorCode)));
460         }
461 
462         /**
463          * Present the pairing/authentication string to the user.
464          */
465         @Override
onAuthStringAvailable(BluetoothDevice device, String authString)466         public void onAuthStringAvailable(BluetoothDevice device, String authString) {
467             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
468             if (enrollmentManager == null) {
469                 return;
470             }
471             enrollmentManager.getEventCallbackHandler().sendMessage(
472                     enrollmentManager.getEventCallbackHandler().obtainMessage(
473                             MSG_ENROLL_AUTH_STRING_AVAILABLE, new AuthInfo(device, authString, 0)));
474         }
475 
476         /**
477          * Escrow token was received and the Trust Agent framework has generated a corresponding
478          * handle.
479          */
480         @Override
onEscrowTokenAdded(long handle)481         public void onEscrowTokenAdded(long handle) {
482             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
483             if (enrollmentManager == null) {
484                 return;
485             }
486             Message message = enrollmentManager.getEventCallbackHandler().obtainMessage(
487                     MSG_ENROLL_TOKEN_ADDED);
488             Bundle data = new Bundle();
489             data.putLong(KEY_HANDLE, handle);
490             message.setData(data);
491             enrollmentManager.getEventCallbackHandler().sendMessage(message);
492         }
493 
494         /**
495          * Escrow token was removed.
496          */
497         @Override
onEscrowTokenRemoved(long handle)498         public void onEscrowTokenRemoved(long handle) {
499             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
500             if (enrollmentManager == null) {
501                 return;
502             }
503             Message message = enrollmentManager.getEventCallbackHandler().obtainMessage(
504                     MSG_ENROLL_TOKEN_REMOVED);
505             Bundle data = new Bundle();
506             data.putLong(KEY_HANDLE, handle);
507             message.setData(data);
508             enrollmentManager.getEventCallbackHandler().sendMessage(message);
509         }
510 
511         /**
512          * Escrow token's active state changed.
513          */
514         @Override
onEscrowTokenActiveStateChanged(long handle, boolean active)515         public void onEscrowTokenActiveStateChanged(long handle, boolean active) {
516             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
517             if (enrollmentManager == null) {
518                 return;
519             }
520             Message message = enrollmentManager.getEventCallbackHandler().obtainMessage(
521                     MSG_ENROLL_TOKEN_STATE_CHANGED);
522             Bundle data = new Bundle();
523             data.putLong(KEY_HANDLE, handle);
524             data.putBoolean(KEY_ACTIVE, active);
525             message.setData(data);
526             enrollmentManager.getEventCallbackHandler().sendMessage(message);
527         }
528     }
529 
530     private static final class ListenerToBleService extends ICarTrustAgentBleCallback.Stub {
531         private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
532 
ListenerToBleService(CarTrustAgentEnrollmentManager mgr)533         ListenerToBleService(CarTrustAgentEnrollmentManager mgr) {
534             mMgr = new WeakReference<>(mgr);
535         }
536 
537         /**
538          * Called when the GATT server is started and BLE is successfully advertising for
539          * enrollment.
540          */
onEnrollmentAdvertisingStarted()541         public void onEnrollmentAdvertisingStarted() {
542             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
543             if (enrollmentManager == null) {
544                 return;
545             }
546             enrollmentManager.getEventCallbackHandler().sendMessage(
547                     enrollmentManager.getEventCallbackHandler().obtainMessage(
548                             MSG_ENROLL_ADVERTISING_STARTED));
549         }
550 
551         /**
552          * Called when the BLE enrollment advertisement fails to start.
553          * see AdvertiseCallback#ADVERTISE_FAILED_* for possible error codes.
554          */
onEnrollmentAdvertisingFailed()555         public void onEnrollmentAdvertisingFailed() {
556             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
557             if (enrollmentManager == null) {
558                 return;
559             }
560             enrollmentManager.getEventCallbackHandler().sendMessage(
561                     enrollmentManager.getEventCallbackHandler().obtainMessage(
562                             MSG_ENROLL_ADVERTISING_FAILED));
563         }
564 
565         /**
566          * Called when a remote device is connected on BLE.
567          */
onBleEnrollmentDeviceConnected(BluetoothDevice device)568         public void onBleEnrollmentDeviceConnected(BluetoothDevice device) {
569             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
570             if (enrollmentManager == null) {
571                 return;
572             }
573             enrollmentManager.getEventCallbackHandler().sendMessage(
574                     enrollmentManager.getEventCallbackHandler().obtainMessage(
575                             MSG_ENROLL_DEVICE_CONNECTED, device));
576         }
577 
578         /**
579          * Called when a remote device is disconnected on BLE.
580          */
onBleEnrollmentDeviceDisconnected(BluetoothDevice device)581         public void onBleEnrollmentDeviceDisconnected(BluetoothDevice device) {
582             CarTrustAgentEnrollmentManager enrollmentManager = mMgr.get();
583             if (enrollmentManager == null) {
584                 return;
585             }
586             enrollmentManager.getEventCallbackHandler().sendMessage(
587                     enrollmentManager.getEventCallbackHandler().obtainMessage(
588                             MSG_ENROLL_DEVICE_DISCONNECTED, device));
589         }
590     }
591 
592     /**
593      * Callback Handler to handle dispatching the enrollment state changes to the corresponding
594      * listeners
595      */
596     private static final class EventCallbackHandler extends Handler {
597         private final WeakReference<CarTrustAgentEnrollmentManager> mEnrollmentManager;
598 
EventCallbackHandler(CarTrustAgentEnrollmentManager manager, Looper looper)599         EventCallbackHandler(CarTrustAgentEnrollmentManager manager, Looper looper) {
600             super(looper);
601             mEnrollmentManager = new WeakReference<>(manager);
602         }
603 
604         @Override
handleMessage(Message message)605         public void handleMessage(Message message) {
606             CarTrustAgentEnrollmentManager enrollmentManager = mEnrollmentManager.get();
607             if (enrollmentManager == null) {
608                 return;
609             }
610             switch (message.what) {
611                 case MSG_ENROLL_ADVERTISING_STARTED:
612                 case MSG_ENROLL_ADVERTISING_FAILED:
613                 case MSG_ENROLL_DEVICE_CONNECTED:
614                 case MSG_ENROLL_DEVICE_DISCONNECTED:
615                     enrollmentManager.dispatchBleCallback(message);
616                     break;
617                 case MSG_ENROLL_HANDSHAKE_FAILURE:
618                 case MSG_ENROLL_AUTH_STRING_AVAILABLE:
619                 case MSG_ENROLL_TOKEN_ADDED:
620                 case MSG_ENROLL_TOKEN_STATE_CHANGED:
621                 case MSG_ENROLL_TOKEN_REMOVED:
622                     enrollmentManager.dispatchEnrollmentCallback(message);
623                     break;
624                 default:
625                     Log.e(TAG, "Unknown message:" + message.what);
626                     break;
627             }
628         }
629     }
630 
631     /**
632      * Dispatch BLE related state change callbacks
633      *
634      * @param message Message to handle and dispatch
635      */
dispatchBleCallback(Message message)636     private void dispatchBleCallback(Message message) {
637         CarTrustAgentBleCallback bleCallback;
638         synchronized (mListenerLock) {
639             bleCallback = mBleCallback;
640         }
641         if (bleCallback == null) {
642             return;
643         }
644         switch (message.what) {
645             case MSG_ENROLL_ADVERTISING_STARTED:
646                 bleCallback.onEnrollmentAdvertisingStarted();
647                 break;
648             case MSG_ENROLL_ADVERTISING_FAILED:
649                 bleCallback.onEnrollmentAdvertisingFailed();
650                 break;
651             case MSG_ENROLL_DEVICE_CONNECTED:
652                 bleCallback.onBleEnrollmentDeviceConnected((BluetoothDevice) message.obj);
653                 break;
654             case MSG_ENROLL_DEVICE_DISCONNECTED:
655                 bleCallback.onBleEnrollmentDeviceDisconnected((BluetoothDevice) message.obj);
656                 break;
657             default:
658                 break;
659         }
660     }
661 
662     /**
663      * Dispatch Enrollment related state changes to the listener.
664      *
665      * @param message Message to handle and dispatch
666      */
dispatchEnrollmentCallback(Message message)667     private void dispatchEnrollmentCallback(Message message) {
668         CarTrustAgentEnrollmentCallback enrollmentCallback;
669         synchronized (mListenerLock) {
670             enrollmentCallback = mEnrollmentCallback;
671         }
672         if (enrollmentCallback == null) {
673             return;
674         }
675         AuthInfo auth;
676         Bundle data;
677         switch (message.what) {
678             case MSG_ENROLL_HANDSHAKE_FAILURE:
679                 auth = (AuthInfo) message.obj;
680                 enrollmentCallback.onEnrollmentHandshakeFailure(auth.mDevice, auth.mErrorCode);
681                 break;
682             case MSG_ENROLL_AUTH_STRING_AVAILABLE:
683                 auth = (AuthInfo) message.obj;
684                 if (auth.mDevice != null && auth.mAuthString != null) {
685                     enrollmentCallback.onAuthStringAvailable(auth.mDevice, auth.mAuthString);
686                 }
687                 break;
688             case MSG_ENROLL_TOKEN_ADDED:
689                 data = message.getData();
690                 if (data == null) {
691                     break;
692                 }
693                 enrollmentCallback.onEscrowTokenAdded(data.getLong(KEY_HANDLE));
694                 break;
695             case MSG_ENROLL_TOKEN_STATE_CHANGED:
696                 data = message.getData();
697                 if (data == null) {
698                     break;
699                 }
700                 enrollmentCallback.onEscrowTokenActiveStateChanged(data.getLong(KEY_HANDLE),
701                         data.getBoolean(KEY_ACTIVE));
702                 break;
703             case MSG_ENROLL_TOKEN_REMOVED:
704                 data = message.getData();
705                 if (data == null) {
706                     break;
707                 }
708                 enrollmentCallback.onEscrowTokenRemoved(data.getLong(KEY_HANDLE));
709                 break;
710             default:
711                 break;
712         }
713     }
714 
715     /**
716      * Container class to pass information through a Message to the handler.
717      */
718     private static class AuthInfo {
719         final BluetoothDevice mDevice;
720         @Nullable
721         final String mAuthString;
722         final int mErrorCode;
723 
AuthInfo(BluetoothDevice device, @Nullable String authString, @TrustedDeviceEnrollmentError int errorCode)724         AuthInfo(BluetoothDevice device, @Nullable String authString,
725                 @TrustedDeviceEnrollmentError int errorCode) {
726             mDevice = device;
727             mAuthString = authString;
728             mErrorCode = errorCode;
729         }
730     }
731 }
732