Merge "Show next alarm on ambient display"

This commit is contained in:
TreeHugger Robot
2018-02-28 00:19:29 +00:00
committed by Android (Google) Code Review
4 changed files with 127 additions and 29 deletions

View File

@@ -167,7 +167,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
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(),

View File

@@ -19,6 +19,7 @@ package com.android.systemui.keyguard;
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.DateFormat;
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 com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
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 class KeyguardSliceProvider extends SliceProvider implements
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 @@ public class KeyguardSliceProvider extends SliceProvider implements
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 class KeyguardSliceProvider extends SliceProvider implements
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 @@ public class KeyguardSliceProvider extends SliceProvider implements
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 @@ public class KeyguardSliceProvider extends SliceProvider implements
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 @@ public class KeyguardSliceProvider extends SliceProvider implements
@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();
}
}

View File

@@ -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;
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 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
@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 class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
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();
}
}

View File

@@ -16,10 +16,17 @@
package com.android.systemui.keyguard;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import androidx.app.slice.Slice;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Debug;
import android.os.Handler;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -32,24 +39,31 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import androidx.app.slice.SliceItem;
import androidx.app.slice.SliceProvider;
import androidx.app.slice.SliceSpecs;
import androidx.app.slice.core.SliceQuery;
import androidx.app.slice.widget.SliceLiveData;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
public class KeyguardSliceProviderTest extends SysuiTestCase {
@Mock
private ContentResolver mContentResolver;
@Mock
private AlarmManager mAlarmManager;
private TestableKeyguardSliceProvider mProvider;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mProvider = new TestableKeyguardSliceProvider();
mProvider.attachInfo(getContext(), null);
SliceProvider.setSpecs(Arrays.asList(SliceSpecs.LIST));
@@ -70,7 +84,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void returnsValidSlice() {
Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI));
Slice slice = mProvider.onBindSlice(mProvider.getUri());
SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT,
android.app.slice.Slice.HINT_TITLE,
null /* nonHints */);
@@ -87,21 +101,52 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
@Test
public void updatesClock() {
mProvider.mUpdateClockInvokations = 0;
mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
TestableLooper.get(this).processAllMessages();
Assert.assertEquals("Clock should have been updated.", 1 /* expected */,
mProvider.mUpdateClockInvokations);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
}
@Test
public void schedulesAlarm12hBefore() {
long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(16);
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
mProvider.onNextAlarmChanged(alarmClockInfo);
long twelveHours = TimeUnit.HOURS.toMillis(KeyguardSliceProvider.ALARM_VISIBILITY_HOURS);
long triggerAt = in16Hours - twelveHours;
verify(mAlarmManager).setExact(eq(AlarmManager.RTC), eq(triggerAt), anyString(), any(),
any());
}
@Test
public void updatingNextAlarmInvalidatesSlice() {
long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(8);
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null);
mProvider.onNextAlarmChanged(alarmClockInfo);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
}
private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
int mCleanDateFormatInvokations;
int mUpdateClockInvokations;
private int mCounter;
TestableKeyguardSliceProvider() {
super(new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper()));
}
Uri getUri() {
return mSliceUri;
}
@Override
public boolean onCreateSliceProvider() {
super.onCreateSliceProvider();
mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager;
mContentResolver = KeyguardSliceProviderTest.this.mContentResolver;
return true;
}
@Override
void cleanDateFormat() {
super.cleanDateFormat();
@@ -109,9 +154,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
}
@Override
protected void updateClock() {
super.updateClock();
mUpdateClockInvokations++;
protected String getFormattedDate() {
return super.getFormattedDate() + mCounter++;
}
}