chore: Begone system clock related function
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
data class AlarmData(
|
||||
val nextAlarmMillis: Long?,
|
||||
val descriptionId: String?,
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
|
||||
/** Methods which trigger various clock animations */
|
||||
@ProtectedInterface
|
||||
interface ClockAnimations {
|
||||
/** Runs an enter animation (if any) */
|
||||
fun enter()
|
||||
|
||||
/** Sets how far into AOD the device currently is. */
|
||||
fun doze(fraction: Float)
|
||||
|
||||
/** Sets how far into the folding animation the device is. */
|
||||
fun fold(fraction: Float)
|
||||
|
||||
/** Runs the battery animation (if any). */
|
||||
fun charge()
|
||||
|
||||
/** Runs when the clock's position changed during the move animation. */
|
||||
fun onPositionAnimated(anim: ClockPositionAnimationArgs)
|
||||
|
||||
/**
|
||||
* Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview,
|
||||
* 0.0 -> clock is scaled down in the shade; previewRatio is previewSize / screenSize
|
||||
*/
|
||||
fun onPickerCarouselSwiping(swipingFraction: Float)
|
||||
|
||||
/** Runs when an animation when the view is tapped on the lockscreen */
|
||||
fun onFidgetTap(x: Float, y: Float)
|
||||
|
||||
/** Update reactive axes for this clock */
|
||||
fun onFontAxesChanged(style: ClockAxisStyle)
|
||||
}
|
||||
|
||||
data class ClockPositionAnimationArgs(val fromLeft: Int, val direction: Int, val fraction: Float)
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
/**
|
||||
* Exposes the rendering capabilities of this clock to SystemUI so that it can be hosted and render
|
||||
* correctly in SystemUI's process. Ideally all clocks could be rendered identically, but in
|
||||
* practice we different clocks require different behavior from SystemUI.
|
||||
*/
|
||||
data class ClockConfig(
|
||||
val id: ClockId,
|
||||
|
||||
/** Localized name of the clock */
|
||||
val name: String,
|
||||
|
||||
/** Localized accessibility description for the clock */
|
||||
val description: String,
|
||||
|
||||
/** Transition to AOD should move smartspace like large clock instead of small clock */
|
||||
val useAlternateSmartspaceAODTransition: Boolean = false,
|
||||
|
||||
/** True if the clock is large frame clock, which will use weather in compose. */
|
||||
val useCustomClockScene: Boolean = false,
|
||||
)
|
||||
|
||||
/** Render configuration options for a specific clock face. */
|
||||
data class ClockFaceConfig(
|
||||
/** Expected interval between calls to onTimeTick. Can always reduce to PER_MINUTE in AOD. */
|
||||
val tickRate: ClockTickRate = ClockTickRate.PER_MINUTE,
|
||||
|
||||
/** Call to check whether the clock consumes weather data */
|
||||
val hasCustomWeatherDataDisplay: Boolean = false,
|
||||
|
||||
/**
|
||||
* Whether this clock has a custom position update animation. If true, the keyguard will call
|
||||
* `onPositionAnimated` to notify the clock of a position update animation. If false, a default
|
||||
* animation will be used (e.g. a simple translation).
|
||||
*/
|
||||
val hasCustomPositionUpdatedAnimation: Boolean = false,
|
||||
|
||||
/** True if the clock is large frame clock, which will use weatherBlueprint in compose. */
|
||||
val useCustomClockScene: Boolean = false,
|
||||
)
|
||||
|
||||
/** Tick rates for clocks */
|
||||
enum class ClockTickRate(val value: Int) {
|
||||
PER_MINUTE(2), // Update the clock once per minute.
|
||||
PER_SECOND(1), // Update the clock once per second.
|
||||
PER_FRAME(0), // Update the clock every second.
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.plugins.annotations.SimpleProperty
|
||||
import java.io.PrintWriter
|
||||
|
||||
/** Interface for controlling an active clock */
|
||||
@ProtectedInterface
|
||||
interface ClockController {
|
||||
@get:SimpleProperty
|
||||
/** A small version of the clock, appropriate for smaller viewports */
|
||||
val smallClock: ClockFaceController
|
||||
|
||||
@get:SimpleProperty
|
||||
/** A large version of the clock, appropriate when a bigger viewport is available */
|
||||
val largeClock: ClockFaceController
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Determines the way the hosting app should behave when rendering either clock face */
|
||||
val config: ClockConfig
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Events that this clock may need to respond to */
|
||||
val events: ClockEvents
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Listener group that will receive events from the clock */
|
||||
val eventListeners: ClockEventListeners
|
||||
|
||||
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
|
||||
fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float)
|
||||
|
||||
/** Optional method for dumping debug information */
|
||||
fun dump(pw: PrintWriter)
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.util.TimeZone
|
||||
import android.text.format.DateFormat
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.plugins.annotations.ProtectedReturn
|
||||
import java.util.Locale
|
||||
|
||||
/** Denotes format kind that should be used when rendering the clock */
|
||||
enum class TimeFormatKind {
|
||||
HALF_DAY,
|
||||
FULL_DAY;
|
||||
|
||||
companion object {
|
||||
fun getFromContext(context: Context): TimeFormatKind {
|
||||
return lookup(DateFormat.is24HourFormat(context))
|
||||
}
|
||||
|
||||
fun getFromContext(context: Context, userId: Int): TimeFormatKind {
|
||||
return lookup(DateFormat.is24HourFormat(context, userId))
|
||||
}
|
||||
|
||||
fun lookup(is24Hr: Boolean): TimeFormatKind {
|
||||
return if (is24Hr) FULL_DAY else HALF_DAY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Events that should call when various rendering parameters change */
|
||||
@ProtectedInterface
|
||||
interface ClockEvents {
|
||||
@get:ProtectedReturn("return false;")
|
||||
/** Set to enable or disable swipe interaction */
|
||||
var isReactiveTouchInteractionEnabled: Boolean // TODO(b/364664388): Remove/Rename
|
||||
|
||||
/** Call whenever timezone changes */
|
||||
fun onTimeZoneChanged(timeZone: TimeZone)
|
||||
|
||||
/** Call whenever the text time format kind changes */
|
||||
fun onTimeFormatChanged(formatKind: TimeFormatKind)
|
||||
|
||||
/** Call whenever the locale changes */
|
||||
fun onLocaleChanged(locale: Locale)
|
||||
|
||||
/** Call whenever the weather data should update */
|
||||
fun onWeatherDataChanged(data: WeatherData)
|
||||
|
||||
/** Call with alarm information */
|
||||
fun onAlarmDataChanged(data: AlarmData)
|
||||
|
||||
/** Call with zen/dnd information */
|
||||
fun onZenDataChanged(data: ZenData)
|
||||
}
|
||||
|
||||
class ClockEventListeners {
|
||||
private val listeners = mutableListOf<ClockEventListener>()
|
||||
|
||||
fun attach(listener: ClockEventListener) = listeners.add(listener)
|
||||
|
||||
fun detach(listener: ClockEventListener) = listeners.remove(listener)
|
||||
|
||||
fun fire(func: ClockEventListener.() -> Unit) = listeners.forEach { it.func() }
|
||||
}
|
||||
|
||||
interface ClockEventListener {
|
||||
fun onBoundsChanged(bounds: VRectF)
|
||||
|
||||
fun onChangeComplete()
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.view.View
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.plugins.annotations.SimpleProperty
|
||||
|
||||
/** Interface for a specific clock face version rendered by the clock */
|
||||
@ProtectedInterface
|
||||
interface ClockFaceController {
|
||||
@get:SimpleProperty
|
||||
@Deprecated("Prefer use of layout")
|
||||
/** View that renders the clock face */
|
||||
val view: View
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Layout specification for this clock */
|
||||
val layout: ClockFaceLayout
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Determines the way the hosting app should behave when rendering this clock face */
|
||||
val config: ClockFaceConfig
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Current theme information the clock is using */
|
||||
var theme: ThemeConfig
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Events specific to this clock face */
|
||||
val events: ClockFaceEvents
|
||||
|
||||
@get:SimpleProperty
|
||||
/** Triggers for various animations */
|
||||
val animations: ClockAnimations
|
||||
|
||||
companion object {
|
||||
fun ClockFaceController.updateTheme(mutateTheme: (ThemeConfig) -> ThemeConfig) {
|
||||
val theme = mutateTheme(this.theme)
|
||||
|
||||
// Themes with null seeds are always considered to have changed since we don't know
|
||||
// at this point if the context's color theme has been updated externally.
|
||||
// TODO(b/364680879): Capture context's color and compare when applicable.
|
||||
val hasChanged = this.theme != theme || theme.seedColor == null
|
||||
if (!hasChanged) return
|
||||
|
||||
events.onThemeChanged(theme)
|
||||
this.theme = theme
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import com.android.systemui.monet.ColorScheme
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.shared.Flags.ambientAod
|
||||
|
||||
/** Events that have specific data about the related face */
|
||||
@ProtectedInterface
|
||||
interface ClockFaceEvents {
|
||||
/** Call every tick to update the rendered time */
|
||||
fun onTimeTick()
|
||||
|
||||
/**
|
||||
* Call whenever the theme or seedColor is updated
|
||||
*
|
||||
* Theme can be specific to the clock face.
|
||||
* - isDarkTheme -> clock should be light
|
||||
* - !isDarkTheme -> clock should be dark
|
||||
*/
|
||||
fun onThemeChanged(theme: ThemeConfig)
|
||||
|
||||
/**
|
||||
* Call whenever font settings change. Pass in a target font size in pixels. The specific clock
|
||||
* design is allowed to ignore this target size on a case-by-case basis.
|
||||
*/
|
||||
fun onFontSettingChanged(fontSizePx: Float)
|
||||
|
||||
/**
|
||||
* Target region information for the clock face. For small clock, this will match the bounds of
|
||||
* the parent view mostly, but have a target height based on the height of the default clock.
|
||||
* For large clocks, the parent view is the entire device size, but most clocks will want to
|
||||
* render within the centered targetRect to avoid obstructing other elements. The specified
|
||||
* targetRegion is relative to the parent view.
|
||||
*/
|
||||
@Deprecated("No longer necessary, pending removal")
|
||||
fun onTargetRegionChanged(targetRegion: Rect?)
|
||||
|
||||
/** Called to notify the clock about its display. */
|
||||
fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean)
|
||||
}
|
||||
|
||||
/** Contains Theming information for the clock face */
|
||||
data class ThemeConfig(
|
||||
/** True if the clock should use dark theme (light text on dark background) */
|
||||
val isDarkTheme: Boolean,
|
||||
|
||||
/**
|
||||
* A clock specific seed color to use when theming, if any was specified by the user. A null
|
||||
* value denotes that we should use the seed color for the current system theme.
|
||||
*/
|
||||
val seedColor: Int?,
|
||||
) {
|
||||
fun getDefaultColor(context: Context): Int {
|
||||
return when {
|
||||
seedColor != null -> seedColor!!
|
||||
isDarkTheme -> context.resources.getColor(android.R.color.system_accent1_100)
|
||||
else -> context.resources.getColor(android.R.color.system_accent2_600)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAodColor(context: Context): Int {
|
||||
return if (!ambientAod()) {
|
||||
Color.WHITE
|
||||
} else {
|
||||
seedColor?.let {
|
||||
val colorScheme =
|
||||
ColorScheme(
|
||||
it,
|
||||
false, // darkTheme is not used for palette generation
|
||||
)
|
||||
colorScheme.accent1.s100
|
||||
} ?: context.resources.getColor(android.R.color.system_accent1_100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import com.android.systemui.plugins.annotations.GeneratedImport
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.plugins.annotations.ProtectedReturn
|
||||
|
||||
/** Specifies layout information for the clock face */
|
||||
@ProtectedInterface
|
||||
@GeneratedImport("java.util.ArrayList")
|
||||
@GeneratedImport("android.view.View")
|
||||
interface ClockFaceLayout {
|
||||
@get:ProtectedReturn("return new ArrayList<View>();")
|
||||
/** All clock views to add to the root constraint layout before applying constraints. */
|
||||
val views: List<View>
|
||||
|
||||
@ProtectedReturn("return constraints;")
|
||||
/** Custom constraints to apply to Lockscreen ConstraintLayout. */
|
||||
fun applyConstraints(constraints: ConstraintSet): ConstraintSet
|
||||
|
||||
@ProtectedReturn("return constraints;")
|
||||
/** Custom constraints to apply to the external display presentation ConstraintLayout. */
|
||||
fun applyExternalDisplayPresentationConstraints(constraints: ConstraintSet): ConstraintSet
|
||||
|
||||
@ProtectedReturn("return constraints;")
|
||||
/** Custom constraints to apply to preview ConstraintLayout. */
|
||||
fun applyPreviewConstraints(
|
||||
clockPreviewConfig: ClockPreviewConfig,
|
||||
constraints: ConstraintSet,
|
||||
): ConstraintSet
|
||||
|
||||
/** Apply specified AOD BurnIn parameters to this layout */
|
||||
fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
|
||||
}
|
||||
|
||||
/** Data class to contain AOD BurnIn information for correct aod rendering */
|
||||
data class AodClockBurnInModel(
|
||||
/** Scale that the clock should render at to mitigate burnin */
|
||||
val scale: Float,
|
||||
|
||||
/** X-Translation for the clock to mitigate burnin */
|
||||
val translationX: Float,
|
||||
|
||||
/** Y-Translation for the clock to mitigate burnin */
|
||||
val translationY: Float,
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import com.android.systemui.log.core.MessageBuffer
|
||||
|
||||
/** MessageBuffers for clocks that want to log information to SystemUI dumps */
|
||||
data class ClockMessageBuffers(
|
||||
/** Message buffer for general infrastructure */
|
||||
val infraMessageBuffer: MessageBuffer,
|
||||
|
||||
/** Message buffer for small clock rendering */
|
||||
val smallClockMessageBuffer: MessageBuffer,
|
||||
|
||||
/** Message buffer for large clock rendering */
|
||||
val largeClockMessageBuffer: MessageBuffer,
|
||||
) {
|
||||
constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
data class ClockPickerConfig
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
val id: String,
|
||||
|
||||
/** Localized name of the clock */
|
||||
val name: String,
|
||||
|
||||
/** Localized accessibility description for the clock */
|
||||
val description: String,
|
||||
|
||||
/* Static & lightweight thumbnail version of the clock */
|
||||
val thumbnail: Drawable,
|
||||
|
||||
/** True if the clock will react to tone changes in the seed color */
|
||||
val isReactiveToTone: Boolean = true,
|
||||
|
||||
/** Font axes that can be modified on this clock */
|
||||
val axes: List<ClockFontAxis> = listOf(),
|
||||
|
||||
/** Presets for this clock. Null indicates the preset list should be disabled. */
|
||||
val presetConfig: AxisPresetConfig? = null,
|
||||
)
|
||||
|
||||
data class AxisPresetConfig(
|
||||
/** Groups of Presets. Each group can be used together in a single control. */
|
||||
val groups: List<Group>,
|
||||
|
||||
/** Preset item currently being used, null when the current style is not a preset */
|
||||
val current: IndexedStyle? = null,
|
||||
) {
|
||||
/** The selected clock axis style, and its indices */
|
||||
data class IndexedStyle(
|
||||
/** Index of the group that this clock axis style appears in */
|
||||
val groupIndex: Int,
|
||||
|
||||
/** Index of the preset within the group */
|
||||
val presetIndex: Int,
|
||||
|
||||
/** Reference to the style in question */
|
||||
val style: ClockAxisStyle,
|
||||
)
|
||||
|
||||
/** A group of preset styles */
|
||||
data class Group(
|
||||
/* List of preset styles in this group */
|
||||
val presets: List<ClockAxisStyle>,
|
||||
|
||||
/* Icon to use when this preset-group is active */
|
||||
val icon: Drawable,
|
||||
)
|
||||
|
||||
fun findStyle(style: ClockAxisStyle): IndexedStyle? {
|
||||
groups.forEachIndexed { groupIndex, group ->
|
||||
group.presets.forEachIndexed { presetIndex, preset ->
|
||||
if (preset == style) {
|
||||
return@findStyle IndexedStyle(
|
||||
groupIndex = groupIndex,
|
||||
presetIndex = presetIndex,
|
||||
style = preset,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents an Axis that can be modified */
|
||||
data class ClockFontAxis(
|
||||
/** Axis key, not user renderable */
|
||||
val key: String,
|
||||
|
||||
/** Intended mode of user interaction */
|
||||
val type: AxisType,
|
||||
|
||||
/** Maximum value the axis supports */
|
||||
val maxValue: Float,
|
||||
|
||||
/** Minimum value the axis supports */
|
||||
val minValue: Float,
|
||||
|
||||
/** Current value the axis is set to */
|
||||
val currentValue: Float,
|
||||
|
||||
/** User-renderable name of the axis */
|
||||
val name: String,
|
||||
|
||||
/** Description of the axis */
|
||||
val description: String,
|
||||
) {
|
||||
companion object {
|
||||
fun List<ClockFontAxis>.merge(axisStyle: ClockAxisStyle): List<ClockFontAxis> {
|
||||
return this.map { axis ->
|
||||
axisStyle.get(axis.key)?.let { axis.copy(currentValue = it) } ?: axis
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Axis user interaction modes */
|
||||
enum class AxisType {
|
||||
/** Continuous range between minValue & maxValue. */
|
||||
Float,
|
||||
|
||||
/** Only minValue & maxValue are valid. No intermediate values between them are allowed. */
|
||||
Boolean,
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
data class ClockPreviewConfig(
|
||||
val isShadeLayoutWide: Boolean,
|
||||
val isSceneContainerFlagEnabled: Boolean,
|
||||
val statusBarHeight: Int,
|
||||
val splitShadeTopMargin: Int,
|
||||
val clockTopMargin: Int,
|
||||
val statusViewMarginHorizontal: Int,
|
||||
val lockViewId: Int? = null,
|
||||
val udfpsTop: Float? = null,
|
||||
) {
|
||||
fun getSmallClockTopPadding(statusBarHeight: Int = this.statusBarHeight): Int {
|
||||
return if (isShadeLayoutWide) {
|
||||
splitShadeTopMargin - if (isSceneContainerFlagEnabled) statusBarHeight else 0
|
||||
} else {
|
||||
clockTopMargin + if (!isSceneContainerFlagEnabled) statusBarHeight else 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.content.Context
|
||||
import com.android.systemui.plugins.Plugin
|
||||
import com.android.systemui.plugins.annotations.GeneratedImport
|
||||
import com.android.systemui.plugins.annotations.ProtectedInterface
|
||||
import com.android.systemui.plugins.annotations.ProtectedReturn
|
||||
import com.android.systemui.plugins.annotations.ProvidesInterface
|
||||
|
||||
/** A Plugin which exposes the ClockProvider interface */
|
||||
@ProtectedInterface
|
||||
@ProvidesInterface(action = ClockProviderPlugin.ACTION, version = ClockProviderPlugin.VERSION)
|
||||
interface ClockProviderPlugin : Plugin, ClockProvider {
|
||||
companion object {
|
||||
const val ACTION = "com.android.systemui.action.PLUGIN_CLOCK_PROVIDER"
|
||||
const val VERSION = 1
|
||||
}
|
||||
}
|
||||
|
||||
/** Interface for building clocks and providing information about those clocks */
|
||||
@ProtectedInterface
|
||||
@GeneratedImport("java.util.List")
|
||||
@GeneratedImport("java.util.ArrayList")
|
||||
interface ClockProvider {
|
||||
/** Initializes the clock provider with debug log buffers */
|
||||
fun initialize(buffers: ClockMessageBuffers?)
|
||||
|
||||
@ProtectedReturn("return new ArrayList<ClockMetadata>();")
|
||||
/** Returns metadata for all clocks this provider knows about */
|
||||
fun getClocks(): List<ClockMetadata>
|
||||
|
||||
@ProtectedReturn("return null;")
|
||||
/** Initializes and returns the target clock design */
|
||||
fun createClock(ctx: Context, settings: ClockSettings): ClockController?
|
||||
|
||||
@ProtectedReturn("return new ClockPickerConfig(\"\", \"\", \"\", null);")
|
||||
/** Settings configuration parameters for the clock */
|
||||
fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig
|
||||
}
|
||||
|
||||
/** Identifies a clock design */
|
||||
typealias ClockId = String
|
||||
|
||||
/** Some metadata about a clock design */
|
||||
data class ClockMetadata(
|
||||
/** Id for the clock design. */
|
||||
val clockId: ClockId,
|
||||
|
||||
/**
|
||||
* true if this clock is deprecated and should not be used. The ID may still show up in certain
|
||||
* locations to help migrations, but it will not be selectable by new users.
|
||||
*/
|
||||
val isDeprecated: Boolean = false,
|
||||
|
||||
/**
|
||||
* Optional mapping of a legacy clock to a new id. This will map users that already are using
|
||||
* `clockId` to the `replacementTarget` instead. The provider should still support the old id
|
||||
* w/o crashing, but can consider it deprecated and the id reserved.
|
||||
*/
|
||||
val replacementTarget: ClockId? = null,
|
||||
)
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
/** Structure for keeping clock-specific settings */
|
||||
data class ClockSettings(
|
||||
val clockId: ClockId? = null,
|
||||
val seedColor: Int? = null,
|
||||
val axes: ClockAxisStyle = ClockAxisStyle(),
|
||||
) {
|
||||
// Exclude metadata from equality checks
|
||||
var metadata: JSONObject = JSONObject()
|
||||
|
||||
companion object {
|
||||
private val KEY_CLOCK_ID = "clockId"
|
||||
private val KEY_SEED_COLOR = "seedColor"
|
||||
private val KEY_METADATA = "metadata"
|
||||
private val KEY_AXIS_LIST = "axes"
|
||||
|
||||
fun toJson(setting: ClockSettings): JSONObject {
|
||||
return JSONObject().apply {
|
||||
put(KEY_CLOCK_ID, setting.clockId)
|
||||
put(KEY_SEED_COLOR, setting.seedColor)
|
||||
put(KEY_METADATA, setting.metadata)
|
||||
put(KEY_AXIS_LIST, ClockAxisStyle.toJson(setting.axes))
|
||||
}
|
||||
}
|
||||
|
||||
fun fromJson(json: JSONObject): ClockSettings {
|
||||
val clockId = if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null
|
||||
val seedColor = if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
|
||||
val axisList = json.optJSONArray(KEY_AXIS_LIST)?.let(ClockAxisStyle::fromJson)
|
||||
return ClockSettings(clockId, seedColor, axisList ?: ClockAxisStyle()).apply {
|
||||
metadata = json.optJSONObject(KEY_METADATA) ?: JSONObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ClockAxisStyle {
|
||||
private val settings: MutableMap<String, Float>
|
||||
|
||||
// Iterable would be implemented on ClockAxisStyle directly,
|
||||
// but that doesn't appear to work with plugins/dynamic libs.
|
||||
val items: Iterable<Map.Entry<String, Float>>
|
||||
get() = settings.asIterable()
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = settings.isEmpty()
|
||||
|
||||
constructor(initialize: ClockAxisStyle.() -> Unit = {}) {
|
||||
settings = mutableMapOf()
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
constructor(style: ClockAxisStyle) {
|
||||
settings = style.settings.toMutableMap()
|
||||
}
|
||||
|
||||
constructor(items: Map<String, Float>) {
|
||||
settings = items.toMutableMap()
|
||||
}
|
||||
|
||||
constructor(key: String, value: Float) {
|
||||
settings = mutableMapOf(key to value)
|
||||
}
|
||||
|
||||
constructor(items: List<ClockFontAxis>) {
|
||||
settings = items.associate { it.key to it.currentValue }.toMutableMap()
|
||||
}
|
||||
|
||||
fun copy(initialize: ClockAxisStyle.() -> Unit): ClockAxisStyle {
|
||||
return ClockAxisStyle(this).apply { initialize() }
|
||||
}
|
||||
|
||||
operator fun get(key: String): Float? = settings[key]
|
||||
|
||||
operator fun set(key: String, value: Float) = put(key, value)
|
||||
|
||||
fun put(key: String, value: Float) {
|
||||
settings.put(key, value)
|
||||
}
|
||||
|
||||
fun toFVar(): String {
|
||||
val sb = StringBuilder()
|
||||
for (axis in settings) {
|
||||
if (sb.length > 0) sb.append(", ")
|
||||
sb.append("'${axis.key}' ${axis.value.toInt()}")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun copyWith(replacements: ClockAxisStyle): ClockAxisStyle {
|
||||
val result = ClockAxisStyle(this)
|
||||
for ((key, value) in replacements.settings) {
|
||||
result[key] = value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is ClockAxisStyle) return false
|
||||
return settings == other.settings
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KEY_AXIS_KEY = "key"
|
||||
private val KEY_AXIS_VALUE = "value"
|
||||
|
||||
fun fromJson(jsonArray: JSONArray): ClockAxisStyle {
|
||||
val result = ClockAxisStyle()
|
||||
for (i in 0..jsonArray.length() - 1) {
|
||||
val obj = jsonArray.getJSONObject(i)
|
||||
if (obj == null) continue
|
||||
|
||||
result.put(
|
||||
key = obj.getString(KEY_AXIS_KEY),
|
||||
value = obj.getDouble(KEY_AXIS_VALUE).toFloat(),
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun toJson(style: ClockAxisStyle): JSONArray {
|
||||
return JSONArray().apply {
|
||||
for ((key, value) in style.settings) {
|
||||
put(
|
||||
JSONObject().apply {
|
||||
put(KEY_AXIS_KEY, key)
|
||||
put(KEY_AXIS_VALUE, value)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Defines several view ids which are useful for sharing views between the host process and the
|
||||
* client. Normally these would be defined in ids.xml, but android_library is incapable of being
|
||||
* dynamically referenced by the plugin apks. This approach means the identifiers are no longer
|
||||
* compile-time constants, but is preferable as it eliminates our need to look them up them by name.
|
||||
*/
|
||||
object ClockViewIds {
|
||||
val LOCKSCREEN_CLOCK_VIEW_LARGE = View.generateViewId()
|
||||
val LOCKSCREEN_CLOCK_VIEW_SMALL = View.generateViewId()
|
||||
|
||||
// View ids for different digit views
|
||||
val HOUR_DIGIT_PAIR = View.generateViewId()
|
||||
val MINUTE_DIGIT_PAIR = View.generateViewId()
|
||||
val HOUR_FIRST_DIGIT = View.generateViewId()
|
||||
val HOUR_SECOND_DIGIT = View.generateViewId()
|
||||
val MINUTE_FIRST_DIGIT = View.generateViewId()
|
||||
val MINUTE_SECOND_DIGIT = View.generateViewId()
|
||||
val TIME_FULL_FORMAT = View.generateViewId()
|
||||
val DATE_FORMAT = View.generateViewId()
|
||||
|
||||
// View ids for elements in large weather clock
|
||||
// TODO(b/364680879): Move these to the weather clock apk w/ WeatherClockSection
|
||||
val WEATHER_CLOCK_TIME = View.generateViewId()
|
||||
val WEATHER_CLOCK_DATE = View.generateViewId()
|
||||
val WEATHER_CLOCK_ICON = View.generateViewId()
|
||||
val WEATHER_CLOCK_TEMP = View.generateViewId()
|
||||
val WEATHER_CLOCK_ALARM_DND = View.generateViewId()
|
||||
val WEATHER_CLOCK_DATE_BARRIER_BOTTOM = View.generateViewId()
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private val X_MASK: ULong = 0xFFFFFFFF00000000U
|
||||
private val Y_MASK: ULong = 0x00000000FFFFFFFFU
|
||||
|
||||
private fun unpackX(data: ULong): Int = ((data and X_MASK) shr 32).toInt()
|
||||
|
||||
private fun unpackY(data: ULong): Int = ((data and Y_MASK) shr 0).toInt()
|
||||
|
||||
private fun pack(x: Int, y: Int): ULong {
|
||||
return ((x.toULong() shl 32) and X_MASK) or ((y.toULong() shl 0) and Y_MASK)
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class VPointF(val data: ULong) {
|
||||
val x: Float
|
||||
get() = Float.fromBits(unpackX(data))
|
||||
|
||||
val y: Float
|
||||
get() = Float.fromBits(unpackY(data))
|
||||
|
||||
constructor(pt: PointF) : this(pt.x, pt.y)
|
||||
|
||||
constructor(x: Int, y: Int) : this(x.toFloat(), y.toFloat())
|
||||
|
||||
constructor(x: Int, y: Float) : this(x.toFloat(), y)
|
||||
|
||||
constructor(x: Float, y: Int) : this(x, y.toFloat())
|
||||
|
||||
constructor(x: Float, y: Float) : this(pack(x.toBits(), y.toBits()))
|
||||
|
||||
fun toPointF() = PointF(x, y)
|
||||
|
||||
fun toLong(): Long = data.toLong()
|
||||
|
||||
fun lengthSq(): Float = x * x + y * y
|
||||
|
||||
fun length(): Float = sqrt(lengthSq())
|
||||
|
||||
fun abs() = VPointF(abs(x), abs(y))
|
||||
|
||||
fun dot(pt: VPointF): Float = x * pt.x + y * pt.y
|
||||
|
||||
fun normalize(): VPointF {
|
||||
val length = this.length()
|
||||
return VPointF(x / length, y / length)
|
||||
}
|
||||
|
||||
operator fun component1(): Float = x
|
||||
|
||||
operator fun component2(): Float = y
|
||||
|
||||
override fun toString() = "($x, $y)"
|
||||
|
||||
operator fun plus(pt: VPoint) = VPointF(x + pt.x, y + pt.y)
|
||||
|
||||
operator fun plus(pt: VPointF) = VPointF(x + pt.x, y + pt.y)
|
||||
|
||||
operator fun plus(value: Int) = VPointF(x + value, y + value)
|
||||
|
||||
operator fun plus(value: Float) = VPointF(x + value, y + value)
|
||||
|
||||
operator fun minus(pt: VPoint) = VPointF(x - pt.x, y - pt.y)
|
||||
|
||||
operator fun minus(pt: VPointF) = VPointF(x - pt.x, y - pt.y)
|
||||
|
||||
operator fun minus(value: Int) = VPointF(x - value, y - value)
|
||||
|
||||
operator fun minus(value: Float) = VPointF(x - value, y - value)
|
||||
|
||||
operator fun times(pt: VPoint) = VPointF(x * pt.x, y * pt.y)
|
||||
|
||||
operator fun times(pt: VPointF) = VPointF(x * pt.x, y * pt.y)
|
||||
|
||||
operator fun times(value: Int) = VPointF(x * value, y * value)
|
||||
|
||||
operator fun times(value: Float) = VPointF(x * value, y * value)
|
||||
|
||||
operator fun div(pt: VPoint) = VPointF(x / pt.x, y / pt.y)
|
||||
|
||||
operator fun div(pt: VPointF) = VPointF(x / pt.x, y / pt.y)
|
||||
|
||||
operator fun div(value: Int) = VPointF(x / value, y / value)
|
||||
|
||||
operator fun div(value: Float) = VPointF(x / value, y / value)
|
||||
|
||||
companion object {
|
||||
val ZERO = VPointF(0, 0)
|
||||
|
||||
fun fromLong(data: Long) = VPointF(data.toULong())
|
||||
|
||||
fun max(lhs: VPointF, rhs: VPointF) = VPointF(max(lhs.x, rhs.x), max(lhs.y, rhs.y))
|
||||
|
||||
fun min(lhs: VPointF, rhs: VPointF) = VPointF(min(lhs.x, rhs.x), min(lhs.y, rhs.y))
|
||||
|
||||
operator fun Float.plus(value: VPointF) = VPointF(this + value.x, this + value.y)
|
||||
|
||||
operator fun Int.minus(value: VPointF) = VPointF(this - value.x, this - value.y)
|
||||
|
||||
operator fun Float.minus(value: VPointF) = VPointF(this - value.x, this - value.y)
|
||||
|
||||
operator fun Int.times(value: VPointF) = VPointF(this * value.x, this * value.y)
|
||||
|
||||
operator fun Float.times(value: VPointF) = VPointF(this * value.x, this * value.y)
|
||||
|
||||
operator fun Int.div(value: VPointF) = VPointF(this / value.x, this / value.y)
|
||||
|
||||
operator fun Float.div(value: VPointF) = VPointF(this / value.x, this / value.y)
|
||||
|
||||
val RectF.center: VPointF
|
||||
get() = VPointF(centerX(), centerY())
|
||||
|
||||
val RectF.size: VPointF
|
||||
get() = VPointF(width(), height())
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class VPoint(val data: ULong) {
|
||||
val x: Int
|
||||
get() = unpackX(data)
|
||||
|
||||
val y: Int
|
||||
get() = unpackY(data)
|
||||
|
||||
constructor(x: Int, y: Int) : this(pack(x, y))
|
||||
|
||||
fun toPoint() = Point(x, y)
|
||||
|
||||
fun toLong(): Long = data.toLong()
|
||||
|
||||
fun abs() = VPoint(abs(x), abs(y))
|
||||
|
||||
operator fun component1(): Int = x
|
||||
|
||||
operator fun component2(): Int = y
|
||||
|
||||
override fun toString() = "($x, $y)"
|
||||
|
||||
operator fun plus(pt: VPoint) = VPoint(x + pt.x, y + pt.y)
|
||||
|
||||
operator fun plus(pt: VPointF) = VPointF(x + pt.x, y + pt.y)
|
||||
|
||||
operator fun plus(value: Int) = VPoint(x + value, y + value)
|
||||
|
||||
operator fun plus(value: Float) = VPointF(x + value, y + value)
|
||||
|
||||
operator fun minus(pt: VPoint) = VPoint(x - pt.x, y - pt.y)
|
||||
|
||||
operator fun minus(pt: VPointF) = VPointF(x - pt.x, y - pt.y)
|
||||
|
||||
operator fun minus(value: Int) = VPoint(x - value, y - value)
|
||||
|
||||
operator fun minus(value: Float) = VPointF(x - value, y - value)
|
||||
|
||||
operator fun times(pt: VPoint) = VPoint(x * pt.x, y * pt.y)
|
||||
|
||||
operator fun times(pt: VPointF) = VPointF(x * pt.x, y * pt.y)
|
||||
|
||||
operator fun times(value: Int) = VPoint(x * value, y * value)
|
||||
|
||||
operator fun times(value: Float) = VPointF(x * value, y * value)
|
||||
|
||||
operator fun div(pt: VPoint) = VPoint(x / pt.x, y / pt.y)
|
||||
|
||||
operator fun div(pt: VPointF) = VPointF(x / pt.x, y / pt.y)
|
||||
|
||||
operator fun div(value: Int) = VPoint(x / value, y / value)
|
||||
|
||||
operator fun div(value: Float) = VPointF(x / value, y / value)
|
||||
|
||||
companion object {
|
||||
val ZERO = VPoint(0, 0)
|
||||
|
||||
fun fromLong(data: Long) = VPoint(data.toULong())
|
||||
|
||||
fun max(lhs: VPoint, rhs: VPoint) = VPoint(max(lhs.x, rhs.x), max(lhs.y, rhs.y))
|
||||
|
||||
fun min(lhs: VPoint, rhs: VPoint) = VPoint(min(lhs.x, rhs.x), min(lhs.y, rhs.y))
|
||||
|
||||
operator fun Int.plus(value: VPoint) = VPoint(this + value.x, this + value.y)
|
||||
|
||||
operator fun Float.plus(value: VPoint) = VPointF(this + value.x, this + value.y)
|
||||
|
||||
operator fun Int.minus(value: VPoint) = VPoint(this - value.x, this - value.y)
|
||||
|
||||
operator fun Float.minus(value: VPoint) = VPointF(this - value.x, this - value.y)
|
||||
|
||||
operator fun Int.times(value: VPoint) = VPoint(this * value.x, this * value.y)
|
||||
|
||||
operator fun Float.times(value: VPoint) = VPointF(this * value.x, this * value.y)
|
||||
|
||||
operator fun Int.div(value: VPoint) = VPoint(this / value.x, this / value.y)
|
||||
|
||||
operator fun Float.div(value: VPoint) = VPointF(this / value.x, this / value.y)
|
||||
|
||||
val Rect.center: VPoint
|
||||
get() = VPoint(centerX(), centerY())
|
||||
|
||||
val Rect.size: VPoint
|
||||
get() = VPoint(width(), height())
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.util.Half
|
||||
|
||||
private val LEFT_MASK: ULong = 0xFFFF000000000000U
|
||||
private val TOP_MASK: ULong = 0x0000FFFF00000000U
|
||||
private val RIGHT_MASK: ULong = 0x00000000FFFF0000U
|
||||
private val BOTTOM_MASK: ULong = 0x000000000000FFFFU
|
||||
|
||||
private fun unpackLeft(data: ULong): Short = ((data and LEFT_MASK) shr 48).toShort()
|
||||
|
||||
private fun unpackTop(data: ULong): Short = ((data and TOP_MASK) shr 32).toShort()
|
||||
|
||||
private fun unpackRight(data: ULong): Short = ((data and RIGHT_MASK) shr 16).toShort()
|
||||
|
||||
private fun unpackBottom(data: ULong): Short = ((data and BOTTOM_MASK) shr 0).toShort()
|
||||
|
||||
private fun pack(left: Short, top: Short, right: Short, bottom: Short): ULong {
|
||||
return ((left.toULong() shl 48) and LEFT_MASK) or
|
||||
((top.toULong() shl 32) and TOP_MASK) or
|
||||
((right.toULong() shl 16) and RIGHT_MASK) or
|
||||
((bottom.toULong() shl 0) and BOTTOM_MASK)
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class VRectF(val data: ULong) {
|
||||
val left: Float
|
||||
get() = fromBits(unpackLeft(data))
|
||||
|
||||
val top: Float
|
||||
get() = fromBits(unpackTop(data))
|
||||
|
||||
val right: Float
|
||||
get() = fromBits(unpackRight(data))
|
||||
|
||||
val bottom: Float
|
||||
get() = fromBits(unpackBottom(data))
|
||||
|
||||
val width: Float
|
||||
get() = right - left
|
||||
|
||||
val height: Float
|
||||
get() = bottom - top
|
||||
|
||||
constructor(rect: RectF) : this(rect.left, rect.top, rect.right, rect.bottom)
|
||||
|
||||
constructor(
|
||||
rect: Rect
|
||||
) : this(
|
||||
left = rect.left.toFloat(),
|
||||
top = rect.top.toFloat(),
|
||||
right = rect.right.toFloat(),
|
||||
bottom = rect.bottom.toFloat(),
|
||||
)
|
||||
|
||||
constructor(
|
||||
left: Float,
|
||||
top: Float,
|
||||
right: Float,
|
||||
bottom: Float,
|
||||
) : this(pack(toBits(left), toBits(top), toBits(right), toBits(bottom)))
|
||||
|
||||
val center: VPointF
|
||||
get() = VPointF(left, top) + size / 2f
|
||||
|
||||
val size: VPointF
|
||||
get() = VPointF(width, height)
|
||||
|
||||
fun toRectF(): RectF = RectF(left, top, right, bottom)
|
||||
|
||||
fun toLong(): Long = data.toLong()
|
||||
|
||||
override fun toString() = "($left, $top) -> ($right, $bottom)"
|
||||
|
||||
companion object {
|
||||
private fun toBits(value: Float): Short = Half.halfToShortBits(Half.toHalf(value))
|
||||
|
||||
private fun fromBits(value: Short): Float = Half.toFloat(Half.intBitsToHalf(value.toInt()))
|
||||
|
||||
fun fromLong(data: Long) = VRectF(data.toULong())
|
||||
|
||||
fun fromCenter(center: VPointF, size: VPointF): VRectF {
|
||||
return VRectF(
|
||||
center.x - size.x / 2,
|
||||
center.y - size.y / 2,
|
||||
center.x + size.x / 2,
|
||||
center.y + size.y / 2,
|
||||
)
|
||||
}
|
||||
|
||||
fun fromTopLeft(pos: VPointF, size: VPointF): VRectF {
|
||||
return VRectF(pos.x, pos.y, pos.x + size.x, pos.y + size.y)
|
||||
}
|
||||
|
||||
val ZERO = VRectF(0f, 0f, 0f, 0f)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class VRect(val data: ULong) {
|
||||
val left: Int
|
||||
get() = unpackLeft(data).toInt()
|
||||
|
||||
val top: Int
|
||||
get() = unpackTop(data).toInt()
|
||||
|
||||
val right: Int
|
||||
get() = unpackRight(data).toInt()
|
||||
|
||||
val bottom: Int
|
||||
get() = unpackBottom(data).toInt()
|
||||
|
||||
val width: Int
|
||||
get() = right - left
|
||||
|
||||
val height: Int
|
||||
get() = bottom - top
|
||||
|
||||
constructor(
|
||||
rect: Rect
|
||||
) : this(
|
||||
left = rect.left.toShort(),
|
||||
top = rect.top.toShort(),
|
||||
right = rect.right.toShort(),
|
||||
bottom = rect.bottom.toShort(),
|
||||
)
|
||||
|
||||
constructor(
|
||||
left: Int,
|
||||
top: Int,
|
||||
right: Int,
|
||||
bottom: Int,
|
||||
) : this(
|
||||
left = left.toShort(),
|
||||
top = top.toShort(),
|
||||
right = right.toShort(),
|
||||
bottom = bottom.toShort(),
|
||||
)
|
||||
|
||||
constructor(
|
||||
left: Short,
|
||||
top: Short,
|
||||
right: Short,
|
||||
bottom: Short,
|
||||
) : this(pack(left, top, right, bottom))
|
||||
|
||||
val center: VPoint
|
||||
get() = VPoint(left, top) + size / 2
|
||||
|
||||
val size: VPoint
|
||||
get() = VPoint(width, height)
|
||||
|
||||
fun toRect(): Rect = Rect(left, top, right, bottom)
|
||||
|
||||
fun toLong(): Long = data.toLong()
|
||||
|
||||
override fun toString() = "($left, $top) -> ($right, $bottom)"
|
||||
|
||||
companion object {
|
||||
val ZERO = VRect(0, 0, 0, 0)
|
||||
|
||||
fun fromLong(data: Long) = VRect(data.toULong())
|
||||
|
||||
fun fromCenter(center: VPoint, size: VPoint): VRect {
|
||||
return VRect(
|
||||
(center.x - size.x / 2).toShort(),
|
||||
(center.y - size.y / 2).toShort(),
|
||||
(center.x + size.x / 2).toShort(),
|
||||
(center.y + size.y / 2).toShort(),
|
||||
)
|
||||
}
|
||||
|
||||
fun fromTopLeft(pos: VPoint, size: VPoint): VRect {
|
||||
return VRect(
|
||||
pos.x.toShort(),
|
||||
pos.y.toShort(),
|
||||
(pos.x + size.x).toShort(),
|
||||
(pos.y + size.y).toShort(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.text.util.LocalePreferences
|
||||
|
||||
typealias WeatherTouchAction = (View) -> Unit
|
||||
|
||||
data class WeatherData(
|
||||
val description: String,
|
||||
val state: WeatherStateIcon,
|
||||
val useCelsius: Boolean,
|
||||
val temperature: Int,
|
||||
val touchAction: WeatherTouchAction? = null,
|
||||
) {
|
||||
companion object {
|
||||
const val DEBUG = true
|
||||
private const val TAG = "WeatherData"
|
||||
@VisibleForTesting const val DESCRIPTION_KEY = "description"
|
||||
@VisibleForTesting const val STATE_KEY = "state"
|
||||
@VisibleForTesting const val USE_CELSIUS_KEY = "use_celsius"
|
||||
@VisibleForTesting const val TEMPERATURE_KEY = "temperature"
|
||||
private const val INVALID_WEATHER_ICON_STATE = -1
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun fromBundle(extras: Bundle, touchAction: WeatherTouchAction? = null): WeatherData? {
|
||||
val description = extras.getString(DESCRIPTION_KEY)
|
||||
val state =
|
||||
WeatherStateIcon.fromInt(extras.getInt(STATE_KEY, INVALID_WEATHER_ICON_STATE))
|
||||
val temperature = readIntFromBundle(extras, TEMPERATURE_KEY)
|
||||
if (
|
||||
description == null ||
|
||||
state == null ||
|
||||
!extras.containsKey(USE_CELSIUS_KEY) ||
|
||||
temperature == null
|
||||
) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, "Weather data did not parse from $extras")
|
||||
}
|
||||
return null
|
||||
} else {
|
||||
val result =
|
||||
WeatherData(
|
||||
description = description,
|
||||
state = state,
|
||||
useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
|
||||
temperature = temperature,
|
||||
touchAction = touchAction,
|
||||
)
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "Weather data parsed $result from $extras")
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun readIntFromBundle(extras: Bundle, key: String): Int? {
|
||||
try {
|
||||
return extras.getString(key)?.toInt()
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlaceholderWeatherData(): WeatherData {
|
||||
return getPlaceholderWeatherData(
|
||||
LocalePreferences.getTemperatureUnit() == LocalePreferences.TemperatureUnit.CELSIUS
|
||||
)
|
||||
}
|
||||
|
||||
private const val DESCRIPTION_PLACEHODLER = ""
|
||||
private const val TEMPERATURE_FAHRENHEIT_PLACEHOLDER = 58
|
||||
private const val TEMPERATURE_CELSIUS_PLACEHOLDER = 21
|
||||
private val WEATHERICON_PLACEHOLDER = WeatherData.WeatherStateIcon.MOSTLY_SUNNY
|
||||
|
||||
fun getPlaceholderWeatherData(useCelsius: Boolean): WeatherData {
|
||||
return WeatherData(
|
||||
description = DESCRIPTION_PLACEHODLER,
|
||||
state = WEATHERICON_PLACEHOLDER,
|
||||
temperature =
|
||||
if (useCelsius) TEMPERATURE_CELSIUS_PLACEHOLDER
|
||||
else TEMPERATURE_FAHRENHEIT_PLACEHOLDER,
|
||||
useCelsius = useCelsius,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Values for WeatherStateIcon must stay in sync with go/g3-WeatherStateIcon
|
||||
enum class WeatherStateIcon(val id: Int, val icon: String) {
|
||||
UNKNOWN_ICON(0, ""),
|
||||
|
||||
// Clear, day & night.
|
||||
SUNNY(1, "a"),
|
||||
CLEAR_NIGHT(2, "f"),
|
||||
|
||||
// Mostly clear, day & night.
|
||||
MOSTLY_SUNNY(3, "b"),
|
||||
MOSTLY_CLEAR_NIGHT(4, "n"),
|
||||
|
||||
// Partly cloudy, day & night.
|
||||
PARTLY_CLOUDY(5, "b"),
|
||||
PARTLY_CLOUDY_NIGHT(6, "n"),
|
||||
|
||||
// Mostly cloudy, day & night.
|
||||
MOSTLY_CLOUDY_DAY(7, "e"),
|
||||
MOSTLY_CLOUDY_NIGHT(8, "e"),
|
||||
CLOUDY(9, "e"),
|
||||
HAZE_FOG_DUST_SMOKE(10, "d"),
|
||||
DRIZZLE(11, "c"),
|
||||
HEAVY_RAIN(12, "c"),
|
||||
SHOWERS_RAIN(13, "c"),
|
||||
|
||||
// Scattered showers, day & night.
|
||||
SCATTERED_SHOWERS_DAY(14, "c"),
|
||||
SCATTERED_SHOWERS_NIGHT(15, "c"),
|
||||
|
||||
// Isolated scattered thunderstorms, day & night.
|
||||
ISOLATED_SCATTERED_TSTORMS_DAY(16, "i"),
|
||||
ISOLATED_SCATTERED_TSTORMS_NIGHT(17, "i"),
|
||||
STRONG_TSTORMS(18, "i"),
|
||||
BLIZZARD(19, "j"),
|
||||
BLOWING_SNOW(20, "j"),
|
||||
FLURRIES(21, "h"),
|
||||
HEAVY_SNOW(22, "j"),
|
||||
|
||||
// Scattered snow showers, day & night.
|
||||
SCATTERED_SNOW_SHOWERS_DAY(23, "h"),
|
||||
SCATTERED_SNOW_SHOWERS_NIGHT(24, "h"),
|
||||
SNOW_SHOWERS_SNOW(25, "g"),
|
||||
MIXED_RAIN_HAIL_RAIN_SLEET(26, "h"),
|
||||
SLEET_HAIL(27, "h"),
|
||||
TORNADO(28, "l"),
|
||||
TROPICAL_STORM_HURRICANE(29, "m"),
|
||||
WINDY_BREEZY(30, "k"),
|
||||
WINTRY_MIX_RAIN_SNOW(31, "h");
|
||||
|
||||
companion object {
|
||||
@JvmStatic fun fromInt(value: Int) = entries.firstOrNull { it.id == value }
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val unit = if (useCelsius) "C" else "F"
|
||||
return "$state (\"$description\") $temperature°$unit"
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.android.systemui.plugins.clocks
|
||||
|
||||
import android.provider.Settings.Global.ZEN_MODE_ALARMS
|
||||
import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
|
||||
import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
|
||||
import android.provider.Settings.Global.ZEN_MODE_OFF
|
||||
|
||||
data class ZenData(
|
||||
val zenMode: ZenMode,
|
||||
val descriptionId: String?,
|
||||
) {
|
||||
enum class ZenMode(val zenMode: Int) {
|
||||
OFF(ZEN_MODE_OFF),
|
||||
IMPORTANT_INTERRUPTIONS(ZEN_MODE_IMPORTANT_INTERRUPTIONS),
|
||||
NO_INTERRUPTIONS(ZEN_MODE_NO_INTERRUPTIONS),
|
||||
ALARMS(ZEN_MODE_ALARMS);
|
||||
|
||||
companion object {
|
||||
fun fromInt(zenMode: Int) = values().firstOrNull { it.zenMode == zenMode }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user