6

我需要通过以下方式提醒用户某些事件:

  • 振动
  • 通知

在用户确认通知之前,振动应无限期保持。

问题是当设备进入睡眠状态时振动停止。我已阅读以下问题:
屏幕关闭时允许手机
振动 即使在 Android 中屏幕进入睡眠模式后仍继续振动

上面提到的一个问题有一个答案,说没有模式的振动可以解决问题。因此,我尝试调用Vibrator.vibrate接受毫秒的版本,而不是具有大量数字的模式,但无论如何振动都会停止。

其他答案建议在操作上注册接收器ACTION_SCREEN_OFF。如果设备在警报开始后进入睡眠状态,这将允许我恢复振动,但如果设备已经睡眠,则不会工作。

但是,如果我能够先打开屏幕,然后注册接收器以处理从那里可能发生的任何屏幕关闭事件,我就可以让它工作。因此,我尝试在收到触发事件时,在开始声音或振动之前获取完整的唤醒锁,但尽管我使用了标志 FULL_WAKE_LOCK 和 ACQUIRE_CAUSES_WAKEUP,但它不起作用。唤醒部分有效,但不久之后设备再次进入睡眠状态。我想认为FULL_WAKE_LOCK标志不起作用,因为它在 API 17 中已被弃用,但我的设备是运行 4.1.2 即 API 16 的三星!

现在推荐的方法似乎是使用 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON但这应该从活动中调用,除非用户单击通知,否则我没有任何屏幕,如果发生这种情况,声音和振动应该已经有被阻止了。

所以它看起来像一个死胡同。

我还能尝试什么?

更新:
我没有运气通过唤醒锁保持屏幕始终打开,但另一方面,它们允许我打开屏幕几秒钟。我实际上不需要保持屏幕打开,所以我在Intent.ACTION_SCREEN_OFF动作上注册了接收器,当屏幕关闭时,接收器再次恢复振动。这在三星中运行良好,但我现在已经切换到华为继续测试并且接收器无法正常工作。

更新:
这是华为设备中异常的堆栈跟踪:

    java.util.NoSuchElementException: Death link does not exist
    at android.os.BinderProxy.unlinkToDeath(Native Method)
    at com.android.server.VibratorService.unlinkVibration(VibratorService.java:294)
    at com.android.server.VibratorService.removeVibrationLocked(VibratorService.java:284)
    at com.android.server.VibratorService.cancelVibrate(VibratorService.java:213)
    at android.os.IVibratorService$Stub.onTransact(IVibratorService.java:83)
    at android.os.Binder.execTransact(Binder.java:338)
    at dalvik.system.NativeStart.run(Native Method)
4

2 回答 2

1

您是否打算让设备进入睡眠状态?您可以获得唤醒屏幕的唤醒锁。

    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "myTAG");
    wl.acquire(LOCK_SCREEN_TIME_MINUTES * 60 * 1000);

这对你不起作用?之后你可以显示通知,但我不确定效果,它会保持振动吗?以上一个适用于具有 android 4.2.2 的 GalaxyTab 2 和具有 android 2.3.4 的 HTC Hero。

于 2014-06-11T10:08:30.040 回答
1

经过一些测试,我终于设法让它工作。

Vibrator类有两种方法:

  • vibrate (long[] pattern, int repeat)
  • vibrate (long milliseconds)

一个是使用 API 无限期振动的唯一方法(将 0 作为第二个参数传递)。但正如我在问题中发布的那样,这已被证明会破坏某些设备(华为)。我不是在谈论当设备进入睡眠状态时操作系统停止振动,这是使用接收器和问题中描述的唤醒锁来处理的。我说的是由错误的实现引起的异常(Vibrator 类是抽象的)。

该方法的第二个变体不接受模式,也不允许无限振动,但我们可以通过传递大量毫秒作为参数来作弊。这在某些设备(华为)中运行良好,正如我在问题中正确指出的答案,但在其他设备(三星)中不起作用,其中实现具有默认最大值,如果作为参数传递的值超过,则将使用该最大值它。这个最大值实际上不到一分钟,这意味着我们不能依赖这种方法。

所以我全力以赴并创建了一个服务,我在其中手动无限期地振动,如下所示:

    while(vibrationActive){
        Vibrator.vibrate(1000); 
        Thread.sleep(1000);
    }

不再需要检测屏幕何时关闭的接收器技巧。当然,当这种情况发生时,操作系统会继续关闭振动器,但循环的下一次迭代将再次恢复振动。使用这种方法,如果睡眠时间大于振动时间,也可以创建一种模式,但是如果屏幕关闭,这种模式将在任何时候被中断。

一项专门的服务,只是为了可靠地打开和关闭振动器。你相信吗?大约 150 行代码(没有单元测试),用几行就可以实现。

于 2014-06-11T15:44:02.187 回答