1 /*
2  * Copyright (C) 2021 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 
17 package com.android.systemui.controls.ui
18 
19 import android.app.PendingIntent
20 import android.content.ComponentName
21 import android.content.res.ColorStateList
22 import android.graphics.drawable.GradientDrawable
23 import android.graphics.drawable.Icon
24 import android.service.controls.Control
25 import android.service.controls.DeviceTypes
26 import android.service.controls.templates.ControlTemplate
27 import android.testing.TestableLooper
28 import android.view.LayoutInflater
29 import android.view.View
30 import android.view.ViewGroup
31 import androidx.test.ext.junit.runners.AndroidJUnit4
32 import androidx.test.filters.SmallTest
33 import com.android.systemui.res.R
34 import com.android.systemui.SysuiTestCase
35 import com.android.systemui.controls.ControlsMetricsLogger
36 import com.android.systemui.controls.controller.ControlInfo
37 import com.android.systemui.controls.controller.ControlsController
38 import com.android.systemui.util.concurrency.FakeExecutor
39 import com.android.systemui.util.time.FakeSystemClock
40 import com.google.common.truth.Truth.assertThat
41 import org.junit.Before
42 import org.junit.Test
43 import org.junit.runner.RunWith
44 import org.mockito.Mockito.mock
45 
46 @SmallTest
47 @RunWith(AndroidJUnit4::class)
48 @TestableLooper.RunWithLooper
49 class ControlViewHolderTest : SysuiTestCase() {
50 
51     private val clock = FakeSystemClock()
52 
53     private lateinit var cvh: ControlViewHolder
54     private lateinit var baseLayout: ViewGroup
55 
56     @Before
setUpnull57     fun setUp() {
58         TestableLooper.get(this).runWithLooper {
59             baseLayout = LayoutInflater.from(mContext).inflate(
60                     R.layout.controls_base_item, null, false) as ViewGroup
61 
62             cvh = ControlViewHolder(
63                     baseLayout,
64                     mock(ControlsController::class.java),
65                     FakeExecutor(clock),
66                     FakeExecutor(clock),
67                     mock(ControlActionCoordinator::class.java),
68                     mock(ControlsMetricsLogger::class.java),
69                     uid = 100,
70                     0,
71             )
72 
73             val cws = ControlWithState(
74                     ComponentName.createRelative("pkg", "cls"),
75                     ControlInfo(
76                             CONTROL_ID, CONTROL_TITLE, "subtitle", DeviceTypes.TYPE_AIR_FRESHENER
77                     ),
78                     Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)).build()
79             )
80 
81             cvh.bindData(cws, isLocked = false)
82         }
83     }
84 
85     @Test
updateStatusRow_customIconWithTint_iconTintRemainsnull86     fun updateStatusRow_customIconWithTint_iconTintRemains() {
87         val control = Control.StatelessBuilder(DEFAULT_CONTROL)
88                 .setCustomIcon(
89                         Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star)
90                                 .setTint(TINT_COLOR)
91                 )
92                 .build()
93 
94         cvh.updateStatusRow(enabled = true, CONTROL_TITLE, DRAWABLE, COLOR, control)
95 
96         assertThat(cvh.icon.imageTintList).isEqualTo(ColorStateList.valueOf(TINT_COLOR))
97     }
98 
99     @Test
updateStatusRow_customIconWithTintList_iconTintListRemainsnull100     fun updateStatusRow_customIconWithTintList_iconTintListRemains() {
101         val customIconTintList = ColorStateList.valueOf(TINT_COLOR)
102         val control = Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java))
103                 .setCustomIcon(
104                         Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star)
105                                 .setTintList(customIconTintList)
106                 )
107                 .build()
108 
109         cvh.updateStatusRow(enabled = true, CONTROL_TITLE, DRAWABLE, COLOR, control)
110 
111         assertThat(cvh.icon.imageTintList).isEqualTo(customIconTintList)
112     }
113 
114     @Test
chevronIconnull115     fun chevronIcon() {
116         val control = Control.StatefulBuilder(CONTROL_ID, mock(PendingIntent::class.java))
117             .setStatus(Control.STATUS_OK)
118             .setControlTemplate(ControlTemplate.NO_TEMPLATE)
119             .build()
120         val cws = ControlWithState(
121             ComponentName.createRelative("pkg", "cls"),
122             ControlInfo(
123                 CONTROL_ID, CONTROL_TITLE, "subtitle", DeviceTypes.TYPE_AIR_FRESHENER
124             ),
125             control
126         )
127         cvh.bindData(cws, false)
128         val chevronIcon = baseLayout.requireViewById<View>(R.id.chevron_icon)
129 
130         assertThat(chevronIcon.visibility).isEqualTo(View.VISIBLE)
131     }
132 }
133 
134 private const val CONTROL_ID = "CONTROL_ID"
135 private const val CONTROL_TITLE = "CONTROL_TITLE"
136 private const val TINT_COLOR = 0x00ff00 // Should be different from [COLOR]
137 
138 private val DRAWABLE = GradientDrawable()
139 private val COLOR = ColorStateList.valueOf(0xffff00)
140 private val DEFAULT_CONTROL = Control.StatelessBuilder(
141         CONTROL_ID, mock(PendingIntent::class.java)).build()
142