• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"