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 package android.car.experimental; 17 18 19 import android.annotation.CallSuper; 20 import android.app.Service; 21 import android.content.Intent; 22 import android.os.IBinder; 23 import android.os.RemoteException; 24 import android.util.Log; 25 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.internal.annotations.VisibleForTesting; 28 29 /** 30 * The supplier for providing a stream of the driver's current situational awareness. 31 * 32 * <p>A perfect understanding of driver awareness requires years of extensive research and signals 33 * that suggest the cognitive situational awareness of the driver. Implementations of this class 34 * attempt to approximate driver awareness using concrete, but less accurate signals, such as gaze 35 * or touch. 36 * 37 * <p>Suppliers should notify of updates to the driver awareness level through {@link 38 * #onDriverAwarenessUpdated(DriverAwarenessEvent)}. 39 * 40 * <p>Suppliers define the amount of time until their data should be considered stale through 41 * {@link #getMaxStalenessMillis()}. After that amount of time data from this supplier will no 42 * longer be considered fresh. {@link #NO_STALENESS} is meant to be used by change-based suppliers 43 * such as a touch supplier - it is not appropriate for data signals that change continuous over 44 * time. 45 * 46 * <p>If this supplier has its own internal configuration, that configuration must be configurable 47 * by locale. 48 * 49 * <p>It is the attention supplier's responsibility to make sure that it only sends high-quality 50 * data events. 51 */ 52 public abstract class DriverAwarenessSupplierService extends Service { 53 private static final String TAG = "DriverAwarenessSupplierService"; 54 55 /** 56 * Value that can be returned by {@link #getMaxStalenessMillis()} to indicate that an attention 57 * supplier sends change-events instead of push events on a regular interval. Should only be 58 * used for a supplier that is guaranteed to always be running (e.g. it won't crash or have 59 * periods of poor data). 60 */ 61 public static final long NO_STALENESS = -1; 62 63 private final Object mLock = new Object(); 64 65 private SupplierBinder mSupplierBinder; 66 67 @GuardedBy("mLock") 68 private IDriverAwarenessSupplierCallback mDriverAwarenessSupplierCallback; 69 70 /** 71 * Returns the duration in milliseconds after which the input from this supplier should be 72 * considered stale. This method should return a positive value greater than 0. There is no 73 * technical limit on the value returned here, but a value of 1000ms (1 second) would likely be 74 * considered too high since the driving environment can change drastically in that amount of 75 * time. 76 * 77 * <p>This can also return {@link #NO_STALENESS} if the supplier only emits change events and 78 * has no risk of failing to emit those change events within a reasonable amount of time. 79 * 80 * <p>Data should be sent more frequently than the staleness period defined here. 81 */ getMaxStalenessMillis()82 public abstract long getMaxStalenessMillis(); 83 84 /** 85 * The distraction service is ready to start receiving events via {@link 86 * #onDriverAwarenessUpdated(DriverAwarenessEvent)}. 87 */ onReady()88 protected abstract void onReady(); 89 90 @Override 91 @CallSuper onBind(Intent intent)92 public IBinder onBind(Intent intent) { 93 logd("onBind, intent: " + intent); 94 if (mSupplierBinder == null) { 95 mSupplierBinder = new SupplierBinder(); 96 } 97 return mSupplierBinder; 98 } 99 100 /** 101 * The driver awareness has changed - emit that update to the {@link 102 * com.android.experimentalcar.DriverDistractionExperimentalFeatureService}. 103 */ onDriverAwarenessUpdated(DriverAwarenessEvent event)104 protected void onDriverAwarenessUpdated(DriverAwarenessEvent event) { 105 logd("onDriverAwarenessUpdated: " + event); 106 synchronized (mLock) { 107 if (mDriverAwarenessSupplierCallback != null) { 108 try { 109 mDriverAwarenessSupplierCallback.onDriverAwarenessUpdated(event); 110 } catch (RemoteException e) { 111 Log.e(TAG, "Remote exception", e); 112 } 113 } 114 } 115 } 116 handleReady()117 private void handleReady() { 118 synchronized (mLock) { 119 try { 120 mDriverAwarenessSupplierCallback.onConfigLoaded( 121 new DriverAwarenessSupplierConfig(getMaxStalenessMillis())); 122 } catch (RemoteException e) { 123 Log.e(TAG, "Unable to send config - abandoning ready process", e); 124 return; 125 } 126 } 127 onReady(); 128 } 129 130 /** 131 * The binder between this service and 132 * {@link com.android.experimentalcar.DriverDistractionExperimentalFeatureService}. 133 */ 134 @VisibleForTesting 135 public class SupplierBinder extends IDriverAwarenessSupplier.Stub { 136 137 @Override onReady()138 public void onReady() { 139 handleReady(); 140 } 141 142 @Override setCallback(IDriverAwarenessSupplierCallback callback)143 public void setCallback(IDriverAwarenessSupplierCallback callback) { 144 synchronized (mLock) { 145 mDriverAwarenessSupplierCallback = callback; 146 } 147 } 148 } 149 logd(String message)150 private static void logd(String message) { 151 if (Log.isLoggable(TAG, Log.DEBUG)) { 152 Log.d(TAG, message); 153 } 154 } 155 } 156