安卓如何获取当前正在运行的闹钟列表

38

在我们的应用程序中,有没有办法以编程方式获取Android设备中所有活动警报的列表。只需指出一些有帮助的链接,我基本上正在尝试为用户提供查看设备中所有警报的功能,因此我想获取设备中所有活动警报的列表。

6个回答

29

据我所知,你无法通过编程实现将该信息显示在UI上,因此这种做法不可行。

然而,你可以通过以下方式转储报警数据以供自己参考:

adb shell dumpsys alarm

你不需要root权限。

但是你从上述内容中获得的可能非常难以理解。为了完全理解那个dump,你应该查看morphatic的答案 这里


23

简短回答:你做不到。

闹钟管理器没有提供当前系统中预定的闹钟的可见性。每个使用闹钟管理器的应用程序都必须保存他们设置的每个闹钟的状态。

然而,你可以通过 adb 获取列表,如这个问题描述的获取 AlarmManager 中活动 PendingIntents 的列表。一个应用程序可以获取系统转储并以这种方式获取闹钟,但这需要 root 权限。


1
但是有一些应用程序可以设置/更新活动警报。它们是如何做到的? - julio
1
应用程序可以通过维护活动闹钟列表来设置/修改它们自己的闹钟。该列表将使用SharedPreferences或sqlite进行持久化。要修改或删除闹钟,请完全重新创建设置时的闹钟对象并使用AlarmManger方法。干杯。 - Steven Trigg
1
我所说的活动警报是指在安卓的“时钟”应用程序中创建的警报。我们能够访问这些警报吗? - julio
1
好的,我认为你在寻找这个链接:http://developer.android.com/reference/android/provider/AlarmClock.html 它只涉及由闹钟应用设置的闹钟,而这个问题是关于设备上任何应用设置的闹钟,因为他们已经说“所有设备上的闹钟”。 - Steven Trigg
1
这有点令人沮丧。 - Matt

11
如果你指的是设备闹钟应用程序中的活动警报,则我认为可以。请尝试查看这里的方法。
然而,如果你想查看在你的设备上由AlarmManager创建的所有警报,那么很遗憾,你无法通过编程实现。
但是,你可以查看像这样的文本文件中的转储数据:
adb shell dumpsys alarm > dump.txt

5
您可以获取下一个已安排的闹钟(文档)
getSystemService(AlarmManager::class.java).nextAlarmClock.triggerTime

返回警报将触发的时间。此值为UTC墙上时钟时间(以毫秒为单位)。

这仅适用于AlarmClocks,而不适用于任何其他类型的闹钟。 - Mooing Duck

0

我刚刚在我的新手机上遇到了这个问题。我从旧手机迁移数据,事后我认为发生的情况是一个未激活的闹钟应用程序突然激活了,或者在迁移后启用了该应用程序中的禁用闹钟。无论如何,突然之间每天早上8:30我都听到了一个我无法识别的闹钟声。

以下概述了我是如何解决这个问题的。如果您不关心此内容,请滚动到结尾处的 TL;DR 部分。

故障排除过程

我采用的方法是使用其他答案中描述的 adb。但是,如果您这样做,您很快就会感到不知所措。对我来说,输出结果是一个超过2,000行的输出,其中大约在第260行左右有这样一个简短的消息:

Pending alarm batches: 130

这是因为它们不是你和我所说的警报。相反,它们是各种应用程序要求在特定时间唤醒(例如,邮件应用程序要求在一分钟内被唤醒以检查新邮件)。所以我猜是为应用程序设定的闹钟。我的做法是首先确定“正确”的警报是什么样子的。我已经在正式闹钟应用程序中启用了两个闹钟,并且它们在过去24小时内已经响铃了。所以我首先运行了以下命令:
adb shell dumpsys alarm > two-alarms.txt

然后我禁用了其中一个警报并运行:

adb shell dumpsys alarm > one-alarm.txt

我随后比较了这两个输出,并注意到大部分差异都与时间戳有关(这很合理——它们在不同的时间运行,输出重点关注“X毫秒后我应该做什么”)。例如,我会看到像这样的diff输出:

287c293
<       type=3 expectedWhenElapsed=+1m51s619ms expectedMaxWhenElapsed=+1m51s619ms whenElapsed=+1m51s619ms maxWhenElapsed=+1m51s619ms when=+1m51s619ms
---
>       type=3 expectedWhenElapsed=+1m48s727ms expectedMaxWhenElapsed=+1m48s727ms whenElapsed=+1m48s727ms maxWhenElapsed=+1m48s727ms when=+1m48s727ms

我重新运行了diff,过滤掉包含type=的行:

$ diff -I 'type=' two-alarms.txt one-alarm.txt|less

这段内容仍然包含很多噪音,但相关部分更容易定位。例如,我发现的第一个实质性差异是:

561c567,573
< Batch{b03e994 num=1 start=1851593838 end=1851593838 flgs=0x1}:
---
> Batch{849c837 num=1 start=1851593838 end=1851593838 flgs=0x5}:
>     RTC_WAKEUP #0: Alarm{e855db5 statsTag *walarm*:com.google.android.gms.reminders.notification.ACTION_REFRESH_TIME_REMINDERS type 0 when 1606626000000 com.google.android.gms}
>       tag=*walarm*:com.google.android.gms.reminders.notification.ACTION_REFRESH_TIME_REMINDERS
>       type=0 expectedWhenElapsed=+4h30m42s565ms expectedMaxWhenElapsed=+4h30m42s565ms whenElapsed=+4h30m42s565ms maxWhenElapsed=+4h30m42s565ms when=2020-11-29 00:00:00.000
>       window=0 repeatInterval=0 count=0 flags=0x5
>       operation=PendingIntent{543c4a: PendingIntentRecord{97867bb com.google.android.gms startService}}
> Batch{3f531a4 num=1 start=1851593838 end=1851593838 flgs=0x1}:

这显然是我设置的提醒(或者可能是 Google 提醒设置的通用“叫醒我检查提醒”的闹钟,以检查提醒)。

在输出中进行更深入的挖掘,我们可以得到:

1027c1033,1039
<       type=0 expectedWhenElapsed=+1d13h20m45s459ms expectedMaxWhenElapsed=+1d13h20m45s459ms whenElapsed=+1d13h20m45s459ms maxWhenElapsed=+1d13h20m45s459ms when=2020-11-30 08:50:00.002
---
>       type=0 expectedWhenElapsed=+1d13h20m42s566ms expectedMaxWhenElapsed=+1d13h20m42s566ms whenElapsed=+1d13h20m42s566ms maxWhenElapsed=+1d13h20m42s566ms when=2020-11-30 08:50:00.002
>       window=0 repeatInterval=0 count=0 flags=0x9
>       operation=PendingIntent{89757d2: PendingIntentRecord{127f2fd com.lge.clock broadcastIntent}}
> Batch{39e90a3 num=1 start=2045693838 end=2045693838 flgs=0x9}:
>     RTC_WAKEUP #0: Alarm{ba76fa0 statsTag *walarm*:com.lge.clock.show_quick_dismiss_noti type 0 when 1606820100000 com.lge.clock}
>       tag=*walarm*:com.lge.clock.show_quick_dismiss_noti
>       type=0 expectedWhenElapsed=+2d10h25m42s565ms expectedMaxWhenElapsed=+2d10h25m42s565ms whenElapsed=+2d10h25m42s565ms maxWhenElapsed=+2d10h25m42s565ms when=2020-12-01 05:55:00.000

所以官方的闹钟应用似乎是 com.lge.clock,这完全合情合理 -- 这是一款LG手机。让我们在原始输出中找找看:

  u0a194:com.lge.clock +21s656ms running, 61 wakeups:
    +12s50ms 11 wakes 11 alarms, last -1d10h37m18s647ms:
      *walarm*:com.lge.clock.alarmclock.internal.for.lmk
    +8s338ms 17 wakes 17 alarms, last -1d12h42m26s219ms:
      *walarm*:com.lge.clock.show_quick_dismiss_noti
    +4s272ms 11 wakes 11 alarms, last -1d10h37m18s647ms:
      *walarm*:com.lge.clock.alarmclock.internal
    +1s2ms 11 wakes 11 alarms, last -1d10h38m15s71ms:
      *walarm*:com.lge.sizechangable.weather.action.force.update.currentonly
    +996ms 11 wakes 11 alarms, last -1d10h37m18s647ms:
      *walarm*:indicator

在这里,我们可以看到这个应用程序已经有一些警报在一天、10小时、37分钟和一些秒和毫秒前响起了 (-1d10h37m18s647ms)。这是有道理的。这个输出是在18:32(下午6:32)运行的,我的一个真正的警报设置在7:55。认识到如何识别“最后触发”的时间,我们现在可以搜索那个难以捉摸的8:30闹钟。从报告时间算起,8:30大约是一天、10小时和两分钟,所以我们搜索-1d10h2m,得到:

  u0a235:net.fredericosilva.mornify +14s944ms running, 20 wakeups:
    +14s944ms 20 wakes 20 alarms, last -1d10h2m26s3ms:
      *walarm*:net.fredericosilva.mornify/.alarm.AlarmBroadcastReceiver

嗯...什么是net.fredericosilva.mornify?快速搜索结果为Mornify Play Page。看哪!我安装了这个闹钟应用Mornify。我完全忘记了我曾经测试过这个应用程序,并在决定它不适合我的情况下忘记删除它。问题解决了!

TL;DR

步骤1:

运行闹钟输出:

adb shell dumpsys alarm > my-alarms.txt

步骤2:

计算从现在到上次闹钟响起的相对时间。例如,如果输出运行的时间是下午6:32:18,而闹钟在昨天早上7点响了,那么差值就是6:32pm-7am+24小时,即1天11小时32分钟18秒(使用电子表格可以方便地进行时间计算)。

步骤3:

将时间差重新格式化为-DdHhMm,其中D表示天数,H表示小时数,M表示分钟数。我们将忽略秒以避免时钟漂移问题。在之前的例子中,这将是-1d11h32m

步骤4:

在步骤1的输出中搜索此字符串。如果找不到它,则需要在字符串中减去或加上一分钟以纠正时钟差异。


0

获取当前激活的警报目前还没有解决方法,但可以使用RingtoneManager获取警报铃声、铃声和通知声音的列表。

1. 要启动用户选择警报的默认意图,可以像以下这样启动隐式意图:

private void selectAlarmTone(){
    Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM); //Incase you want the user to set a notification use => RingtoneManager.TYPE_NOTIFICATION, ringtone use => RingtoneManager.TYPE_RINGTONE
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select an alarm tone");
    intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
    startActivityForResult(intent, 1);
}

并且要获取用户选择的闹钟,请使用 onActivityResult

@Override
protected void onActivityResult(final int requestCode, final int resultCode, final
Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK && requestCode == 1) {
        Uri selectedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);

        Ringtone ringtone = RingtoneManager.getRingtone(this, selectedUri);
        String title = ringtone.getTitle(this);
        Log.i("ALARM_SELECTED: ", title);
    }
}

2. 如果您想以编程方式获取音调列表,请使用:

public void listAlarmtones() {
    RingtoneManager ringtoneManager = new RingtoneManager(this);
    ringtoneManager.setType(RingtoneManager.TYPE_ALARM);
    Cursor cursor = ringtoneManager.getCursor();

      while (cursor.moveToNext()) {
        String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
        String uri = String.valueOf(ringtoneManager.getRingtoneUri(cursor.getPosition()));

        String alarmTone = cursor.getString(cursor.getColumnIndex("title"));

        Log.e("ALARM_TONE: ", title + "=>" + uri + "=>" + alarmTone);
      }
}

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