1 /*
2  * Copyright 2024 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.photopicker.core.theme
18 
19 import android.content.Intent
20 import android.provider.MediaStore
21 import androidx.compose.ui.graphics.Color
22 import androidx.test.ext.junit.runners.AndroidJUnit4
23 import androidx.test.filters.SmallTest
24 import com.google.common.truth.Truth.assertThat
25 import org.junit.Assert
26 import org.junit.Test
27 import org.junit.runner.RunWith
28 
29 @SmallTest
30 @RunWith(AndroidJUnit4::class)
31 class AccentColorHelperTest {
32     @Test
testAccentColorHelper_differentIntentActions_accentColorsNotSetnull33     fun testAccentColorHelper_differentIntentActions_accentColorsNotSet() {
34         // helper class reads colors from input intent and validates it.
35         // create input intent:
36         var pickerIntent = Intent()
37         val validAccentColor: Long = 0xFF0000
38 
39         // Verify that the helper does not work with [MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP]
40         // intent action.
41         pickerIntent.setAction(MediaStore.ACTION_USER_SELECT_IMAGES_FOR_APP)
42         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, validAccentColor)
43         assertExceptionThrownDueToInvalidInput(pickerIntent)
44 
45         // Verify that the helper does not work with [Intent.ACTION_GET_CONTENT] intent action.
46         pickerIntent.setAction(Intent.ACTION_GET_CONTENT)
47         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, validAccentColor)
48         assertExceptionThrownDueToInvalidInput(pickerIntent)
49 
50         // Verify that the helper does not work with [Intent.ACTION_GET_CONTENT] intent action.
51         pickerIntent.setAction(MediaStore.ACTION_PICK_IMAGES)
52         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, validAccentColor)
53         val accentColorHelperPickImagesMode = AccentColorHelper.withIntent(pickerIntent)
54         assertThat(accentColorHelperPickImagesMode.getAccentColor()).isNotEqualTo(Color.Unspecified)
55         assertThat(accentColorHelperPickImagesMode.getAccentColor())
56             .isEqualTo(
57                 createColorFromLongFormat(validAccentColor),
58             )
59     }
60 
61     @Test
testAccentColorHelper_invalidInputColors_accentColorsNotSetnull62     fun testAccentColorHelper_invalidInputColors_accentColorsNotSet() {
63         // helper class reads colors from input intent and validates it.
64         // create input intent:
65         var pickerIntent = Intent(MediaStore.ACTION_PICK_IMAGES)
66         val invalidInputColor: Long = 0
67         val colorWithLowLuminance: Long = 0xFFFFF0 // a color close to white
68         val colorWithHighLuminance: Long = 0x000001 // a color close to black
69 
70         // Verify that the helper does not work with invalid colors
71 
72         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, invalidInputColor)
73         assertExceptionThrownDueToInvalidInput(pickerIntent)
74 
75         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, colorWithLowLuminance)
76         assertExceptionThrownDueToInvalidInput(pickerIntent)
77 
78         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, colorWithHighLuminance)
79         assertExceptionThrownDueToInvalidInput(pickerIntent)
80     }
81 
82     @Test
testAccentColorHelper_validInputColor_accentColorsSetnull83     fun testAccentColorHelper_validInputColor_accentColorsSet() {
84         // helper class reads colors from input intent and validates it.
85         // create input intent:
86         var pickerIntent = Intent(MediaStore.ACTION_PICK_IMAGES)
87         val validAccentColor: Long = 0xFF0000
88 
89         // Verify that the helper works with valid color
90         pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR, validAccentColor)
91         val accentColorHelperInvalidInputColor = AccentColorHelper.withIntent(pickerIntent)
92         assertThat(accentColorHelperInvalidInputColor.getAccentColor())
93             .isNotEqualTo(Color.Unspecified)
94         assertThat(accentColorHelperInvalidInputColor.getAccentColor())
95             .isEqualTo(
96                 createColorFromLongFormat(validAccentColor),
97             )
98     }
99 
100     @Test
testAccentColorHelper_textColorAlwaysUnspecifiedIfAccentColorUnspecifiednull101     fun testAccentColorHelper_textColorAlwaysUnspecifiedIfAccentColorUnspecified() {
102 
103         // Intent with no custom color set
104         var pickerIntent = Intent(MediaStore.ACTION_PICK_IMAGES)
105 
106         val accentColorHelper = AccentColorHelper.withIntent(pickerIntent)
107         assertThat(accentColorHelper.getAccentColor()).isEqualTo(Color.Unspecified)
108         assertThat(accentColorHelper.getTextColorForAccentComponents()).isEqualTo(Color.Unspecified)
109     }
110 
111     @Test
testAccentColorHelper_textColorForDifferentLuminance_changesAccordinglynull112     fun testAccentColorHelper_textColorForDifferentLuminance_changesAccordingly() {
113         // helper class reads colors from input intent and validates it.
114         // create input intent:
115         var pickerIntent = Intent(MediaStore.ACTION_PICK_IMAGES)
116         val validAccentColorWithHighLuminance: Long = 0x144F28 // dark green
117         val validAccentColorWithLowLuminance: Long = 0xd6E0D7 // light pink
118 
119         // Verify that the helper works with validAccentColorWithHighLuminance. In this case the
120         // text color set should be white since the accent color is dark.
121         pickerIntent.putExtra(
122             MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR,
123             validAccentColorWithHighLuminance
124         )
125         val accentColorHelperHighLuminance = AccentColorHelper.withIntent(pickerIntent)
126         assertThat(accentColorHelperHighLuminance.getAccentColor()).isNotEqualTo(Color.Unspecified)
127         assertThat(accentColorHelperHighLuminance.getAccentColor())
128             .isEqualTo(
129                 createColorFromLongFormat(validAccentColorWithHighLuminance),
130             )
131         assertThat(accentColorHelperHighLuminance.getTextColorForAccentComponents())
132             .isEqualTo(
133                 Color.White,
134             )
135 
136         // Verify that the helper works with validAccentColorWithLowLuminance. In this case the
137         // text color set should be black since the accent color is light.
138         pickerIntent.putExtra(
139             MediaStore.EXTRA_PICK_IMAGES_ACCENT_COLOR,
140             validAccentColorWithLowLuminance
141         )
142         val accentColorHelperLowLuminance = AccentColorHelper.withIntent(pickerIntent)
143         assertThat(accentColorHelperLowLuminance.getAccentColor()).isNotEqualTo(Color.Unspecified)
144         assertThat(accentColorHelperLowLuminance.getAccentColor())
145             .isEqualTo(
146                 createColorFromLongFormat(validAccentColorWithLowLuminance),
147             )
148         assertThat(accentColorHelperLowLuminance.getTextColorForAccentComponents())
149             .isEqualTo(
150                 Color.Black,
151             )
152     }
153 
createColorFromLongFormatnull154     private fun createColorFromLongFormat(color: Long): Color {
155         // Gives us the formatted color string where the mask gives us the color in the RRGGBB
156         // format and the %06X gives zero-padded hex (6 characters long)
157         val hexColor = String.format("#%06X", (0xFFFFFF.toLong() and color))
158         val inputColor = android.graphics.Color.parseColor(hexColor)
159         return Color(inputColor)
160     }
161 
assertExceptionThrownDueToInvalidInputnull162     private fun assertExceptionThrownDueToInvalidInput(pickerIntent: Intent) {
163         try {
164             AccentColorHelper.withIntent(pickerIntent)
165             Assert.fail("Should have failed since the input was invalid")
166         } catch (exception: IllegalArgumentException) {
167             // expected result, yippee!!
168         }
169     }
170 }
171