Show next alarm on ambient display
Next alarm will be visible 12h before triggering.
Test: Set alarm that will ring in 8h
Test: Set alarm that will ring in 14h
Test: Set alarm that will ring in 11:59, wait one minute
Test: atest packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
Change-Id: Icd4253771efcdf5afb4e9e52329fa410d7fd1cc1
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index b54d09a..2adb286 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -167,7 +167,8 @@
}
mClickActions.put(button, pendingIntent);
- button.setText(rc.getTitleItem().getText());
+ final SliceItem titleItem = rc.getTitleItem();
+ button.setText(titleItem == null ? null : titleItem.getText());
Drawable iconDrawable = null;
SliceItem icon = SliceQuery.find(item.getSlice(),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index c7d276c..26618bf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -27,6 +28,7 @@
import android.icu.text.DisplayContext;
import android.net.Uri;
import android.os.Handler;
+import android.os.SystemClock;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,6 +38,7 @@
import java.util.Date;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import androidx.app.slice.Slice;
import androidx.app.slice.SliceProvider;
@@ -53,6 +56,12 @@
public static final String KEYGUARD_NEXT_ALARM_URI =
"content://com.android.systemui.keyguard/alarm";
+ /**
+ * Only show alarms that will ring within N hours.
+ */
+ @VisibleForTesting
+ static final int ALARM_VISIBILITY_HOURS = 12;
+
private final Date mCurrentTime = new Date();
protected final Uri mSliceUri;
protected final Uri mDateUri;
@@ -65,6 +74,10 @@
private boolean mRegisteredEveryMinute;
private String mNextAlarm;
private NextAlarmController mNextAlarmController;
+ protected AlarmManager mAlarmManager;
+ protected ContentResolver mContentResolver;
+ private AlarmManager.AlarmClockInfo mNextAlarmInfo;
+ private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -105,17 +118,26 @@
public Slice onBindSlice(Uri sliceUri) {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText));
- if (!TextUtils.isEmpty(mNextAlarm)) {
- Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
- builder.addRow(new RowBuilder(builder, mAlarmUri)
- .setTitle(mNextAlarm).addEndItem(icon));
+ addNextAlarm(builder);
+ return builder.build();
+ }
+
+ protected void addNextAlarm(ListBuilder builder) {
+ if (TextUtils.isEmpty(mNextAlarm)) {
+ return;
}
- return builder.build();
+ Icon alarmIcon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
+ RowBuilder alarmRowBuilder = new RowBuilder(builder, mAlarmUri)
+ .setTitle(mNextAlarm)
+ .addEndItem(alarmIcon);
+ builder.addRow(alarmRowBuilder);
}
@Override
public boolean onCreateSliceProvider() {
+ mAlarmManager = getContext().getSystemService(AlarmManager.class);
+ mContentResolver = getContext().getContentResolver();
mNextAlarmController = new NextAlarmControllerImpl(getContext());
mNextAlarmController.addCallback(this);
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
@@ -124,15 +146,25 @@
return true;
}
- public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
- if (info == null) {
- return "";
+ private void updateNextAlarm() {
+ if (withinNHours(mNextAlarmInfo, ALARM_VISIBILITY_HOURS)) {
+ String pattern = android.text.format.DateFormat.is24HourFormat(getContext(),
+ ActivityManager.getCurrentUser()) ? "H:mm" : "h:mm";
+ mNextAlarm = android.text.format.DateFormat.format(pattern,
+ mNextAlarmInfo.getTriggerTime()).toString();
+ } else {
+ mNextAlarm = "";
}
- String skeleton = android.text.format.DateFormat
- .is24HourFormat(context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
- String pattern = android.text.format.DateFormat
- .getBestDateTimePattern(Locale.getDefault(), skeleton);
- return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
+ mContentResolver.notifyChange(mSliceUri, null /* observer */);
+ }
+
+ private boolean withinNHours(AlarmManager.AlarmClockInfo alarmClockInfo, int hours) {
+ if (alarmClockInfo == null) {
+ return false;
+ }
+
+ long limit = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(hours);
+ return mNextAlarmInfo.getTriggerTime() <= limit;
}
/**
@@ -181,7 +213,7 @@
final String text = getFormattedDate();
if (!text.equals(mLastText)) {
mLastText = text;
- getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ mContentResolver.notifyChange(mSliceUri, null /* observer */);
}
}
@@ -203,7 +235,15 @@
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarm = formatNextAlarm(getContext(), nextAlarm);
- getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ mNextAlarmInfo = nextAlarm;
+ mAlarmManager.cancel(mUpdateNextAlarm);
+
+ long triggerAt = mNextAlarmInfo == null ? -1 : mNextAlarmInfo.getTriggerTime()
+ - TimeUnit.HOURS.toMillis(ALARM_VISIBILITY_HOURS);
+ if (triggerAt > 0) {
+ mAlarmManager.setExact(AlarmManager.RTC, triggerAt, "lock_screen_next_alarm",
+ mUpdateNextAlarm, mHandler);
+ }
+ updateNextAlarm();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 78481d3..2151436 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,10 +15,10 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
-import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
@@ -51,6 +51,8 @@
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.NextAlarmController;
+import java.util.Locale;
+
/**
* View that contains the top-most bits of the screen (primarily the status bar with date, time, and
* battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
@@ -289,7 +291,7 @@
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarmText = nextAlarm != null ? formatNextAlarm(mContext, nextAlarm) : null;
+ mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null;
if (mNextAlarmText != null) {
hideLongPressTooltip(true /* shouldFadeInAlarmText */);
} else {
@@ -430,4 +432,15 @@
public void setCallback(Callback qsPanelCallback) {
mHeaderQsPanel.setCallback(qsPanelCallback);
}
+
+ private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
+ if (info == null) {
+ return "";
+ }
+ String skeleton = android.text.format.DateFormat
+ .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
+ String pattern = android.text.format.DateFormat
+ .getBestDateTimePattern(Locale.getDefault(), skeleton);
+ return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
+ }
}