Custom message in AoD
Optional message that lives under the clock and also
in AoD. Implemented using a slice.
Test: launch sysui, look at the date in AoD
Test: runtest -x packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
Change-Id: I9dbc827bd48c6a3d1b25b0a481ffaecc0dd37f25
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
new file mode 100644
index 0000000..c18f9b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard;
+
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.R;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+
+/**
+ * View visible under the clock on the lock screen and AoD.
+ */
+public class KeyguardSliceView extends LinearLayout {
+
+ private final Uri mKeyguardSliceUri;
+ private TextView mTitle;
+ private TextView mText;
+ private Slice mSlice;
+ private PendingIntent mSliceAction;
+ private int mTextColor;
+ private float mDarkAmount = 0;
+
+ private final ContentObserver mObserver;
+
+ public KeyguardSliceView(Context context) {
+ this(context, null, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mObserver = new KeyguardSliceObserver(new Handler());
+ mKeyguardSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
+ mText = findViewById(R.id.text);
+ mTextColor = mTitle.getCurrentTextColor();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ // Set initial content
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+
+ // Make sure we always have the most current slice
+ getContext().getContentResolver().registerContentObserver(mKeyguardSliceUri,
+ false /* notifyDescendants */, mObserver);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ private void showSlice(Slice slice) {
+ // Items will be wrapped into an action when they have tap targets.
+ SliceItem actionSlice = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
+ if (actionSlice != null) {
+ mSlice = actionSlice.getSlice();
+ mSliceAction = actionSlice.getAction();
+ } else {
+ mSlice = slice;
+ mSliceAction = null;
+ }
+
+ if (mSlice == null) {
+ setVisibility(GONE);
+ return;
+ }
+
+ SliceItem title = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null);
+ if (title == null) {
+ mTitle.setVisibility(GONE);
+ } else {
+ mTitle.setVisibility(VISIBLE);
+ mTitle.setText(title.getText());
+ }
+
+ SliceItem text = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, null, Slice.HINT_TITLE);
+ if (text == null) {
+ mText.setVisibility(GONE);
+ } else {
+ mText.setVisibility(VISIBLE);
+ mText.setText(text.getText());
+ }
+
+ final int visibility = title == null && text == null ? GONE : VISIBLE;
+ if (visibility != getVisibility()) {
+ setVisibility(visibility);
+ }
+ }
+
+ public void setDark(float darkAmount) {
+ mDarkAmount = darkAmount;
+ updateTextColors();
+ }
+
+ public void setTextColor(int textColor) {
+ mTextColor = textColor;
+ }
+
+ private void updateTextColors() {
+ final int blendedColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
+ mTitle.setTextColor(blendedColor);
+ mText.setTextColor(blendedColor);
+ }
+
+ private class KeyguardSliceObserver extends ContentObserver {
+ KeyguardSliceObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ this.onChange(selfChange, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index bc2a59d..78cf2b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -19,11 +19,9 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.PorterDuff;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -42,8 +40,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.ChargingView;
-import com.android.systemui.statusbar.policy.DateView;
import java.util.Locale;
@@ -55,13 +53,11 @@
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
- private TextView mAlarmStatusView;
- private DateView mDateView;
private TextClock mClockView;
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
- private View mKeyguardStatusArea;
+ private KeyguardSliceView mKeyguardSlice;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
@@ -69,8 +65,6 @@
private boolean mPulsing;
private float mDarkAmount = 0;
private int mTextColor;
- private int mDateTextColor;
- private int mAlarmTextColor;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -141,7 +135,6 @@
private void setEnableMarqueeImpl(boolean enabled) {
if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
- if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
}
@@ -149,8 +142,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
mClockContainer = findViewById(R.id.keyguard_clock_container);
- mAlarmStatusView = findViewById(R.id.alarm_status);
- mDateView = findViewById(R.id.date_view);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
@@ -158,11 +149,9 @@
}
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
- mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardStatusArea};
+ mKeyguardSlice = findViewById(R.id.keyguard_status_area);
+ mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardSlice};
mTextColor = mClockView.getCurrentTextColor();
- mDateTextColor = mDateView.getCurrentTextColor();
- mAlarmTextColor = mAlarmStatusView.getCurrentTextColor();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -184,8 +173,6 @@
layoutParams.bottomMargin = getResources().getDimensionPixelSize(
R.dimen.bottom_text_spacing_digital);
mClockView.setLayoutParams(layoutParams);
- mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
if (mOwnerInfo != null) {
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
@@ -193,8 +180,6 @@
}
public void refreshTime() {
- mDateView.setDatePattern(Patterns.dateViewSkel);
-
mClockView.setFormat12Hour(Patterns.clockView12);
mClockView.setFormat24Hour(Patterns.clockView24);
}
@@ -205,23 +190,11 @@
Patterns.update(mContext, nextAlarm != null);
refreshTime();
- refreshAlarmStatus(nextAlarm);
- }
-
- void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
- if (nextAlarm != null) {
- String alarm = formatNextAlarm(mContext, nextAlarm);
- mAlarmStatusView.setText(alarm);
- mAlarmStatusView.setContentDescription(
- getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
- mAlarmStatusView.setVisibility(View.VISIBLE);
- } else {
- mAlarmStatusView.setVisibility(View.GONE);
- }
}
public int getClockBottom() {
- return mKeyguardStatusArea.getBottom();
+ return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
+ : mClockView.getBottom();
}
public float getClockTextSize() {
@@ -341,11 +314,8 @@
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
+ mKeyguardSlice.setDark(darkAmount);
mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
- mDateView.setTextColor(ColorUtils.blendARGB(mDateTextColor, Color.WHITE, darkAmount));
- int blendedAlarmColor = ColorUtils.blendARGB(mAlarmTextColor, Color.WHITE, darkAmount);
- mAlarmStatusView.setTextColor(blendedAlarmColor);
- mAlarmStatusView.setCompoundDrawableTintList(ColorStateList.valueOf(blendedAlarmColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
new file mode 100644
index 0000000..03018f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.icu.text.DateFormat;
+import android.icu.text.DisplayContext;
+import android.net.Uri;
+import android.os.Handler;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Simple Slice provider that shows the current date.
+ */
+public class KeyguardSliceProvider extends SliceProvider {
+
+ public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
+
+ private final Date mCurrentTime = new Date();
+ protected final Uri mSliceUri;
+ private final Handler mHandler;
+ private String mDatePattern;
+ private DateFormat mDateFormat;
+ private String mLastText;
+ private boolean mRegistered;
+ private boolean mRegisteredEveryMinute;
+
+ /**
+ * Receiver responsible for time ticking and updating the date format.
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_TIME_TICK.equals(action)
+ || Intent.ACTION_DATE_CHANGED.equals(action)
+ || Intent.ACTION_TIME_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
+ || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+ // need to get a fresh date format
+ mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
+ }
+ mHandler.post(KeyguardSliceProvider.this::updateClock);
+ }
+ }
+ };
+
+ public KeyguardSliceProvider() {
+ this(new Handler());
+ }
+
+ @VisibleForTesting
+ KeyguardSliceProvider(Handler handler) {
+ mHandler = handler;
+ mSliceUri = Uri.parse(KEYGUARD_SLICE_URI);
+ }
+
+ @Override
+ public Slice onBindSlice(Uri sliceUri) {
+ return new Slice.Builder(sliceUri).addText(mLastText, Slice.HINT_TITLE).build();
+ }
+
+ @Override
+ public boolean onCreate() {
+
+ mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
+
+ registerClockUpdate(false /* everyMinute */);
+ updateClock();
+ return true;
+ }
+
+ protected void registerClockUpdate(boolean everyMinute) {
+ if (mRegistered) {
+ if (mRegisteredEveryMinute == everyMinute) {
+ return;
+ } else {
+ unregisterClockUpdate();
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ if (everyMinute) {
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ }
+ filter.addAction(Intent.ACTION_DATE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
+ null /* scheduler */);
+ mRegistered = true;
+ mRegisteredEveryMinute = everyMinute;
+ }
+
+ protected void unregisterClockUpdate() {
+ if (!mRegistered) {
+ return;
+ }
+ getContext().unregisterReceiver(mIntentReceiver);
+ mRegistered = false;
+ }
+
+ @VisibleForTesting
+ boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected void updateClock() {
+ final String text = getFormattedDate();
+ if (!text.equals(mLastText)) {
+ mLastText = text;
+ getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ }
+ }
+
+ protected String getFormattedDate() {
+ if (mDateFormat == null) {
+ final Locale l = Locale.getDefault();
+ DateFormat format = DateFormat.getInstanceForSkeleton(mDatePattern, l);
+ format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
+ mDateFormat = format;
+ }
+ mCurrentTime.setTime(System.currentTimeMillis());
+ return mDateFormat.format(mCurrentTime);
+ }
+
+ @VisibleForTesting
+ void cleanDateFormat() {
+ mDateFormat = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index fa34d4a..3f0994d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -7112,7 +7112,7 @@
mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
}
- private void updateLockscreenNotificationSetting() {
+ protected void updateLockscreenNotificationSetting() {
final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
1,