From b8eef87bc2beb34b700c4af73a25037c656d1071 Mon Sep 17 00:00:00 2001 From: Hawkwood Glazier Date: Fri, 11 Nov 2022 17:56:14 +0000 Subject: Add Customization Lib Bug: 258424862 Test: Manually rebuilt everything Change-Id: If683023d2f592bb09827a50fbc79559b5b57cb3a --- packages/SystemUI/Android.bp | 2 + packages/SystemUI/customization/Android.bp | 52 ++ .../SystemUI/customization/AndroidManifest.xml | 21 + .../res/drawable/clock_default_thumbnail.xml | 20 + .../res/layout/clock_default_large.xml | 31 + .../res/layout/clock_default_small.xml | 33 ++ .../SystemUI/customization/res/values/attrs.xml | 28 + .../SystemUI/customization/res/values/dimens.xml | 27 + .../customization/res/values/donottranslate.xml | 23 + .../systemui/shared/clocks/AnimatableClockView.kt | 649 +++++++++++++++++++++ .../systemui/shared/clocks/ClockRegistry.kt | 229 ++++++++ .../shared/clocks/DefaultClockController.kt | 272 +++++++++ .../systemui/shared/clocks/DefaultClockProvider.kt | 55 ++ packages/SystemUI/ktfmt_includes.txt | 6 +- .../android/systemui/plugins/PluginManager.java | 58 ++ .../res/drawable/clock_default_thumbnail.xml | 20 - .../shared/res/layout/clock_default_large.xml | 31 - .../shared/res/layout/clock_default_small.xml | 33 -- packages/SystemUI/shared/res/values/attrs.xml | 6 - packages/SystemUI/shared/res/values/dimens.xml | 27 - .../SystemUI/shared/res/values/donottranslate.xml | 23 - .../systemui/shared/clocks/AnimatableClockView.kt | 649 --------------------- .../systemui/shared/clocks/ClockRegistry.kt | 229 -------- .../shared/clocks/DefaultClockController.kt | 272 --------- .../systemui/shared/clocks/DefaultClockProvider.kt | 57 -- .../shared/plugins/PluginActionManager.java | 1 + .../systemui/shared/plugins/PluginManager.java | 60 -- .../systemui/shared/plugins/PluginManagerImpl.java | 1 + .../com/android/keyguard/clock/ClockManager.java | 2 +- .../keyguard/dagger/ClockRegistryModule.java | 11 +- .../src/com/android/systemui/Dependency.java | 2 +- .../android/systemui/PluginInflateContainer.java | 2 +- .../systemui/classifier/FalsingManagerProxy.java | 2 +- .../src/com/android/systemui/doze/DozeService.java | 2 +- .../gestural/EdgeBackGestureHandler.java | 2 +- .../systemui/plugins/PluginDependencyProvider.java | 1 - .../android/systemui/plugins/PluginsModule.java | 1 - .../src/com/android/systemui/qs/QSTileHost.java | 2 +- .../systemui/statusbar/NotificationListener.java | 2 +- .../row/ExpandableNotificationRowController.java | 2 +- .../statusbar/phone/CentralSurfacesImpl.java | 2 +- .../phone/NotificationListenerWithPlugins.java | 2 +- .../statusbar/policy/ExtensionControllerImpl.java | 2 +- .../com/android/systemui/toast/ToastFactory.java | 2 +- .../com/android/systemui/tuner/PluginFragment.java | 2 +- .../systemui/util/sensors/AsyncSensorManager.java | 2 +- .../android/keyguard/clock/ClockManagerTest.java | 2 +- .../com/android/systemui/qs/QSTileHostTest.java | 2 +- .../systemui/qs/external/TileServicesTest.java | 2 +- .../systemui/shared/clocks/ClockRegistryTest.kt | 2 +- .../statusbar/NotificationListenerTest.java | 2 +- .../statusbar/phone/CentralSurfacesImplTest.java | 2 +- .../policy/ExtensionControllerImplTest.java | 2 +- .../com/android/systemui/toast/ToastUITest.java | 2 +- .../util/sensors/AsyncSensorManagerTest.java | 2 +- .../systemui/utils/leaks/FakePluginManager.java | 2 +- .../systemui/utils/leaks/LeakCheckedTest.java | 2 +- 57 files changed, 1538 insertions(+), 1442 deletions(-) create mode 100644 packages/SystemUI/customization/Android.bp create mode 100644 packages/SystemUI/customization/AndroidManifest.xml create mode 100644 packages/SystemUI/customization/res/drawable/clock_default_thumbnail.xml create mode 100644 packages/SystemUI/customization/res/layout/clock_default_large.xml create mode 100644 packages/SystemUI/customization/res/layout/clock_default_small.xml create mode 100644 packages/SystemUI/customization/res/values/attrs.xml create mode 100644 packages/SystemUI/customization/res/values/dimens.xml create mode 100644 packages/SystemUI/customization/res/values/donottranslate.xml create mode 100644 packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt create mode 100644 packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt create mode 100644 packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt create mode 100644 packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt create mode 100644 packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginManager.java delete mode 100644 packages/SystemUI/shared/res/drawable/clock_default_thumbnail.xml delete mode 100644 packages/SystemUI/shared/res/layout/clock_default_large.xml delete mode 100644 packages/SystemUI/shared/res/layout/clock_default_small.xml delete mode 100644 packages/SystemUI/shared/res/values/dimens.xml delete mode 100644 packages/SystemUI/shared/res/values/donottranslate.xml delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 9d7a9e7aac8a..3c6f18c76f83 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -91,6 +91,7 @@ android_library { "SystemUIAnimationLib", "SystemUIPluginLib", "SystemUISharedLib", + "SystemUICustomizationLib", "SystemUI-statsd", "SettingsLib", "androidx.core_core-ktx", @@ -190,6 +191,7 @@ android_library { "SystemUIAnimationLib", "SystemUIPluginLib", "SystemUISharedLib", + "SystemUICustomizationLib", "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", diff --git a/packages/SystemUI/customization/Android.bp b/packages/SystemUI/customization/Android.bp new file mode 100644 index 000000000000..dc450bb71dfe --- /dev/null +++ b/packages/SystemUI/customization/Android.bp @@ -0,0 +1,52 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +android_library { + name: "SystemUICustomizationLib", + srcs: [ + "src/**/*.java", + "src/**/*.kt", + "src/**/*.aidl", + ], + static_libs: [ + "PluginCoreLib", + "SystemUIAnimationLib", + "SystemUIPluginLib", + "SystemUIUnfoldLib", + "androidx.dynamicanimation_dynamicanimation", + "androidx.concurrent_concurrent-futures", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.lifecycle_lifecycle-viewmodel-ktx", + "androidx.recyclerview_recyclerview", + "kotlinx_coroutines_android", + "kotlinx_coroutines", + "dagger2", + "jsr330", + ], + resource_dirs: [ + "res", + ], + min_sdk_version: "current", + plugins: ["dagger2-compiler"], + kotlincflags: ["-Xjvm-default=enable"], +} diff --git a/packages/SystemUI/customization/AndroidManifest.xml b/packages/SystemUI/customization/AndroidManifest.xml new file mode 100644 index 000000000000..3277bff2bf4e --- /dev/null +++ b/packages/SystemUI/customization/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/packages/SystemUI/customization/res/drawable/clock_default_thumbnail.xml b/packages/SystemUI/customization/res/drawable/clock_default_thumbnail.xml new file mode 100644 index 000000000000..be72d0b82dbb --- /dev/null +++ b/packages/SystemUI/customization/res/drawable/clock_default_thumbnail.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/packages/SystemUI/customization/res/layout/clock_default_large.xml b/packages/SystemUI/customization/res/layout/clock_default_large.xml new file mode 100644 index 000000000000..0139d50dcfba --- /dev/null +++ b/packages/SystemUI/customization/res/layout/clock_default_large.xml @@ -0,0 +1,31 @@ + + + diff --git a/packages/SystemUI/customization/res/layout/clock_default_small.xml b/packages/SystemUI/customization/res/layout/clock_default_small.xml new file mode 100644 index 000000000000..ff6d7f9e2240 --- /dev/null +++ b/packages/SystemUI/customization/res/layout/clock_default_small.xml @@ -0,0 +1,33 @@ + + + diff --git a/packages/SystemUI/customization/res/values/attrs.xml b/packages/SystemUI/customization/res/values/attrs.xml new file mode 100644 index 000000000000..f9d66ee583da --- /dev/null +++ b/packages/SystemUI/customization/res/values/attrs.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml new file mode 100644 index 000000000000..8f90f0fefdb5 --- /dev/null +++ b/packages/SystemUI/customization/res/values/dimens.xml @@ -0,0 +1,27 @@ + + + + + 150sp + 86sp + + + .7 + + 1 + \ No newline at end of file diff --git a/packages/SystemUI/customization/res/values/donottranslate.xml b/packages/SystemUI/customization/res/values/donottranslate.xml new file mode 100644 index 000000000000..383d5521f156 --- /dev/null +++ b/packages/SystemUI/customization/res/values/donottranslate.xml @@ -0,0 +1,23 @@ + + + + + + hm + + + Hm + diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt new file mode 100644 index 000000000000..22944b8fba89 --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -0,0 +1,649 @@ +/* + * Copyright (C) 2021 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.shared.clocks + +import android.animation.TimeInterpolator +import android.annotation.ColorInt +import android.annotation.FloatRange +import android.annotation.IntRange +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.Rect +import android.text.Layout +import android.text.TextUtils +import android.text.format.DateFormat +import android.util.AttributeSet +import android.util.MathUtils +import android.widget.TextView +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.animation.GlyphCallback +import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.TextAnimator +import com.android.systemui.customization.R +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.DEBUG +import java.io.PrintWriter +import java.util.Calendar +import java.util.Locale +import java.util.TimeZone +import kotlin.math.max +import kotlin.math.min + +/** + * Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30) + * The time's text color is a gradient that changes its colors based on its controller. + */ +@SuppressLint("AppCompatCustomView") +class AnimatableClockView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextView(context, attrs, defStyleAttr, defStyleRes) { + var tag: String = "UnnamedClockView" + var logBuffer: LogBuffer? = null + + private val time = Calendar.getInstance() + + private val dozingWeightInternal: Int + private val lockScreenWeightInternal: Int + private val isSingleLineInternal: Boolean + + private var format: CharSequence? = null + private var descFormat: CharSequence? = null + + @ColorInt + private var dozingColor = 0 + + @ColorInt + private var lockScreenColor = 0 + + private var lineSpacingScale = 1f + private val chargeAnimationDelay: Int + private var textAnimator: TextAnimator? = null + private var onTextAnimatorInitialized: Runnable? = null + + @VisibleForTesting var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = + { layout, invalidateCb -> TextAnimator(layout, invalidateCb) } + @VisibleForTesting var isAnimationEnabled: Boolean = true + @VisibleForTesting var timeOverrideInMillis: Long? = null + + val dozingWeight: Int + get() = if (useBoldedVersion()) dozingWeightInternal + 100 else dozingWeightInternal + + val lockScreenWeight: Int + get() = if (useBoldedVersion()) lockScreenWeightInternal + 100 else lockScreenWeightInternal + + /** + * The number of pixels below the baseline. For fonts that support languages such as + * Burmese, this space can be significant and should be accounted for when computing layout. + */ + val bottom get() = paint?.fontMetrics?.bottom ?: 0f + + init { + val animatableClockViewAttributes = context.obtainStyledAttributes( + attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes + ) + + try { + dozingWeightInternal = animatableClockViewAttributes.getInt( + R.styleable.AnimatableClockView_dozeWeight, + 100 + ) + lockScreenWeightInternal = animatableClockViewAttributes.getInt( + R.styleable.AnimatableClockView_lockScreenWeight, + 300 + ) + chargeAnimationDelay = animatableClockViewAttributes.getInt( + R.styleable.AnimatableClockView_chargeAnimationDelay, 200 + ) + } finally { + animatableClockViewAttributes.recycle() + } + + val textViewAttributes = context.obtainStyledAttributes( + attrs, android.R.styleable.TextView, + defStyleAttr, defStyleRes + ) + + isSingleLineInternal = + try { + textViewAttributes.getBoolean(android.R.styleable.TextView_singleLine, false) + } finally { + textViewAttributes.recycle() + } + + refreshFormat() + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + logBuffer?.log(tag, DEBUG, "onAttachedToWindow") + refreshFormat() + } + + /** + * Whether to use a bolded version based on the user specified fontWeightAdjustment. + */ + fun useBoldedVersion(): Boolean { + // "Bold text" fontWeightAdjustment is 300. + return resources.configuration.fontWeightAdjustment > 100 + } + + fun refreshTime() { + time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis() + contentDescription = DateFormat.format(descFormat, time) + val formattedText = DateFormat.format(format, time) + logBuffer?.log(tag, DEBUG, + { str1 = formattedText?.toString() }, + { "refreshTime: new formattedText=$str1" } + ) + // Setting text actually triggers a layout pass (because the text view is set to + // wrap_content width and TextView always relayouts for this). Avoid needless + // relayout if the text didn't actually change. + if (!TextUtils.equals(text, formattedText)) { + text = formattedText + logBuffer?.log(tag, DEBUG, + { str1 = formattedText?.toString() }, + { "refreshTime: done setting new time text to: $str1" } + ) + // 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) + logBuffer?.log(tag, DEBUG, "refreshTime: done updating textAnimator layout") + } + requestLayout() + logBuffer?.log(tag, DEBUG, "refreshTime: after requestLayout") + } + } + + fun onTimeZoneChanged(timeZone: TimeZone?) { + time.timeZone = timeZone + refreshFormat() + logBuffer?.log(tag, DEBUG, + { str1 = timeZone?.toString() }, + { "onTimeZoneChanged newTimeZone=$str1" } + ) + } + + @SuppressLint("DrawAllocation") + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val animator = textAnimator + if (animator == null) { + textAnimator = textAnimatorFactory(layout, ::invalidate) + onTextAnimatorInitialized?.run() + onTextAnimatorInitialized = null + } else { + animator.updateLayout(layout) + } + logBuffer?.log(tag, DEBUG, "onMeasure") + } + + override fun onDraw(canvas: Canvas) { + // Use textAnimator to render text if animation is enabled. + // Otherwise default to using standard draw functions. + if (isAnimationEnabled) { + // intentionally doesn't call super.onDraw here or else the text will be rendered twice + textAnimator?.draw(canvas) + } else { + super.onDraw(canvas) + } + logBuffer?.log(tag, DEBUG, "onDraw lastDraw") + } + + override fun invalidate() { + super.invalidate() + logBuffer?.log(tag, DEBUG, "invalidate") + } + + override fun onTextChanged( + text: CharSequence, + start: Int, + lengthBefore: Int, + lengthAfter: Int + ) { + super.onTextChanged(text, start, lengthBefore, lengthAfter) + logBuffer?.log(tag, DEBUG, + { str1 = text.toString() }, + { "onTextChanged text=$str1" } + ) + } + + fun setLineSpacingScale(scale: Float) { + lineSpacingScale = scale + setLineSpacing(0f, lineSpacingScale) + } + + fun setColors(@ColorInt dozingColor: Int, lockScreenColor: Int) { + this.dozingColor = dozingColor + this.lockScreenColor = lockScreenColor + } + + fun animateAppearOnLockscreen() { + logBuffer?.log(tag, DEBUG, "animateAppearOnLockscreen") + setTextStyle( + weight = dozingWeight, + textSize = -1f, + color = lockScreenColor, + animate = false, + duration = 0, + delay = 0, + onAnimationEnd = null + ) + setTextStyle( + weight = lockScreenWeight, + textSize = -1f, + color = lockScreenColor, + animate = isAnimationEnabled, + duration = APPEAR_ANIM_DURATION, + delay = 0, + onAnimationEnd = null + ) + } + + fun animateFoldAppear(animate: Boolean = true) { + if (isAnimationEnabled && textAnimator == null) { + return + } + logBuffer?.log(tag, DEBUG, "animateFoldAppear") + setTextStyle( + weight = lockScreenWeightInternal, + textSize = -1f, + color = lockScreenColor, + animate = false, + duration = 0, + delay = 0, + onAnimationEnd = null + ) + setTextStyle( + weight = dozingWeightInternal, + textSize = -1f, + color = dozingColor, + animate = animate && isAnimationEnabled, + interpolator = Interpolators.EMPHASIZED_DECELERATE, + duration = ANIMATION_DURATION_FOLD_TO_AOD.toLong(), + delay = 0, + onAnimationEnd = null + ) + } + + fun animateCharge(isDozing: () -> Boolean) { + if (textAnimator == null || textAnimator!!.isRunning()) { + // Skip charge animation if dozing animation is already playing. + return + } + logBuffer?.log(tag, DEBUG, "animateCharge") + val startAnimPhase2 = Runnable { + setTextStyle( + weight = if (isDozing()) dozingWeight else lockScreenWeight, + textSize = -1f, + color = null, + animate = isAnimationEnabled, + duration = CHARGE_ANIM_DURATION_PHASE_1, + delay = 0, + onAnimationEnd = null + ) + } + setTextStyle( + weight = if (isDozing()) lockScreenWeight else dozingWeight, + textSize = -1f, + color = null, + animate = isAnimationEnabled, + duration = CHARGE_ANIM_DURATION_PHASE_0, + delay = chargeAnimationDelay.toLong(), + onAnimationEnd = startAnimPhase2 + ) + } + + fun animateDoze(isDozing: Boolean, animate: Boolean) { + logBuffer?.log(tag, DEBUG, "animateDoze") + setTextStyle( + weight = if (isDozing) dozingWeight else lockScreenWeight, + textSize = -1f, + color = if (isDozing) dozingColor else lockScreenColor, + animate = animate && isAnimationEnabled, + duration = DOZE_ANIM_DURATION, + delay = 0, + onAnimationEnd = null + ) + } + + // The offset of each glyph from where it should be. + private var glyphOffsets = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f) + + private var lastSeenAnimationProgress = 1.0f + + // If the animation is being reversed, the target offset for each glyph for the "stop". + private var animationCancelStartPosition = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f) + private var animationCancelStopPosition = 0.0f + + // Whether the currently playing animation needed a stop (and thus, is shortened). + private var currentAnimationNeededStop = false + + private val glyphFilter: GlyphCallback = { positionedGlyph, _ -> + val offset = positionedGlyph.lineNo * DIGITS_PER_LINE + positionedGlyph.glyphIndex + if (offset < glyphOffsets.size) { + positionedGlyph.x += glyphOffsets[offset] + } + } + + /** + * Set text style with an optional animation. + * + * By passing -1 to weight, the view preserves its current weight. + * By passing -1 to textSize, the view preserves its current text size. + * + * @param weight text weight. + * @param textSize font size. + * @param animate true to animate the text style change, otherwise false. + */ + private fun setTextStyle( + @IntRange(from = 0, to = 1000) weight: Int, + @FloatRange(from = 0.0) textSize: Float, + color: Int?, + animate: Boolean, + interpolator: TimeInterpolator?, + duration: Long, + delay: Long, + onAnimationEnd: Runnable? + ) { + if (textAnimator != null) { + textAnimator?.setTextStyle( + weight = weight, + textSize = textSize, + color = color, + animate = animate && isAnimationEnabled, + duration = duration, + interpolator = interpolator, + delay = delay, + onAnimationEnd = onAnimationEnd + ) + textAnimator?.glyphFilter = glyphFilter + if (color != null && !isAnimationEnabled) { + setTextColor(color) + } + } else { + // when the text animator is set, update its start values + onTextAnimatorInitialized = Runnable { + textAnimator?.setTextStyle( + weight = weight, + textSize = textSize, + color = color, + animate = false, + duration = duration, + interpolator = interpolator, + delay = delay, + onAnimationEnd = onAnimationEnd + ) + textAnimator?.glyphFilter = glyphFilter + if (color != null && !isAnimationEnabled) { + setTextColor(color) + } + } + } + } + + private fun setTextStyle( + @IntRange(from = 0, to = 1000) weight: Int, + @FloatRange(from = 0.0) textSize: Float, + color: Int?, + animate: Boolean, + duration: Long, + delay: Long, + onAnimationEnd: Runnable? + ) { + setTextStyle( + weight = weight, + textSize = textSize, + color = color, + animate = animate && isAnimationEnabled, + interpolator = null, + duration = duration, + delay = delay, + onAnimationEnd = onAnimationEnd + ) + } + + fun refreshFormat() = refreshFormat(DateFormat.is24HourFormat(context)) + fun refreshFormat(use24HourFormat: Boolean) { + Patterns.update(context) + + format = when { + isSingleLineInternal && use24HourFormat -> Patterns.sClockView24 + !isSingleLineInternal && use24HourFormat -> DOUBLE_LINE_FORMAT_24_HOUR + isSingleLineInternal && !use24HourFormat -> Patterns.sClockView12 + else -> DOUBLE_LINE_FORMAT_12_HOUR + } + logBuffer?.log(tag, DEBUG, + { str1 = format?.toString() }, + { "refreshFormat format=$str1" } + ) + + descFormat = if (use24HourFormat) Patterns.sClockView24 else Patterns.sClockView12 + refreshTime() + } + + fun dump(pw: PrintWriter) { + pw.println("$this") + pw.println(" measuredWidth=$measuredWidth") + pw.println(" measuredHeight=$measuredHeight") + pw.println(" singleLineInternal=$isSingleLineInternal") + pw.println(" currText=$text") + pw.println(" currTimeContextDesc=$contentDescription") + pw.println(" dozingWeightInternal=$dozingWeightInternal") + pw.println(" lockScreenWeightInternal=$lockScreenWeightInternal") + pw.println(" dozingColor=$dozingColor") + pw.println(" lockScreenColor=$lockScreenColor") + pw.println(" time=$time") + } + + fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { + // Do we need to cancel an in-flight animation? + // Need to also check against 0.0f here; we can sometimes get two calls with fraction == 0, + // which trips up the check otherwise. + if (lastSeenAnimationProgress != 1.0f && + lastSeenAnimationProgress != 0.0f && + fraction == 0.0f) { + // New animation, but need to stop the old one. Figure out where each glyph currently + // is in relation to the box position. After that, use the leading digit's current + // position as the stop target. + currentAnimationNeededStop = true + + // We assume that the current glyph offsets would be relative to the "from" position. + val moveAmount = toRect.left - fromRect.left + + // Remap the current glyph offsets to be relative to the new "end" position, and figure + // out the start/end positions for the stop animation. + for (i in 0 until NUM_DIGITS) { + glyphOffsets[i] = -moveAmount + glyphOffsets[i] + animationCancelStartPosition[i] = glyphOffsets[i] + } + + // Use the leading digit's offset as the stop position. + if (toRect.left > fromRect.left) { + // It _was_ moving left + animationCancelStopPosition = glyphOffsets[0] + } else { + // It was moving right + animationCancelStopPosition = glyphOffsets[1] + } + } + + // Is there a cancellation in progress? + if (currentAnimationNeededStop && fraction < ANIMATION_CANCELLATION_TIME) { + val animationStopProgress = MathUtils.constrainedMap( + 0.0f, 1.0f, 0.0f, ANIMATION_CANCELLATION_TIME, fraction + ) + + // One of the digits has already stopped. + val animationStopStep = 1.0f / (NUM_DIGITS - 1) + + for (i in 0 until NUM_DIGITS) { + val stopAmount = if (toRect.left > fromRect.left) { + // It was moving left (before flipping) + MOVE_LEFT_DELAYS[i] * animationStopStep + } else { + // It was moving right (before flipping) + MOVE_RIGHT_DELAYS[i] * animationStopStep + } + + // Leading digit stops immediately. + if (stopAmount == 0.0f) { + glyphOffsets[i] = animationCancelStopPosition + } else { + val actualStopAmount = MathUtils.constrainedMap( + 0.0f, 1.0f, 0.0f, stopAmount, animationStopProgress + ) + val easedProgress = MOVE_INTERPOLATOR.getInterpolation(actualStopAmount) + val glyphMoveAmount = + animationCancelStopPosition - animationCancelStartPosition[i] + glyphOffsets[i] = + animationCancelStartPosition[i] + glyphMoveAmount * easedProgress + } + } + } else { + // Normal part of the animation. + // Do we need to remap the animation progress to take account of the cancellation? + val actualFraction = if (currentAnimationNeededStop) { + MathUtils.constrainedMap( + 0.0f, 1.0f, ANIMATION_CANCELLATION_TIME, 1.0f, fraction + ) + } else { + fraction + } + + val digitFractions = (0 until NUM_DIGITS).map { + // The delay for each digit, in terms of fraction (i.e. the digit should not move + // during 0.0 - 0.1). + val initialDelay = if (toRect.left > fromRect.left) { + MOVE_RIGHT_DELAYS[it] * MOVE_DIGIT_STEP + } else { + MOVE_LEFT_DELAYS[it] * MOVE_DIGIT_STEP + } + + val f = MathUtils.constrainedMap( + 0.0f, 1.0f, + initialDelay, initialDelay + AVAILABLE_ANIMATION_TIME, + actualFraction + ) + MOVE_INTERPOLATOR.getInterpolation(max(min(f, 1.0f), 0.0f)) + } + + // Was there an animation halt? + val moveAmount = if (currentAnimationNeededStop) { + // Only need to animate over the remaining space if the animation was aborted. + -animationCancelStopPosition + } else { + toRect.left.toFloat() - fromRect.left.toFloat() + } + + for (i in 0 until NUM_DIGITS) { + glyphOffsets[i] = -moveAmount + (moveAmount * digitFractions[i]) + } + } + + invalidate() + + if (fraction == 1.0f) { + // Reset + currentAnimationNeededStop = false + } + + lastSeenAnimationProgress = fraction + + // Ensure that the actual clock container is always in the "end" position. + this.setLeftTopRightBottom(toRect.left, toRect.top, toRect.right, toRect.bottom) + } + + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. + // This is an optimization to ensure we only recompute the patterns when the inputs change. + private object Patterns { + var sClockView12: String? = null + var sClockView24: String? = null + var sCacheKey: String? = null + + fun update(context: Context) { + val locale = Locale.getDefault() + val res = context.resources + val clockView12Skel = res.getString(R.string.clock_12hr_format) + val clockView24Skel = res.getString(R.string.clock_24hr_format) + val key = locale.toString() + clockView12Skel + clockView24Skel + if (key == sCacheKey) return + + val clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel) + sClockView12 = clockView12 + + // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton + // format. The following code removes the AM/PM indicator if we didn't want it. + if (!clockView12Skel.contains("a")) { + sClockView12 = clockView12.replace("a".toRegex(), "").trim { it <= ' ' } + } + + sClockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel) + sCacheKey = key + } + } + + companion object { + private val TAG = AnimatableClockView::class.simpleName + const val ANIMATION_DURATION_FOLD_TO_AOD: Int = 600 + private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm" + private const val DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm" + private const val DOZE_ANIM_DURATION: Long = 300 + private const val APPEAR_ANIM_DURATION: Long = 350 + private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500 + private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000 + + // Constants for the animation + private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED + + // Calculate the positions of all of the digits... + // Offset each digit by, say, 0.1 + // This means that each digit needs to move over a slice of "fractions", i.e. digit 0 should + // move from 0.0 - 0.7, digit 1 from 0.1 - 0.8, digit 2 from 0.2 - 0.9, and digit 3 + // from 0.3 - 1.0. + private const val NUM_DIGITS = 4 + private const val DIGITS_PER_LINE = 2 + + // How much of "fraction" to spend on canceling the animation, if needed + private const val ANIMATION_CANCELLATION_TIME = 0.4f + + // Delays. Each digit's animation should have a slight delay, so we get a nice + // "stepping" effect. When moving right, the second digit of the hour should move first. + // When moving left, the first digit of the hour should move first. The lists encode + // the delay for each digit (hour[0], hour[1], minute[0], minute[1]), to be multiplied + // by delayMultiplier. + private val MOVE_LEFT_DELAYS = listOf(0, 1, 2, 3) + private val MOVE_RIGHT_DELAYS = listOf(1, 0, 3, 2) + + // How much delay to apply to each subsequent digit. This is measured in terms of "fraction" + // (i.e. a value of 0.1 would cause a digit to wait until fraction had hit 0.1, or 0.2 etc + // before moving). + // + // The current specs dictate that each digit should have a 33ms gap between them. The + // overall time is 1s right now. + private const val MOVE_DIGIT_STEP = 0.033f + + // Total available transition time for each digit, taking into account the step. If step is + // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7. + private val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) + } +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt new file mode 100644 index 000000000000..59b48480cba7 --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -0,0 +1,229 @@ +/* + * 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.shared.clocks + +import android.content.Context +import android.database.ContentObserver +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Handler +import android.provider.Settings +import android.util.Log +import androidx.annotation.OpenForTesting +import com.android.internal.annotations.Keep +import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.ClockId +import com.android.systemui.plugins.ClockMetadata +import com.android.systemui.plugins.ClockProvider +import com.android.systemui.plugins.ClockProviderPlugin +import com.android.systemui.plugins.PluginListener +import com.android.systemui.plugins.PluginManager +import org.json.JSONObject + +private val TAG = ClockRegistry::class.simpleName +private const val DEBUG = true + +/** ClockRegistry aggregates providers and plugins */ +open class ClockRegistry( + val context: Context, + val pluginManager: PluginManager, + val handler: Handler, + val isEnabled: Boolean, + userHandle: Int, + defaultClockProvider: ClockProvider, + val fallbackClockId: ClockId = DEFAULT_CLOCK_ID, +) { + // Usually this would be a typealias, but a SAM provides better java interop + fun interface ClockChangeListener { + fun onClockChanged() + } + + private val availableClocks = mutableMapOf() + private val clockChangeListeners = mutableListOf() + private val settingObserver = object : ContentObserver(handler) { + override fun onChange(selfChange: Boolean, uris: Collection, flags: Int, userId: Int) = + clockChangeListeners.forEach { it.onClockChanged() } + } + + private val pluginListener = object : PluginListener { + override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) = + connectClocks(plugin) + + override fun onPluginDisconnected(plugin: ClockProviderPlugin) = + disconnectClocks(plugin) + } + + open var currentClockId: ClockId + get() { + return try { + val json = Settings.Secure.getString( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE + ) + if (json == null || json.isEmpty()) { + return fallbackClockId + } + ClockSetting.deserialize(json).clockId + } catch (ex: Exception) { + Log.e(TAG, "Failed to parse clock setting", ex) + fallbackClockId + } + } + set(value) { + try { + val json = ClockSetting.serialize(ClockSetting(value, System.currentTimeMillis())) + Settings.Secure.putString( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json + ) + } catch (ex: Exception) { + Log.e(TAG, "Failed to set clock setting", ex) + } + } + + init { + connectClocks(defaultClockProvider) + if (!availableClocks.containsKey(DEFAULT_CLOCK_ID)) { + throw IllegalArgumentException( + "$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID" + ) + } + + if (isEnabled) { + pluginManager.addPluginListener( + pluginListener, + ClockProviderPlugin::class.java, + /*allowMultiple=*/ true + ) + context.contentResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), + /*notifyForDescendants=*/ false, + settingObserver, + userHandle + ) + } + } + + private fun connectClocks(provider: ClockProvider) { + val currentId = currentClockId + for (clock in provider.getClocks()) { + val id = clock.clockId + val current = availableClocks[id] + if (current != null) { + Log.e( + TAG, + "Clock Id conflict: $id is registered by both " + + "${provider::class.simpleName} and ${current.provider::class.simpleName}" + ) + return + } + + availableClocks[id] = ClockInfo(clock, provider) + if (DEBUG) { + Log.i(TAG, "Added ${clock.clockId}") + } + + if (currentId == id) { + if (DEBUG) { + Log.i(TAG, "Current clock ($currentId) was connected") + } + clockChangeListeners.forEach { it.onClockChanged() } + } + } + } + + private fun disconnectClocks(provider: ClockProvider) { + val currentId = currentClockId + for (clock in provider.getClocks()) { + availableClocks.remove(clock.clockId) + if (DEBUG) { + Log.i(TAG, "Removed ${clock.clockId}") + } + + if (currentId == clock.clockId) { + Log.w(TAG, "Current clock ($currentId) was disconnected") + clockChangeListeners.forEach { it.onClockChanged() } + } + } + } + + @OpenForTesting + open fun getClocks(): List { + if (!isEnabled) { + return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) + } + return availableClocks.map { (_, clock) -> clock.metadata } + } + + fun getClockThumbnail(clockId: ClockId): Drawable? = + availableClocks[clockId]?.provider?.getClockThumbnail(clockId) + + fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId) + + fun registerClockChangeListener(listener: ClockChangeListener) = + clockChangeListeners.add(listener) + + fun unregisterClockChangeListener(listener: ClockChangeListener) = + clockChangeListeners.remove(listener) + + fun createCurrentClock(): ClockController { + val clockId = currentClockId + if (isEnabled && clockId.isNotEmpty()) { + val clock = createClock(clockId) + if (clock != null) { + if (DEBUG) { + Log.i(TAG, "Rendering clock $clockId") + } + return clock + } else { + Log.e(TAG, "Clock $clockId not found; using default") + } + } + + return createClock(DEFAULT_CLOCK_ID)!! + } + + private fun createClock(clockId: ClockId): ClockController? = + availableClocks[clockId]?.provider?.createClock(clockId) + + private data class ClockInfo( + val metadata: ClockMetadata, + val provider: ClockProvider + ) + + @Keep + data class ClockSetting( + val clockId: ClockId, + val _applied_timestamp: Long? + ) { + companion object { + private val KEY_CLOCK_ID = "clockId" + private val KEY_TIMESTAMP = "_applied_timestamp" + + fun serialize(setting: ClockSetting): String { + return JSONObject() + .put(KEY_CLOCK_ID, setting.clockId) + .put(KEY_TIMESTAMP, setting._applied_timestamp) + .toString() + } + + fun deserialize(jsonStr: String): ClockSetting { + val json = JSONObject(jsonStr) + return ClockSetting( + json.getString(KEY_CLOCK_ID), + if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null) + } + } + } +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt new file mode 100644 index 000000000000..869884474ffe --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -0,0 +1,272 @@ +/* + * 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.shared.clocks + +import android.content.Context +import android.content.res.Resources +import android.graphics.Color +import android.graphics.Rect +import android.icu.text.NumberFormat +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.annotation.VisibleForTesting +import com.android.systemui.customization.R +import com.android.systemui.plugins.ClockAnimations +import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.ClockEvents +import com.android.systemui.plugins.ClockFaceController +import com.android.systemui.plugins.ClockFaceEvents +import com.android.systemui.plugins.log.LogBuffer +import java.io.PrintWriter +import java.util.Locale +import java.util.TimeZone + +private val TAG = DefaultClockController::class.simpleName + +/** + * Controls the default clock visuals. + * + * This serves as an adapter between the clock interface and the AnimatableClockView used by the + * existing lockscreen clock. + */ +class DefaultClockController( + ctx: Context, + private val layoutInflater: LayoutInflater, + private val resources: Resources, +) : ClockController { + override val smallClock: DefaultClockFaceController + override val largeClock: LargeClockFaceController + private val clocks: List + + private val burmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my")) + private val burmeseNumerals = burmeseNf.format(FORMAT_NUMBER.toLong()) + private val burmeseLineSpacing = + resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese) + private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale) + + override val events: DefaultClockEvents + override lateinit var animations: DefaultClockAnimations + private set + + init { + val parent = FrameLayout(ctx) + smallClock = + DefaultClockFaceController( + layoutInflater.inflate(R.layout.clock_default_small, parent, false) + as AnimatableClockView + ) + largeClock = + LargeClockFaceController( + layoutInflater.inflate(R.layout.clock_default_large, parent, false) + as AnimatableClockView + ) + clocks = listOf(smallClock.view, largeClock.view) + + events = DefaultClockEvents() + animations = DefaultClockAnimations(0f, 0f) + events.onLocaleChanged(Locale.getDefault()) + } + + override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { + largeClock.recomputePadding(null) + animations = DefaultClockAnimations(dozeFraction, foldFraction) + events.onColorPaletteChanged(resources) + events.onTimeZoneChanged(TimeZone.getDefault()) + events.onTimeTick() + } + + override fun setLogBuffer(logBuffer: LogBuffer) { + smallClock.view.tag = "smallClockView" + largeClock.view.tag = "largeClockView" + smallClock.view.logBuffer = logBuffer + largeClock.view.logBuffer = logBuffer + } + + open inner class DefaultClockFaceController( + override val view: AnimatableClockView, + ) : ClockFaceController { + + // MAGENTA is a placeholder, and will be assigned correctly in initialize + private var currentColor = Color.MAGENTA + private var isRegionDark = false + protected var targetRegion: Rect? = null + + init { + view.setColors(currentColor, currentColor) + } + + override val events = + object : ClockFaceEvents { + override fun onRegionDarknessChanged(isRegionDark: Boolean) { + this@DefaultClockFaceController.isRegionDark = isRegionDark + updateColor() + } + + override fun onTargetRegionChanged(targetRegion: Rect?) { + this@DefaultClockFaceController.targetRegion = targetRegion + recomputePadding(targetRegion) + } + + override fun onFontSettingChanged(fontSizePx: Float) { + view.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSizePx) + recomputePadding(targetRegion) + } + } + + open fun recomputePadding(targetRegion: Rect?) {} + + fun updateColor() { + val color = + if (isRegionDark) { + resources.getColor(android.R.color.system_accent1_100) + } else { + resources.getColor(android.R.color.system_accent2_600) + } + + if (currentColor == color) { + return + } + + currentColor = color + view.setColors(DOZE_COLOR, color) + if (!animations.dozeState.isActive) { + view.animateAppearOnLockscreen() + } + } + } + + inner class LargeClockFaceController( + view: AnimatableClockView, + ) : DefaultClockFaceController(view) { + override fun recomputePadding(targetRegion: Rect?) { + // We center the view within the targetRegion instead of within the parent + // view by computing the difference and adding that to the padding. + val parent = view.parent + val yDiff = + if (targetRegion != null && parent is View && parent.isLaidOut()) + targetRegion.centerY() - parent.height / 2f + else 0f + val lp = view.getLayoutParams() as FrameLayout.LayoutParams + lp.topMargin = (-0.5f * view.bottom + yDiff).toInt() + view.setLayoutParams(lp) + } + + fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { + view.moveForSplitShade(fromRect, toRect, fraction) + } + } + + inner class DefaultClockEvents : ClockEvents { + override fun onTimeTick() = clocks.forEach { it.refreshTime() } + + override fun onTimeFormatChanged(is24Hr: Boolean) = + clocks.forEach { it.refreshFormat(is24Hr) } + + override fun onTimeZoneChanged(timeZone: TimeZone) = + clocks.forEach { it.onTimeZoneChanged(timeZone) } + + override fun onColorPaletteChanged(resources: Resources) { + largeClock.updateColor() + smallClock.updateColor() + } + + override fun onLocaleChanged(locale: Locale) { + val nf = NumberFormat.getInstance(locale) + if (nf.format(FORMAT_NUMBER.toLong()) == burmeseNumerals) { + clocks.forEach { it.setLineSpacingScale(burmeseLineSpacing) } + } else { + clocks.forEach { it.setLineSpacingScale(defaultLineSpacing) } + } + + clocks.forEach { it.refreshFormat() } + } + } + + inner class DefaultClockAnimations( + dozeFraction: Float, + foldFraction: Float, + ) : ClockAnimations { + internal val dozeState = AnimationState(dozeFraction) + private val foldState = AnimationState(foldFraction) + + init { + if (foldState.isActive) { + clocks.forEach { it.animateFoldAppear(false) } + } else { + clocks.forEach { it.animateDoze(dozeState.isActive, false) } + } + } + + override fun enter() { + if (!dozeState.isActive) { + clocks.forEach { it.animateAppearOnLockscreen() } + } + } + + override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } } + + override fun fold(fraction: Float) { + val (hasChanged, hasJumped) = foldState.update(fraction) + if (hasChanged) { + clocks.forEach { it.animateFoldAppear(!hasJumped) } + } + } + + override fun doze(fraction: Float) { + val (hasChanged, hasJumped) = dozeState.update(fraction) + if (hasChanged) { + clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) } + } + } + + override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) { + largeClock.moveForSplitShade(fromRect, toRect, fraction) + } + + override val hasCustomPositionUpdatedAnimation: Boolean + get() = true + } + + class AnimationState( + var fraction: Float, + ) { + var isActive: Boolean = fraction > 0.5f + fun update(newFraction: Float): Pair { + if (newFraction == fraction) { + return Pair(isActive, false) + } + val wasActive = isActive + val hasJumped = + (fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f) + isActive = newFraction > fraction + fraction = newFraction + return Pair(wasActive != isActive, hasJumped) + } + } + + override fun dump(pw: PrintWriter) { + pw.print("smallClock=") + smallClock.view.dump(pw) + + pw.print("largeClock=") + largeClock.view.dump(pw) + } + + companion object { + @VisibleForTesting const val DOZE_COLOR = Color.WHITE + private const val FORMAT_NUMBER = 1234567890 + } +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt new file mode 100644 index 000000000000..4c0504bbea47 --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -0,0 +1,55 @@ +/* + * 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.shared.clocks + +import android.content.Context +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.view.LayoutInflater +import com.android.systemui.customization.R +import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.ClockId +import com.android.systemui.plugins.ClockMetadata +import com.android.systemui.plugins.ClockProvider + +private val TAG = DefaultClockProvider::class.simpleName +const val DEFAULT_CLOCK_NAME = "Default Clock" +const val DEFAULT_CLOCK_ID = "DEFAULT" + +/** Provides the default system clock */ +class DefaultClockProvider constructor( + val ctx: Context, + val layoutInflater: LayoutInflater, + val resources: Resources +) : ClockProvider { + override fun getClocks(): List = + listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME)) + + override fun createClock(id: ClockId): ClockController { + if (id != DEFAULT_CLOCK_ID) { + throw IllegalArgumentException("$id is unsupported by $TAG") + } + + return DefaultClockController(ctx, layoutInflater, resources) + } + + override fun getClockThumbnail(id: ClockId): Drawable? { + if (id != DEFAULT_CLOCK_ID) { + throw IllegalArgumentException("$id is unsupported by $TAG") + } + + // TODO: Update placeholder to actual resource + return resources.getDrawable(R.drawable.clock_default_thumbnail, null) + } +} diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt index 553b86bb833f..0abbb1e5bd84 100644 --- a/packages/SystemUI/ktfmt_includes.txt +++ b/packages/SystemUI/ktfmt_includes.txt @@ -23,9 +23,9 @@ -packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt -packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt -packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt --packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt --packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt --packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt -packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt -packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt -packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginManager.java new file mode 100644 index 000000000000..80c64cd41641 --- /dev/null +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.text.TextUtils; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +public interface PluginManager { + + String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED"; + + // must be one of the channels created in NotificationChannels.java + String NOTIFICATION_CHANNEL_ID = "ALR"; + + /** Returns plugins that don't get disabled when an exceptoin occurs. */ + String[] getPrivilegedPlugins(); + + /** */ + void addPluginListener(PluginListener listener, Class cls); + /** */ + void addPluginListener(PluginListener listener, Class cls, + boolean allowMultiple); + void addPluginListener(String action, PluginListener listener, + Class cls); + void addPluginListener(String action, PluginListener listener, + Class cls, boolean allowMultiple); + + void removePluginListener(PluginListener listener); + + boolean dependsOn(Plugin p, Class cls); + + class Helper { + public static

String getAction(Class

cls) { + ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); + if (info == null) { + throw new RuntimeException(cls + " doesn't provide an interface"); + } + if (TextUtils.isEmpty(info.action())) { + throw new RuntimeException(cls + " doesn't provide an action"); + } + return info.action(); + } + } + +} diff --git a/packages/SystemUI/shared/res/drawable/clock_default_thumbnail.xml b/packages/SystemUI/shared/res/drawable/clock_default_thumbnail.xml deleted file mode 100644 index be72d0b82dbb..000000000000 --- a/packages/SystemUI/shared/res/drawable/clock_default_thumbnail.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/packages/SystemUI/shared/res/layout/clock_default_large.xml b/packages/SystemUI/shared/res/layout/clock_default_large.xml deleted file mode 100644 index 0139d50dcfba..000000000000 --- a/packages/SystemUI/shared/res/layout/clock_default_large.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/packages/SystemUI/shared/res/layout/clock_default_small.xml b/packages/SystemUI/shared/res/layout/clock_default_small.xml deleted file mode 100644 index ff6d7f9e2240..000000000000 --- a/packages/SystemUI/shared/res/layout/clock_default_small.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/packages/SystemUI/shared/res/values/attrs.xml b/packages/SystemUI/shared/res/values/attrs.xml index 96a58405a764..f3aeaef4cfe7 100644 --- a/packages/SystemUI/shared/res/values/attrs.xml +++ b/packages/SystemUI/shared/res/values/attrs.xml @@ -20,12 +20,6 @@ --> - - - - - - diff --git a/packages/SystemUI/shared/res/values/dimens.xml b/packages/SystemUI/shared/res/values/dimens.xml deleted file mode 100644 index 8f90f0fefdb5..000000000000 --- a/packages/SystemUI/shared/res/values/dimens.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 150sp - 86sp - - - .7 - - 1 - \ No newline at end of file diff --git a/packages/SystemUI/shared/res/values/donottranslate.xml b/packages/SystemUI/shared/res/values/donottranslate.xml deleted file mode 100644 index 383d5521f156..000000000000 --- a/packages/SystemUI/shared/res/values/donottranslate.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - hm - - - Hm - diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt deleted file mode 100644 index 81a85c3d2dd9..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright (C) 2021 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.shared.clocks - -import android.animation.TimeInterpolator -import android.annotation.ColorInt -import android.annotation.FloatRange -import android.annotation.IntRange -import android.annotation.SuppressLint -import android.content.Context -import android.graphics.Canvas -import android.graphics.Rect -import android.text.Layout -import android.text.TextUtils -import android.text.format.DateFormat -import android.util.AttributeSet -import android.util.MathUtils -import android.widget.TextView -import com.android.internal.annotations.VisibleForTesting -import com.android.systemui.animation.GlyphCallback -import com.android.systemui.animation.Interpolators -import com.android.systemui.animation.TextAnimator -import com.android.systemui.plugins.log.LogBuffer -import com.android.systemui.plugins.log.LogLevel.DEBUG -import com.android.systemui.shared.R -import java.io.PrintWriter -import java.util.Calendar -import java.util.Locale -import java.util.TimeZone -import kotlin.math.max -import kotlin.math.min - -/** - * Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30) - * The time's text color is a gradient that changes its colors based on its controller. - */ -@SuppressLint("AppCompatCustomView") -class AnimatableClockView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0, - defStyleRes: Int = 0 -) : TextView(context, attrs, defStyleAttr, defStyleRes) { - var tag: String = "UnnamedClockView" - var logBuffer: LogBuffer? = null - - private val time = Calendar.getInstance() - - private val dozingWeightInternal: Int - private val lockScreenWeightInternal: Int - private val isSingleLineInternal: Boolean - - private var format: CharSequence? = null - private var descFormat: CharSequence? = null - - @ColorInt - private var dozingColor = 0 - - @ColorInt - private var lockScreenColor = 0 - - private var lineSpacingScale = 1f - private val chargeAnimationDelay: Int - private var textAnimator: TextAnimator? = null - private var onTextAnimatorInitialized: Runnable? = null - - @VisibleForTesting var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = - { layout, invalidateCb -> TextAnimator(layout, invalidateCb) } - @VisibleForTesting var isAnimationEnabled: Boolean = true - @VisibleForTesting var timeOverrideInMillis: Long? = null - - val dozingWeight: Int - get() = if (useBoldedVersion()) dozingWeightInternal + 100 else dozingWeightInternal - - val lockScreenWeight: Int - get() = if (useBoldedVersion()) lockScreenWeightInternal + 100 else lockScreenWeightInternal - - /** - * The number of pixels below the baseline. For fonts that support languages such as - * Burmese, this space can be significant and should be accounted for when computing layout. - */ - val bottom get() = paint?.fontMetrics?.bottom ?: 0f - - init { - val animatableClockViewAttributes = context.obtainStyledAttributes( - attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes - ) - - try { - dozingWeightInternal = animatableClockViewAttributes.getInt( - R.styleable.AnimatableClockView_dozeWeight, - 100 - ) - lockScreenWeightInternal = animatableClockViewAttributes.getInt( - R.styleable.AnimatableClockView_lockScreenWeight, - 300 - ) - chargeAnimationDelay = animatableClockViewAttributes.getInt( - R.styleable.AnimatableClockView_chargeAnimationDelay, 200 - ) - } finally { - animatableClockViewAttributes.recycle() - } - - val textViewAttributes = context.obtainStyledAttributes( - attrs, android.R.styleable.TextView, - defStyleAttr, defStyleRes - ) - - isSingleLineInternal = - try { - textViewAttributes.getBoolean(android.R.styleable.TextView_singleLine, false) - } finally { - textViewAttributes.recycle() - } - - refreshFormat() - } - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - logBuffer?.log(tag, DEBUG, "onAttachedToWindow") - refreshFormat() - } - - /** - * Whether to use a bolded version based on the user specified fontWeightAdjustment. - */ - fun useBoldedVersion(): Boolean { - // "Bold text" fontWeightAdjustment is 300. - return resources.configuration.fontWeightAdjustment > 100 - } - - fun refreshTime() { - time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis() - contentDescription = DateFormat.format(descFormat, time) - val formattedText = DateFormat.format(format, time) - logBuffer?.log(tag, DEBUG, - { str1 = formattedText?.toString() }, - { "refreshTime: new formattedText=$str1" } - ) - // Setting text actually triggers a layout pass (because the text view is set to - // wrap_content width and TextView always relayouts for this). Avoid needless - // relayout if the text didn't actually change. - if (!TextUtils.equals(text, formattedText)) { - text = formattedText - logBuffer?.log(tag, DEBUG, - { str1 = formattedText?.toString() }, - { "refreshTime: done setting new time text to: $str1" } - ) - // 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) - logBuffer?.log(tag, DEBUG, "refreshTime: done updating textAnimator layout") - } - requestLayout() - logBuffer?.log(tag, DEBUG, "refreshTime: after requestLayout") - } - } - - fun onTimeZoneChanged(timeZone: TimeZone?) { - time.timeZone = timeZone - refreshFormat() - logBuffer?.log(tag, DEBUG, - { str1 = timeZone?.toString() }, - { "onTimeZoneChanged newTimeZone=$str1" } - ) - } - - @SuppressLint("DrawAllocation") - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec) - val animator = textAnimator - if (animator == null) { - textAnimator = textAnimatorFactory(layout, ::invalidate) - onTextAnimatorInitialized?.run() - onTextAnimatorInitialized = null - } else { - animator.updateLayout(layout) - } - logBuffer?.log(tag, DEBUG, "onMeasure") - } - - override fun onDraw(canvas: Canvas) { - // Use textAnimator to render text if animation is enabled. - // Otherwise default to using standard draw functions. - if (isAnimationEnabled) { - // intentionally doesn't call super.onDraw here or else the text will be rendered twice - textAnimator?.draw(canvas) - } else { - super.onDraw(canvas) - } - logBuffer?.log(tag, DEBUG, "onDraw lastDraw") - } - - override fun invalidate() { - super.invalidate() - logBuffer?.log(tag, DEBUG, "invalidate") - } - - override fun onTextChanged( - text: CharSequence, - start: Int, - lengthBefore: Int, - lengthAfter: Int - ) { - super.onTextChanged(text, start, lengthBefore, lengthAfter) - logBuffer?.log(tag, DEBUG, - { str1 = text.toString() }, - { "onTextChanged text=$str1" } - ) - } - - fun setLineSpacingScale(scale: Float) { - lineSpacingScale = scale - setLineSpacing(0f, lineSpacingScale) - } - - fun setColors(@ColorInt dozingColor: Int, lockScreenColor: Int) { - this.dozingColor = dozingColor - this.lockScreenColor = lockScreenColor - } - - fun animateAppearOnLockscreen() { - logBuffer?.log(tag, DEBUG, "animateAppearOnLockscreen") - setTextStyle( - weight = dozingWeight, - textSize = -1f, - color = lockScreenColor, - animate = false, - duration = 0, - delay = 0, - onAnimationEnd = null - ) - setTextStyle( - weight = lockScreenWeight, - textSize = -1f, - color = lockScreenColor, - animate = isAnimationEnabled, - duration = APPEAR_ANIM_DURATION, - delay = 0, - onAnimationEnd = null - ) - } - - fun animateFoldAppear(animate: Boolean = true) { - if (isAnimationEnabled && textAnimator == null) { - return - } - logBuffer?.log(tag, DEBUG, "animateFoldAppear") - setTextStyle( - weight = lockScreenWeightInternal, - textSize = -1f, - color = lockScreenColor, - animate = false, - duration = 0, - delay = 0, - onAnimationEnd = null - ) - setTextStyle( - weight = dozingWeightInternal, - textSize = -1f, - color = dozingColor, - animate = animate && isAnimationEnabled, - interpolator = Interpolators.EMPHASIZED_DECELERATE, - duration = ANIMATION_DURATION_FOLD_TO_AOD.toLong(), - delay = 0, - onAnimationEnd = null - ) - } - - fun animateCharge(isDozing: () -> Boolean) { - if (textAnimator == null || textAnimator!!.isRunning()) { - // Skip charge animation if dozing animation is already playing. - return - } - logBuffer?.log(tag, DEBUG, "animateCharge") - val startAnimPhase2 = Runnable { - setTextStyle( - weight = if (isDozing()) dozingWeight else lockScreenWeight, - textSize = -1f, - color = null, - animate = isAnimationEnabled, - duration = CHARGE_ANIM_DURATION_PHASE_1, - delay = 0, - onAnimationEnd = null - ) - } - setTextStyle( - weight = if (isDozing()) lockScreenWeight else dozingWeight, - textSize = -1f, - color = null, - animate = isAnimationEnabled, - duration = CHARGE_ANIM_DURATION_PHASE_0, - delay = chargeAnimationDelay.toLong(), - onAnimationEnd = startAnimPhase2 - ) - } - - fun animateDoze(isDozing: Boolean, animate: Boolean) { - logBuffer?.log(tag, DEBUG, "animateDoze") - setTextStyle( - weight = if (isDozing) dozingWeight else lockScreenWeight, - textSize = -1f, - color = if (isDozing) dozingColor else lockScreenColor, - animate = animate && isAnimationEnabled, - duration = DOZE_ANIM_DURATION, - delay = 0, - onAnimationEnd = null - ) - } - - // The offset of each glyph from where it should be. - private var glyphOffsets = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f) - - private var lastSeenAnimationProgress = 1.0f - - // If the animation is being reversed, the target offset for each glyph for the "stop". - private var animationCancelStartPosition = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f) - private var animationCancelStopPosition = 0.0f - - // Whether the currently playing animation needed a stop (and thus, is shortened). - private var currentAnimationNeededStop = false - - private val glyphFilter: GlyphCallback = { positionedGlyph, _ -> - val offset = positionedGlyph.lineNo * DIGITS_PER_LINE + positionedGlyph.glyphIndex - if (offset < glyphOffsets.size) { - positionedGlyph.x += glyphOffsets[offset] - } - } - - /** - * Set text style with an optional animation. - * - * By passing -1 to weight, the view preserves its current weight. - * By passing -1 to textSize, the view preserves its current text size. - * - * @param weight text weight. - * @param textSize font size. - * @param animate true to animate the text style change, otherwise false. - */ - private fun setTextStyle( - @IntRange(from = 0, to = 1000) weight: Int, - @FloatRange(from = 0.0) textSize: Float, - color: Int?, - animate: Boolean, - interpolator: TimeInterpolator?, - duration: Long, - delay: Long, - onAnimationEnd: Runnable? - ) { - if (textAnimator != null) { - textAnimator?.setTextStyle( - weight = weight, - textSize = textSize, - color = color, - animate = animate && isAnimationEnabled, - duration = duration, - interpolator = interpolator, - delay = delay, - onAnimationEnd = onAnimationEnd - ) - textAnimator?.glyphFilter = glyphFilter - if (color != null && !isAnimationEnabled) { - setTextColor(color) - } - } else { - // when the text animator is set, update its start values - onTextAnimatorInitialized = Runnable { - textAnimator?.setTextStyle( - weight = weight, - textSize = textSize, - color = color, - animate = false, - duration = duration, - interpolator = interpolator, - delay = delay, - onAnimationEnd = onAnimationEnd - ) - textAnimator?.glyphFilter = glyphFilter - if (color != null && !isAnimationEnabled) { - setTextColor(color) - } - } - } - } - - private fun setTextStyle( - @IntRange(from = 0, to = 1000) weight: Int, - @FloatRange(from = 0.0) textSize: Float, - color: Int?, - animate: Boolean, - duration: Long, - delay: Long, - onAnimationEnd: Runnable? - ) { - setTextStyle( - weight = weight, - textSize = textSize, - color = color, - animate = animate && isAnimationEnabled, - interpolator = null, - duration = duration, - delay = delay, - onAnimationEnd = onAnimationEnd - ) - } - - fun refreshFormat() = refreshFormat(DateFormat.is24HourFormat(context)) - fun refreshFormat(use24HourFormat: Boolean) { - Patterns.update(context) - - format = when { - isSingleLineInternal && use24HourFormat -> Patterns.sClockView24 - !isSingleLineInternal && use24HourFormat -> DOUBLE_LINE_FORMAT_24_HOUR - isSingleLineInternal && !use24HourFormat -> Patterns.sClockView12 - else -> DOUBLE_LINE_FORMAT_12_HOUR - } - logBuffer?.log(tag, DEBUG, - { str1 = format?.toString() }, - { "refreshFormat format=$str1" } - ) - - descFormat = if (use24HourFormat) Patterns.sClockView24 else Patterns.sClockView12 - refreshTime() - } - - fun dump(pw: PrintWriter) { - pw.println("$this") - pw.println(" measuredWidth=$measuredWidth") - pw.println(" measuredHeight=$measuredHeight") - pw.println(" singleLineInternal=$isSingleLineInternal") - pw.println(" currText=$text") - pw.println(" currTimeContextDesc=$contentDescription") - pw.println(" dozingWeightInternal=$dozingWeightInternal") - pw.println(" lockScreenWeightInternal=$lockScreenWeightInternal") - pw.println(" dozingColor=$dozingColor") - pw.println(" lockScreenColor=$lockScreenColor") - pw.println(" time=$time") - } - - fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { - // Do we need to cancel an in-flight animation? - // Need to also check against 0.0f here; we can sometimes get two calls with fraction == 0, - // which trips up the check otherwise. - if (lastSeenAnimationProgress != 1.0f && - lastSeenAnimationProgress != 0.0f && - fraction == 0.0f) { - // New animation, but need to stop the old one. Figure out where each glyph currently - // is in relation to the box position. After that, use the leading digit's current - // position as the stop target. - currentAnimationNeededStop = true - - // We assume that the current glyph offsets would be relative to the "from" position. - val moveAmount = toRect.left - fromRect.left - - // Remap the current glyph offsets to be relative to the new "end" position, and figure - // out the start/end positions for the stop animation. - for (i in 0 until NUM_DIGITS) { - glyphOffsets[i] = -moveAmount + glyphOffsets[i] - animationCancelStartPosition[i] = glyphOffsets[i] - } - - // Use the leading digit's offset as the stop position. - if (toRect.left > fromRect.left) { - // It _was_ moving left - animationCancelStopPosition = glyphOffsets[0] - } else { - // It was moving right - animationCancelStopPosition = glyphOffsets[1] - } - } - - // Is there a cancellation in progress? - if (currentAnimationNeededStop && fraction < ANIMATION_CANCELLATION_TIME) { - val animationStopProgress = MathUtils.constrainedMap( - 0.0f, 1.0f, 0.0f, ANIMATION_CANCELLATION_TIME, fraction - ) - - // One of the digits has already stopped. - val animationStopStep = 1.0f / (NUM_DIGITS - 1) - - for (i in 0 until NUM_DIGITS) { - val stopAmount = if (toRect.left > fromRect.left) { - // It was moving left (before flipping) - MOVE_LEFT_DELAYS[i] * animationStopStep - } else { - // It was moving right (before flipping) - MOVE_RIGHT_DELAYS[i] * animationStopStep - } - - // Leading digit stops immediately. - if (stopAmount == 0.0f) { - glyphOffsets[i] = animationCancelStopPosition - } else { - val actualStopAmount = MathUtils.constrainedMap( - 0.0f, 1.0f, 0.0f, stopAmount, animationStopProgress - ) - val easedProgress = MOVE_INTERPOLATOR.getInterpolation(actualStopAmount) - val glyphMoveAmount = - animationCancelStopPosition - animationCancelStartPosition[i] - glyphOffsets[i] = - animationCancelStartPosition[i] + glyphMoveAmount * easedProgress - } - } - } else { - // Normal part of the animation. - // Do we need to remap the animation progress to take account of the cancellation? - val actualFraction = if (currentAnimationNeededStop) { - MathUtils.constrainedMap( - 0.0f, 1.0f, ANIMATION_CANCELLATION_TIME, 1.0f, fraction - ) - } else { - fraction - } - - val digitFractions = (0 until NUM_DIGITS).map { - // The delay for each digit, in terms of fraction (i.e. the digit should not move - // during 0.0 - 0.1). - val initialDelay = if (toRect.left > fromRect.left) { - MOVE_RIGHT_DELAYS[it] * MOVE_DIGIT_STEP - } else { - MOVE_LEFT_DELAYS[it] * MOVE_DIGIT_STEP - } - - val f = MathUtils.constrainedMap( - 0.0f, 1.0f, - initialDelay, initialDelay + AVAILABLE_ANIMATION_TIME, - actualFraction - ) - MOVE_INTERPOLATOR.getInterpolation(max(min(f, 1.0f), 0.0f)) - } - - // Was there an animation halt? - val moveAmount = if (currentAnimationNeededStop) { - // Only need to animate over the remaining space if the animation was aborted. - -animationCancelStopPosition - } else { - toRect.left.toFloat() - fromRect.left.toFloat() - } - - for (i in 0 until NUM_DIGITS) { - glyphOffsets[i] = -moveAmount + (moveAmount * digitFractions[i]) - } - } - - invalidate() - - if (fraction == 1.0f) { - // Reset - currentAnimationNeededStop = false - } - - lastSeenAnimationProgress = fraction - - // Ensure that the actual clock container is always in the "end" position. - this.setLeftTopRightBottom(toRect.left, toRect.top, toRect.right, toRect.bottom) - } - - // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. - // This is an optimization to ensure we only recompute the patterns when the inputs change. - private object Patterns { - var sClockView12: String? = null - var sClockView24: String? = null - var sCacheKey: String? = null - - fun update(context: Context) { - val locale = Locale.getDefault() - val res = context.resources - val clockView12Skel = res.getString(R.string.clock_12hr_format) - val clockView24Skel = res.getString(R.string.clock_24hr_format) - val key = locale.toString() + clockView12Skel + clockView24Skel - if (key == sCacheKey) return - - val clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel) - sClockView12 = clockView12 - - // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton - // format. The following code removes the AM/PM indicator if we didn't want it. - if (!clockView12Skel.contains("a")) { - sClockView12 = clockView12.replace("a".toRegex(), "").trim { it <= ' ' } - } - - sClockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel) - sCacheKey = key - } - } - - companion object { - private val TAG = AnimatableClockView::class.simpleName - const val ANIMATION_DURATION_FOLD_TO_AOD: Int = 600 - private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm" - private const val DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm" - private const val DOZE_ANIM_DURATION: Long = 300 - private const val APPEAR_ANIM_DURATION: Long = 350 - private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500 - private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000 - - // Constants for the animation - private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED - - // Calculate the positions of all of the digits... - // Offset each digit by, say, 0.1 - // This means that each digit needs to move over a slice of "fractions", i.e. digit 0 should - // move from 0.0 - 0.7, digit 1 from 0.1 - 0.8, digit 2 from 0.2 - 0.9, and digit 3 - // from 0.3 - 1.0. - private const val NUM_DIGITS = 4 - private const val DIGITS_PER_LINE = 2 - - // How much of "fraction" to spend on canceling the animation, if needed - private const val ANIMATION_CANCELLATION_TIME = 0.4f - - // Delays. Each digit's animation should have a slight delay, so we get a nice - // "stepping" effect. When moving right, the second digit of the hour should move first. - // When moving left, the first digit of the hour should move first. The lists encode - // the delay for each digit (hour[0], hour[1], minute[0], minute[1]), to be multiplied - // by delayMultiplier. - private val MOVE_LEFT_DELAYS = listOf(0, 1, 2, 3) - private val MOVE_RIGHT_DELAYS = listOf(1, 0, 3, 2) - - // How much delay to apply to each subsequent digit. This is measured in terms of "fraction" - // (i.e. a value of 0.1 would cause a digit to wait until fraction had hit 0.1, or 0.2 etc - // before moving). - // - // The current specs dictate that each digit should have a 33ms gap between them. The - // overall time is 1s right now. - private const val MOVE_DIGIT_STEP = 0.033f - - // Total available transition time for each digit, taking into account the step. If step is - // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7. - private val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt deleted file mode 100644 index abfbc5e09a6c..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ /dev/null @@ -1,229 +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.shared.clocks - -import android.content.Context -import android.database.ContentObserver -import android.graphics.drawable.Drawable -import android.net.Uri -import android.os.Handler -import android.provider.Settings -import android.util.Log -import androidx.annotation.OpenForTesting -import com.android.internal.annotations.Keep -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId -import com.android.systemui.plugins.ClockMetadata -import com.android.systemui.plugins.ClockProvider -import com.android.systemui.plugins.ClockProviderPlugin -import com.android.systemui.plugins.PluginListener -import com.android.systemui.shared.plugins.PluginManager -import org.json.JSONObject - -private val TAG = ClockRegistry::class.simpleName -private const val DEBUG = true - -/** ClockRegistry aggregates providers and plugins */ -open class ClockRegistry( - val context: Context, - val pluginManager: PluginManager, - val handler: Handler, - val isEnabled: Boolean, - userHandle: Int, - defaultClockProvider: ClockProvider, - val fallbackClockId: ClockId = DEFAULT_CLOCK_ID, -) { - // Usually this would be a typealias, but a SAM provides better java interop - fun interface ClockChangeListener { - fun onClockChanged() - } - - private val availableClocks = mutableMapOf() - private val clockChangeListeners = mutableListOf() - private val settingObserver = object : ContentObserver(handler) { - override fun onChange(selfChange: Boolean, uris: Collection, flags: Int, userId: Int) = - clockChangeListeners.forEach { it.onClockChanged() } - } - - private val pluginListener = object : PluginListener { - override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) = - connectClocks(plugin) - - override fun onPluginDisconnected(plugin: ClockProviderPlugin) = - disconnectClocks(plugin) - } - - open var currentClockId: ClockId - get() { - return try { - val json = Settings.Secure.getString( - context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE - ) - if (json == null || json.isEmpty()) { - return fallbackClockId - } - ClockSetting.deserialize(json).clockId - } catch (ex: Exception) { - Log.e(TAG, "Failed to parse clock setting", ex) - fallbackClockId - } - } - set(value) { - try { - val json = ClockSetting.serialize(ClockSetting(value, System.currentTimeMillis())) - Settings.Secure.putString( - context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json - ) - } catch (ex: Exception) { - Log.e(TAG, "Failed to set clock setting", ex) - } - } - - init { - connectClocks(defaultClockProvider) - if (!availableClocks.containsKey(DEFAULT_CLOCK_ID)) { - throw IllegalArgumentException( - "$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID" - ) - } - - if (isEnabled) { - pluginManager.addPluginListener( - pluginListener, - ClockProviderPlugin::class.java, - /*allowMultiple=*/ true - ) - context.contentResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), - /*notifyForDescendants=*/ false, - settingObserver, - userHandle - ) - } - } - - private fun connectClocks(provider: ClockProvider) { - val currentId = currentClockId - for (clock in provider.getClocks()) { - val id = clock.clockId - val current = availableClocks[id] - if (current != null) { - Log.e( - TAG, - "Clock Id conflict: $id is registered by both " + - "${provider::class.simpleName} and ${current.provider::class.simpleName}" - ) - return - } - - availableClocks[id] = ClockInfo(clock, provider) - if (DEBUG) { - Log.i(TAG, "Added ${clock.clockId}") - } - - if (currentId == id) { - if (DEBUG) { - Log.i(TAG, "Current clock ($currentId) was connected") - } - clockChangeListeners.forEach { it.onClockChanged() } - } - } - } - - private fun disconnectClocks(provider: ClockProvider) { - val currentId = currentClockId - for (clock in provider.getClocks()) { - availableClocks.remove(clock.clockId) - if (DEBUG) { - Log.i(TAG, "Removed ${clock.clockId}") - } - - if (currentId == clock.clockId) { - Log.w(TAG, "Current clock ($currentId) was disconnected") - clockChangeListeners.forEach { it.onClockChanged() } - } - } - } - - @OpenForTesting - open fun getClocks(): List { - if (!isEnabled) { - return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) - } - return availableClocks.map { (_, clock) -> clock.metadata } - } - - fun getClockThumbnail(clockId: ClockId): Drawable? = - availableClocks[clockId]?.provider?.getClockThumbnail(clockId) - - fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId) - - fun registerClockChangeListener(listener: ClockChangeListener) = - clockChangeListeners.add(listener) - - fun unregisterClockChangeListener(listener: ClockChangeListener) = - clockChangeListeners.remove(listener) - - fun createCurrentClock(): ClockController { - val clockId = currentClockId - if (isEnabled && clockId.isNotEmpty()) { - val clock = createClock(clockId) - if (clock != null) { - if (DEBUG) { - Log.i(TAG, "Rendering clock $clockId") - } - return clock - } else { - Log.e(TAG, "Clock $clockId not found; using default") - } - } - - return createClock(DEFAULT_CLOCK_ID)!! - } - - private fun createClock(clockId: ClockId): ClockController? = - availableClocks[clockId]?.provider?.createClock(clockId) - - private data class ClockInfo( - val metadata: ClockMetadata, - val provider: ClockProvider - ) - - @Keep - data class ClockSetting( - val clockId: ClockId, - val _applied_timestamp: Long? - ) { - companion object { - private val KEY_CLOCK_ID = "clockId" - private val KEY_TIMESTAMP = "_applied_timestamp" - - fun serialize(setting: ClockSetting): String { - return JSONObject() - .put(KEY_CLOCK_ID, setting.clockId) - .put(KEY_TIMESTAMP, setting._applied_timestamp) - .toString() - } - - fun deserialize(jsonStr: String): ClockSetting { - val json = JSONObject(jsonStr) - return ClockSetting( - json.getString(KEY_CLOCK_ID), - if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null) - } - } - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt deleted file mode 100644 index 23a7271afbdb..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ /dev/null @@ -1,272 +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.shared.clocks - -import android.content.Context -import android.content.res.Resources -import android.graphics.Color -import android.graphics.Rect -import android.icu.text.NumberFormat -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.widget.FrameLayout -import androidx.annotation.VisibleForTesting -import com.android.systemui.plugins.ClockAnimations -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockEvents -import com.android.systemui.plugins.ClockFaceController -import com.android.systemui.plugins.ClockFaceEvents -import com.android.systemui.plugins.log.LogBuffer -import com.android.systemui.shared.R -import java.io.PrintWriter -import java.util.Locale -import java.util.TimeZone - -private val TAG = DefaultClockController::class.simpleName - -/** - * Controls the default clock visuals. - * - * This serves as an adapter between the clock interface and the AnimatableClockView used by the - * existing lockscreen clock. - */ -class DefaultClockController( - ctx: Context, - private val layoutInflater: LayoutInflater, - private val resources: Resources, -) : ClockController { - override val smallClock: DefaultClockFaceController - override val largeClock: LargeClockFaceController - private val clocks: List - - private val burmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my")) - private val burmeseNumerals = burmeseNf.format(FORMAT_NUMBER.toLong()) - private val burmeseLineSpacing = - resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese) - private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale) - - override val events: DefaultClockEvents - override lateinit var animations: DefaultClockAnimations - private set - - init { - val parent = FrameLayout(ctx) - smallClock = - DefaultClockFaceController( - layoutInflater.inflate(R.layout.clock_default_small, parent, false) - as AnimatableClockView - ) - largeClock = - LargeClockFaceController( - layoutInflater.inflate(R.layout.clock_default_large, parent, false) - as AnimatableClockView - ) - clocks = listOf(smallClock.view, largeClock.view) - - events = DefaultClockEvents() - animations = DefaultClockAnimations(0f, 0f) - events.onLocaleChanged(Locale.getDefault()) - } - - override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) { - largeClock.recomputePadding(null) - animations = DefaultClockAnimations(dozeFraction, foldFraction) - events.onColorPaletteChanged(resources) - events.onTimeZoneChanged(TimeZone.getDefault()) - events.onTimeTick() - } - - override fun setLogBuffer(logBuffer: LogBuffer) { - smallClock.view.tag = "smallClockView" - largeClock.view.tag = "largeClockView" - smallClock.view.logBuffer = logBuffer - largeClock.view.logBuffer = logBuffer - } - - open inner class DefaultClockFaceController( - override val view: AnimatableClockView, - ) : ClockFaceController { - - // MAGENTA is a placeholder, and will be assigned correctly in initialize - private var currentColor = Color.MAGENTA - private var isRegionDark = false - protected var targetRegion: Rect? = null - - init { - view.setColors(currentColor, currentColor) - } - - override val events = - object : ClockFaceEvents { - override fun onRegionDarknessChanged(isRegionDark: Boolean) { - this@DefaultClockFaceController.isRegionDark = isRegionDark - updateColor() - } - - override fun onTargetRegionChanged(targetRegion: Rect?) { - this@DefaultClockFaceController.targetRegion = targetRegion - recomputePadding(targetRegion) - } - - override fun onFontSettingChanged(fontSizePx: Float) { - view.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSizePx) - recomputePadding(targetRegion) - } - } - - open fun recomputePadding(targetRegion: Rect?) {} - - fun updateColor() { - val color = - if (isRegionDark) { - resources.getColor(android.R.color.system_accent1_100) - } else { - resources.getColor(android.R.color.system_accent2_600) - } - - if (currentColor == color) { - return - } - - currentColor = color - view.setColors(DOZE_COLOR, color) - if (!animations.dozeState.isActive) { - view.animateAppearOnLockscreen() - } - } - } - - inner class LargeClockFaceController( - view: AnimatableClockView, - ) : DefaultClockFaceController(view) { - override fun recomputePadding(targetRegion: Rect?) { - // We center the view within the targetRegion instead of within the parent - // view by computing the difference and adding that to the padding. - val parent = view.parent - val yDiff = - if (targetRegion != null && parent is View && parent.isLaidOut()) - targetRegion.centerY() - parent.height / 2f - else 0f - val lp = view.getLayoutParams() as FrameLayout.LayoutParams - lp.topMargin = (-0.5f * view.bottom + yDiff).toInt() - view.setLayoutParams(lp) - } - - fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) { - view.moveForSplitShade(fromRect, toRect, fraction) - } - } - - inner class DefaultClockEvents : ClockEvents { - override fun onTimeTick() = clocks.forEach { it.refreshTime() } - - override fun onTimeFormatChanged(is24Hr: Boolean) = - clocks.forEach { it.refreshFormat(is24Hr) } - - override fun onTimeZoneChanged(timeZone: TimeZone) = - clocks.forEach { it.onTimeZoneChanged(timeZone) } - - override fun onColorPaletteChanged(resources: Resources) { - largeClock.updateColor() - smallClock.updateColor() - } - - override fun onLocaleChanged(locale: Locale) { - val nf = NumberFormat.getInstance(locale) - if (nf.format(FORMAT_NUMBER.toLong()) == burmeseNumerals) { - clocks.forEach { it.setLineSpacingScale(burmeseLineSpacing) } - } else { - clocks.forEach { it.setLineSpacingScale(defaultLineSpacing) } - } - - clocks.forEach { it.refreshFormat() } - } - } - - inner class DefaultClockAnimations( - dozeFraction: Float, - foldFraction: Float, - ) : ClockAnimations { - internal val dozeState = AnimationState(dozeFraction) - private val foldState = AnimationState(foldFraction) - - init { - if (foldState.isActive) { - clocks.forEach { it.animateFoldAppear(false) } - } else { - clocks.forEach { it.animateDoze(dozeState.isActive, false) } - } - } - - override fun enter() { - if (!dozeState.isActive) { - clocks.forEach { it.animateAppearOnLockscreen() } - } - } - - override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } } - - override fun fold(fraction: Float) { - val (hasChanged, hasJumped) = foldState.update(fraction) - if (hasChanged) { - clocks.forEach { it.animateFoldAppear(!hasJumped) } - } - } - - override fun doze(fraction: Float) { - val (hasChanged, hasJumped) = dozeState.update(fraction) - if (hasChanged) { - clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) } - } - } - - override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) { - largeClock.moveForSplitShade(fromRect, toRect, fraction) - } - - override val hasCustomPositionUpdatedAnimation: Boolean - get() = true - } - - class AnimationState( - var fraction: Float, - ) { - var isActive: Boolean = fraction > 0.5f - fun update(newFraction: Float): Pair { - if (newFraction == fraction) { - return Pair(isActive, false) - } - val wasActive = isActive - val hasJumped = - (fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f) - isActive = newFraction > fraction - fraction = newFraction - return Pair(wasActive != isActive, hasJumped) - } - } - - override fun dump(pw: PrintWriter) { - pw.print("smallClock=") - smallClock.view.dump(pw) - - pw.print("largeClock=") - largeClock.view.dump(pw) - } - - companion object { - @VisibleForTesting const val DOZE_COLOR = Color.WHITE - private const val FORMAT_NUMBER = 1234567890 - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt deleted file mode 100644 index 6627c5d8a1c5..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ /dev/null @@ -1,57 +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.shared.clocks - -import android.content.Context -import android.content.res.Resources -import android.graphics.drawable.Drawable -import android.view.LayoutInflater -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId -import com.android.systemui.plugins.ClockMetadata -import com.android.systemui.plugins.ClockProvider -import com.android.systemui.shared.R -import javax.inject.Inject - -private val TAG = DefaultClockProvider::class.simpleName -const val DEFAULT_CLOCK_NAME = "Default Clock" -const val DEFAULT_CLOCK_ID = "DEFAULT" - -/** Provides the default system clock */ -class DefaultClockProvider @Inject constructor( - val ctx: Context, - val layoutInflater: LayoutInflater, - @Main val resources: Resources -) : ClockProvider { - override fun getClocks(): List = - listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME)) - - override fun createClock(id: ClockId): ClockController { - if (id != DEFAULT_CLOCK_ID) { - throw IllegalArgumentException("$id is unsupported by $TAG") - } - - return DefaultClockController(ctx, layoutInflater, resources) - } - - override fun getClockThumbnail(id: ClockId): Drawable? { - if (id != DEFAULT_CLOCK_ID) { - throw IllegalArgumentException("$id is unsupported by $TAG") - } - - // TODO: Update placeholder to actual resource - return resources.getDrawable(R.drawable.clock_default_thumbnail, null) - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java index 9ea4b578ad3b..e226d58203f4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException; import java.util.ArrayList; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java deleted file mode 100644 index c89be869115b..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui.shared.plugins; - -import android.text.TextUtils; - -import com.android.systemui.plugins.Plugin; -import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.annotations.ProvidesInterface; - -public interface PluginManager { - - String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED"; - - // must be one of the channels created in NotificationChannels.java - String NOTIFICATION_CHANNEL_ID = "ALR"; - - /** Returns plugins that don't get disabled when an exceptoin occurs. */ - String[] getPrivilegedPlugins(); - - /** */ - void addPluginListener(PluginListener listener, Class cls); - /** */ - void addPluginListener(PluginListener listener, Class cls, - boolean allowMultiple); - void addPluginListener(String action, PluginListener listener, - Class cls); - void addPluginListener(String action, PluginListener listener, - Class cls, boolean allowMultiple); - - void removePluginListener(PluginListener listener); - - boolean dependsOn(Plugin p, Class cls); - - class Helper { - public static

String getAction(Class

cls) { - ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); - if (info == null) { - throw new RuntimeException(cls + " doesn't provide an interface"); - } - if (TextUtils.isEmpty(info.action())) { - throw new RuntimeException(cls + " doesn't provide an action"); - } - return info.action(); - } - } - -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java index 131f728be3f1..2f9f5b2ac938 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java @@ -31,6 +31,7 @@ import android.widget.Toast; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager; import java.io.FileDescriptor; diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java index ad9609f9ec42..122c52138b08 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java @@ -39,8 +39,8 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManager.DockEventListener; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import java.util.ArrayList; import java.util.Collection; diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index b514f60efc7d..676979cd3931 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -17,8 +17,10 @@ package com.android.keyguard.dagger; import android.content.Context; +import android.content.res.Resources; import android.os.Handler; import android.os.UserHandle; +import android.view.LayoutInflater; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; @@ -26,9 +28,9 @@ import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.shared.clocks.ClockRegistry; import com.android.systemui.shared.clocks.DefaultClockProvider; -import com.android.systemui.shared.plugins.PluginManager; import dagger.Module; import dagger.Provides; @@ -43,15 +45,16 @@ public abstract class ClockRegistryModule { @Application Context context, PluginManager pluginManager, @Main Handler handler, - DefaultClockProvider defaultClockProvider, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + @Main Resources resources, + LayoutInflater layoutInflater) { return new ClockRegistry( context, pluginManager, handler, featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS), UserHandle.USER_ALL, - defaultClockProvider, + new DefaultClockProvider(context, layoutInflater, resources), context.getString(R.string.lockscreen_clock_id_fallback)); } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 51bcd6b18936..ef16a3a3c63d 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -61,6 +61,7 @@ import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; @@ -72,7 +73,6 @@ import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.DevicePolicyManagerWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java index 95f666c5d0eb..1bb03291996d 100644 --- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java +++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java @@ -21,8 +21,8 @@ import android.util.Log; import android.view.View; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.ViewProvider; -import com.android.systemui.shared.plugins.PluginManager; /** * Define an interface or abstract class as follows that includes the diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index c4723e895ee7..5c905df25bbf 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -29,7 +29,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingPlugin; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.util.DeviceConfigProxy; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index e8d7e4642e3e..f8bd1e712b1b 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -27,7 +27,7 @@ import com.android.systemui.doze.dagger.DozeComponent; import com.android.systemui.plugins.DozeServicePlugin; import com.android.systemui.plugins.DozeServicePlugin.RequestDoze; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index ed1e018c681a..cb0f3e26c6a7 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -69,9 +69,9 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.NavigationEdgeBackPlugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.shared.system.QuickStepContract; diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java index 0b565ea25911..e6575d5ab9fa 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java @@ -18,7 +18,6 @@ import android.util.ArrayMap; import com.android.systemui.Dependency; import com.android.systemui.plugins.PluginDependency.DependencyProvider; -import com.android.systemui.shared.plugins.PluginManager; import javax.inject.Inject; import javax.inject.Singleton; diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java index 638f81b71a34..146633d0d9f0 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java @@ -27,7 +27,6 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.plugins.PluginActionManager; import com.android.systemui.shared.plugins.PluginEnabler; import com.android.systemui.shared.plugins.PluginInstance; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.plugins.PluginPrefs; import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index f37d66877069..6240c10a9d5b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -41,6 +41,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.nano.SystemUIProtoDump; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTileView; @@ -53,7 +54,6 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.nano.QsTileState; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java index 824d3a3f5af1..56b689efaa79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java @@ -31,7 +31,7 @@ import android.util.Log; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.PipelineDumpable; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 842526ee0371..7b53925adbce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -33,9 +33,9 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.FeedbackIcon; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index a592da47a0d5..bc2ee1fd4f7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -168,6 +168,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.OverlayPlugin; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -183,7 +184,6 @@ import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shade.ShadeExpansionStateManager; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CircleReveal; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java index 3811689a2295..4fe03017dc24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java @@ -25,7 +25,7 @@ import android.service.notification.StatusBarNotification; import com.android.systemui.plugins.NotificationListenerController; import com.android.systemui.plugins.NotificationListenerController.NotificationProvider; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java index 4c6c7e0f6c0f..3d0e69cc96da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java @@ -22,7 +22,7 @@ import android.util.ArrayMap; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java index 26cc6ba38178..f3b9cc12713c 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java @@ -25,8 +25,8 @@ import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.ToastPlugin; -import com.android.systemui.shared.plugins.PluginManager; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java index fe183fc9e872..49995155f251 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -38,9 +38,9 @@ import com.android.internal.util.ArrayUtils; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.PluginEnablerImpl; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginActionManager; import com.android.systemui.shared.plugins.PluginEnabler; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginPrefs; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java index 48759824f5ef..9b06a37e681f 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java @@ -31,8 +31,8 @@ import android.util.Log; import com.android.internal.util.Preconditions; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.SensorManagerPlugin; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.concurrency.ThreadFactory; import java.util.ArrayList; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java index 27701be66761..7a5b772e2f1b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java @@ -36,8 +36,8 @@ import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.plugins.ClockPlugin; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index c452872a527e..fb1a720b82f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -54,6 +54,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.nano.SystemUIProtoDump; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -66,7 +67,6 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 213eca895eb9..25c95ef58d85 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -42,12 +42,12 @@ import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserFileManager; import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.CentralSurfaces; diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 28bd26a9094b..4d7741addc37 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -28,7 +28,7 @@ import com.android.systemui.plugins.ClockId import com.android.systemui.plugins.ClockMetadata import com.android.systemui.plugins.ClockProviderPlugin import com.android.systemui.plugins.PluginListener -import com.android.systemui.shared.plugins.PluginManager +import com.android.systemui.plugins.PluginManager import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import junit.framework.Assert.assertEquals diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java index 5e11858c7653..34126798e87e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java @@ -37,7 +37,7 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.NotificationListener.NotificationHandler; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 157b99dd3ef4..013e7278753d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -109,6 +109,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.PluginDependencyProvider; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.settings.brightness.BrightnessSliderController; @@ -120,7 +121,6 @@ import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeControllerImpl; import com.android.systemui.shade.ShadeExpansionStateManager; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java index 14cc032b1cec..71ac7c48d5ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java @@ -33,7 +33,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.OverlayPlugin; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.statusbar.policy.ExtensionController.Extension; import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory; diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java index 797f86ae14c2..27957ed06d11 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java @@ -62,7 +62,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java index 0d8dd2c0f140..df08efaf16d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java @@ -28,8 +28,8 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.SensorManagerPlugin; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; import com.android.systemui.util.time.FakeSystemClock; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakePluginManager.java index d245c727dcf8..63756c6478f2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakePluginManager.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakePluginManager.java @@ -18,7 +18,7 @@ import android.testing.LeakCheck; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; public class FakePluginManager implements PluginManager { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java index dc6a8fb9a4c4..ec1f352e1439 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java @@ -18,7 +18,7 @@ import android.testing.LeakCheck; import android.util.ArrayMap; import com.android.systemui.SysuiTestCase; -import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.phone.StatusBarIconController; -- cgit v1.2.3-59-g8ed1b