1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.wm.shell.bubbles 17 18 import android.content.Context 19 import android.graphics.Color 20 import android.graphics.Rect 21 import android.view.LayoutInflater 22 import android.view.View 23 import android.widget.Button 24 import android.widget.LinearLayout 25 import android.widget.TextView 26 import com.android.internal.util.ContrastColorUtil 27 import com.android.wm.shell.R 28 import com.android.wm.shell.animation.Interpolators 29 30 /** 31 * User education view to highlight the manage button that allows a user to configure the settings 32 * for the bubble. Shown only the first time a user expands a bubble. 33 */ 34 class ManageEducationView constructor(context: Context) : LinearLayout(context) { 35 36 private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView" 37 else BubbleDebugConfig.TAG_BUBBLES 38 39 private val ANIMATE_DURATION: Long = 200 40 private val ANIMATE_DURATION_SHORT: Long = 40 41 <lambda>null42 private val manageView by lazy { findViewById<View>(R.id.manage_education_view) } <lambda>null43 private val manageButton by lazy { findViewById<Button>(R.id.manage) } <lambda>null44 private val gotItButton by lazy { findViewById<Button>(R.id.got_it) } <lambda>null45 private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) } <lambda>null46 private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) } 47 48 private var isHiding = false 49 50 init { 51 LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this) 52 visibility = View.GONE 53 elevation = resources.getDimensionPixelSize(R.dimen.bubble_elevation).toFloat() 54 55 // BubbleStackView forces LTR by default 56 // since most of Bubble UI direction depends on positioning by the user. 57 // This view actually lays out differently in RTL, so we set layout LOCALE here. 58 layoutDirection = View.LAYOUT_DIRECTION_LOCALE 59 } 60 setLayoutDirectionnull61 override fun setLayoutDirection(layoutDirection: Int) { 62 super.setLayoutDirection(layoutDirection) 63 setDrawableDirection() 64 } 65 onFinishInflatenull66 override fun onFinishInflate() { 67 super.onFinishInflate() 68 layoutDirection = resources.configuration.layoutDirection 69 setTextColor() 70 } 71 setTextColornull72 private fun setTextColor() { 73 val typedArray = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent, 74 android.R.attr.textColorPrimaryInverse)) 75 val bgColor = typedArray.getColor(0 /* index */, Color.BLACK) 76 var textColor = typedArray.getColor(1 /* index */, Color.WHITE) 77 typedArray.recycle() 78 textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true) 79 titleTextView.setTextColor(textColor) 80 descTextView.setTextColor(textColor) 81 } 82 setDrawableDirectionnull83 private fun setDrawableDirection() { 84 manageView.setBackgroundResource( 85 if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) 86 R.drawable.bubble_stack_user_education_bg_rtl 87 else R.drawable.bubble_stack_user_education_bg) 88 } 89 90 /** 91 * If necessary, toggles the user education view for the manage button. This is shown when the 92 * bubble stack is expanded for the first time. 93 * 94 * @param show whether the user education view should show or not. 95 */ shownull96 fun show(expandedView: BubbleExpandedView, rect: Rect) { 97 if (visibility == VISIBLE) return 98 99 alpha = 0f 100 visibility = View.VISIBLE 101 post { 102 expandedView.getManageButtonBoundsOnScreen(rect) 103 104 manageButton 105 .setOnClickListener { 106 expandedView.findViewById<View>(R.id.settings_button).performClick() 107 hide(true /* isStackExpanding */) 108 } 109 gotItButton.setOnClickListener { hide(true /* isStackExpanding */) } 110 setOnClickListener { hide(true /* isStackExpanding */) } 111 112 with(manageView) { 113 translationX = 0f 114 val inset = resources.getDimensionPixelSize( 115 R.dimen.bubbles_manage_education_top_inset) 116 translationY = (rect.top - manageView.height + inset).toFloat() 117 } 118 bringToFront() 119 animate() 120 .setDuration(ANIMATE_DURATION) 121 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) 122 .alpha(1f) 123 } 124 setShouldShow(false) 125 } 126 hidenull127 fun hide(isStackExpanding: Boolean) { 128 if (visibility != VISIBLE || isHiding) return 129 130 animate() 131 .withStartAction { isHiding = true } 132 .alpha(0f) 133 .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION) 134 .withEndAction { 135 isHiding = false 136 visibility = GONE 137 } 138 } 139 setShouldShownull140 private fun setShouldShow(shouldShow: Boolean) { 141 context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE) 142 .edit().putBoolean(PREF_MANAGED_EDUCATION, !shouldShow).apply() 143 } 144 } 145 146 const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"