mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 11:18:21 +00:00
210 lines
7.9 KiB
Kotlin
210 lines
7.9 KiB
Kotlin
/*
|
|
* Copyright (C) 2023 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.launcher3.taskbar
|
|
|
|
import android.graphics.PorterDuff.Mode.SRC_ATOP
|
|
import android.graphics.PorterDuffColorFilter
|
|
import android.view.View
|
|
import android.view.View.GONE
|
|
import android.view.View.VISIBLE
|
|
import android.view.ViewGroup
|
|
import androidx.annotation.IntDef
|
|
import androidx.annotation.LayoutRes
|
|
import com.airbnb.lottie.LottieAnimationView
|
|
import com.airbnb.lottie.LottieProperty.COLOR_FILTER
|
|
import com.airbnb.lottie.model.KeyPath
|
|
import com.android.launcher3.R
|
|
import com.android.launcher3.Utilities
|
|
import com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS
|
|
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_EDU_TOOLTIP
|
|
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
|
|
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
|
|
import com.android.launcher3.util.DisplayController
|
|
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
|
|
import java.io.PrintWriter
|
|
|
|
/** First EDU step for swiping up to show transient Taskbar. */
|
|
const val TOOLTIP_STEP_SWIPE = 0
|
|
/** Second EDU step for explaining Taskbar functionality when unstashed. */
|
|
const val TOOLTIP_STEP_FEATURES = 1
|
|
/**
|
|
* EDU is completed.
|
|
*
|
|
* This value should match the maximum count for [TASKBAR_EDU_TOOLTIP_STEP].
|
|
*/
|
|
const val TOOLTIP_STEP_NONE = 2
|
|
|
|
/** Current step in the tooltip EDU flow. */
|
|
@Retention(AnnotationRetention.SOURCE)
|
|
@IntDef(TOOLTIP_STEP_SWIPE, TOOLTIP_STEP_FEATURES, TOOLTIP_STEP_NONE)
|
|
annotation class TaskbarEduTooltipStep
|
|
|
|
/** Controls stepping through the Taskbar tooltip EDU. */
|
|
class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
|
|
LoggableTaskbarController {
|
|
|
|
private val isTooltipEnabled = !IS_RUNNING_IN_TEST_HARNESS && ENABLE_TASKBAR_EDU_TOOLTIP.get()
|
|
private val isOpen: Boolean
|
|
get() = tooltip?.isOpen ?: false
|
|
|
|
private lateinit var controllers: TaskbarControllers
|
|
|
|
@TaskbarEduTooltipStep
|
|
var tooltipStep: Int
|
|
get() {
|
|
return activityContext.onboardingPrefs?.getCount(TASKBAR_EDU_TOOLTIP_STEP)
|
|
?: TOOLTIP_STEP_NONE
|
|
}
|
|
private set(step) {
|
|
activityContext.onboardingPrefs?.setEventCount(step, TASKBAR_EDU_TOOLTIP_STEP)
|
|
}
|
|
|
|
private var tooltip: TaskbarEduTooltip? = null
|
|
|
|
fun init(controllers: TaskbarControllers) {
|
|
this.controllers = controllers
|
|
}
|
|
|
|
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
|
|
fun maybeShowSwipeEdu() {
|
|
if (
|
|
!isTooltipEnabled ||
|
|
!DisplayController.isTransientTaskbar(activityContext) ||
|
|
tooltipStep > TOOLTIP_STEP_SWIPE
|
|
) {
|
|
return
|
|
}
|
|
|
|
tooltipStep = TOOLTIP_STEP_FEATURES
|
|
inflateTooltip(R.layout.taskbar_edu_swipe)
|
|
tooltip?.run {
|
|
findViewById<LottieAnimationView>(R.id.swipe_animation).supportLightTheme()
|
|
show()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shows feature EDU tooltip if this step has not been seen.
|
|
*
|
|
* If [TOOLTIP_STEP_SWIPE] has not been seen at this point, the first step is skipped because a
|
|
* swipe up is necessary to show this step.
|
|
*/
|
|
fun maybeShowFeaturesEdu() {
|
|
if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
|
|
return
|
|
}
|
|
|
|
tooltipStep = TOOLTIP_STEP_NONE
|
|
inflateTooltip(R.layout.taskbar_edu_features)
|
|
tooltip?.run {
|
|
val splitscreenAnim = findViewById<LottieAnimationView>(R.id.splitscreen_animation)
|
|
val suggestionsAnim = findViewById<LottieAnimationView>(R.id.suggestions_animation)
|
|
val settingsAnim = findViewById<LottieAnimationView>(R.id.settings_animation)
|
|
val settingsEdu = findViewById<View>(R.id.settings_edu)
|
|
splitscreenAnim.supportLightTheme()
|
|
suggestionsAnim.supportLightTheme()
|
|
settingsAnim.supportLightTheme()
|
|
if (DisplayController.isTransientTaskbar(activityContext)) {
|
|
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
|
|
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
|
|
settingsEdu.visibility = GONE
|
|
} else {
|
|
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_persistent)
|
|
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_persistent)
|
|
settingsEdu.visibility = VISIBLE
|
|
}
|
|
|
|
findViewById<View>(R.id.done_button)?.setOnClickListener { hide() }
|
|
if (DisplayController.isTransientTaskbar(activityContext)) {
|
|
(layoutParams as ViewGroup.MarginLayoutParams).bottomMargin +=
|
|
activityContext.deviceProfile.taskbarSize
|
|
}
|
|
show()
|
|
}
|
|
}
|
|
|
|
/** Closes the current [tooltip]. */
|
|
fun hide() = tooltip?.close(true)
|
|
|
|
/** Initializes [tooltip] with content from [contentResId]. */
|
|
private fun inflateTooltip(@LayoutRes contentResId: Int) {
|
|
val overlayContext = controllers.taskbarOverlayController.requestWindow()
|
|
val tooltip =
|
|
overlayContext.layoutInflater.inflate(
|
|
R.layout.taskbar_edu_tooltip,
|
|
overlayContext.dragLayer,
|
|
false
|
|
) as TaskbarEduTooltip
|
|
|
|
controllers.taskbarAutohideSuspendController.updateFlag(
|
|
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
|
|
true
|
|
)
|
|
tooltip.onCloseCallback = {
|
|
this.tooltip = null
|
|
controllers.taskbarAutohideSuspendController.updateFlag(
|
|
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
|
|
false
|
|
)
|
|
controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true)
|
|
}
|
|
|
|
overlayContext.layoutInflater.inflate(contentResId, tooltip.content, true)
|
|
this.tooltip = tooltip
|
|
}
|
|
|
|
override fun dumpLogs(prefix: String?, pw: PrintWriter?) {
|
|
pw?.println(prefix + "TaskbarEduTooltipController:")
|
|
pw?.println("$prefix\tisTooltipEnabled=$isTooltipEnabled")
|
|
pw?.println("$prefix\tisOpen=$isOpen")
|
|
pw?.println("$prefix\ttooltipStep=$tooltipStep")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Maps colors in the dark-themed Lottie assets to their light-themed equivalents.
|
|
*
|
|
* For instance, `".blue100" to R.color.lottie_blue400` means objects that are material blue100 in
|
|
* dark theme should be changed to material blue400 in light theme.
|
|
*/
|
|
private val DARK_TO_LIGHT_COLORS =
|
|
mapOf(
|
|
".blue100" to R.color.lottie_blue400,
|
|
".blue400" to R.color.lottie_blue600,
|
|
".green100" to R.color.lottie_green400,
|
|
".green400" to R.color.lottie_green600,
|
|
".grey300" to R.color.lottie_grey600,
|
|
".grey400" to R.color.lottie_grey700,
|
|
".grey800" to R.color.lottie_grey200,
|
|
".red400" to R.color.lottie_red600,
|
|
".yellow100" to R.color.lottie_yellow400,
|
|
".yellow400" to R.color.lottie_yellow600,
|
|
)
|
|
|
|
private fun LottieAnimationView.supportLightTheme() {
|
|
if (Utilities.isDarkTheme(context)) {
|
|
return
|
|
}
|
|
|
|
addLottieOnCompositionLoadedListener {
|
|
DARK_TO_LIGHT_COLORS.forEach { (key, color) ->
|
|
addValueCallback(KeyPath("**", key, "**"), COLOR_FILTER) {
|
|
PorterDuffColorFilter(context.getColor(color), SRC_ATOP)
|
|
}
|
|
}
|
|
}
|
|
}
|