diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index bf2963cd0b7f6..7e2e36a4907d4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -61,6 +61,28 @@
android:visibility="invisible"
/>
+
+
+
{
+ if (bottom != oldBottom || top != oldTop) {
+ updatePaint();
+ }
+ };
+
+ public static final CharSequence FORMAT_12 = "hh\nmm";
+ public static final CharSequence FORMAT_24 = "HH\nmm";
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 272954df6dd64..cf363cc649f04 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -71,6 +71,16 @@ public class KeyguardClockSwitch extends RelativeLayout {
*/
private TextClock mClockViewBold;
+ /**
+ * Gradient clock for usage when mode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL.
+ */
+ private TimeBasedColorsClockController mNewLockscreenClockViewController;
+
+ /**
+ * Frame for clock when mode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL.
+ */
+ private FrameLayout mNewLockscreenClockFrame;
+
/**
* Frame for default and custom clock.
*/
@@ -137,23 +147,22 @@ public class KeyguardClockSwitch extends RelativeLayout {
mLockScreenMode = mode;
RelativeLayout.LayoutParams statusAreaLP = (RelativeLayout.LayoutParams)
mKeyguardStatusArea.getLayoutParams();
- RelativeLayout.LayoutParams clockLP = (RelativeLayout.LayoutParams)
- mSmallClockFrame.getLayoutParams();
if (mode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- statusAreaLP.removeRule(RelativeLayout.BELOW);
- statusAreaLP.addRule(RelativeLayout.LEFT_OF, R.id.clock_view);
- statusAreaLP.addRule(RelativeLayout.ALIGN_PARENT_START);
+ mSmallClockFrame.setVisibility(GONE);
+ mNewLockscreenClockFrame.setVisibility(VISIBLE);
+ mNewLockscreenClockViewController.init();
- clockLP.addRule(RelativeLayout.ALIGN_PARENT_END);
- clockLP.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+ statusAreaLP.removeRule(RelativeLayout.BELOW);
+ statusAreaLP.addRule(RelativeLayout.LEFT_OF, R.id.new_lockscreen_clock_view);
+ statusAreaLP.addRule(RelativeLayout.ALIGN_PARENT_START);
} else {
+ mSmallClockFrame.setVisibility(VISIBLE);
+ mNewLockscreenClockFrame.setVisibility(GONE);
+
statusAreaLP.removeRule(RelativeLayout.LEFT_OF);
statusAreaLP.removeRule(RelativeLayout.ALIGN_PARENT_START);
statusAreaLP.addRule(RelativeLayout.BELOW, R.id.clock_view);
-
- clockLP.removeRule(RelativeLayout.ALIGN_PARENT_END);
- clockLP.width = ViewGroup.LayoutParams.MATCH_PARENT;
}
requestLayout();
@@ -164,6 +173,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
super.onFinishInflate();
mClockView = findViewById(R.id.default_clock_view);
mClockViewBold = findViewById(R.id.default_clock_view_bold);
+ mNewLockscreenClockFrame = findViewById(R.id.new_lockscreen_clock_view);
+ mNewLockscreenClockViewController =
+ new TimeBasedColorsClockController(findViewById(R.id.gradient_clock_view));
mSmallClockFrame = findViewById(R.id.clock_view);
mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
}
@@ -336,6 +348,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
* Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
*/
public void refresh() {
+ mNewLockscreenClockViewController.refreshTime(System.currentTimeMillis());
mClockView.refreshTime();
mClockViewBold.refreshTime();
if (mClockPlugin != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index a479bca56c2ac..a9c06edf46ccb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -33,9 +33,11 @@ import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.slice.SliceItem;
@@ -55,8 +57,10 @@ import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* View visible under the clock on the lock screen and AoD.
@@ -86,6 +90,8 @@ public class KeyguardSliceView extends LinearLayout {
private float mRowWithHeaderTextSize;
private View.OnClickListener mOnClickListener;
+ private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+
public KeyguardSliceView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -142,6 +148,40 @@ public class KeyguardSliceView extends LinearLayout {
}
}
+ /**
+ * Updates the lockscreen mode which may change the layout of the keyguard slice view.
+ */
+ public void updateLockScreenMode(int mode) {
+ mLockScreenMode = mode;
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ // add top padding to better align with top of clock
+ final int topPadding = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ 20,
+ getResources().getDisplayMetrics());
+ mTitle.setPaddingRelative(0, topPadding, 0, 0);
+ mTitle.setGravity(Gravity.START);
+ setGravity(Gravity.START);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
+ lp.removeRule(RelativeLayout.CENTER_HORIZONTAL);
+ setLayoutParams(lp);
+ } else {
+ final int horizontalPaddingDpValue = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ 44,
+ getResources().getDisplayMetrics()
+ );
+ mTitle.setPaddingRelative(horizontalPaddingDpValue, 0, horizontalPaddingDpValue, 0);
+ mTitle.setGravity(Gravity.CENTER_HORIZONTAL);
+ setGravity(Gravity.CENTER_HORIZONTAL);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
+ lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
+ setLayoutParams(lp);
+ }
+ mRow.setLockscreenMode(mode);
+ requestLayout();
+ }
+
Map showSlice(RowContent header, List subItems) {
Trace.beginSection("KeyguardSliceView#showSlice");
mHasHeader = header != null;
@@ -166,6 +206,8 @@ public class KeyguardSliceView extends LinearLayout {
final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
LinearLayout.LayoutParams layoutParams = (LayoutParams) mRow.getLayoutParams();
+ layoutParams.gravity = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL
+ ? Gravity.START : Gravity.CENTER;
layoutParams.topMargin = mHasHeader ? mRowWithHeaderPadding : mRowPadding;
mRow.setLayoutParams(layoutParams);
@@ -282,6 +324,7 @@ public class KeyguardSliceView extends LinearLayout {
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mHasHeader: " + mHasHeader);
+ pw.println(" mLockScreenMode: " + mLockScreenMode);
}
@Override
@@ -291,6 +334,8 @@ public class KeyguardSliceView extends LinearLayout {
}
public static class Row extends LinearLayout {
+ private Set mKeyguardSliceTextViewSet = new HashSet();
+ private int mLockScreenModeRow = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
/**
* This view is visible in AOD, which means that the device will sleep if we
@@ -361,12 +406,18 @@ public class KeyguardSliceView extends LinearLayout {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int childCount = getChildCount();
+
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof KeyguardSliceTextView) {
- ((KeyguardSliceTextView) child).setMaxWidth(width / 3);
+ if (mLockScreenModeRow == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ ((KeyguardSliceTextView) child).setMaxWidth(Integer.MAX_VALUE);
+ } else {
+ ((KeyguardSliceTextView) child).setMaxWidth(width / 3);
+ }
}
}
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -384,6 +435,42 @@ public class KeyguardSliceView extends LinearLayout {
public boolean hasOverlappingRendering() {
return false;
}
+
+ @Override
+ public void addView(View view, int index) {
+ super.addView(view, index);
+
+ if (view instanceof KeyguardSliceTextView) {
+ ((KeyguardSliceTextView) view).setLockScreenMode(mLockScreenModeRow);
+ mKeyguardSliceTextViewSet.add((KeyguardSliceTextView) view);
+ }
+ }
+
+ @Override
+ public void removeView(View view) {
+ super.removeView(view);
+ if (view instanceof KeyguardSliceTextView) {
+ mKeyguardSliceTextViewSet.remove((KeyguardSliceTextView) view);
+ }
+ }
+
+ /**
+ * Updates the lockscreen mode which may change the layout of this view.
+ */
+ public void setLockscreenMode(int mode) {
+ mLockScreenModeRow = mode;
+ if (mLockScreenModeRow == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ setOrientation(LinearLayout.VERTICAL);
+ setGravity(Gravity.START);
+ } else {
+ setOrientation(LinearLayout.HORIZONTAL);
+ setGravity(Gravity.CENTER);
+ }
+
+ for (KeyguardSliceTextView textView : mKeyguardSliceTextViewSet) {
+ textView.setLockScreenMode(mLockScreenModeRow);
+ }
+ }
}
/**
@@ -392,6 +479,7 @@ public class KeyguardSliceView extends LinearLayout {
@VisibleForTesting
static class KeyguardSliceTextView extends TextView implements
ConfigurationController.ConfigurationListener {
+ private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@StyleRes
private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary;
@@ -432,9 +520,16 @@ public class KeyguardSliceView extends LinearLayout {
private void updatePadding() {
boolean hasText = !TextUtils.isEmpty(getText());
- int horizontalPadding = (int) getContext().getResources()
+ int padding = (int) getContext().getResources()
.getDimension(R.dimen.widget_horizontal_padding) / 2;
- setPadding(horizontalPadding, 0, horizontalPadding * (hasText ? 1 : -1), 0);
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ // orientation is vertical, so add padding to top & bottom
+ setPadding(0, padding, 0, padding * (hasText ? 1 : -1));
+ } else {
+ // oreintation is horizontal, so add padding to left & right
+ setPadding(padding, 0, padding * (hasText ? 1 : -1), 0);
+ }
+
setCompoundDrawablePadding((int) mContext.getResources()
.getDimension(R.dimen.widget_icon_padding));
}
@@ -461,5 +556,18 @@ public class KeyguardSliceView extends LinearLayout {
}
}
}
+
+ /**
+ * Updates the lockscreen mode which may change the layout of this view.
+ */
+ public void setLockScreenMode(int mode) {
+ mLockScreenMode = mode;
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ setGravity(Gravity.START);
+ } else {
+ setGravity(Gravity.CENTER);
+ }
+ updatePadding();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 3be7e0a2b0b3a..8b55b06e5e5e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -44,6 +44,7 @@ import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.ViewController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -55,10 +56,10 @@ import javax.inject.Inject;
/** Controller for a {@link KeyguardSliceView}. */
@KeyguardStatusViewScope
-public class KeyguardSliceViewController implements Dumpable {
+public class KeyguardSliceViewController extends ViewController implements
+ Dumpable {
private static final String TAG = "KeyguardSliceViewCtrl";
- private final KeyguardSliceView mView;
private final ActivityStarter mActivityStarter;
private final ConfigurationController mConfigurationController;
private final TunerService mTunerService;
@@ -68,41 +69,7 @@ public class KeyguardSliceViewController implements Dumpable {
private Uri mKeyguardSliceUri;
private Slice mSlice;
private Map mClickActions;
-
- private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
- new View.OnAttachStateChangeListener() {
-
- @Override
- public void onViewAttachedToWindow(View v) {
-
- Display display = mView.getDisplay();
- if (display != null) {
- mDisplayId = display.getDisplayId();
- }
- mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
- // Make sure we always have the most current slice
- if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
- mLiveData.observeForever(mObserver);
- }
- mConfigurationController.addCallback(mConfigurationListener);
- mDumpManager.registerDumpable(
- TAG + "@" + Integer.toHexString(
- KeyguardSliceViewController.this.hashCode()),
- KeyguardSliceViewController.this);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
-
- // TODO(b/117344873) Remove below work around after this issue be fixed.
- if (mDisplayId == DEFAULT_DISPLAY) {
- mLiveData.removeObserver(mObserver);
- }
- mTunerService.removeTunable(mTunable);
- mConfigurationController.removeCallback(mConfigurationListener);
- mDumpManager.unregisterDumpable(TAG);
- }
- };
+ private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);
@@ -133,24 +100,57 @@ public class KeyguardSliceViewController implements Dumpable {
};
@Inject
- public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView,
+ public KeyguardSliceViewController(
+ KeyguardSliceView keyguardSliceView,
ActivityStarter activityStarter,
- ConfigurationController configurationController, TunerService tunerService,
+ ConfigurationController configurationController,
+ TunerService tunerService,
DumpManager dumpManager) {
- mView = keyguardSliceView;
+ super(keyguardSliceView);
mActivityStarter = activityStarter;
mConfigurationController = configurationController;
mTunerService = tunerService;
mDumpManager = dumpManager;
}
- /** Initialize the controller. */
- public void init() {
- if (mView.isAttachedToWindow()) {
- mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
+ @Override
+ protected void onViewAttached() {
+ Display display = mView.getDisplay();
+ if (display != null) {
+ mDisplayId = display.getDisplayId();
}
- mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
- mView.setOnClickListener(mOnClickListener);
+ mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
+ // Make sure we always have the most current slice
+ if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
+ mLiveData.observeForever(mObserver);
+ }
+ mConfigurationController.addCallback(mConfigurationListener);
+ mDumpManager.registerDumpable(
+ TAG + "@" + Integer.toHexString(
+ KeyguardSliceViewController.this.hashCode()),
+ KeyguardSliceViewController.this);
+ mView.updateLockScreenMode(mLockScreenMode);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ // TODO(b/117344873) Remove below work around after this issue be fixed.
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ mLiveData.removeObserver(mObserver);
+ }
+ mTunerService.removeTunable(mTunable);
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mDumpManager.unregisterDumpable(
+ TAG + "@" + Integer.toHexString(
+ KeyguardSliceViewController.this.hashCode()));
+ }
+
+ /**
+ * Updates the lockscreen mode which may change the layout of the keyguard slice view.
+ */
+ public void updateLockScreenMode(int mode) {
+ mLockScreenMode = mode;
+ mView.updateLockScreenMode(mLockScreenMode);
}
/**
@@ -224,10 +224,10 @@ public class KeyguardSliceViewController implements Dumpable {
Trace.endSection();
}
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mSlice: " + mSlice);
pw.println(" mClickActions: " + mClickActions);
+ pw.println(" mLockScreenMode: " + mLockScreenMode);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 0efb5eea42174..7705db4e31472 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -267,6 +267,7 @@ public class KeyguardStatusViewController extends ViewController {
+ private final int[] mGradientColors = new int[3];
+ private final float[] mPositions = new float[3];
+
+ public TimeBasedColorsClockController(GradientTextClock view) {
+ super(view);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ refreshTime(System.currentTimeMillis());
+ }
+
+ @Override
+ protected void onViewDetached() {
+
+ }
+
+ /**
+ * Updates the time for this view. Also updates any color changes.
+ */
+ public void refreshTime(long timeInMillis) {
+ Calendar now = new GregorianCalendar();
+ now.setTimeInMillis(timeInMillis);
+ updateColors(now);
+ updatePositions(now);
+ mView.refreshTime();
+ }
+
+ private int getTimeIndex(Calendar now) {
+ int hour = now.get(Calendar.HOUR_OF_DAY); // 0 - 23
+ if (hour < mTimes[0]) {
+ return mTimes.length - 1;
+ }
+
+ for (int i = 1; i < mTimes.length; i++) {
+ if (hour < mTimes[i]) {
+ return i - 1;
+ }
+ }
+
+ return mTimes.length - 1;
+ }
+
+ private void updateColors(Calendar now) {
+ final int index = getTimeIndex(now);
+ for (int i = 0; i < mGradientColors.length; i++) {
+ mGradientColors[i] = COLORS[index][i];
+ }
+ mView.setGradientColors(mGradientColors);
+ }
+
+ private void updatePositions(Calendar now) {
+ final int index = getTimeIndex(now);
+
+ final Calendar startTime = new GregorianCalendar();
+ startTime.setTimeInMillis(now.getTimeInMillis());
+ startTime.set(Calendar.HOUR_OF_DAY, mTimes[index]);
+ if (startTime.getTimeInMillis() > now.getTimeInMillis()) {
+ // start should be earlier than 'now'
+ startTime.add(Calendar.DATE, -1);
+ }
+
+ final Calendar endTime = new GregorianCalendar();
+ endTime.setTimeInMillis(now.getTimeInMillis());
+ if (index == mTimes.length - 1) {
+ endTime.set(Calendar.HOUR_OF_DAY, mTimes[0]);
+ endTime.add(Calendar.DATE, 1); // end time is tomorrow
+ } else {
+ endTime.set(Calendar.HOUR_OF_DAY, mTimes[index + 1]);
+ }
+
+ long totalTimeInThisColorGradient = endTime.getTimeInMillis() - startTime.getTimeInMillis();
+ long timeIntoThisColorGradient = now.getTimeInMillis() - startTime.getTimeInMillis();
+ float percentageWithinGradient =
+ (float) timeIntoThisColorGradient / (float) totalTimeInThisColorGradient;
+
+ for (int i = 0; i < mPositions.length; i++) {
+ // currently hard-coded .3 movement of gradient
+ mPositions[i] = POSITIONS[index][i] - (.3f * percentageWithinGradient);
+ }
+ mView.setColorPositions(mPositions);
+ }
+
+ private static final int[] SUNRISE = new int[] {0xFF6F75AA, 0xFFAFF0FF, 0xFFFFDEBF};
+ private static final int[] DAY = new int[] {0xFF9BD8FB, 0xFFD7F5FF, 0xFFFFF278};
+ private static final int[] NIGHT = new int[] {0xFF333D5E, 0xFFC5A1D6, 0xFF907359};
+
+ private static final float[] SUNRISE_START_POSITIONS = new float[] {.3f, .5f, .8f};
+ private static final float[] DAY_START_POSITIONS = new float[] {.4f, .8f, 1f};
+ private static final float[] NIGHT_START_POSITIONS = new float[] {.25f, .5f, .8f};
+
+ // TODO (b/170228350): use TwilightManager to set sunrise/sunset times
+ private final int mSunriseTime = 6; // 6am
+ private final int mDaytime = 9; // 9 am
+ private final int mNightTime = 19; // 7pm
+
+ private int[] mTimes = new int[] {
+ mSunriseTime,
+ mDaytime,
+ mNightTime
+ };
+ private static final int[][] COLORS = new int[][] {
+ SUNRISE,
+ DAY,
+ NIGHT
+ };
+ private static final float[][] POSITIONS = new float[][] {
+ SUNRISE_START_POSITIONS,
+ DAY_START_POSITIONS,
+ NIGHT_START_POSITIONS
+ };
+}