[DO NOT MERGE]Revert "Migrate KeyguardClockSwitch to new shared Clock library" am: 23535e29d1
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19508951 Change-Id: Icdaadd733731bec3def086de80c2a32200e694c9 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -485,13 +485,7 @@ class TextInterpolator(
|
||||
val out = mutableListOf<List<PositionedGlyphs>>()
|
||||
for (lineNo in 0 until layout.lineCount) { // Shape all lines.
|
||||
val lineStart = layout.getLineStart(lineNo)
|
||||
var count = layout.getLineEnd(lineNo) - lineStart
|
||||
// Do not render the last character in the line if it's a newline and unprintable
|
||||
val last = lineStart + count - 1
|
||||
if (last > lineStart && last < layout.text.length && layout.text[last] == '\n') {
|
||||
count--
|
||||
}
|
||||
|
||||
val count = layout.getLineEnd(lineNo) - lineStart
|
||||
val runs = mutableListOf<PositionedGlyphs>()
|
||||
TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
|
||||
paint) { _, _, glyphs, _ ->
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
*/
|
||||
package com.android.systemui.plugins
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import com.android.internal.colorextraction.ColorExtractor
|
||||
import com.android.systemui.plugins.annotations.ProvidesInterface
|
||||
import java.io.PrintWriter
|
||||
import java.util.Locale
|
||||
@@ -57,15 +57,7 @@ interface Clock {
|
||||
val events: ClockEvents
|
||||
|
||||
/** Triggers for various animations */
|
||||
val animations: ClockAnimations
|
||||
|
||||
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
|
||||
fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
|
||||
events.onColorPaletteChanged(resources)
|
||||
animations.doze(dozeFraction)
|
||||
animations.fold(foldFraction)
|
||||
events.onTimeTick()
|
||||
}
|
||||
val animation: ClockAnimation
|
||||
|
||||
/** Optional method for dumping debug information */
|
||||
fun dump(pw: PrintWriter) { }
|
||||
@@ -88,12 +80,15 @@ interface ClockEvents {
|
||||
/** Call whenever font settings change */
|
||||
fun onFontSettingChanged() { }
|
||||
|
||||
/** Call whenever the color palette should update */
|
||||
fun onColorPaletteChanged(resources: Resources) { }
|
||||
/** Call whenever the color pallete should update */
|
||||
fun onColorPaletteChanged(palette: ColorExtractor.GradientColors) { }
|
||||
}
|
||||
|
||||
/** Methods which trigger various clock animations */
|
||||
interface ClockAnimations {
|
||||
interface ClockAnimation {
|
||||
/** Initializes the doze & fold animation positions. Defaults to neither folded nor dozing. */
|
||||
fun initialize(dozeFraction: Float, foldFraction: Float) { }
|
||||
|
||||
/** Runs an enter animation (if any) */
|
||||
fun enter() { }
|
||||
|
||||
|
||||
28
packages/SystemUI/res-keyguard/font/clock.xml
Normal file
28
packages/SystemUI/res-keyguard/font/clock.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2020, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!--
|
||||
** AOD/LockScreen Clock font.
|
||||
** Should include all numeric glyphs in all supported locales.
|
||||
** Recommended: font with variable width to support AOD => LS animations
|
||||
-->
|
||||
<!-- TODO: Remove when clock migration complete -->
|
||||
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<font android:typeface="monospace"/>
|
||||
</font-family>
|
||||
@@ -31,14 +31,42 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:paddingStart="@dimen/clock_padding_start">
|
||||
<com.android.systemui.shared.clocks.AnimatableClockView
|
||||
android:id="@+id/animatable_clock_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:gravity="start"
|
||||
android:textSize="@dimen/clock_text_size"
|
||||
android:fontFamily="@font/clock"
|
||||
android:elegantTextHeight="false"
|
||||
android:singleLine="true"
|
||||
android:fontFeatureSettings="pnum"
|
||||
chargeAnimationDelay="350"
|
||||
dozeWeight="200"
|
||||
lockScreenWeight="400"
|
||||
/>
|
||||
</FrameLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/lockscreen_clock_view_large"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/keyguard_slice_view"
|
||||
android:paddingTop="@dimen/keyguard_large_clock_top_padding"
|
||||
android:visibility="gone">
|
||||
<com.android.systemui.shared.clocks.AnimatableClockView
|
||||
android:id="@+id/animatable_clock_view_large"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="@dimen/large_clock_text_size"
|
||||
android:fontFamily="@font/clock"
|
||||
android:typeface="monospace"
|
||||
android:elegantTextHeight="false"
|
||||
chargeAnimationDelay="200"
|
||||
dozeWeight="200"
|
||||
lockScreenWeight="400"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
<!-- Not quite optimal but needed to translate these items as a group. The
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
android:id="@+id/time_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@*android:string/config_clockFontFamily"
|
||||
android:fontFamily="@font/clock"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@android:color/white"
|
||||
android:format12Hour="@string/dream_time_complication_12_hr_time_format"
|
||||
|
||||
@@ -664,7 +664,13 @@
|
||||
<!-- When large clock is showing, offset the smartspace by this amount -->
|
||||
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
|
||||
<!-- With the large clock, move up slightly from the center -->
|
||||
<dimen name="keyguard_large_clock_top_padding">100dp</dimen>
|
||||
<dimen name="keyguard_large_clock_top_margin">-60dp</dimen>
|
||||
|
||||
<!-- TODO: Remove during migration -->
|
||||
<!-- Default line spacing multiplier between hours and minutes of the keyguard clock -->
|
||||
<item name="keyguard_clock_line_spacing_scale" type="dimen" format="float">.7</item>
|
||||
<!-- Burmese line spacing multiplier between hours and minutes of the keyguard clock -->
|
||||
<item name="keyguard_clock_line_spacing_scale_burmese" type="dimen" format="float">1</item>
|
||||
|
||||
<dimen name="notification_scrim_corner_radius">32dp</dimen>
|
||||
|
||||
@@ -884,6 +890,11 @@
|
||||
burn-in on AOD. -->
|
||||
<dimen name="burn_in_prevention_offset_y_clock">42dp</dimen>
|
||||
|
||||
<!-- Clock maximum font size (dp is intentional, to prevent any further scaling) -->
|
||||
<!-- TODO: Remove when clock migration complete -->
|
||||
<dimen name="large_clock_text_size">150dp</dimen>
|
||||
<dimen name="clock_text_size">86dp</dimen>
|
||||
|
||||
<!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
|
||||
<dimen name="default_burn_in_prevention_offset">15dp</dimen>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
-->
|
||||
<com.android.systemui.shared.clocks.AnimatableClockView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/animatable_clock_view_large"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
-->
|
||||
<com.android.systemui.shared.clocks.AnimatableClockView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/animatable_clock_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
@@ -25,7 +26,6 @@
|
||||
android:textSize="@dimen/small_clock_text_size"
|
||||
android:fontFamily="@*android:string/config_clockFontFamily"
|
||||
android:elegantTextHeight="false"
|
||||
android:ellipsize="none"
|
||||
android:singleLine="true"
|
||||
android:fontFeatureSettings="pnum"
|
||||
chargeAnimationDelay="350"
|
||||
|
||||
@@ -20,15 +20,12 @@ import android.annotation.ColorInt
|
||||
import android.annotation.FloatRange
|
||||
import android.annotation.IntRange
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.compat.ChangeIdStateCache.invalidate
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.text.TextUtils
|
||||
import android.text.format.DateFormat
|
||||
import android.util.AttributeSet
|
||||
import android.widget.TextView
|
||||
import com.android.internal.R.attr.contentDescription
|
||||
import com.android.internal.R.attr.format
|
||||
import com.android.systemui.animation.GlyphCallback
|
||||
import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.animation.TextAnimator
|
||||
@@ -78,12 +75,6 @@ class AnimatableClockView @JvmOverloads constructor(
|
||||
val lockScreenWeight: Int
|
||||
get() = if (useBoldedVersion()) lockScreenWeightInternal + 100 else lockScreenWeightInternal
|
||||
|
||||
/**
|
||||
* The number of pixels below the baseline. For fonts that support languages such as
|
||||
* Burmese, this space can be significant and should be accounted for when computing layout.
|
||||
*/
|
||||
val bottom get() = paint?.fontMetrics?.bottom ?: 0f
|
||||
|
||||
init {
|
||||
val animatableClockViewAttributes = context.obtainStyledAttributes(
|
||||
attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes
|
||||
@@ -142,15 +133,6 @@ class AnimatableClockView @JvmOverloads constructor(
|
||||
// relayout if the text didn't actually change.
|
||||
if (!TextUtils.equals(text, formattedText)) {
|
||||
text = formattedText
|
||||
|
||||
// Because the TextLayout may mutate under the hood as a result of the new text, we
|
||||
// notify the TextAnimator that it may have changed and request a measure/layout. A
|
||||
// crash will occur on the next invocation of setTextStyle if the layout is mutated
|
||||
// without being notified TextInterpolator being notified.
|
||||
if (layout != null) {
|
||||
textAnimator?.updateLayout(layout)
|
||||
}
|
||||
requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ import javax.inject.Inject
|
||||
private val TAG = ClockRegistry::class.simpleName
|
||||
private val DEBUG = true
|
||||
|
||||
typealias ClockChangeListener = () -> Unit
|
||||
|
||||
/** ClockRegistry aggregates providers and plugins */
|
||||
open class ClockRegistry(
|
||||
val context: Context,
|
||||
@@ -49,11 +51,6 @@ open class ClockRegistry(
|
||||
defaultClockProvider: DefaultClockProvider
|
||||
) : this(context, pluginManager, handler, defaultClockProvider as ClockProvider) { }
|
||||
|
||||
// Usually this would be a typealias, but a SAM provides better java interop
|
||||
fun interface ClockChangeListener {
|
||||
fun onClockChanged()
|
||||
}
|
||||
|
||||
var isEnabled: Boolean = false
|
||||
|
||||
private val gson = Gson()
|
||||
@@ -61,7 +58,7 @@ open class ClockRegistry(
|
||||
private val clockChangeListeners = mutableListOf<ClockChangeListener>()
|
||||
private val settingObserver = object : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) =
|
||||
clockChangeListeners.forEach { it.onClockChanged() }
|
||||
clockChangeListeners.forEach { it() }
|
||||
}
|
||||
|
||||
private val pluginListener = object : PluginListener<ClockProviderPlugin> {
|
||||
@@ -120,11 +117,8 @@ open class ClockRegistry(
|
||||
val id = clock.clockId
|
||||
val current = availableClocks[id]
|
||||
if (current != null) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Clock Id conflict: $id is registered by both " +
|
||||
"${provider::class.simpleName} and ${current.provider::class.simpleName}"
|
||||
)
|
||||
Log.e(TAG, "Clock Id conflict: $id is registered by both " +
|
||||
"${provider::class.simpleName} and ${current.provider::class.simpleName}")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -133,7 +127,7 @@ open class ClockRegistry(
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "Current clock ($currentId) was connected")
|
||||
}
|
||||
clockChangeListeners.forEach { it.onClockChanged() }
|
||||
clockChangeListeners.forEach { it() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +139,7 @@ open class ClockRegistry(
|
||||
|
||||
if (currentId == clock.clockId) {
|
||||
Log.w(TAG, "Current clock ($currentId) was disconnected")
|
||||
clockChangeListeners.forEach { it.onClockChanged() }
|
||||
clockChangeListeners.forEach { it() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@ import android.graphics.drawable.Drawable
|
||||
import android.icu.text.NumberFormat
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import com.android.internal.colorextraction.ColorExtractor
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.plugins.Clock
|
||||
import com.android.systemui.plugins.ClockAnimations
|
||||
import com.android.systemui.plugins.ClockAnimation
|
||||
import com.android.systemui.plugins.ClockEvents
|
||||
import com.android.systemui.plugins.ClockId
|
||||
import com.android.systemui.plugins.ClockMetadata
|
||||
@@ -101,13 +102,10 @@ class DefaultClock(
|
||||
TypedValue.COMPLEX_UNIT_PX,
|
||||
resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
|
||||
)
|
||||
recomputePadding()
|
||||
}
|
||||
|
||||
override fun onColorPaletteChanged(resources: Resources) {
|
||||
val color = resources.getColor(android.R.color.system_accent1_100)
|
||||
clocks.forEach { it.setColors(DOZE_COLOR, color) }
|
||||
}
|
||||
override fun onColorPaletteChanged(palette: ColorExtractor.GradientColors) =
|
||||
clocks.forEach { it.setColors(DOZE_COLOR, palette.mainColor) }
|
||||
|
||||
override fun onLocaleChanged(locale: Locale) {
|
||||
val nf = NumberFormat.getInstance(locale)
|
||||
@@ -121,17 +119,8 @@ class DefaultClock(
|
||||
}
|
||||
}
|
||||
|
||||
override var animations = DefaultClockAnimations(0f, 0f)
|
||||
private set
|
||||
|
||||
inner class DefaultClockAnimations(
|
||||
dozeFraction: Float,
|
||||
foldFraction: Float
|
||||
) : ClockAnimations {
|
||||
private var foldState = AnimationState(0f)
|
||||
private var dozeState = AnimationState(0f)
|
||||
|
||||
init {
|
||||
override val animation = object : ClockAnimation {
|
||||
override fun initialize(dozeFraction: Float, foldFraction: Float) {
|
||||
dozeState = AnimationState(dozeFraction)
|
||||
foldState = AnimationState(foldFraction)
|
||||
|
||||
@@ -143,13 +132,14 @@ class DefaultClock(
|
||||
}
|
||||
|
||||
override fun enter() {
|
||||
if (!dozeState.isActive) {
|
||||
if (dozeState.isActive) {
|
||||
clocks.forEach { it.animateAppearOnLockscreen() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } }
|
||||
|
||||
private var foldState = AnimationState(0f)
|
||||
override fun fold(fraction: Float) {
|
||||
val (hasChanged, hasJumped) = foldState.update(fraction)
|
||||
if (hasChanged) {
|
||||
@@ -157,6 +147,7 @@ class DefaultClock(
|
||||
}
|
||||
}
|
||||
|
||||
private var dozeState = AnimationState(0f)
|
||||
override fun doze(fraction: Float) {
|
||||
val (hasChanged, hasJumped) = dozeState.update(fraction)
|
||||
if (hasChanged) {
|
||||
@@ -181,19 +172,6 @@ class DefaultClock(
|
||||
|
||||
init {
|
||||
events.onLocaleChanged(Locale.getDefault())
|
||||
clocks.forEach { it.setColors(DOZE_COLOR, DOZE_COLOR) }
|
||||
}
|
||||
|
||||
override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
|
||||
recomputePadding()
|
||||
animations = DefaultClockAnimations(dozeFraction, foldFraction)
|
||||
events.onColorPaletteChanged(resources)
|
||||
events.onTimeTick()
|
||||
}
|
||||
|
||||
private fun recomputePadding() {
|
||||
val topPadding = -1 * (largeClock.bottom.toInt() - 180)
|
||||
largeClock.setPadding(0, topPadding, 0, 0)
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter) = clocks.forEach { it.dump(pw) }
|
||||
|
||||
@@ -182,6 +182,18 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
|
||||
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of pixels below the baseline. For fonts that support languages such as
|
||||
* Burmese, this space can be significant.
|
||||
*/
|
||||
public float getBottom() {
|
||||
if (mView.getPaint() != null && mView.getPaint().getFontMetrics() != null) {
|
||||
return mView.getPaint().getFontMetrics().bottom;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/** Animate the clock appearance */
|
||||
public void animateAppear() {
|
||||
if (!mIsDozing) mView.animateAppearOnLockscreen();
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.res.Resources
|
||||
import android.text.format.DateFormat
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.plugins.Clock
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.policy.BatteryController
|
||||
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import java.io.PrintWriter
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
|
||||
* [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController].
|
||||
*/
|
||||
class ClockEventController @Inject constructor(
|
||||
private val statusBarStateController: StatusBarStateController,
|
||||
private val broadcastDispatcher: BroadcastDispatcher,
|
||||
private val batteryController: BatteryController,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val configurationController: ConfigurationController,
|
||||
@Main private val resources: Resources,
|
||||
private val context: Context
|
||||
) {
|
||||
var clock: Clock? = null
|
||||
set(value) {
|
||||
field = value
|
||||
if (value != null) {
|
||||
value.initialize(resources, dozeAmount, 0f)
|
||||
}
|
||||
}
|
||||
|
||||
private var isDozing = false
|
||||
private set
|
||||
|
||||
private var isCharging = false
|
||||
private var dozeAmount = 0f
|
||||
private var isKeyguardShowing = false
|
||||
|
||||
private val configListener = object : ConfigurationController.ConfigurationListener {
|
||||
override fun onThemeChanged() {
|
||||
clock?.events?.onColorPaletteChanged(resources)
|
||||
}
|
||||
}
|
||||
|
||||
private val batteryCallback = object : BatteryStateChangeCallback {
|
||||
override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
|
||||
if (isKeyguardShowing && !isCharging && charging) {
|
||||
clock?.animations?.charge()
|
||||
}
|
||||
isCharging = charging
|
||||
}
|
||||
}
|
||||
|
||||
private val localeBroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
clock?.events?.onLocaleChanged(Locale.getDefault())
|
||||
}
|
||||
}
|
||||
|
||||
private val statusBarStateListener = object : StatusBarStateController.StateListener {
|
||||
override fun onDozeAmountChanged(linear: Float, eased: Float) {
|
||||
clock?.animations?.doze(linear)
|
||||
|
||||
isDozing = linear > dozeAmount
|
||||
dozeAmount = linear
|
||||
}
|
||||
}
|
||||
|
||||
private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
|
||||
override fun onKeyguardVisibilityChanged(showing: Boolean) {
|
||||
isKeyguardShowing = showing
|
||||
if (!isKeyguardShowing) {
|
||||
clock?.animations?.doze(if (isDozing) 1f else 0f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTimeFormatChanged(timeFormat: String) {
|
||||
clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
||||
}
|
||||
|
||||
override fun onTimeZoneChanged(timeZone: TimeZone) {
|
||||
clock?.events?.onTimeZoneChanged(timeZone)
|
||||
}
|
||||
|
||||
override fun onUserSwitchComplete(userId: Int) {
|
||||
clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
isDozing = statusBarStateController.isDozing
|
||||
}
|
||||
|
||||
fun registerListeners() {
|
||||
dozeAmount = statusBarStateController.dozeAmount
|
||||
isDozing = statusBarStateController.isDozing || dozeAmount != 0f
|
||||
|
||||
broadcastDispatcher.registerReceiver(
|
||||
localeBroadcastReceiver,
|
||||
IntentFilter(Intent.ACTION_LOCALE_CHANGED)
|
||||
)
|
||||
configurationController.addCallback(configListener)
|
||||
batteryController.addCallback(batteryCallback)
|
||||
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
|
||||
statusBarStateController.addCallback(statusBarStateListener)
|
||||
}
|
||||
|
||||
fun unregisterListeners() {
|
||||
broadcastDispatcher.unregisterReceiver(localeBroadcastReceiver)
|
||||
configurationController.removeCallback(configListener)
|
||||
batteryController.removeCallback(batteryCallback)
|
||||
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
|
||||
statusBarStateController.removeCallback(statusBarStateListener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump information for debugging
|
||||
*/
|
||||
fun dump(pw: PrintWriter) {
|
||||
pw.println(this)
|
||||
clock?.dump(pw)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = ClockEventController::class.simpleName
|
||||
private const val FORMAT_NUMBER = 1234567890
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -15,14 +17,19 @@ import android.widget.RelativeLayout;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.keyguard.dagger.KeyguardStatusViewScope;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.plugins.Clock;
|
||||
import com.android.systemui.plugins.ClockPlugin;
|
||||
import com.android.systemui.shared.clocks.AnimatableClockView;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
|
||||
*/
|
||||
@@ -42,11 +49,18 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
public static final int LARGE = 0;
|
||||
public static final int SMALL = 1;
|
||||
|
||||
/**
|
||||
* Optional/alternative clock injected via plugin.
|
||||
*/
|
||||
private ClockPlugin mClockPlugin;
|
||||
|
||||
/**
|
||||
* Frame for small/large clocks
|
||||
*/
|
||||
private FrameLayout mSmallClockFrame;
|
||||
private FrameLayout mClockFrame;
|
||||
private FrameLayout mLargeClockFrame;
|
||||
private AnimatableClockView mClockView;
|
||||
private AnimatableClockView mLargeClockView;
|
||||
|
||||
private View mStatusArea;
|
||||
private int mSmartspaceTopOffset;
|
||||
@@ -66,6 +80,12 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
@VisibleForTesting AnimatorSet mClockOutAnim = null;
|
||||
private ObjectAnimator mStatusAreaAnim = null;
|
||||
|
||||
/**
|
||||
* If the Keyguard Slice has a header (big center-aligned text.)
|
||||
*/
|
||||
private boolean mSupportsDarkText;
|
||||
private int[] mColorPalette;
|
||||
|
||||
private int mClockSwitchYAmount;
|
||||
@VisibleForTesting boolean mChildrenAreLaidOut = false;
|
||||
|
||||
@@ -77,38 +97,97 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
* Apply dp changes on font/scale change
|
||||
*/
|
||||
public void onDensityOrFontScaleChanged() {
|
||||
mLargeClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.large_clock_text_size));
|
||||
mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.clock_text_size));
|
||||
|
||||
mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.keyguard_clock_switch_y_shift);
|
||||
|
||||
mSmartspaceTopOffset = mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.keyguard_smartspace_top_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this view is presenting a custom clock, or the default implementation.
|
||||
*/
|
||||
public boolean hasCustomClock() {
|
||||
return mClockPlugin != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mSmallClockFrame = findViewById(R.id.lockscreen_clock_view);
|
||||
mClockFrame = findViewById(R.id.lockscreen_clock_view);
|
||||
mClockView = findViewById(R.id.animatable_clock_view);
|
||||
mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
|
||||
mLargeClockView = findViewById(R.id.animatable_clock_view_large);
|
||||
mStatusArea = findViewById(R.id.keyguard_status_area);
|
||||
|
||||
onDensityOrFontScaleChanged();
|
||||
}
|
||||
|
||||
void setClock(Clock clock, int statusBarState) {
|
||||
void setClockPlugin(ClockPlugin plugin, int statusBarState) {
|
||||
// Disconnect from existing plugin.
|
||||
mSmallClockFrame.removeAllViews();
|
||||
mLargeClockFrame.removeAllViews();
|
||||
|
||||
if (clock == null) {
|
||||
Log.e(TAG, "No clock being shown");
|
||||
if (mClockPlugin != null) {
|
||||
View smallClockView = mClockPlugin.getView();
|
||||
if (smallClockView != null && smallClockView.getParent() == mClockFrame) {
|
||||
mClockFrame.removeView(smallClockView);
|
||||
}
|
||||
View bigClockView = mClockPlugin.getBigClockView();
|
||||
if (bigClockView != null && bigClockView.getParent() == mLargeClockFrame) {
|
||||
mLargeClockFrame.removeView(bigClockView);
|
||||
}
|
||||
mClockPlugin.onDestroyView();
|
||||
mClockPlugin = null;
|
||||
}
|
||||
if (plugin == null) {
|
||||
mClockView.setVisibility(View.VISIBLE);
|
||||
mLargeClockView.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach small and big clock views to hierarchy.
|
||||
mSmallClockFrame.addView(clock.getSmallClock(), -1,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
mLargeClockFrame.addView(clock.getLargeClock());
|
||||
View smallClockView = plugin.getView();
|
||||
if (smallClockView != null) {
|
||||
mClockFrame.addView(smallClockView, -1,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
mClockView.setVisibility(View.GONE);
|
||||
}
|
||||
View bigClockView = plugin.getBigClockView();
|
||||
if (bigClockView != null) {
|
||||
mLargeClockFrame.addView(bigClockView);
|
||||
mLargeClockView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Initialize plugin parameters.
|
||||
mClockPlugin = plugin;
|
||||
mClockPlugin.setStyle(getPaint().getStyle());
|
||||
mClockPlugin.setTextColor(getCurrentTextColor());
|
||||
mClockPlugin.setDarkAmount(mDarkAmount);
|
||||
if (mColorPalette != null) {
|
||||
mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It will also update plugin setStyle if plugin is connected.
|
||||
*/
|
||||
public void setStyle(Style style) {
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.setStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It will also update plugin setTextColor if plugin is connected.
|
||||
*/
|
||||
public void setTextColor(int color) {
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.setTextColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateClockViews(boolean useLargeClock, boolean animate) {
|
||||
@@ -124,14 +203,14 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
int direction = 1;
|
||||
float statusAreaYTranslation;
|
||||
if (useLargeClock) {
|
||||
out = mSmallClockFrame;
|
||||
out = mClockFrame;
|
||||
in = mLargeClockFrame;
|
||||
if (indexOfChild(in) == -1) addView(in);
|
||||
direction = -1;
|
||||
statusAreaYTranslation = mSmallClockFrame.getTop() - mStatusArea.getTop()
|
||||
statusAreaYTranslation = mClockFrame.getTop() - mStatusArea.getTop()
|
||||
+ mSmartspaceTopOffset;
|
||||
} else {
|
||||
in = mSmallClockFrame;
|
||||
in = mClockFrame;
|
||||
out = mLargeClockFrame;
|
||||
statusAreaYTranslation = 0f;
|
||||
|
||||
@@ -189,6 +268,18 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
mStatusAreaAnim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount (ratio) that the device has transitioned to doze.
|
||||
*
|
||||
* @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
|
||||
*/
|
||||
public void setDarkAmount(float darkAmount) {
|
||||
mDarkAmount = darkAmount;
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.setDarkAmount(darkAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the desired clock and hide the other one
|
||||
*
|
||||
@@ -220,11 +311,64 @@ public class KeyguardClockSwitch extends RelativeLayout {
|
||||
mChildrenAreLaidOut = true;
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return mClockView.getPaint();
|
||||
}
|
||||
|
||||
public int getCurrentTextColor() {
|
||||
return mClockView.getCurrentTextColor();
|
||||
}
|
||||
|
||||
public float getTextSize() {
|
||||
return mClockView.getTextSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
|
||||
*/
|
||||
public void refresh() {
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.onTimeTick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that the time zone has changed.
|
||||
*/
|
||||
public void onTimeZoneChanged(TimeZone timeZone) {
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.onTimeZoneChanged(timeZone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that the time format has changed.
|
||||
*
|
||||
* @param timeFormat "12" for 12-hour format, "24" for 24-hour format
|
||||
*/
|
||||
public void onTimeFormatChanged(String timeFormat) {
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.onTimeFormatChanged(timeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
void updateColors(ColorExtractor.GradientColors colors) {
|
||||
mSupportsDarkText = colors.supportsDarkText();
|
||||
mColorPalette = colors.getColorPalette();
|
||||
if (mClockPlugin != null) {
|
||||
mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String[] args) {
|
||||
pw.println("KeyguardClockSwitch:");
|
||||
pw.println(" mClockFrame: " + mSmallClockFrame);
|
||||
pw.println(" mClockPlugin: " + mClockPlugin);
|
||||
pw.println(" mClockFrame: " + mClockFrame);
|
||||
pw.println(" mLargeClockFrame: " + mLargeClockFrame);
|
||||
pw.println(" mStatusArea: " + mStatusArea);
|
||||
pw.println(" mDarkAmount: " + mDarkAmount);
|
||||
pw.println(" mSupportsDarkText: " + mSupportsDarkText);
|
||||
pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
|
||||
pw.println(" mDisplayedClockSize: " + mDisplayedClockSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
|
||||
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
|
||||
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
@@ -30,30 +32,36 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.keyguard.clock.ClockManager;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.plugins.Clock;
|
||||
import com.android.systemui.plugins.ClockPlugin;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.clocks.ClockRegistry;
|
||||
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
|
||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
|
||||
import com.android.systemui.statusbar.phone.NotificationIconContainer;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -63,24 +71,48 @@ import javax.inject.Inject;
|
||||
*/
|
||||
public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch>
|
||||
implements Dumpable {
|
||||
private static final boolean CUSTOM_CLOCKS_ENABLED = true;
|
||||
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
private final ClockRegistry mClockRegistry;
|
||||
private final SysuiColorExtractor mColorExtractor;
|
||||
private final ClockManager mClockManager;
|
||||
private final KeyguardSliceViewController mKeyguardSliceViewController;
|
||||
private final NotificationIconAreaController mNotificationIconAreaController;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
private final BatteryController mBatteryController;
|
||||
private final LockscreenSmartspaceController mSmartspaceController;
|
||||
private final Resources mResources;
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final DumpManager mDumpManager;
|
||||
private final ClockEventController mClockEventController;
|
||||
|
||||
/** Clock frames for both small and large sizes */
|
||||
private FrameLayout mSmallClockFrame; // top aligned clock
|
||||
/**
|
||||
* Clock for both small and large sizes
|
||||
*/
|
||||
private AnimatableClockController mClockViewController;
|
||||
private FrameLayout mClockFrame; // top aligned clock
|
||||
private AnimatableClockController mLargeClockViewController;
|
||||
private FrameLayout mLargeClockFrame; // centered clock
|
||||
|
||||
@KeyguardClockSwitch.ClockSize
|
||||
private int mCurrentClockSize = SMALL;
|
||||
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
|
||||
private int mKeyguardClockTopMargin = 0;
|
||||
private final ClockRegistry.ClockChangeListener mClockChangedListener;
|
||||
|
||||
/**
|
||||
* Listener for changes to the color palette.
|
||||
*
|
||||
* The color palette changes when the wallpaper is changed.
|
||||
*/
|
||||
private final ColorExtractor.OnColorsChangedListener mColorsListener =
|
||||
(extractor, which) -> {
|
||||
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
|
||||
mView.updateColors(getGradientColors());
|
||||
}
|
||||
};
|
||||
|
||||
private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
|
||||
|
||||
private ViewGroup mStatusArea;
|
||||
// If set will replace keyguard_slice_view
|
||||
@@ -89,9 +121,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
|
||||
private boolean mOnlyClock = false;
|
||||
private final Executor mUiExecutor;
|
||||
private Executor mUiExecutor;
|
||||
private boolean mCanShowDoubleLineClock = true;
|
||||
private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
|
||||
private ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean change) {
|
||||
updateDoubleLineClock();
|
||||
@@ -112,32 +144,34 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
public KeyguardClockSwitchController(
|
||||
KeyguardClockSwitch keyguardClockSwitch,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ClockRegistry clockRegistry,
|
||||
SysuiColorExtractor colorExtractor,
|
||||
ClockManager clockManager,
|
||||
KeyguardSliceViewController keyguardSliceViewController,
|
||||
NotificationIconAreaController notificationIconAreaController,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
BatteryController batteryController,
|
||||
KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
LockscreenSmartspaceController smartspaceController,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
|
||||
SecureSettings secureSettings,
|
||||
@Main Executor uiExecutor,
|
||||
DumpManager dumpManager,
|
||||
ClockEventController clockEventController,
|
||||
FeatureFlags featureFlags) {
|
||||
@Main Resources resources,
|
||||
DumpManager dumpManager) {
|
||||
super(keyguardClockSwitch);
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mClockRegistry = clockRegistry;
|
||||
mColorExtractor = colorExtractor;
|
||||
mClockManager = clockManager;
|
||||
mKeyguardSliceViewController = keyguardSliceViewController;
|
||||
mNotificationIconAreaController = notificationIconAreaController;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mBatteryController = batteryController;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mSmartspaceController = smartspaceController;
|
||||
mResources = resources;
|
||||
mSecureSettings = secureSettings;
|
||||
mUiExecutor = uiExecutor;
|
||||
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
|
||||
mDumpManager = dumpManager;
|
||||
mClockEventController = clockEventController;
|
||||
|
||||
mClockRegistry.setEnabled(featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS));
|
||||
mClockChangedListener = () -> {
|
||||
setClock(mClockRegistry.createCurrentClock());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,18 +188,40 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
public void onInit() {
|
||||
mKeyguardSliceViewController.init();
|
||||
|
||||
mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
|
||||
mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
|
||||
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
|
||||
|
||||
mClockViewController =
|
||||
new AnimatableClockController(
|
||||
mView.findViewById(R.id.animatable_clock_view),
|
||||
mStatusBarStateController,
|
||||
mBroadcastDispatcher,
|
||||
mBatteryController,
|
||||
mKeyguardUpdateMonitor,
|
||||
mResources);
|
||||
mClockViewController.init();
|
||||
|
||||
mLargeClockViewController =
|
||||
new AnimatableClockController(
|
||||
mView.findViewById(R.id.animatable_clock_view_large),
|
||||
mStatusBarStateController,
|
||||
mBroadcastDispatcher,
|
||||
mBatteryController,
|
||||
mKeyguardUpdateMonitor,
|
||||
mResources);
|
||||
mLargeClockViewController.init();
|
||||
|
||||
mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
|
||||
mDumpManager.registerDumpable(getClass().toString(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mClockRegistry.registerClockChangeListener(mClockChangedListener);
|
||||
setClock(mClockRegistry.createCurrentClock());
|
||||
mClockEventController.registerListeners();
|
||||
if (CUSTOM_CLOCKS_ENABLED) {
|
||||
mClockManager.addOnClockChangedListener(mClockChangedListener);
|
||||
}
|
||||
mColorExtractor.addOnColorsChangedListener(mColorsListener);
|
||||
mView.updateColors(getGradientColors());
|
||||
mKeyguardClockTopMargin =
|
||||
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||
|
||||
@@ -188,6 +244,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
ksv.setVisibility(View.GONE);
|
||||
|
||||
addSmartspaceView(ksvIndex);
|
||||
updateClockLayout();
|
||||
}
|
||||
|
||||
mSecureSettings.registerContentObserverForUser(
|
||||
@@ -209,9 +266,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
|
||||
@Override
|
||||
protected void onViewDetached() {
|
||||
mClockRegistry.unregisterClockChangeListener(mClockChangedListener);
|
||||
mClockEventController.unregisterListeners();
|
||||
setClock(null);
|
||||
if (CUSTOM_CLOCKS_ENABLED) {
|
||||
mClockManager.removeOnClockChangedListener(mClockChangedListener);
|
||||
}
|
||||
mColorExtractor.removeOnColorsChangedListener(mColorsListener);
|
||||
mView.setClockPlugin(null, mStatusBarStateController.getState());
|
||||
|
||||
mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver);
|
||||
|
||||
@@ -250,6 +309,18 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
mView.onDensityOrFontScaleChanged();
|
||||
mKeyguardClockTopMargin =
|
||||
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||
|
||||
updateClockLayout();
|
||||
}
|
||||
|
||||
private void updateClockLayout() {
|
||||
int largeClockTopMargin = getContext().getResources().getDimensionPixelSize(
|
||||
R.dimen.keyguard_large_clock_top_margin)
|
||||
- (int) mLargeClockViewController.getBottom();
|
||||
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
|
||||
MATCH_PARENT);
|
||||
lp.topMargin = largeClockTopMargin;
|
||||
mLargeClockFrame.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,34 +334,46 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
|
||||
mCurrentClockSize = clockSize;
|
||||
|
||||
Clock clock = getClock();
|
||||
boolean appeared = mView.switchToClock(clockSize, animate);
|
||||
if (clock != null && animate && appeared && clockSize == LARGE) {
|
||||
clock.getAnimations().enter();
|
||||
if (animate && appeared && clockSize == LARGE) {
|
||||
mLargeClockViewController.animateAppear();
|
||||
}
|
||||
}
|
||||
|
||||
public void animateFoldToAod() {
|
||||
if (mClockViewController != null) {
|
||||
mClockViewController.animateFoldAppear();
|
||||
mLargeClockViewController.animateFoldAppear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the clock view between folded and unfolded states
|
||||
* If we're presenting a custom clock of just the default one.
|
||||
*/
|
||||
public void animateFoldToAod(float foldFraction) {
|
||||
Clock clock = getClock();
|
||||
if (clock != null) {
|
||||
clock.getAnimations().fold(foldFraction);
|
||||
}
|
||||
public boolean hasCustomClock() {
|
||||
return mView.hasCustomClock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clock text size.
|
||||
*/
|
||||
public float getClockTextSize() {
|
||||
return mView.getTextSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh clock. Called in response to TIME_TICK broadcasts.
|
||||
*/
|
||||
void refresh() {
|
||||
if (mClockViewController != null) {
|
||||
mClockViewController.refreshTime();
|
||||
mLargeClockViewController.refreshTime();
|
||||
}
|
||||
if (mSmartspaceController != null) {
|
||||
mSmartspaceController.requestSmartspaceUpdate();
|
||||
}
|
||||
Clock clock = getClock();
|
||||
if (clock != null) {
|
||||
clock.getEvents().onTimeTick();
|
||||
}
|
||||
|
||||
mView.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,7 +385,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
|
||||
x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x;
|
||||
|
||||
PropertyAnimator.setProperty(mSmallClockFrame, AnimatableProperty.TRANSLATION_X,
|
||||
PropertyAnimator.setProperty(mClockFrame, AnimatableProperty.TRANSLATION_X,
|
||||
x, props, animate);
|
||||
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X,
|
||||
scale, props, animate);
|
||||
@@ -315,39 +398,25 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
}
|
||||
}
|
||||
|
||||
void updateTimeZone(TimeZone timeZone) {
|
||||
mView.onTimeZoneChanged(timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get y-bottom position of the currently visible clock on the keyguard.
|
||||
* We can't directly getBottom() because clock changes positions in AOD for burn-in
|
||||
*/
|
||||
int getClockBottom(int statusBarHeaderHeight) {
|
||||
Clock clock = getClock();
|
||||
if (clock == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
|
||||
View clock = mLargeClockFrame.findViewById(
|
||||
com.android.systemui.R.id.animatable_clock_view_large);
|
||||
int frameHeight = mLargeClockFrame.getHeight();
|
||||
int clockHeight = clock.getLargeClock().getHeight();
|
||||
int clockHeight = clock.getHeight();
|
||||
return frameHeight / 2 + clockHeight / 2;
|
||||
} else {
|
||||
int clockHeight = clock.getSmallClock().getHeight();
|
||||
return clockHeight + statusBarHeaderHeight + mKeyguardClockTopMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the currently visible clock on the keyguard.
|
||||
*/
|
||||
int getClockHeight() {
|
||||
Clock clock = getClock();
|
||||
if (clock == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
|
||||
return clock.getLargeClock().getHeight();
|
||||
} else {
|
||||
return clock.getSmallClock().getHeight();
|
||||
return mClockFrame.findViewById(
|
||||
com.android.systemui.R.id.animatable_clock_view).getHeight()
|
||||
+ statusBarHeaderHeight + mKeyguardClockTopMargin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,13 +431,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
mNotificationIconAreaController.setupAodIcons(nic);
|
||||
}
|
||||
|
||||
private void setClock(Clock clock) {
|
||||
mClockEventController.setClock(clock);
|
||||
mView.setClock(clock, mStatusBarStateController.getState());
|
||||
private void setClockPlugin(ClockPlugin plugin) {
|
||||
mView.setClockPlugin(plugin, mStatusBarStateController.getState());
|
||||
}
|
||||
|
||||
private Clock getClock() {
|
||||
return mClockEventController.getClock();
|
||||
private ColorExtractor.GradientColors getGradientColors() {
|
||||
return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK);
|
||||
}
|
||||
|
||||
private int getCurrentLayoutDirection() {
|
||||
@@ -401,10 +469,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE));
|
||||
pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock);
|
||||
Clock clock = getClock();
|
||||
if (clock != null) {
|
||||
clock.dump(pw);
|
||||
}
|
||||
mClockViewController.dump(pw);
|
||||
mLargeClockViewController.dump(pw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,14 @@
|
||||
package com.android.keyguard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.GridLayout;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.CrossFadeHelper;
|
||||
|
||||
@@ -43,6 +46,7 @@ public class KeyguardStatusView extends GridLayout {
|
||||
private View mMediaHostContainer;
|
||||
|
||||
private float mDarkAmount = 0;
|
||||
private int mTextColor;
|
||||
|
||||
public KeyguardStatusView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -67,6 +71,7 @@ public class KeyguardStatusView extends GridLayout {
|
||||
}
|
||||
|
||||
mKeyguardSlice = findViewById(R.id.keyguard_slice_view);
|
||||
mTextColor = mClockView.getCurrentTextColor();
|
||||
|
||||
mMediaHostContainer = findViewById(R.id.status_view_media_container);
|
||||
|
||||
@@ -78,12 +83,15 @@ public class KeyguardStatusView extends GridLayout {
|
||||
return;
|
||||
}
|
||||
mDarkAmount = darkAmount;
|
||||
mClockView.setDarkAmount(darkAmount);
|
||||
CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
|
||||
updateDark();
|
||||
}
|
||||
|
||||
void updateDark() {
|
||||
final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
|
||||
mKeyguardSlice.setDarkAmount(mDarkAmount);
|
||||
mClockView.setTextColor(blendedTextColor);
|
||||
}
|
||||
|
||||
/** Sets a translationY value on every child view except for the media view. */
|
||||
@@ -105,6 +113,7 @@ public class KeyguardStatusView extends GridLayout {
|
||||
public void dump(PrintWriter pw, String[] args) {
|
||||
pw.println("KeyguardStatusView:");
|
||||
pw.println(" mDarkAmount: " + mDarkAmount);
|
||||
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
|
||||
if (mClockView != null) {
|
||||
mClockView.dump(pw, args);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
@@ -93,6 +95,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
mKeyguardSliceViewController.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount we're in doze.
|
||||
*/
|
||||
public void setDarkAmount(float darkAmount) {
|
||||
mView.setDarkAmount(darkAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which clock should be displayed on the keyguard. The other one will be automatically
|
||||
* hidden.
|
||||
@@ -105,10 +114,16 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
* Performs fold to aod animation of the clocks (changes font weight from bold to thin).
|
||||
* This animation is played when AOD is enabled and foldable device is fully folded, it is
|
||||
* displayed on the outer screen
|
||||
* @param foldFraction current fraction of fold animation complete
|
||||
*/
|
||||
public void animateFoldToAod(float foldFraction) {
|
||||
mKeyguardClockSwitchController.animateFoldToAod(foldFraction);
|
||||
public void animateFoldToAod() {
|
||||
mKeyguardClockSwitchController.animateFoldToAod();
|
||||
}
|
||||
|
||||
/**
|
||||
* If we're presenting a custom clock of just the default one.
|
||||
*/
|
||||
public boolean hasCustomClock() {
|
||||
return mKeyguardClockSwitchController.hasCustomClock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +143,24 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the pivot position based on the parent view
|
||||
* Set pivot x.
|
||||
*/
|
||||
public void updatePivot(float parentWidth, float parentHeight) {
|
||||
mView.setPivotX(parentWidth / 2f);
|
||||
mView.setPivotY(mKeyguardClockSwitchController.getClockHeight() / 2f);
|
||||
public void setPivotX(float pivot) {
|
||||
mView.setPivotX(pivot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pivot y.
|
||||
*/
|
||||
public void setPivotY(float pivot) {
|
||||
mView.setPivotY(pivot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clock text size.
|
||||
*/
|
||||
public float getClockTextSize() {
|
||||
return mKeyguardClockSwitchController.getClockTextSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,6 +239,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
refreshTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeZoneChanged(TimeZone timeZone) {
|
||||
mKeyguardClockSwitchController.updateTimeZone(timeZone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyguardVisibilityChanged(boolean showing) {
|
||||
if (showing) {
|
||||
|
||||
@@ -292,6 +292,11 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
|
||||
private final NotificationIconAreaController mNotificationIconAreaController;
|
||||
|
||||
// Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
|
||||
// changed.
|
||||
private static final int CAP_HEIGHT = 1456;
|
||||
private static final int FONT_HEIGHT = 2163;
|
||||
|
||||
/**
|
||||
* Maximum time before which we will expand the panel even for slow motions when getting a
|
||||
* touch passed over from launcher.
|
||||
@@ -1117,6 +1122,13 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there's a custom clock being presented.
|
||||
*/
|
||||
public boolean hasCustomClock() {
|
||||
return mKeyguardStatusViewController.hasCustomClock();
|
||||
}
|
||||
|
||||
private void setCentralSurfaces(CentralSurfaces centralSurfaces) {
|
||||
// TODO: this can be injected.
|
||||
mCentralSurfaces = centralSurfaces;
|
||||
@@ -3910,9 +3922,9 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
endAction.run();
|
||||
}
|
||||
}).setUpdateListener(anim -> {
|
||||
mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
|
||||
}).start();
|
||||
|
||||
mKeyguardStatusViewController.animateFoldToAod();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4625,6 +4637,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
public void onDozeAmountChanged(float linearAmount, float amount) {
|
||||
mInterpolatedDarkAmount = amount;
|
||||
mLinearDarkAmount = linearAmount;
|
||||
mKeyguardStatusViewController.setDarkAmount(mInterpolatedDarkAmount);
|
||||
mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
|
||||
positionClockAndNotifications();
|
||||
}
|
||||
@@ -4734,8 +4747,11 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount());
|
||||
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
|
||||
|
||||
// Update Clock Pivot (used by anti-burnin transformations)
|
||||
mKeyguardStatusViewController.updatePivot(mView.getWidth(), mView.getHeight());
|
||||
// Update Clock Pivot
|
||||
mKeyguardStatusViewController.setPivotX(((float) mView.getWidth()) / 2f);
|
||||
mKeyguardStatusViewController.setPivotY(
|
||||
(FONT_HEIGHT - CAP_HEIGHT) / 2048f
|
||||
* mKeyguardStatusViewController.getClockTextSize());
|
||||
|
||||
// Calculate quick setting heights.
|
||||
int oldMaxHeight = mQsMaxExpansionHeight;
|
||||
|
||||
@@ -439,6 +439,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
|
||||
state |= DISABLE_CLOCK;
|
||||
}
|
||||
|
||||
|
||||
if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
|
||||
if (mNetworkController.hasEmergencyCryptKeeperText()) {
|
||||
state |= DISABLE_NOTIFICATION_ICONS;
|
||||
@@ -448,6 +449,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
|
||||
}
|
||||
}
|
||||
|
||||
// The shelf will be hidden when dozing with a custom clock, we must show notification
|
||||
// icons in this occasion.
|
||||
if (mStatusBarStateController.isDozing()
|
||||
&& mNotificationPanelViewController.hasCustomClock()) {
|
||||
state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
|
||||
}
|
||||
|
||||
if (mOngoingCallController.hasOngoingCall()) {
|
||||
state &= ~DISABLE_ONGOING_CALL_CHIP;
|
||||
} else {
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.content.BroadcastReceiver
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.widget.TextView
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.plugins.Clock
|
||||
import com.android.systemui.plugins.ClockAnimations
|
||||
import com.android.systemui.plugins.ClockEvents
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.policy.BatteryController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import java.util.TimeZone
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyFloat
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class ClockEventControllerTest : SysuiTestCase() {
|
||||
|
||||
@JvmField @Rule val mockito = MockitoJUnit.rule()
|
||||
@Mock private lateinit var statusBarStateController: StatusBarStateController
|
||||
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||
@Mock private lateinit var batteryController: BatteryController
|
||||
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var configurationController: ConfigurationController
|
||||
@Mock private lateinit var animations: ClockAnimations
|
||||
@Mock private lateinit var events: ClockEvents
|
||||
@Mock private lateinit var clock: Clock
|
||||
|
||||
private lateinit var clockEventController: ClockEventController
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
whenever(clock.smallClock).thenReturn(TextView(context))
|
||||
whenever(clock.largeClock).thenReturn(TextView(context))
|
||||
whenever(clock.events).thenReturn(events)
|
||||
whenever(clock.animations).thenReturn(animations)
|
||||
|
||||
clockEventController = ClockEventController(
|
||||
statusBarStateController,
|
||||
broadcastDispatcher,
|
||||
batteryController,
|
||||
keyguardUpdateMonitor,
|
||||
configurationController,
|
||||
context.resources,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clockSet_validateInitialization() {
|
||||
clockEventController.clock = clock
|
||||
|
||||
verify(clock).initialize(any(), anyFloat(), anyFloat())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clockUnset_validateState() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.clock = null
|
||||
|
||||
assertEquals(clockEventController.clock, null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun themeChanged_verifyClockPaletteUpdated() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
|
||||
verify(configurationController).addCallback(capture(captor))
|
||||
captor.value.onThemeChanged()
|
||||
|
||||
verify(events).onColorPaletteChanged(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
|
||||
verify(batteryController).addCallback(capture(batteryCaptor))
|
||||
val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
|
||||
keyguardCaptor.value.onKeyguardVisibilityChanged(true)
|
||||
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
|
||||
|
||||
verify(animations).charge()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
|
||||
verify(batteryController).addCallback(capture(batteryCaptor))
|
||||
val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
|
||||
keyguardCaptor.value.onKeyguardVisibilityChanged(true)
|
||||
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
|
||||
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
|
||||
|
||||
verify(animations, times(1)).charge()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
|
||||
verify(batteryController).addCallback(capture(batteryCaptor))
|
||||
val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
|
||||
keyguardCaptor.value.onKeyguardVisibilityChanged(false)
|
||||
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
|
||||
|
||||
verify(animations, never()).charge()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
|
||||
verify(batteryController).addCallback(capture(batteryCaptor))
|
||||
val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
|
||||
keyguardCaptor.value.onKeyguardVisibilityChanged(true)
|
||||
batteryCaptor.value.onBatteryLevelChanged(10, false, false)
|
||||
|
||||
verify(animations, never()).charge()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun localeCallback_verifyClockNotified() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<BroadcastReceiver>()
|
||||
verify(broadcastDispatcher).registerReceiver(
|
||||
capture(captor), any(), eq(null), eq(null), anyInt(), eq(null)
|
||||
)
|
||||
captor.value.onReceive(context, mock())
|
||||
|
||||
verify(events).onLocaleChanged(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun keyguardCallback_visibilityChanged_clockDozeCalled() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(captor))
|
||||
|
||||
captor.value.onKeyguardVisibilityChanged(true)
|
||||
verify(animations, never()).doze(0f)
|
||||
|
||||
captor.value.onKeyguardVisibilityChanged(false)
|
||||
verify(animations, times(1)).doze(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun keyguardCallback_timeFormat_clockNotified() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(captor))
|
||||
captor.value.onTimeFormatChanged("12h")
|
||||
|
||||
verify(events).onTimeFormatChanged(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun keyguardCallback_timezoneChanged_clockNotified() {
|
||||
val mockTimeZone = mock<TimeZone>()
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(captor))
|
||||
captor.value.onTimeZoneChanged(mockTimeZone)
|
||||
|
||||
verify(events).onTimeZoneChanged(mockTimeZone)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun keyguardCallback_userSwitched_clockNotified() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(captor))
|
||||
captor.value.onUserSwitchComplete(10)
|
||||
|
||||
verify(events).onTimeFormatChanged(false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun keyguardCallback_verifyKeyguardChanged() {
|
||||
clockEventController.clock = clock
|
||||
clockEventController.registerListeners()
|
||||
|
||||
val captor = argumentCaptor<StatusBarStateController.StateListener>()
|
||||
verify(statusBarStateController).addCallback(capture(captor))
|
||||
captor.value.onDozeAmountChanged(0.4f, 0.6f)
|
||||
|
||||
verify(animations).doze(0.4f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unregisterListeners_validate() {
|
||||
clockEventController.unregisterListeners()
|
||||
verify(broadcastDispatcher).unregisterReceiver(any())
|
||||
verify(configurationController).removeCallback(any())
|
||||
verify(batteryController).removeCallback(any())
|
||||
verify(keyguardUpdateMonitor).removeCallback(any())
|
||||
verify(statusBarStateController).removeCallback(any())
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.keyguard;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -40,19 +41,24 @@ import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.keyguard.clock.ClockManager;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.plugins.Clock;
|
||||
import com.android.systemui.plugins.ClockPlugin;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.clocks.AnimatableClockView;
|
||||
import com.android.systemui.shared.clocks.ClockRegistry;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
|
||||
import com.android.systemui.statusbar.phone.NotificationIconContainer;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
@@ -74,12 +80,22 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
@Mock
|
||||
private ClockRegistry mClockRegistry;
|
||||
private SysuiColorExtractor mColorExtractor;
|
||||
@Mock
|
||||
private ClockManager mClockManager;
|
||||
@Mock
|
||||
KeyguardSliceViewController mKeyguardSliceViewController;
|
||||
@Mock
|
||||
NotificationIconAreaController mNotificationIconAreaController;
|
||||
@Mock
|
||||
BroadcastDispatcher mBroadcastDispatcher;
|
||||
@Mock
|
||||
BatteryController mBatteryController;
|
||||
@Mock
|
||||
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock
|
||||
KeyguardBypassController mBypassController;
|
||||
@Mock
|
||||
LockscreenSmartspaceController mSmartspaceController;
|
||||
|
||||
@Mock
|
||||
@@ -87,11 +103,11 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||
@Mock
|
||||
private Clock mClock;
|
||||
private ClockPlugin mClockPlugin;
|
||||
@Mock
|
||||
ColorExtractor.GradientColors mGradientColors;
|
||||
@Mock
|
||||
DumpManager mDumpManager;
|
||||
@Mock
|
||||
ClockEventController mClockEventController;
|
||||
|
||||
@Mock
|
||||
private NotificationIconContainer mNotificationIcons;
|
||||
@@ -123,6 +139,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
when(mView.getContext()).thenReturn(getContext());
|
||||
when(mView.getResources()).thenReturn(mResources);
|
||||
|
||||
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
|
||||
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
|
||||
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
|
||||
when(mClockView.getContext()).thenReturn(getContext());
|
||||
when(mLargeClockView.getContext()).thenReturn(getContext());
|
||||
@@ -133,20 +151,23 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
mController = new KeyguardClockSwitchController(
|
||||
mView,
|
||||
mStatusBarStateController,
|
||||
mClockRegistry,
|
||||
mColorExtractor,
|
||||
mClockManager,
|
||||
mKeyguardSliceViewController,
|
||||
mNotificationIconAreaController,
|
||||
mBroadcastDispatcher,
|
||||
mBatteryController,
|
||||
mKeyguardUpdateMonitor,
|
||||
mSmartspaceController,
|
||||
mKeyguardUnlockAnimationController,
|
||||
mSecureSettings,
|
||||
mExecutor,
|
||||
mDumpManager,
|
||||
mClockEventController,
|
||||
mFeatureFlags
|
||||
mResources,
|
||||
mDumpManager
|
||||
);
|
||||
|
||||
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
|
||||
when(mClockRegistry.createCurrentClock()).thenReturn(mClock);
|
||||
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
|
||||
|
||||
mSliceView = new View(getContext());
|
||||
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
|
||||
@@ -193,20 +214,20 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
verifyAttachment(times(1));
|
||||
|
||||
listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
|
||||
verify(mClockEventController).unregisterListeners();
|
||||
verify(mColorExtractor).removeOnColorsChangedListener(
|
||||
any(ColorExtractor.OnColorsChangedListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginPassesStatusBarState() {
|
||||
ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor =
|
||||
ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class);
|
||||
ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
|
||||
ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
|
||||
|
||||
mController.init();
|
||||
verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
|
||||
verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
|
||||
|
||||
listenerArgumentCaptor.getValue().onClockChanged();
|
||||
verify(mView, times(2)).setClock(mClock, StatusBarState.SHADE);
|
||||
verify(mClockEventController, times(2)).setClock(mClock);
|
||||
listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);
|
||||
verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -263,8 +284,10 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void verifyAttachment(VerificationMode times) {
|
||||
verify(mClockRegistry, times).registerClockChangeListener(
|
||||
any(ClockRegistry.ClockChangeListener.class));
|
||||
verify(mClockEventController, times).registerListeners();
|
||||
verify(mClockManager, times).addOnClockChangedListener(
|
||||
any(ClockManager.ClockChangedListener.class));
|
||||
verify(mColorExtractor, times).addOnColorsChangedListener(
|
||||
any(ColorExtractor.OnColorsChangedListener.class));
|
||||
verify(mView, times).updateColors(mGradientColors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
|
||||
@@ -23,61 +24,56 @@ import static com.android.keyguard.KeyguardClockSwitch.SMALL;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextClock;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.plugins.Clock;
|
||||
import com.android.systemui.plugins.ClockPlugin;
|
||||
import com.android.systemui.shared.clocks.AnimatableClockView;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
// Need to run on the main thread because KeyguardSliceView$Row init checks for
|
||||
// the main thread before acquiring a wake lock. This class is constructed when
|
||||
// the keyguard_clock_switch layout is inflated.
|
||||
// the keyguard_clcok_switch layout is inflated.
|
||||
@RunWithLooper(setAsMainLooper = true)
|
||||
public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
@Mock
|
||||
ViewGroup mMockKeyguardSliceView;
|
||||
|
||||
@Mock
|
||||
Clock mClock;
|
||||
|
||||
private FrameLayout mSmallClockFrame;
|
||||
private FrameLayout mClockFrame;
|
||||
private FrameLayout mLargeClockFrame;
|
||||
private TextClock mBigClock;
|
||||
|
||||
private AnimatableClockView mClockView;
|
||||
private AnimatableClockView mLargeClockView;
|
||||
View mMockKeyguardSliceView;
|
||||
KeyguardClockSwitch mKeyguardClockSwitch;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mMockKeyguardSliceView = mock(KeyguardSliceView.class);
|
||||
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
|
||||
when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
|
||||
.thenReturn(mMockKeyguardSliceView);
|
||||
|
||||
when(mClock.getSmallClock()).thenReturn(new TextView(getContext()));
|
||||
when(mClock.getLargeClock()).thenReturn(new TextView(getContext()));
|
||||
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
|
||||
layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
|
||||
|
||||
@@ -97,68 +93,164 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
});
|
||||
mKeyguardClockSwitch =
|
||||
(KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
|
||||
mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
|
||||
mClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
|
||||
mClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view);
|
||||
mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large);
|
||||
mLargeClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view_large);
|
||||
mBigClock = new TextClock(getContext());
|
||||
mKeyguardClockSwitch.mChildrenAreLaidOut = true;
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPluginConnected_showNothing() {
|
||||
mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
|
||||
assertEquals(mLargeClockFrame.getChildCount(), 0);
|
||||
assertEquals(mSmallClockFrame.getChildCount(), 0);
|
||||
public void onPluginConnected_showPluginClock() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
TextClock pluginView = new TextClock(getContext());
|
||||
when(plugin.getView()).thenReturn(pluginView);
|
||||
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(GONE);
|
||||
assertThat(plugin.getView().getParent()).isEqualTo(mClockFrame);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pluginConnectedThenDisconnected_showNothing() {
|
||||
mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
|
||||
assertEquals(mLargeClockFrame.getChildCount(), 1);
|
||||
assertEquals(mSmallClockFrame.getChildCount(), 1);
|
||||
|
||||
mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
|
||||
assertEquals(mLargeClockFrame.getChildCount(), 0);
|
||||
assertEquals(mSmallClockFrame.getChildCount(), 0);
|
||||
public void onPluginConnected_showPluginBigClock() {
|
||||
// GIVEN the plugin returns a view for the big clock
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
when(plugin.getBigClockView()).thenReturn(mBigClock);
|
||||
// WHEN the plugin is connected
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
// THEN the big clock container is visible and it is the parent of the
|
||||
// big clock view.
|
||||
assertThat(mLargeClockView.getVisibility()).isEqualTo(View.GONE);
|
||||
assertThat(mBigClock.getParent()).isEqualTo(mLargeClockFrame);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginConnected_showClock() {
|
||||
mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
|
||||
|
||||
assertEquals(mClock.getSmallClock().getParent(), mSmallClockFrame);
|
||||
assertEquals(mClock.getLargeClock().getParent(), mLargeClockFrame);
|
||||
public void onPluginConnected_nullView() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginConnected_showSecondPluginClock() {
|
||||
// GIVEN a plugin has already connected
|
||||
Clock otherClock = mock(Clock.class);
|
||||
when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
|
||||
when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
|
||||
mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
|
||||
mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
|
||||
|
||||
ClockPlugin plugin1 = mock(ClockPlugin.class);
|
||||
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
|
||||
// WHEN a second plugin is connected
|
||||
ClockPlugin plugin2 = mock(ClockPlugin.class);
|
||||
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
|
||||
// THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
|
||||
assertThat(otherClock.getSmallClock().getParent()).isEqualTo(mSmallClockFrame);
|
||||
assertThat(otherClock.getLargeClock().getParent()).isEqualTo(mLargeClockFrame);
|
||||
assertThat(mClock.getSmallClock().getParent()).isNull();
|
||||
assertThat(mClock.getLargeClock().getParent()).isNull();
|
||||
assertThat(plugin2.getView().getParent()).isEqualTo(mClockFrame);
|
||||
assertThat(plugin1.getView().getParent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginConnected_darkAmountInitialized() {
|
||||
// GIVEN that the dark amount has already been set
|
||||
mKeyguardClockSwitch.setDarkAmount(0.5f);
|
||||
// WHEN a plugin is connected
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
// THEN dark amount should be initalized on the plugin.
|
||||
verify(plugin).setDarkAmount(0.5f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginDisconnected_showDefaultClock() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
TextClock pluginView = new TextClock(getContext());
|
||||
when(plugin.getView()).thenReturn(pluginView);
|
||||
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(GONE);
|
||||
|
||||
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
|
||||
|
||||
assertThat(plugin.getView().getParent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginDisconnected_hidePluginBigClock() {
|
||||
// GIVEN the plugin returns a view for the big clock
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
TextClock pluginView = new TextClock(getContext());
|
||||
when(plugin.getBigClockView()).thenReturn(pluginView);
|
||||
// WHEN the plugin is connected and then disconnected
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
|
||||
// THEN the big lock container is GONE and the big clock view doesn't have
|
||||
// a parent.
|
||||
assertThat(mLargeClockView.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(pluginView.getParent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginDisconnected_nullView() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginDisconnected_secondOfTwoDisconnected() {
|
||||
// GIVEN two plugins are connected
|
||||
Clock otherClock = mock(Clock.class);
|
||||
when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
|
||||
when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
|
||||
mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
|
||||
mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
|
||||
ClockPlugin plugin1 = mock(ClockPlugin.class);
|
||||
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
|
||||
ClockPlugin plugin2 = mock(ClockPlugin.class);
|
||||
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
|
||||
// WHEN the second plugin is disconnected
|
||||
mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
|
||||
// THEN nothing should be shown
|
||||
assertThat(otherClock.getSmallClock().getParent()).isNull();
|
||||
assertThat(otherClock.getLargeClock().getParent()).isNull();
|
||||
assertThat(mClock.getSmallClock().getParent()).isNull();
|
||||
assertThat(mClock.getLargeClock().getParent()).isNull();
|
||||
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
|
||||
// THEN the default clock should be shown.
|
||||
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(plugin1.getView().getParent()).isNull();
|
||||
assertThat(plugin2.getView().getParent()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPluginDisconnected_onDestroyView() {
|
||||
// GIVEN a plugin is connected
|
||||
ClockPlugin clockPlugin = mock(ClockPlugin.class);
|
||||
when(clockPlugin.getView()).thenReturn(new TextClock(getContext()));
|
||||
mKeyguardClockSwitch.setClockPlugin(clockPlugin, StatusBarState.KEYGUARD);
|
||||
// WHEN the plugin is disconnected
|
||||
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
|
||||
// THEN onDestroyView is called on the plugin
|
||||
verify(clockPlugin).onDestroyView();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setTextColor_pluginClockSetTextColor() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
TextClock pluginView = new TextClock(getContext());
|
||||
when(plugin.getView()).thenReturn(pluginView);
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
|
||||
mKeyguardClockSwitch.setTextColor(Color.WHITE);
|
||||
|
||||
verify(plugin).setTextColor(Color.WHITE);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void setStyle_pluginClockSetStyle() {
|
||||
ClockPlugin plugin = mock(ClockPlugin.class);
|
||||
TextClock pluginView = new TextClock(getContext());
|
||||
when(plugin.getView()).thenReturn(pluginView);
|
||||
Style style = mock(Style.class);
|
||||
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
|
||||
|
||||
mKeyguardClockSwitch.setStyle(style);
|
||||
|
||||
verify(plugin).setStyle(style);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -170,7 +262,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
|
||||
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
|
||||
assertThat(mClockFrame.getAlpha()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,7 +271,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
|
||||
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
|
||||
assertThat(mClockFrame.getAlpha()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -189,8 +281,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
mKeyguardClockSwitch.mClockInAnim.end();
|
||||
mKeyguardClockSwitch.mClockOutAnim.end();
|
||||
|
||||
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(mClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
// only big clock is removed at switch
|
||||
assertThat(mLargeClockFrame.getParent()).isNull();
|
||||
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
|
||||
@@ -200,8 +292,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
|
||||
public void switchingToSmallClockNoAnimation_makesBigClockDisappear() {
|
||||
mKeyguardClockSwitch.switchToClock(SMALL, false);
|
||||
|
||||
assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
assertThat(mClockFrame.getAlpha()).isEqualTo(1);
|
||||
assertThat(mClockFrame.getVisibility()).isEqualTo(VISIBLE);
|
||||
// only big clock is removed at switch
|
||||
assertThat(mLargeClockFrame.getParent()).isNull();
|
||||
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
|
||||
|
||||
@@ -130,16 +130,13 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
pluginListener.onPluginConnected(plugin1, mockContext)
|
||||
pluginListener.onPluginConnected(plugin2, mockContext)
|
||||
val list = registry.getClocks()
|
||||
assertEquals(
|
||||
list,
|
||||
listOf(
|
||||
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
|
||||
ClockMetadata("clock_1", "clock 1"),
|
||||
ClockMetadata("clock_2", "clock 2"),
|
||||
ClockMetadata("clock_3", "clock 3"),
|
||||
ClockMetadata("clock_4", "clock 4")
|
||||
)
|
||||
)
|
||||
assertEquals(list, listOf(
|
||||
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
|
||||
ClockMetadata("clock_1", "clock 1"),
|
||||
ClockMetadata("clock_2", "clock 2"),
|
||||
ClockMetadata("clock_3", "clock 3"),
|
||||
ClockMetadata("clock_4", "clock 4")
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -161,14 +158,11 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
pluginListener.onPluginConnected(plugin1, mockContext)
|
||||
pluginListener.onPluginConnected(plugin2, mockContext)
|
||||
val list = registry.getClocks()
|
||||
assertEquals(
|
||||
list,
|
||||
listOf(
|
||||
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
|
||||
ClockMetadata("clock_1", "clock 1"),
|
||||
ClockMetadata("clock_2", "clock 2")
|
||||
)
|
||||
)
|
||||
assertEquals(list, listOf(
|
||||
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
|
||||
ClockMetadata("clock_1", "clock 1"),
|
||||
ClockMetadata("clock_2", "clock 2")
|
||||
))
|
||||
|
||||
assertEquals(registry.createExampleClock("clock_1"), mockClock)
|
||||
assertEquals(registry.createExampleClock("clock_2"), mockClock)
|
||||
@@ -228,7 +222,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
pluginListener.onPluginConnected(plugin2, mockContext)
|
||||
|
||||
var changeCallCount = 0
|
||||
registry.registerClockChangeListener { changeCallCount++ }
|
||||
registry.registerClockChangeListener({ changeCallCount++ })
|
||||
|
||||
pluginListener.onPluginDisconnected(plugin1)
|
||||
assertEquals(0, changeCallCount)
|
||||
|
||||
@@ -329,9 +329,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disable_isDozing_clockAndSystemInfoVisible() {
|
||||
public void disable_isDozingButNoCustomClock_clockAndSystemInfoVisible() {
|
||||
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(false);
|
||||
|
||||
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
|
||||
|
||||
@@ -340,9 +341,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disable_NotDozing_clockAndSystemInfoVisible() {
|
||||
public void disable_customClockButNotDozing_clockAndSystemInfoVisible() {
|
||||
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
|
||||
|
||||
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
|
||||
|
||||
@@ -350,6 +352,40 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
|
||||
assertEquals(View.VISIBLE, getClockView().getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disable_dozingAndCustomClock_clockAndSystemInfoHidden() {
|
||||
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
|
||||
|
||||
// Make sure they start out as visible
|
||||
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
|
||||
assertEquals(View.VISIBLE, getClockView().getVisibility());
|
||||
|
||||
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
|
||||
|
||||
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
|
||||
assertEquals(View.GONE, getClockView().getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDozingChanged_clockAndSystemInfoVisibilitiesUpdated() {
|
||||
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(true);
|
||||
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
|
||||
|
||||
// Make sure they start out as visible
|
||||
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
|
||||
assertEquals(View.VISIBLE, getClockView().getVisibility());
|
||||
|
||||
fragment.onDozingChanged(true);
|
||||
|
||||
// When this callback is triggered, we want to make sure the clock and system info
|
||||
// visibilities are recalculated. Since dozing=true, they shouldn't be visible.
|
||||
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
|
||||
assertEquals(View.GONE, getClockView().getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
|
||||
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
|
||||
|
||||
Reference in New Issue
Block a user