Migrate KeyguardClockSwitch to new shared Clock library

This change modifies the KeyguardClockSwitch and Controller
to get clocks from the ClockRegistry. Since the only clock
available from the registry is the default one, this should
have no user-facing changes, and is intended only to update
the relevant codepaths.

Bug: 229771520
Test: Manual and Automated
Change-Id: Ia053aaec6987e00de980388a6c024d8bcf5203a2
This commit is contained in:
Hawkwood Glazier
2022-05-27 15:48:58 +00:00
parent 3e2c4a8f55
commit c8b33ca43f
24 changed files with 706 additions and 742 deletions

View File

@@ -474,7 +474,13 @@ class TextInterpolator(layout: Layout) {
val out = mutableListOf<List<PositionedGlyphs>>() val out = mutableListOf<List<PositionedGlyphs>>()
for (lineNo in 0 until layout.lineCount) { // Shape all lines. for (lineNo in 0 until layout.lineCount) { // Shape all lines.
val lineStart = layout.getLineStart(lineNo) val lineStart = layout.getLineStart(lineNo)
val count = layout.getLineEnd(lineNo) - lineStart 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 runs = mutableListOf<PositionedGlyphs>() val runs = mutableListOf<PositionedGlyphs>()
TextShaper.shapeText( TextShaper.shapeText(
layout.text, layout.text,

View File

@@ -13,9 +13,9 @@
*/ */
package com.android.systemui.plugins package com.android.systemui.plugins
import android.content.res.Resources
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import com.android.internal.colorextraction.ColorExtractor
import com.android.systemui.plugins.annotations.ProvidesInterface import com.android.systemui.plugins.annotations.ProvidesInterface
import java.io.PrintWriter import java.io.PrintWriter
import java.util.Locale import java.util.Locale
@@ -57,7 +57,15 @@ interface Clock {
val events: ClockEvents val events: ClockEvents
/** Triggers for various animations */ /** Triggers for various animations */
val animation: ClockAnimation 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()
}
/** Optional method for dumping debug information */ /** Optional method for dumping debug information */
fun dump(pw: PrintWriter) { } fun dump(pw: PrintWriter) { }
@@ -80,15 +88,12 @@ interface ClockEvents {
/** Call whenever font settings change */ /** Call whenever font settings change */
fun onFontSettingChanged() { } fun onFontSettingChanged() { }
/** Call whenever the color pallete should update */ /** Call whenever the color palette should update */
fun onColorPaletteChanged(palette: ColorExtractor.GradientColors) { } fun onColorPaletteChanged(resources: Resources) { }
} }
/** Methods which trigger various clock animations */ /** Methods which trigger various clock animations */
interface ClockAnimation { interface ClockAnimations {
/** Initializes the doze & fold animation positions. Defaults to neither folded nor dozing. */
fun initialize(dozeFraction: Float, foldFraction: Float) { }
/** Runs an enter animation (if any) */ /** Runs an enter animation (if any) */
fun enter() { } fun enter() { }

View File

@@ -1,28 +0,0 @@
<?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>

View File

@@ -31,42 +31,14 @@
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:paddingStart="@dimen/clock_padding_start"> 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>
<FrameLayout <FrameLayout
android:id="@+id/lockscreen_clock_view_large" android:id="@+id/lockscreen_clock_view_large"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_below="@id/keyguard_slice_view" android:layout_below="@id/keyguard_slice_view"
android:paddingTop="@dimen/keyguard_large_clock_top_padding"
android:visibility="gone"> 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> </FrameLayout>
<!-- Not quite optimal but needed to translate these items as a group. The <!-- Not quite optimal but needed to translate these items as a group. The

View File

@@ -19,7 +19,7 @@
android:id="@+id/time_view" android:id="@+id/time_view"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/clock" android:fontFamily="@*android:string/config_clockFontFamily"
android:includeFontPadding="false" android:includeFontPadding="false"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:format12Hour="h:mm" android:format12Hour="h:mm"

View File

@@ -661,13 +661,7 @@
<!-- When large clock is showing, offset the smartspace by this amount --> <!-- When large clock is showing, offset the smartspace by this amount -->
<dimen name="keyguard_smartspace_top_offset">12dp</dimen> <dimen name="keyguard_smartspace_top_offset">12dp</dimen>
<!-- With the large clock, move up slightly from the center --> <!-- With the large clock, move up slightly from the center -->
<dimen name="keyguard_large_clock_top_margin">-60dp</dimen> <dimen name="keyguard_large_clock_top_padding">100dp</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> <dimen name="notification_scrim_corner_radius">32dp</dimen>
@@ -890,11 +884,6 @@
burn-in on AOD. --> burn-in on AOD. -->
<dimen name="burn_in_prevention_offset_y_clock">42dp</dimen> <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. --> <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
<dimen name="default_burn_in_prevention_offset">15dp</dimen> <dimen name="default_burn_in_prevention_offset">15dp</dimen>

View File

@@ -18,7 +18,6 @@
--> -->
<com.android.systemui.shared.clocks.AnimatableClockView <com.android.systemui.shared.clocks.AnimatableClockView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/animatable_clock_view_large"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"

View File

@@ -18,7 +18,6 @@
--> -->
<com.android.systemui.shared.clocks.AnimatableClockView <com.android.systemui.shared.clocks.AnimatableClockView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/animatable_clock_view"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="start" android:layout_gravity="start"
@@ -26,6 +25,7 @@
android:textSize="@dimen/small_clock_text_size" android:textSize="@dimen/small_clock_text_size"
android:fontFamily="@*android:string/config_clockFontFamily" android:fontFamily="@*android:string/config_clockFontFamily"
android:elegantTextHeight="false" android:elegantTextHeight="false"
android:ellipsize="none"
android:singleLine="true" android:singleLine="true"
android:fontFeatureSettings="pnum" android:fontFeatureSettings="pnum"
chargeAnimationDelay="350" chargeAnimationDelay="350"

View File

@@ -20,12 +20,15 @@ import android.annotation.ColorInt
import android.annotation.FloatRange import android.annotation.FloatRange
import android.annotation.IntRange import android.annotation.IntRange
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.compat.ChangeIdStateCache.invalidate
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.text.TextUtils import android.text.TextUtils
import android.text.format.DateFormat import android.text.format.DateFormat
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.TextView 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.GlyphCallback
import com.android.systemui.animation.Interpolators import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.TextAnimator import com.android.systemui.animation.TextAnimator
@@ -75,6 +78,12 @@ class AnimatableClockView @JvmOverloads constructor(
val lockScreenWeight: Int val lockScreenWeight: Int
get() = if (useBoldedVersion()) lockScreenWeightInternal + 100 else lockScreenWeightInternal 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 { init {
val animatableClockViewAttributes = context.obtainStyledAttributes( val animatableClockViewAttributes = context.obtainStyledAttributes(
attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes
@@ -133,6 +142,15 @@ class AnimatableClockView @JvmOverloads constructor(
// relayout if the text didn't actually change. // relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) { if (!TextUtils.equals(text, formattedText)) {
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()
} }
} }

View File

@@ -35,8 +35,6 @@ import javax.inject.Inject
private val TAG = ClockRegistry::class.simpleName private val TAG = ClockRegistry::class.simpleName
private val DEBUG = true private val DEBUG = true
typealias ClockChangeListener = () -> Unit
/** ClockRegistry aggregates providers and plugins */ /** ClockRegistry aggregates providers and plugins */
open class ClockRegistry( open class ClockRegistry(
val context: Context, val context: Context,
@@ -51,12 +49,17 @@ open class ClockRegistry(
defaultClockProvider: DefaultClockProvider defaultClockProvider: DefaultClockProvider
) : this(context, pluginManager, handler, defaultClockProvider as ClockProvider) { } ) : 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()
}
private val gson = Gson() private val gson = Gson()
private val availableClocks = mutableMapOf<ClockId, ClockInfo>() private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
private val clockChangeListeners = mutableListOf<ClockChangeListener>() private val clockChangeListeners = mutableListOf<ClockChangeListener>()
private val settingObserver = object : ContentObserver(handler) { private val settingObserver = object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) = override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) =
clockChangeListeners.forEach { it() } clockChangeListeners.forEach { it.onClockChanged() }
} }
private val pluginListener = object : PluginListener<ClockProviderPlugin> { private val pluginListener = object : PluginListener<ClockProviderPlugin> {
@@ -73,7 +76,7 @@ open class ClockRegistry(
context.contentResolver, context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE
) )
return gson.fromJson(json, ClockSetting::class.java).clockId return gson.fromJson(json, ClockSetting::class.java)?.clockId ?: DEFAULT_CLOCK_ID
} }
set(value) { set(value) {
val json = gson.toJson(ClockSetting(value, System.currentTimeMillis())) val json = gson.toJson(ClockSetting(value, System.currentTimeMillis()))
@@ -100,8 +103,11 @@ open class ClockRegistry(
val id = clock.clockId val id = clock.clockId
val current = availableClocks[id] val current = availableClocks[id]
if (current != null) { if (current != null) {
Log.e(TAG, "Clock Id conflict: $id is registered by both " + Log.e(
"${provider::class.simpleName} and ${current.provider::class.simpleName}") TAG,
"Clock Id conflict: $id is registered by both " +
"${provider::class.simpleName} and ${current.provider::class.simpleName}"
)
return return
} }
@@ -110,7 +116,7 @@ open class ClockRegistry(
if (DEBUG) { if (DEBUG) {
Log.i(TAG, "Current clock ($currentId) was connected") Log.i(TAG, "Current clock ($currentId) was connected")
} }
clockChangeListeners.forEach { it() } clockChangeListeners.forEach { it.onClockChanged() }
} }
} }
} }
@@ -122,7 +128,7 @@ open class ClockRegistry(
if (currentId == clock.clockId) { if (currentId == clock.clockId) {
Log.w(TAG, "Current clock ($currentId) was disconnected") Log.w(TAG, "Current clock ($currentId) was disconnected")
clockChangeListeners.forEach { it() } clockChangeListeners.forEach { it.onClockChanged() }
} }
} }
} }

View File

@@ -19,10 +19,9 @@ import android.graphics.drawable.Drawable
import android.icu.text.NumberFormat import android.icu.text.NumberFormat
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import com.android.internal.colorextraction.ColorExtractor
import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.Clock import com.android.systemui.plugins.Clock
import com.android.systemui.plugins.ClockAnimation import com.android.systemui.plugins.ClockAnimations
import com.android.systemui.plugins.ClockEvents import com.android.systemui.plugins.ClockEvents
import com.android.systemui.plugins.ClockId import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata import com.android.systemui.plugins.ClockMetadata
@@ -102,10 +101,13 @@ class DefaultClock(
TypedValue.COMPLEX_UNIT_PX, TypedValue.COMPLEX_UNIT_PX,
resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat() resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
) )
recomputePadding()
} }
override fun onColorPaletteChanged(palette: ColorExtractor.GradientColors) = override fun onColorPaletteChanged(resources: Resources) {
clocks.forEach { it.setColors(DOZE_COLOR, palette.mainColor) } val color = resources.getColor(android.R.color.system_accent1_100)
clocks.forEach { it.setColors(DOZE_COLOR, color) }
}
override fun onLocaleChanged(locale: Locale) { override fun onLocaleChanged(locale: Locale) {
val nf = NumberFormat.getInstance(locale) val nf = NumberFormat.getInstance(locale)
@@ -119,8 +121,17 @@ class DefaultClock(
} }
} }
override val animation = object : ClockAnimation { override var animations = DefaultClockAnimations(0f, 0f)
override fun initialize(dozeFraction: Float, foldFraction: Float) { private set
inner class DefaultClockAnimations(
dozeFraction: Float,
foldFraction: Float
) : ClockAnimations {
private var foldState = AnimationState(0f)
private var dozeState = AnimationState(0f)
init {
dozeState = AnimationState(dozeFraction) dozeState = AnimationState(dozeFraction)
foldState = AnimationState(foldFraction) foldState = AnimationState(foldFraction)
@@ -132,14 +143,13 @@ class DefaultClock(
} }
override fun enter() { override fun enter() {
if (dozeState.isActive) { if (!dozeState.isActive) {
clocks.forEach { it.animateAppearOnLockscreen() } clocks.forEach { it.animateAppearOnLockscreen() }
} }
} }
override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } } override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } }
private var foldState = AnimationState(0f)
override fun fold(fraction: Float) { override fun fold(fraction: Float) {
val (hasChanged, hasJumped) = foldState.update(fraction) val (hasChanged, hasJumped) = foldState.update(fraction)
if (hasChanged) { if (hasChanged) {
@@ -147,7 +157,6 @@ class DefaultClock(
} }
} }
private var dozeState = AnimationState(0f)
override fun doze(fraction: Float) { override fun doze(fraction: Float) {
val (hasChanged, hasJumped) = dozeState.update(fraction) val (hasChanged, hasJumped) = dozeState.update(fraction)
if (hasChanged) { if (hasChanged) {
@@ -172,6 +181,19 @@ class DefaultClock(
init { init {
events.onLocaleChanged(Locale.getDefault()) 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) } override fun dump(pw: PrintWriter) = clocks.forEach { it.dump(pw) }

View File

@@ -182,18 +182,6 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
mStatusBarStateController.removeCallback(mStatusBarStateListener); 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 */ /** Animate the clock appearance */
public void animateAppear() { public void animateAppear() {
if (!mIsDozing) mView.animateAppearOnLockscreen(); if (!mIsDozing) mView.animateAppearOnLockscreen();

View File

@@ -0,0 +1,153 @@
/*
* 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
}
}

View File

@@ -5,10 +5,8 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.content.Context; import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@@ -17,19 +15,14 @@ import android.widget.RelativeLayout;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.dagger.KeyguardStatusViewScope; import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.Clock;
import com.android.systemui.shared.clocks.AnimatableClockView;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; 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. * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/ */
@@ -49,18 +42,11 @@ public class KeyguardClockSwitch extends RelativeLayout {
public static final int LARGE = 0; public static final int LARGE = 0;
public static final int SMALL = 1; public static final int SMALL = 1;
/**
* Optional/alternative clock injected via plugin.
*/
private ClockPlugin mClockPlugin;
/** /**
* Frame for small/large clocks * Frame for small/large clocks
*/ */
private FrameLayout mClockFrame; private FrameLayout mSmallClockFrame;
private FrameLayout mLargeClockFrame; private FrameLayout mLargeClockFrame;
private AnimatableClockView mClockView;
private AnimatableClockView mLargeClockView;
private View mStatusArea; private View mStatusArea;
private int mSmartspaceTopOffset; private int mSmartspaceTopOffset;
@@ -80,12 +66,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
@VisibleForTesting AnimatorSet mClockOutAnim = null; @VisibleForTesting AnimatorSet mClockOutAnim = null;
private ObjectAnimator mStatusAreaAnim = 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; private int mClockSwitchYAmount;
@VisibleForTesting boolean mChildrenAreLaidOut = false; @VisibleForTesting boolean mChildrenAreLaidOut = false;
@@ -97,97 +77,38 @@ public class KeyguardClockSwitch extends RelativeLayout {
* Apply dp changes on font/scale change * Apply dp changes on font/scale change
*/ */
public void onDensityOrFontScaleChanged() { 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( mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_clock_switch_y_shift); R.dimen.keyguard_clock_switch_y_shift);
mSmartspaceTopOffset = mContext.getResources().getDimensionPixelSize( mSmartspaceTopOffset = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_smartspace_top_offset); 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 @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
mClockFrame = findViewById(R.id.lockscreen_clock_view); mSmallClockFrame = findViewById(R.id.lockscreen_clock_view);
mClockView = findViewById(R.id.animatable_clock_view);
mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large); mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
mLargeClockView = findViewById(R.id.animatable_clock_view_large);
mStatusArea = findViewById(R.id.keyguard_status_area); mStatusArea = findViewById(R.id.keyguard_status_area);
onDensityOrFontScaleChanged(); onDensityOrFontScaleChanged();
} }
void setClockPlugin(ClockPlugin plugin, int statusBarState) { void setClock(Clock clock, int statusBarState) {
// Disconnect from existing plugin. // Disconnect from existing plugin.
if (mClockPlugin != null) { mSmallClockFrame.removeAllViews();
View smallClockView = mClockPlugin.getView(); mLargeClockFrame.removeAllViews();
if (smallClockView != null && smallClockView.getParent() == mClockFrame) {
mClockFrame.removeView(smallClockView); if (clock == null) {
} Log.e(TAG, "No clock being shown");
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; return;
} }
// Attach small and big clock views to hierarchy. // Attach small and big clock views to hierarchy.
View smallClockView = plugin.getView(); mSmallClockFrame.addView(clock.getSmallClock(), -1,
if (smallClockView != null) { new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
mClockFrame.addView(smallClockView, -1, ViewGroup.LayoutParams.WRAP_CONTENT));
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mLargeClockFrame.addView(clock.getLargeClock());
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) { private void updateClockViews(boolean useLargeClock, boolean animate) {
@@ -203,14 +124,14 @@ public class KeyguardClockSwitch extends RelativeLayout {
int direction = 1; int direction = 1;
float statusAreaYTranslation; float statusAreaYTranslation;
if (useLargeClock) { if (useLargeClock) {
out = mClockFrame; out = mSmallClockFrame;
in = mLargeClockFrame; in = mLargeClockFrame;
if (indexOfChild(in) == -1) addView(in); if (indexOfChild(in) == -1) addView(in);
direction = -1; direction = -1;
statusAreaYTranslation = mClockFrame.getTop() - mStatusArea.getTop() statusAreaYTranslation = mSmallClockFrame.getTop() - mStatusArea.getTop()
+ mSmartspaceTopOffset; + mSmartspaceTopOffset;
} else { } else {
in = mClockFrame; in = mSmallClockFrame;
out = mLargeClockFrame; out = mLargeClockFrame;
statusAreaYTranslation = 0f; statusAreaYTranslation = 0f;
@@ -268,18 +189,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
mStatusAreaAnim.start(); 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 * Display the desired clock and hide the other one
* *
@@ -311,64 +220,11 @@ public class KeyguardClockSwitch extends RelativeLayout {
mChildrenAreLaidOut = true; 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) { public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardClockSwitch:"); pw.println("KeyguardClockSwitch:");
pw.println(" mClockPlugin: " + mClockPlugin); pw.println(" mClockFrame: " + mSmallClockFrame);
pw.println(" mClockFrame: " + mClockFrame);
pw.println(" mLargeClockFrame: " + mLargeClockFrame); pw.println(" mLargeClockFrame: " + mLargeClockFrame);
pw.println(" mStatusArea: " + mStatusArea); pw.println(" mStatusArea: " + mStatusArea);
pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mSupportsDarkText: " + mSupportsDarkText);
pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
pw.println(" mDisplayedClockSize: " + mDisplayedClockSize); pw.println(" mDisplayedClockSize: " + mDisplayedClockSize);
} }
} }

View File

@@ -22,8 +22,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import android.app.WallpaperManager;
import android.content.res.Resources;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
@@ -32,34 +30,28 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull; 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.Dumpable;
import com.android.systemui.R; 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.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.Clock;
import com.android.systemui.plugins.statusbar.StatusBarStateController; 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.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer; 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.ViewController;
import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
@@ -69,48 +61,24 @@ import javax.inject.Inject;
*/ */
public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch> public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch>
implements Dumpable { implements Dumpable {
private static final boolean CUSTOM_CLOCKS_ENABLED = true;
private final StatusBarStateController mStatusBarStateController; private final StatusBarStateController mStatusBarStateController;
private final SysuiColorExtractor mColorExtractor; private final ClockRegistry mClockRegistry;
private final ClockManager mClockManager;
private final KeyguardSliceViewController mKeyguardSliceViewController; private final KeyguardSliceViewController mKeyguardSliceViewController;
private final NotificationIconAreaController mNotificationIconAreaController; private final NotificationIconAreaController mNotificationIconAreaController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final BatteryController mBatteryController;
private final LockscreenSmartspaceController mSmartspaceController; private final LockscreenSmartspaceController mSmartspaceController;
private final Resources mResources;
private final SecureSettings mSecureSettings; private final SecureSettings mSecureSettings;
private final DumpManager mDumpManager; private final DumpManager mDumpManager;
private final ClockEventController mClockEventController;
/** /** Clock frames for both small and large sizes */
* Clock for both small and large sizes private FrameLayout mSmallClockFrame; // top aligned clock
*/
private AnimatableClockController mClockViewController;
private FrameLayout mClockFrame; // top aligned clock
private AnimatableClockController mLargeClockViewController;
private FrameLayout mLargeClockFrame; // centered clock private FrameLayout mLargeClockFrame; // centered clock
@KeyguardClockSwitch.ClockSize @KeyguardClockSwitch.ClockSize
private int mCurrentClockSize = SMALL; private int mCurrentClockSize = SMALL;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private int mKeyguardClockTopMargin = 0; 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; private ViewGroup mStatusArea;
// If set will replace keyguard_slice_view // If set will replace keyguard_slice_view
@@ -119,9 +87,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private boolean mOnlyClock = false; private boolean mOnlyClock = false;
private Executor mUiExecutor; private final Executor mUiExecutor;
private boolean mCanShowDoubleLineClock = true; private boolean mCanShowDoubleLineClock = true;
private ContentObserver mDoubleLineClockObserver = new ContentObserver(null) { private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
@Override @Override
public void onChange(boolean change) { public void onChange(boolean change) {
updateDoubleLineClock(); updateDoubleLineClock();
@@ -142,34 +110,30 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
public KeyguardClockSwitchController( public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch, KeyguardClockSwitch keyguardClockSwitch,
StatusBarStateController statusBarStateController, StatusBarStateController statusBarStateController,
SysuiColorExtractor colorExtractor, ClockRegistry clockRegistry,
ClockManager clockManager,
KeyguardSliceViewController keyguardSliceViewController, KeyguardSliceViewController keyguardSliceViewController,
NotificationIconAreaController notificationIconAreaController, NotificationIconAreaController notificationIconAreaController,
BroadcastDispatcher broadcastDispatcher,
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockscreenSmartspaceController smartspaceController, LockscreenSmartspaceController smartspaceController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController, KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SecureSettings secureSettings, SecureSettings secureSettings,
@Main Executor uiExecutor, @Main Executor uiExecutor,
@Main Resources resources, DumpManager dumpManager,
DumpManager dumpManager) { ClockEventController clockEventController) {
super(keyguardClockSwitch); super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController; mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor; mClockRegistry = clockRegistry;
mClockManager = clockManager;
mKeyguardSliceViewController = keyguardSliceViewController; mKeyguardSliceViewController = keyguardSliceViewController;
mNotificationIconAreaController = notificationIconAreaController; mNotificationIconAreaController = notificationIconAreaController;
mBroadcastDispatcher = broadcastDispatcher;
mBatteryController = batteryController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mSmartspaceController = smartspaceController; mSmartspaceController = smartspaceController;
mResources = resources;
mSecureSettings = secureSettings; mSecureSettings = secureSettings;
mUiExecutor = uiExecutor; mUiExecutor = uiExecutor;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mDumpManager = dumpManager; mDumpManager = dumpManager;
mClockEventController = clockEventController;
mClockChangedListener = () -> {
setClock(mClockRegistry.createCurrentClock());
};
} }
/** /**
@@ -186,40 +150,18 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
public void onInit() { public void onInit() {
mKeyguardSliceViewController.init(); mKeyguardSliceViewController.init();
mClockFrame = mView.findViewById(R.id.lockscreen_clock_view); mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large); 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.unregisterDumpable(getClass().toString()); // unregister previous clocks
mDumpManager.registerDumpable(getClass().toString(), this); mDumpManager.registerDumpable(getClass().toString(), this);
} }
@Override @Override
protected void onViewAttached() { protected void onViewAttached() {
if (CUSTOM_CLOCKS_ENABLED) { mClockRegistry.registerClockChangeListener(mClockChangedListener);
mClockManager.addOnClockChangedListener(mClockChangedListener); setClock(mClockRegistry.createCurrentClock());
} mClockEventController.registerListeners();
mColorExtractor.addOnColorsChangedListener(mColorsListener);
mView.updateColors(getGradientColors());
mKeyguardClockTopMargin = mKeyguardClockTopMargin =
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin); mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
@@ -242,7 +184,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
ksv.setVisibility(View.GONE); ksv.setVisibility(View.GONE);
addSmartspaceView(ksvIndex); addSmartspaceView(ksvIndex);
updateClockLayout();
} }
mSecureSettings.registerContentObserverForUser( mSecureSettings.registerContentObserverForUser(
@@ -264,11 +205,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
@Override @Override
protected void onViewDetached() { protected void onViewDetached() {
if (CUSTOM_CLOCKS_ENABLED) { mClockRegistry.unregisterClockChangeListener(mClockChangedListener);
mClockManager.removeOnClockChangedListener(mClockChangedListener); mClockEventController.unregisterListeners();
} setClock(null);
mColorExtractor.removeOnColorsChangedListener(mColorsListener);
mView.setClockPlugin(null, mStatusBarStateController.getState());
mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver); mSecureSettings.unregisterContentObserver(mDoubleLineClockObserver);
@@ -307,18 +246,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mView.onDensityOrFontScaleChanged(); mView.onDensityOrFontScaleChanged();
mKeyguardClockTopMargin = mKeyguardClockTopMargin =
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin); 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);
} }
/** /**
@@ -334,44 +261,31 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
boolean appeared = mView.switchToClock(clockSize, animate); boolean appeared = mView.switchToClock(clockSize, animate);
if (animate && appeared && clockSize == LARGE) { if (animate && appeared && clockSize == LARGE) {
mLargeClockViewController.animateAppear(); getClock().getAnimations().enter();
}
}
public void animateFoldToAod() {
if (mClockViewController != null) {
mClockViewController.animateFoldAppear();
mLargeClockViewController.animateFoldAppear();
} }
} }
/** /**
* If we're presenting a custom clock of just the default one. * Animates the clock view between folded and unfolded states
*/ */
public boolean hasCustomClock() { public void animateFoldToAod(float foldFraction) {
return mView.hasCustomClock(); Clock clock = getClock();
} if (clock != null) {
clock.getAnimations().fold(foldFraction);
/** }
* Get the clock text size.
*/
public float getClockTextSize() {
return mView.getTextSize();
} }
/** /**
* Refresh clock. Called in response to TIME_TICK broadcasts. * Refresh clock. Called in response to TIME_TICK broadcasts.
*/ */
void refresh() { void refresh() {
if (mClockViewController != null) {
mClockViewController.refreshTime();
mLargeClockViewController.refreshTime();
}
if (mSmartspaceController != null) { if (mSmartspaceController != null) {
mSmartspaceController.requestSmartspaceUpdate(); mSmartspaceController.requestSmartspaceUpdate();
} }
Clock clock = getClock();
mView.refresh(); if (clock != null) {
clock.getEvents().onTimeTick();
}
} }
/** /**
@@ -383,7 +297,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
void updatePosition(int x, float scale, AnimationProperties props, boolean animate) { void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x; x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x;
PropertyAnimator.setProperty(mClockFrame, AnimatableProperty.TRANSLATION_X, PropertyAnimator.setProperty(mSmallClockFrame, AnimatableProperty.TRANSLATION_X,
x, props, animate); x, props, animate);
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X, PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X,
scale, props, animate); scale, props, animate);
@@ -396,25 +310,39 @@ 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. * 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 * We can't directly getBottom() because clock changes positions in AOD for burn-in
*/ */
int getClockBottom(int statusBarHeaderHeight) { int getClockBottom(int statusBarHeaderHeight) {
Clock clock = getClock();
if (clock == null) {
return 0;
}
if (mLargeClockFrame.getVisibility() == View.VISIBLE) { if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
View clock = mLargeClockFrame.findViewById(
com.android.systemui.R.id.animatable_clock_view_large);
int frameHeight = mLargeClockFrame.getHeight(); int frameHeight = mLargeClockFrame.getHeight();
int clockHeight = clock.getHeight(); int clockHeight = clock.getLargeClock().getHeight();
return frameHeight / 2 + clockHeight / 2; return frameHeight / 2 + clockHeight / 2;
} else { } else {
return mClockFrame.findViewById( int clockHeight = clock.getSmallClock().getHeight();
com.android.systemui.R.id.animatable_clock_view).getHeight() return clockHeight + statusBarHeaderHeight + mKeyguardClockTopMargin;
+ 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();
} }
} }
@@ -429,12 +357,13 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mNotificationIconAreaController.setupAodIcons(nic); mNotificationIconAreaController.setupAodIcons(nic);
} }
private void setClockPlugin(ClockPlugin plugin) { private void setClock(Clock clock) {
mView.setClockPlugin(plugin, mStatusBarStateController.getState()); mClockEventController.setClock(clock);
mView.setClock(clock, mStatusBarStateController.getState());
} }
private ColorExtractor.GradientColors getGradientColors() { private Clock getClock() {
return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK); return mClockEventController.getClock();
} }
private int getCurrentLayoutDirection() { private int getCurrentLayoutDirection() {
@@ -467,8 +396,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE)); pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE));
pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock); pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock);
mClockViewController.dump(pw); Clock clock = getClock();
mLargeClockViewController.dump(pw); if (clock != null) {
clock.dump(pw);
}
} }
} }

View File

@@ -17,14 +17,11 @@
package com.android.keyguard; package com.android.keyguard;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.GridLayout; import android.widget.GridLayout;
import androidx.core.graphics.ColorUtils;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.CrossFadeHelper;
@@ -46,7 +43,6 @@ public class KeyguardStatusView extends GridLayout {
private View mMediaHostContainer; private View mMediaHostContainer;
private float mDarkAmount = 0; private float mDarkAmount = 0;
private int mTextColor;
public KeyguardStatusView(Context context) { public KeyguardStatusView(Context context) {
this(context, null, 0); this(context, null, 0);
@@ -71,7 +67,6 @@ public class KeyguardStatusView extends GridLayout {
} }
mKeyguardSlice = findViewById(R.id.keyguard_slice_view); mKeyguardSlice = findViewById(R.id.keyguard_slice_view);
mTextColor = mClockView.getCurrentTextColor();
mMediaHostContainer = findViewById(R.id.status_view_media_container); mMediaHostContainer = findViewById(R.id.status_view_media_container);
@@ -83,15 +78,12 @@ public class KeyguardStatusView extends GridLayout {
return; return;
} }
mDarkAmount = darkAmount; mDarkAmount = darkAmount;
mClockView.setDarkAmount(darkAmount);
CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount); CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
updateDark(); updateDark();
} }
void updateDark() { void updateDark() {
final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
mKeyguardSlice.setDarkAmount(mDarkAmount); mKeyguardSlice.setDarkAmount(mDarkAmount);
mClockView.setTextColor(blendedTextColor);
} }
/** Sets a translationY value on every child view except for the media view. */ /** Sets a translationY value on every child view except for the media view. */
@@ -113,7 +105,6 @@ public class KeyguardStatusView extends GridLayout {
public void dump(PrintWriter pw, String[] args) { public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardStatusView:"); pw.println("KeyguardStatusView:");
pw.println(" mDarkAmount: " + mDarkAmount); pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
if (mClockView != null) { if (mClockView != null) {
mClockView.dump(pw, args); mClockView.dump(pw, args);
} }

View File

@@ -30,8 +30,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import java.util.TimeZone;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
@@ -95,13 +93,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mKeyguardSliceViewController.refresh(); 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 * Set which clock should be displayed on the keyguard. The other one will be automatically
* hidden. * hidden.
@@ -114,16 +105,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
* Performs fold to aod animation of the clocks (changes font weight from bold to thin). * 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 * This animation is played when AOD is enabled and foldable device is fully folded, it is
* displayed on the outer screen * displayed on the outer screen
* @param foldFraction current fraction of fold animation complete
*/ */
public void animateFoldToAod() { public void animateFoldToAod(float foldFraction) {
mKeyguardClockSwitchController.animateFoldToAod(); mKeyguardClockSwitchController.animateFoldToAod(foldFraction);
}
/**
* If we're presenting a custom clock of just the default one.
*/
public boolean hasCustomClock() {
return mKeyguardClockSwitchController.hasCustomClock();
} }
/** /**
@@ -143,24 +128,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
} }
/** /**
* Set pivot x. * Update the pivot position based on the parent view
*/ */
public void setPivotX(float pivot) { public void updatePivot(float parentWidth, float parentHeight) {
mView.setPivotX(pivot); mView.setPivotX(parentWidth / 2f);
} mView.setPivotY(mKeyguardClockSwitchController.getClockHeight() / 2f);
/**
* Set pivot y.
*/
public void setPivotY(float pivot) {
mView.setPivotY(pivot);
}
/**
* Get the clock text size.
*/
public float getClockTextSize() {
return mKeyguardClockSwitchController.getClockTextSize();
} }
/** /**
@@ -239,11 +211,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
refreshTime(); refreshTime();
} }
@Override
public void onTimeZoneChanged(TimeZone timeZone) {
mKeyguardClockSwitchController.updateTimeZone(timeZone);
}
@Override @Override
public void onKeyguardVisibilityChanged(boolean showing) { public void onKeyguardVisibilityChanged(boolean showing) {
if (showing) { if (showing) {

View File

@@ -276,11 +276,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private final NotificationIconAreaController mNotificationIconAreaController; 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 * Maximum time before which we will expand the panel even for slow motions when getting a
* touch passed over from launcher. * touch passed over from launcher.
@@ -1123,13 +1118,6 @@ public class NotificationPanelViewController extends PanelViewController {
} }
} }
/**
* Returns if there's a custom clock being presented.
*/
public boolean hasCustomClock() {
return mKeyguardStatusViewController.hasCustomClock();
}
private void setCentralSurfaces(CentralSurfaces centralSurfaces) { private void setCentralSurfaces(CentralSurfaces centralSurfaces) {
// TODO: this can be injected. // TODO: this can be injected.
mCentralSurfaces = centralSurfaces; mCentralSurfaces = centralSurfaces;
@@ -4009,9 +3997,10 @@ public class NotificationPanelViewController extends PanelViewController {
endAction.run(); endAction.run();
} }
}) })
.setUpdateListener(anim -> {
mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
})
.start(); .start();
mKeyguardStatusViewController.animateFoldToAod();
} }
/** /**
@@ -4873,7 +4862,6 @@ public class NotificationPanelViewController extends PanelViewController {
public void onDozeAmountChanged(float linearAmount, float amount) { public void onDozeAmountChanged(float linearAmount, float amount) {
mInterpolatedDarkAmount = amount; mInterpolatedDarkAmount = amount;
mLinearDarkAmount = linearAmount; mLinearDarkAmount = linearAmount;
mKeyguardStatusViewController.setDarkAmount(mInterpolatedDarkAmount);
mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount); mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
positionClockAndNotifications(); positionClockAndNotifications();
} }
@@ -4982,11 +4970,8 @@ public class NotificationPanelViewController extends PanelViewController {
updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount()); updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount());
setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth()); setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot // Update Clock Pivot (used by anti-burnin transformations)
mKeyguardStatusViewController.setPivotX(mView.getWidth() / 2); mKeyguardStatusViewController.updatePivot(mView.getWidth(), mView.getHeight());
mKeyguardStatusViewController.setPivotY(
(FONT_HEIGHT - CAP_HEIGHT) / 2048f
* mKeyguardStatusViewController.getClockTextSize());
// Calculate quick setting heights. // Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight; int oldMaxHeight = mQsMaxExpansionHeight;

View File

@@ -24,7 +24,6 @@ import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedul
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT; import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
import android.animation.Animator; import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Fragment; import android.app.Fragment;
@@ -395,14 +394,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
state |= DISABLE_CLOCK; state |= DISABLE_CLOCK;
} }
// 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()) { if (mOngoingCallController.hasOngoingCall()) {
state &= ~DISABLE_ONGOING_CALL_CHIP; state &= ~DISABLE_ONGOING_CALL_CHIP;
} else { } else {

View File

@@ -0,0 +1,259 @@
/*
* 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())
}
}

View File

@@ -19,7 +19,6 @@ package com.android.keyguard;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -41,23 +40,18 @@ import android.widget.RelativeLayout;
import androidx.test.filters.SmallTest; 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.R;
import com.android.systemui.SysuiTestCase; 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.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.Clock;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.AnimatableClockView; 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.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController; 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.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer; 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.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.time.FakeSystemClock;
@@ -79,22 +73,12 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock @Mock
private StatusBarStateController mStatusBarStateController; private StatusBarStateController mStatusBarStateController;
@Mock @Mock
private SysuiColorExtractor mColorExtractor; private ClockRegistry mClockRegistry;
@Mock
private ClockManager mClockManager;
@Mock @Mock
KeyguardSliceViewController mKeyguardSliceViewController; KeyguardSliceViewController mKeyguardSliceViewController;
@Mock @Mock
NotificationIconAreaController mNotificationIconAreaController; NotificationIconAreaController mNotificationIconAreaController;
@Mock @Mock
BroadcastDispatcher mBroadcastDispatcher;
@Mock
BatteryController mBatteryController;
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
KeyguardBypassController mBypassController;
@Mock
LockscreenSmartspaceController mSmartspaceController; LockscreenSmartspaceController mSmartspaceController;
@Mock @Mock
@@ -102,11 +86,11 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Mock @Mock
KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock @Mock
private ClockPlugin mClockPlugin; private Clock mClock;
@Mock
ColorExtractor.GradientColors mGradientColors;
@Mock @Mock
DumpManager mDumpManager; DumpManager mDumpManager;
@Mock
ClockEventController mClockEventController;
@Mock @Mock
private NotificationIconContainer mNotificationIcons; private NotificationIconContainer mNotificationIcons;
@@ -136,8 +120,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
when(mView.getContext()).thenReturn(getContext()); when(mView.getContext()).thenReturn(getContext());
when(mView.getResources()).thenReturn(mResources); 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(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
when(mClockView.getContext()).thenReturn(getContext()); when(mClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext()); when(mLargeClockView.getContext()).thenReturn(getContext());
@@ -148,23 +130,19 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
mController = new KeyguardClockSwitchController( mController = new KeyguardClockSwitchController(
mView, mView,
mStatusBarStateController, mStatusBarStateController,
mColorExtractor, mClockRegistry,
mClockManager,
mKeyguardSliceViewController, mKeyguardSliceViewController,
mNotificationIconAreaController, mNotificationIconAreaController,
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
mSmartspaceController, mSmartspaceController,
mKeyguardUnlockAnimationController, mKeyguardUnlockAnimationController,
mSecureSettings, mSecureSettings,
mExecutor, mExecutor,
mResources, mDumpManager,
mDumpManager mClockEventController
); );
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors); when(mClockRegistry.createCurrentClock()).thenReturn(mClock);
mSliceView = new View(getContext()); mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView); when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
@@ -211,20 +189,20 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
verifyAttachment(times(1)); verifyAttachment(times(1));
listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
verify(mColorExtractor).removeOnColorsChangedListener( verify(mClockEventController).unregisterListeners();
any(ColorExtractor.OnColorsChangedListener.class));
} }
@Test @Test
public void testPluginPassesStatusBarState() { public void testPluginPassesStatusBarState() {
ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor = ArgumentCaptor<ClockRegistry.ClockChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class); ArgumentCaptor.forClass(ClockRegistry.ClockChangeListener.class);
mController.init(); mController.init();
verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture()); verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin); listenerArgumentCaptor.getValue().onClockChanged();
verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE); verify(mView, times(2)).setClock(mClock, StatusBarState.SHADE);
verify(mClockEventController, times(2)).setClock(mClock);
} }
@Test @Test
@@ -281,10 +259,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
} }
private void verifyAttachment(VerificationMode times) { private void verifyAttachment(VerificationMode times) {
verify(mClockManager, times).addOnClockChangedListener( verify(mClockRegistry, times).registerClockChangeListener(
any(ClockManager.ClockChangedListener.class)); any(ClockRegistry.ClockChangeListener.class));
verify(mColorExtractor, times).addOnColorsChangedListener( verify(mClockEventController, times).registerListeners();
any(ColorExtractor.OnColorsChangedListener.class));
verify(mView, times).updateColors(mGradientColors);
} }
} }

View File

@@ -16,7 +16,6 @@
package com.android.keyguard; package com.android.keyguard;
import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -24,56 +23,61 @@ import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.google.common.truth.Truth.assertThat; 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.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint.Style;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextClock; import android.widget.TextView;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.Clock;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarState;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner.class) @RunWith(AndroidTestingRunner.class)
// Need to run on the main thread because KeyguardSliceView$Row init checks for // 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 main thread before acquiring a wake lock. This class is constructed when
// the keyguard_clcok_switch layout is inflated. // the keyguard_clock_switch layout is inflated.
@RunWithLooper(setAsMainLooper = true) @RunWithLooper(setAsMainLooper = true)
public class KeyguardClockSwitchTest extends SysuiTestCase { public class KeyguardClockSwitchTest extends SysuiTestCase {
private FrameLayout mClockFrame; @Mock
private FrameLayout mLargeClockFrame; ViewGroup mMockKeyguardSliceView;
private TextClock mBigClock;
@Mock
Clock mClock;
private FrameLayout mSmallClockFrame;
private FrameLayout mLargeClockFrame;
private AnimatableClockView mClockView;
private AnimatableClockView mLargeClockView;
View mMockKeyguardSliceView;
KeyguardClockSwitch mKeyguardClockSwitch; KeyguardClockSwitch mKeyguardClockSwitch;
@Before @Before
public void setUp() { public void setUp() {
mMockKeyguardSliceView = mock(KeyguardSliceView.class); MockitoAnnotations.initMocks(this);
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area)) when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
.thenReturn(mMockKeyguardSliceView); .thenReturn(mMockKeyguardSliceView);
when(mClock.getSmallClock()).thenReturn(new TextView(getContext()));
when(mClock.getLargeClock()).thenReturn(new TextView(getContext()));
LayoutInflater layoutInflater = LayoutInflater.from(getContext()); LayoutInflater layoutInflater = LayoutInflater.from(getContext());
layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@@ -93,164 +97,68 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
}); });
mKeyguardClockSwitch = mKeyguardClockSwitch =
(KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
mClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view); mSmallClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view);
mClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view);
mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large); 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; mKeyguardClockSwitch.mChildrenAreLaidOut = true;
MockitoAnnotations.initMocks(this);
} }
@Test @Test
public void onPluginConnected_showPluginClock() { public void noPluginConnected_showNothing() {
ClockPlugin plugin = mock(ClockPlugin.class); mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
TextClock pluginView = new TextClock(getContext()); assertEquals(mLargeClockFrame.getChildCount(), 0);
when(plugin.getView()).thenReturn(pluginView); assertEquals(mSmallClockFrame.getChildCount(), 0);
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
assertThat(mClockView.getVisibility()).isEqualTo(GONE);
assertThat(plugin.getView().getParent()).isEqualTo(mClockFrame);
} }
@Test @Test
public void onPluginConnected_showPluginBigClock() { public void pluginConnectedThenDisconnected_showNothing() {
// GIVEN the plugin returns a view for the big clock mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
ClockPlugin plugin = mock(ClockPlugin.class); assertEquals(mLargeClockFrame.getChildCount(), 1);
when(plugin.getBigClockView()).thenReturn(mBigClock); assertEquals(mSmallClockFrame.getChildCount(), 1);
// WHEN the plugin is connected
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD); mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
// THEN the big clock container is visible and it is the parent of the assertEquals(mLargeClockFrame.getChildCount(), 0);
// big clock view. assertEquals(mSmallClockFrame.getChildCount(), 0);
assertThat(mLargeClockView.getVisibility()).isEqualTo(View.GONE);
assertThat(mBigClock.getParent()).isEqualTo(mLargeClockFrame);
} }
@Test @Test
public void onPluginConnected_nullView() { public void onPluginConnected_showClock() {
ClockPlugin plugin = mock(ClockPlugin.class); mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE); assertEquals(mClock.getSmallClock().getParent(), mSmallClockFrame);
assertEquals(mClock.getLargeClock().getParent(), mLargeClockFrame);
} }
@Test @Test
public void onPluginConnected_showSecondPluginClock() { public void onPluginConnected_showSecondPluginClock() {
// GIVEN a plugin has already connected // GIVEN a plugin has already connected
ClockPlugin plugin1 = mock(ClockPlugin.class); Clock otherClock = mock(Clock.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext())); when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD); when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
// WHEN a second plugin is connected mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
ClockPlugin plugin2 = mock(ClockPlugin.class); mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
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. // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
assertThat(plugin2.getView().getParent()).isEqualTo(mClockFrame); assertThat(otherClock.getSmallClock().getParent()).isEqualTo(mSmallClockFrame);
assertThat(plugin1.getView().getParent()).isNull(); assertThat(otherClock.getLargeClock().getParent()).isEqualTo(mLargeClockFrame);
} assertThat(mClock.getSmallClock().getParent()).isNull();
assertThat(mClock.getLargeClock().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 @Test
public void onPluginDisconnected_secondOfTwoDisconnected() { public void onPluginDisconnected_secondOfTwoDisconnected() {
// GIVEN two plugins are connected // GIVEN two plugins are connected
ClockPlugin plugin1 = mock(ClockPlugin.class); Clock otherClock = mock(Clock.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext())); when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD); when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
ClockPlugin plugin2 = mock(ClockPlugin.class); mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
when(plugin2.getView()).thenReturn(new TextClock(getContext())); mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
// WHEN the second plugin is disconnected // WHEN the second plugin is disconnected
mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD); mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
// THEN the default clock should be shown. // THEN nothing should be shown
assertThat(mClockView.getVisibility()).isEqualTo(VISIBLE); assertThat(otherClock.getSmallClock().getParent()).isNull();
assertThat(plugin1.getView().getParent()).isNull(); assertThat(otherClock.getLargeClock().getParent()).isNull();
assertThat(plugin2.getView().getParent()).isNull(); assertThat(mClock.getSmallClock().getParent()).isNull();
} assertThat(mClock.getLargeClock().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 @Test
@@ -262,7 +170,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mClockFrame.getAlpha()).isEqualTo(0); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
} }
@Test @Test
@@ -271,7 +179,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
assertThat(mClockFrame.getAlpha()).isEqualTo(0); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0);
} }
@Test @Test
@@ -281,8 +189,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
mKeyguardClockSwitch.mClockInAnim.end(); mKeyguardClockSwitch.mClockInAnim.end();
mKeyguardClockSwitch.mClockOutAnim.end(); mKeyguardClockSwitch.mClockOutAnim.end();
assertThat(mClockFrame.getAlpha()).isEqualTo(1); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
assertThat(mClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
// only big clock is removed at switch // only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull(); assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
@@ -292,8 +200,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void switchingToSmallClockNoAnimation_makesBigClockDisappear() { public void switchingToSmallClockNoAnimation_makesBigClockDisappear() {
mKeyguardClockSwitch.switchToClock(SMALL, false); mKeyguardClockSwitch.switchToClock(SMALL, false);
assertThat(mClockFrame.getAlpha()).isEqualTo(1); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(1);
assertThat(mClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mSmallClockFrame.getVisibility()).isEqualTo(VISIBLE);
// only big clock is removed at switch // only big clock is removed at switch
assertThat(mLargeClockFrame.getParent()).isNull(); assertThat(mLargeClockFrame.getParent()).isNull();
assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);

View File

@@ -129,13 +129,16 @@ class ClockRegistryTest : SysuiTestCase() {
pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin1, mockContext)
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
val list = registry.getClocks() val list = registry.getClocks()
assertEquals(list, listOf( assertEquals(
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), list,
ClockMetadata("clock_1", "clock 1"), listOf(
ClockMetadata("clock_2", "clock 2"), ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME),
ClockMetadata("clock_3", "clock 3"), ClockMetadata("clock_1", "clock 1"),
ClockMetadata("clock_4", "clock 4") ClockMetadata("clock_2", "clock 2"),
)) ClockMetadata("clock_3", "clock 3"),
ClockMetadata("clock_4", "clock 4")
)
)
} }
@Test @Test
@@ -157,11 +160,14 @@ class ClockRegistryTest : SysuiTestCase() {
pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin1, mockContext)
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
val list = registry.getClocks() val list = registry.getClocks()
assertEquals(list, listOf( assertEquals(
ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME), list,
ClockMetadata("clock_1", "clock 1"), listOf(
ClockMetadata("clock_2", "clock 2") 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_1"), mockClock)
assertEquals(registry.createExampleClock("clock_2"), mockClock) assertEquals(registry.createExampleClock("clock_2"), mockClock)
@@ -221,7 +227,7 @@ class ClockRegistryTest : SysuiTestCase() {
pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginConnected(plugin2, mockContext)
var changeCallCount = 0 var changeCallCount = 0
registry.registerClockChangeListener({ changeCallCount++ }) registry.registerClockChangeListener { changeCallCount++ }
pluginListener.onPluginDisconnected(plugin1) pluginListener.onPluginDisconnected(plugin1)
assertEquals(0, changeCallCount) assertEquals(0, changeCallCount)

View File

@@ -223,10 +223,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
} }
@Test @Test
public void disable_isDozingButNoCustomClock_clockAndSystemInfoVisible() { public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment(); CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true); when(mStatusBarStateController.isDozing()).thenReturn(true);
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false); fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -235,10 +234,9 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
} }
@Test @Test
public void disable_customClockButNotDozing_clockAndSystemInfoVisible() { public void disable_NotDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment(); CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(false); when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mNotificationPanelViewController.hasCustomClock()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false); fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -246,40 +244,6 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.VISIBLE, getClockView().getVisibility()); 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, getSystemIconAreaView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.INVISIBLE, getSystemIconAreaView().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, getSystemIconAreaView().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, getSystemIconAreaView().getVisibility());
assertEquals(View.GONE, getClockView().getVisibility());
}
@Test @Test
public void disable_headsUpShouldBeVisibleTrue_clockDisabled() { public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment(); CollapsedStatusBarFragment fragment = resumeAndGetFragment();