Акселерометр останавливает доставку образцов, когда экран выключен на Droid/Nexus One даже с WakeLock

У меня есть код, который расширяет сервис и регистрирует показания датчика акселерометра SensorEvent (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. Ведение журнала продолжается, когда экран выключается, когда приложение находится в фоновом режиме и т.д.

Ответ 1

Мы пришли к выводу, что это началось с версии 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, что является особенностью, которую многие мои пользователи действительно хотят работать вместе с тем, что я разрабатываю.

Ответ 2

Только что обновил мой Nexus One с помощью FROYO FRF50 ROM, который за последние несколько дней ходит по сети, и кажется, что теперь датчики работают снова, когда экран выключен, если у вас есть PARTIAL_WAKELOCK. Я не знаю, приведет ли это к официальной сборке, хотя я понимаю, что это основано на официальной сборке, которую получили некоторые пользователи N1. Возможно, они изменили свое мнение (еще раз) и снова включили датчики, когда телефон заблокирован. Пальцы пересекли.

Конечно, они могли бы просто отключить их снова в 2.2-r1, кто знает...

Ответ 3

Использование 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();

Ответ 4

Похоже, что это проблема с прошивкой 2.1, мне нужно, чтобы это было исправлено, но мне нужно работать во всех видах обходных решений, чтобы охватить все версии.

Я собрал список телефонов и прошивок, которые работают/не работают/работают с перерывами, чтобы мы могли либо протестировать телефон, либо прошивку.

http://apprssd.com/2010/09/08/android-onsensorchanged-not-working-when-screen-lock-is-on/

Если у вас есть новый телефон, вы можете обновить список, сообщите мне.

Ответ 5

Здесь есть альтернативное решение (вид), в котором вы постоянно включаете экран, используя:

Settings.System.putInt(getContentResolver(),                    Settings.System.SCREEN_OFF_TIMEOUT, -1);

Но это не мешает пользователю отключить экран, нажав кнопку питания, а затем поток событий датчика прекратится. Для этого вам также потребуется разрешение WRITE_SETTINGS.

Обходной путь выше перерегистрации для событий датчиков не работает на Droid Eris, который работает под управлением Android 2.1 и, как ожидается, никогда не получит обновление. Я использовал следующее, хотя, похоже, работает. Вместо отмены регистрации и повторной регистрации этот подход снова включает экран, когда пользователь отключает его, хотя он возвращается на затемненный. В следующем коде обработчик - это просто простой обработчик, созданный в Activity (т.е. Обработчик Handler = new Handler();) и mTurnBackOn - это WakeLock, инициализированный нулем.

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();
            }});
        }
    }
};