在Droid/Nexus One上,即使使用WakeLock,当屏幕关闭时加速度计仍然停止提供样本

25
我有一些代码,它扩展了一个服务并记录了在Android上的onSensorChanged(SensorEvent事件)加速度传感器读数。即使设备关闭了(我非常注意电池寿命,当运行时会显而易见),我也希望能够记录这些传感器读数。当屏幕开启时,日志记录在2.0.1 Motorola Droid和2.1 Nexus One上都可以正常工作。
然而,当手机进入睡眠状态(通过按下电源按钮),屏幕关闭后,onSensorChanged事件停止传递(通过每N次onSensorChanged被调用使用Log.e消息进行验证)。
该服务获取wakelock以确保在后台保持运行状态,但似乎没有任何效果。我尝试过所有各种PowerManager.wake locks,但它们似乎都无关紧要。
_WakeLock = _PowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
_WakeLock.acquire();

关于在屏幕关闭的情况下是否可以从传感器获取数据一直存在争议... 有没有人在更现代的Android版本(Eclair)和硬件上有相关经验呢?

这似乎表明在Cupcake中可以正常工作: http://groups.google.com/group/android-developers/msg/a616773b12c2d9e5

PS:在G1上,完全相同的代码在1.5上按预期工作。当屏幕关闭、应用程序在后台等情况下,日志记录仍在继续。


请在此跟踪此问题:http://code.google.com/p/android/issues/detail?id=3708 - Roman Nurik
我已经更新了下面的答案,并提供了一个解决办法,我们发现这对摩托罗拉2.0.1设备非常有效。一旦2.1可用,我也会及时汇报任何问题的影响。 - mylock
这个问题的新跟踪器 - 在2.2版本中仍然存在问题 - http://code.google.com/p/android/issues/detail?id=11028 - Artem
支持/不支持的手机列表:http://www.saltwebsites.com/2012/android-accelerometers-screen-off - Fletch
Roman Nurik发布的3708问题仍未解决。遗憾的是,没有通用的解决方法适用于所有受影响的Android设备。 - ChuongPham
5个回答

10
我们推断这是从2.0.1开始的。这似乎是有意为之的,可能是作为宣传的电池寿命提升的一部分。我们在2.0上有一个工作的摇晃唤醒或解锁,然后在更新中就坏了,我们无法得到任何解决方法。即使保持CPU部分锁定,这应该始终防止CPU进入睡眠状态也没有用。从我在USB上记录调试信息看来,当睡眠发生时,偶尔会提到传感器监听器的更改。
一个用户发布了一个解决方法,他声称在摩托罗拉设备上有效 - 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时无法使用,而这正是很多用户希望与我正在开发的功能一起使用的特性。


1
谢谢这个建议;结合PARTIAL_WAKE_LOCK,重新注册技术对我来说大部分都有效。但是我必须将重新注册的部分放在定时执行线程中,以便在所有SCREEN_OFF活动安定下来后再进行。详情请参见:http://nosemaj.org/android-persistent-sensors - Jameson
感谢 @mylock 的回答。 - Sharanabasu Angadi

1
刚刚更新了我的Nexus One,使用了在互联网上流传了几天的FROYO FRF50 ROM。如果你有PARTIAL_WAKELOCK,现在当屏幕关闭时传感器似乎又可以工作了。我不知道这是否会被包含在官方版本中,尽管我的理解是这是基于一些N1用户收到的官方版本构建的。所以也许他们改变了主意(再次),并重新启用了手机锁定时的传感器。祈祷吧。
当然,他们也可能在2.2-r1中再次禁用它们,谁知道呢...

小更新:他们在2.2正式版中没有禁用它。传感器在我Nexus One上的最终2.2构建(FRF91)中即使屏幕关闭也可以工作。 - pableu

1

在HTC EVO上,使用SCREEN_DIM_WAKE_LOCK对我有用。

final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
_WakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG");
_WakeLock.acquire();

1
只是为了补充一下...这种解决方法会更加耗费资源,因为屏幕会保持在昏暗状态。经过大量搜索,似乎这个问题在后来的Android操作系统版本中仍未得到解决... - Ashish

0

有一种替代方案(有点类似),你可以使用以下代码来保持屏幕常亮:

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

但是,这并不能防止用户按下电源键强制关闭屏幕,然后传感器事件流就会停止。此外,您还需要 WRITE_SETTINGS 权限才能使其正常工作。

上述解决方法不适用于运行 Android 2.1 的 Droid Eris,因为该设备不会得到更新。但我已经使用了以下解决方法,看起来是有效的。与其取消注册和重新注册,这种方法在用户关闭屏幕时重新打开它,尽管它会变暗。在下面的代码中,handler 只是在 Activity 中构造的一个简单处理程序(即 Handler handler = new Handler()),而 mTurnBackOn 是一个初始化为 null 的 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();
            }});
        }
    }
};

0

看起来这是一个2.1固件的问题,我需要解决这个问题,但我必须使用各种变通方法来覆盖所有版本。

我已经列出了一张手机和固件的清单,标明哪些可以工作、哪些不能工作、哪些偶尔可以工作,以便我们可以测试手机或固件。

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

如果你有新手机可以更新列表,请让我知道。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接