1 /* 2 * Copyright (C) 2023 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.google.jetpackcamera 17 18 import android.os.Build 19 import androidx.compose.ui.test.isDisplayed 20 import androidx.compose.ui.test.isEnabled 21 import androidx.compose.ui.test.junit4.createEmptyComposeRule 22 import androidx.compose.ui.test.onNodeWithTag 23 import androidx.compose.ui.test.performClick 24 import androidx.test.ext.junit.runners.AndroidJUnit4 25 import androidx.test.platform.app.InstrumentationRegistry 26 import androidx.test.rule.GrantPermissionRule 27 import androidx.test.uiautomator.UiDevice 28 import com.google.common.truth.Truth.assertThat 29 import com.google.common.truth.TruthJUnit.assume 30 import com.google.jetpackcamera.feature.preview.quicksettings.ui.QUICK_SETTINGS_DROP_DOWN 31 import com.google.jetpackcamera.feature.preview.quicksettings.ui.QUICK_SETTINGS_FLASH_BUTTON 32 import com.google.jetpackcamera.feature.preview.ui.CAPTURE_BUTTON 33 import com.google.jetpackcamera.feature.preview.ui.FLIP_CAMERA_BUTTON 34 import com.google.jetpackcamera.feature.preview.ui.IMAGE_CAPTURE_SUCCESS_TAG 35 import com.google.jetpackcamera.feature.preview.ui.SCREEN_FLASH_OVERLAY 36 import com.google.jetpackcamera.settings.model.LensFacing 37 import org.junit.Before 38 import org.junit.Rule 39 import org.junit.Test 40 import org.junit.runner.RunWith 41 42 @RunWith(AndroidJUnit4::class) 43 internal class FlashDeviceTest { 44 45 @get:Rule 46 val permissionsRule: GrantPermissionRule = 47 GrantPermissionRule.grant(*(APP_REQUIRED_PERMISSIONS).toTypedArray()) 48 49 @get:Rule 50 val composeTestRule = createEmptyComposeRule() 51 52 private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 53 54 @Before setUpnull55 fun setUp() { 56 assertThat(uiDevice.isScreenOn).isTrue() 57 } 58 59 @Test <lambda>null60 fun set_flash_on() = runScenarioTest<MainActivity> { 61 // Wait for the capture button to be displayed 62 composeTestRule.waitUntil(timeoutMillis = APP_START_TIMEOUT_MILLIS) { 63 composeTestRule.onNodeWithTag(CAPTURE_BUTTON).isDisplayed() 64 } 65 66 // Navigate to quick settings 67 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 68 .assertExists() 69 .performClick() 70 71 // Click the flash button to switch to ON 72 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 73 .assertExists() 74 .performClick() 75 76 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 77 .assertExists() 78 composeTestRule.onNodeWithContentDescription( 79 com.google.jetpackcamera.feature.preview.R.string.quick_settings_flash_on_description 80 ) 81 } 82 83 @Test <lambda>null84 fun set_flash_auto() = runScenarioTest<MainActivity> { 85 // Wait for the capture button to be displayed 86 composeTestRule.waitUntil(timeoutMillis = APP_START_TIMEOUT_MILLIS) { 87 composeTestRule.onNodeWithTag(CAPTURE_BUTTON).isDisplayed() 88 } 89 90 // Navigate to quick settings 91 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 92 .assertExists() 93 .performClick() 94 95 // Click the flash button twice to switch to AUTO 96 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 97 .assertExists() 98 .performClick() 99 .performClick() 100 101 composeTestRule.onNodeWithContentDescription( 102 com.google.jetpackcamera.feature.preview.R.string.quick_settings_flash_auto_description 103 ) 104 } 105 106 @Test <lambda>null107 fun set_flash_off() = runScenarioTest<MainActivity> { 108 // Wait for the capture button to be displayed 109 composeTestRule.waitUntil(timeoutMillis = APP_START_TIMEOUT_MILLIS) { 110 composeTestRule.onNodeWithTag(CAPTURE_BUTTON).isDisplayed() 111 } 112 113 composeTestRule.onNodeWithContentDescription( 114 com.google.jetpackcamera.feature.preview.R.string.quick_settings_flash_off_description 115 ) 116 117 // Navigate to quick settings 118 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 119 .assertExists() 120 .performClick() 121 122 // Click the flash button three times to switch to OFF 123 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 124 .assertExists() 125 .performClick() 126 .performClick() 127 .performClick() 128 129 composeTestRule.onNodeWithContentDescription( 130 com.google.jetpackcamera.feature.preview.R.string.quick_settings_flash_off_description 131 ) 132 } 133 assumeHalStableOnImageCapturenull134 private fun assumeHalStableOnImageCapture() { 135 // The GMD emulators with API <=31 will often crash the HAL when taking an image capture. 136 // See b/195122056 137 assume().that(Build.HARDWARE == "ranchu" && Build.VERSION.SDK_INT <= 31).isFalse() 138 } 139 140 @Test <lambda>null141 fun set_flash_and_capture_successfully() = runScenarioTest<MainActivity> { 142 // Skip test on unstable devices 143 assumeHalStableOnImageCapture() 144 145 // Wait for the capture button to be displayed 146 composeTestRule.waitUntil(timeoutMillis = APP_START_TIMEOUT_MILLIS) { 147 composeTestRule.onNodeWithTag(CAPTURE_BUTTON).isDisplayed() 148 } 149 150 // Ensure camera has a back camera and flip to it 151 val lensFacing = composeTestRule.getCurrentLensFacing() 152 if (lensFacing != LensFacing.BACK) { 153 composeTestRule.onNodeWithTag(FLIP_CAMERA_BUTTON).assume(isEnabled()) { 154 "Device does not have a back camera to flip to." 155 }.performClick() 156 } 157 158 // Navigate to quick settings 159 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 160 .assertExists() 161 .performClick() 162 163 // Click the flash button to switch to ON 164 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 165 .assertExists() 166 .performClick() 167 168 // Exit quick settings 169 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 170 .assertExists() 171 .performClick() 172 173 composeTestRule.onNodeWithTag(CAPTURE_BUTTON) 174 .assertExists() 175 .performClick() 176 177 composeTestRule.waitUntil(timeoutMillis = IMAGE_CAPTURE_TIMEOUT_MILLIS) { 178 composeTestRule.onNodeWithTag(IMAGE_CAPTURE_SUCCESS_TAG).isDisplayed() 179 } 180 } 181 182 @Test set_screen_flash_and_capture_with_screen_change_overlay_shownnull183 fun set_screen_flash_and_capture_with_screen_change_overlay_shown() = 184 runScenarioTest<MainActivity> { 185 // Wait for the capture button to be displayed 186 composeTestRule.waitUntil(timeoutMillis = APP_START_TIMEOUT_MILLIS) { 187 composeTestRule.onNodeWithTag(CAPTURE_BUTTON).isDisplayed() 188 } 189 190 // Ensure camera has a front camera and flip to it 191 val lensFacing = composeTestRule.getCurrentLensFacing() 192 if (lensFacing != LensFacing.FRONT) { 193 composeTestRule.onNodeWithTag(FLIP_CAMERA_BUTTON).assume(isEnabled()) { 194 "Device does not have a front camera to flip to." 195 }.performClick() 196 } 197 198 // Navigate to quick settings 199 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 200 .assertExists() 201 .performClick() 202 203 // Click the flash button to switch to ON 204 composeTestRule.onNodeWithTag(QUICK_SETTINGS_FLASH_BUTTON) 205 .assertExists() 206 .performClick() 207 208 // Exit quick settings 209 composeTestRule.onNodeWithTag(QUICK_SETTINGS_DROP_DOWN) 210 .assertExists() 211 .performClick() 212 213 // Perform a capture to enable screen flash 214 composeTestRule.onNodeWithTag(CAPTURE_BUTTON) 215 .assertExists() 216 .performClick() 217 218 composeTestRule.waitUntil(timeoutMillis = IMAGE_CAPTURE_TIMEOUT_MILLIS) { 219 composeTestRule.onNodeWithTag(SCREEN_FLASH_OVERLAY).isDisplayed() 220 } 221 } 222 } 223