Акселерометр перестает доставлять образцы, когда на Droid/Nexus One экран выключен, даже с WakeLock
У меня есть некоторый код, который расширяет службу и записывает показания датчика акселерометра SensorChanged(событие SensorEvent) на Android. Я хотел бы иметь возможность записывать эти показания датчика, даже когда устройство выключено (я осторожен с временем работы от батареи, и это становится очевидным, когда оно работает). В то время как экран на логи работает отлично на 2.0.1 Motorola Droid и 2.1 Nexus One.
Однако, когда телефон переходит в режим сна (нажатием кнопки питания), экран выключается и onSensorChanged
события перестают доставляться (проверяется с помощью сообщения Log.e каждые N раз onSensorChanged
вызывается).
Служба получает wakeLock, чтобы гарантировать, что она продолжает работать в фоновом режиме; но, похоже, это не имеет никакого эффекта. Я перепробовал все различные PowerManager. замки, но ни один из них не имеет значения.
_WakeLock = _PowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
_WakeLock.acquire();
Поступали противоречивые сообщения о том, можете ли вы на самом деле получать данные с датчиков, когда экран выключен... Кто-нибудь имеет опыт работы с этим на более современной версии Android (Eclair) и оборудовании?
Кажется, это указывает на то, что он работал в Cupcake: http://groups.google.com/group/android-developers/msg/a616773b12c2d9e5
PS: Точно такой же код работает, как и предполагалось в 1.5 на G1. Регистрация продолжается, когда экран выключается, когда приложение находится в фоновом режиме и т. Д.
5 ответов
Мы пришли к выводу, что это началось с 2.0.1. Это кажется преднамеренным, возможно, частью увеличения срока службы батареи, которое рекламировалось как особенность. У нас был рабочий толчок, чтобы разбудить или разблокировать 2.0, затем он сломался при обновлении, и мы не смогли найти какой-либо обходной путь.;'(Неважно, удерживается ли частичная блокировка ЦП, которая, как предполагается, всегда препятствует сну ЦП. Из того, что я видел, отладка журналирования по USB, иногда появляется упоминание об изменениях в прослушивателе датчиков во время сна.
Пользователь опубликовал обходной путь, который, как он утверждал, работает на устройствах Motorola - https://sites.google.com/a/bug-br.org.br/android/technical-documents
Я протестировал обходной путь, придумав следующий код из учебного пособия и некоторую ручную ревизию (в представленном учебном коде есть несколько "ошибок"):
public class ShakeWakeupService extends Service implements SensorEventListener{
private Context mContext;
SensorManager mSensorEventManager;
Sensor mSensor;
// BroadcastReceiver for handling ACTION_SCREEN_OFF.
public BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Check action just to be on the safe side.
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.v("shake mediator screen off","trying re-registration");
// Unregisters the listener and registers it again.
mSensorEventManager.unregisterListener(ShakeWakeupService.this);
mSensorEventManager.registerListener(ShakeWakeupService.this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
}
};
@Override
public void onCreate() {
super.onCreate();
Log.v("shake service startup","registering for shake");
mContext = getApplicationContext();
// Obtain a reference to system-wide sensor event manager.
mSensorEventManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
// Get the default sensor for accel
mSensor = mSensorEventManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// Register for events.
mSensorEventManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
// Register our receiver for the ACTION_SCREEN_OFF action. This will make our receiver
// code be called whenever the phone enters standby mode.
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, filter);
}
@Override
public void onDestroy() {
// Unregister our receiver.
unregisterReceiver(mReceiver);
// Unregister from SensorManager.
mSensorEventManager.unregisterListener(this);
}
@Override
public IBinder onBind(Intent intent) {
// We don't need a IBinder interface.
return null;
}
public void onShake() {
//Poke a user activity to cause wake?
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//not used right now
}
//Used to decide if it is a shake
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) return;
Log.v("sensor","sensor change is verifying");
}
}
Обходной путь работает для меня, но не будет работать, пока у меня запущен screebl, и эта функция, которую многие мои пользователи действительно хотят работать в сочетании с тем, что я разрабатываю.
Только что обновил мой Nexus One ROM FROYO FRF50, который бродил по интернету в течение последних нескольких дней, и кажется, что сенсоры теперь снова работают, когда экран выключен, если у вас есть PARTIAL_WAKELOCK. Я не знаю, удастся ли это сделать официальной сборкой, хотя, насколько я понимаю, она основана на официальной сборке, которую получили некоторые пользователи N1. Так что, возможно, они передумали (еще раз) и снова включили датчики, когда телефон заблокирован. Скрещенные пальцы.
Конечно, они могли бы просто пойти и отключить их снова в 2.2-r1, кто знает...
Используя SCREEN_DIM_WAKE_LOCK
работал у меня на HTC EVO..
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
_WakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
_WakeLock.acquire();
Есть альтернативное решение (вроде), где вы всегда держите экран включенным:
Settings.System.putInt (getContentResolver (), Settings.System.SCREEN_OFF_TIMEOUT, -1);
Но это не мешает пользователю принудительно выключать экран нажатием кнопки питания, а затем поток событий датчика останавливается. Вам также нужно разрешение WRITE_SETTINGS, чтобы это работало.
Приведенный выше обходной путь перерегистрации для событий сенсора не работает на Droid Eris, который работает под управлением Android 2.1 и, как ожидается, никогда не получит обновление. Я использовал следующее, хотя, кажется, работает. Вместо отмены регистрации и повторной регистрации этот подход снова включает экран, когда пользователь выключает его, хотя он снова включается затемненным. В следующем коде обработчик - это просто простой обработчик, созданный в Activity (т. Е. Handler handler = new Handler();), а mTurnBackOn - это WakeLock, инициализированный значением null.
public BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
// Turn the screen back on again, from the main thread
handler.post(new Runnable() {
public void run() {
if(mTurnBackOn != null)
mTurnBackOn.release();
mTurnBackOn = mPwrMgr.newWakeLock(
PowerManager.SCREEN_DIM_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP,
"AccelOn");
mTurnBackOn.acquire();
}});
}
}
};
Кажется, что это проблема прошивки 2.1, мне необходимо исправить это, но мне нужно работать во всех видах обходных путей, чтобы охватить все версии.
Я составил список телефонов и прошивок, которые работают / не работают / работают с перебоями, чтобы мы могли либо протестировать телефон, либо прошивку.
http://apprssd.com/2010/09/08/android-onsensorchanged-not-working-when-screen-lock-is-on/
Если у вас есть новый телефон, которым вы можете обновить список, дайте мне знать.