| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.systemui.util; |
| |
| import android.content.Context; |
| import android.hardware.HardwareBuffer; |
| import android.hardware.Sensor; |
| import android.hardware.SensorAdditionalInfo; |
| import android.hardware.SensorDirectChannel; |
| import android.hardware.SensorEventListener; |
| import android.hardware.SensorManager; |
| import android.hardware.TriggerEventListener; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.MemoryFile; |
| import android.util.Log; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.util.Preconditions; |
| import com.android.systemui.plugins.PluginListener; |
| import com.android.systemui.plugins.SensorManagerPlugin; |
| import com.android.systemui.shared.plugins.PluginManager; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.inject.Inject; |
| import javax.inject.Singleton; |
| |
| /** |
| * Wrapper around sensor manager that hides potential sources of latency. |
| * |
| * Offloads fetching (non-dynamic) sensors and (un)registering listeners onto a background thread |
| * without blocking. Note that this means registering listeners now always appears successful even |
| * if it is not. |
| */ |
| @Singleton |
| public class AsyncSensorManager extends SensorManager |
| implements PluginListener<SensorManagerPlugin> { |
| |
| private static final String TAG = "AsyncSensorManager"; |
| |
| private final SensorManager mInner; |
| private final List<Sensor> mSensorCache; |
| private final HandlerThread mHandlerThread = new HandlerThread("async_sensor"); |
| @VisibleForTesting final Handler mHandler; |
| private final List<SensorManagerPlugin> mPlugins; |
| |
| @Inject |
| public AsyncSensorManager(Context context, PluginManager pluginManager) { |
| this(context.getSystemService(SensorManager.class), pluginManager); |
| } |
| |
| @VisibleForTesting |
| AsyncSensorManager(SensorManager sensorManager, PluginManager pluginManager) { |
| mInner = sensorManager; |
| mHandlerThread.start(); |
| mHandler = new Handler(mHandlerThread.getLooper()); |
| mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL); |
| mPlugins = new ArrayList<>(); |
| pluginManager.addPluginListener(this, SensorManagerPlugin.class, true /* allowMultiple */); |
| } |
| |
| @Override |
| protected List<Sensor> getFullSensorList() { |
| return mSensorCache; |
| } |
| |
| @Override |
| protected List<Sensor> getFullDynamicSensorList() { |
| return mInner.getSensorList(Sensor.TYPE_ALL); |
| } |
| |
| @Override |
| protected boolean registerListenerImpl(SensorEventListener listener, |
| Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs, |
| int reservedFlags) { |
| mHandler.post(() -> { |
| if (!mInner.registerListener(listener, sensor, delayUs, maxReportLatencyUs, handler)) { |
| Log.e(TAG, "Registering " + listener + " for " + sensor + " failed."); |
| } |
| }); |
| return true; |
| } |
| |
| @Override |
| protected boolean flushImpl(SensorEventListener listener) { |
| return mInner.flush(listener); |
| } |
| |
| @Override |
| protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile, |
| HardwareBuffer hardwareBuffer) { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| protected void destroyDirectChannelImpl(SensorDirectChannel channel) { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback, |
| Handler handler) { |
| mHandler.post(() -> mInner.registerDynamicSensorCallback(callback, handler)); |
| } |
| |
| @Override |
| protected void unregisterDynamicSensorCallbackImpl(DynamicSensorCallback callback) { |
| mHandler.post(() -> mInner.unregisterDynamicSensorCallback(callback)); |
| } |
| |
| @Override |
| protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { |
| mHandler.post(() -> { |
| if (!mInner.requestTriggerSensor(listener, sensor)) { |
| Log.e(TAG, "Requesting " + listener + " for " + sensor + " failed."); |
| } |
| }); |
| return true; |
| } |
| |
| @Override |
| protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, |
| boolean disable) { |
| Preconditions.checkArgument(disable); |
| |
| mHandler.post(() -> { |
| if (!mInner.cancelTriggerSensor(listener, sensor)) { |
| Log.e(TAG, "Canceling " + listener + " for " + sensor + " failed."); |
| } |
| }); |
| return true; |
| } |
| |
| /** |
| * Requests for all sensors that match the given type from all plugins. |
| * @param sensor |
| * @param listener |
| * @return true if there were plugins to register the listener to |
| */ |
| public boolean registerPluginListener(SensorManagerPlugin.Sensor sensor, |
| SensorManagerPlugin.SensorEventListener listener) { |
| if (mPlugins.isEmpty()) { |
| Log.w(TAG, "No plugins registered"); |
| return false; |
| } |
| mHandler.post(() -> { |
| for (int i = 0; i < mPlugins.size(); i++) { |
| mPlugins.get(i).registerListener(sensor, listener); |
| } |
| }); |
| |
| return true; |
| } |
| |
| /** |
| * Unregisters all sensors that match the give type for all plugins. |
| * @param sensor |
| * @param listener |
| */ |
| public void unregisterPluginListener(SensorManagerPlugin.Sensor sensor, |
| SensorManagerPlugin.SensorEventListener listener) { |
| mHandler.post(() -> { |
| for (int i = 0; i < mPlugins.size(); i++) { |
| mPlugins.get(i).unregisterListener(sensor, listener); |
| } |
| }); |
| } |
| |
| @Override |
| protected boolean initDataInjectionImpl(boolean enable) { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, |
| long timestamp) { |
| throw new UnsupportedOperationException("not implemented"); |
| } |
| |
| @Override |
| protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) { |
| mHandler.post(() -> mInner.setOperationParameter(parameter)); |
| return true; |
| } |
| |
| @Override |
| protected void unregisterListenerImpl(SensorEventListener listener, |
| Sensor sensor) { |
| mHandler.post(() -> { |
| if (sensor == null) { |
| mInner.unregisterListener(listener); |
| } else { |
| mInner.unregisterListener(listener, sensor); |
| } |
| }); |
| } |
| |
| @Override |
| public void onPluginConnected(SensorManagerPlugin plugin, Context pluginContext) { |
| mPlugins.add(plugin); |
| } |
| |
| @Override |
| public void onPluginDisconnected(SensorManagerPlugin plugin) { |
| mPlugins.remove(plugin); |
| } |
| } |