1 /* 2 * Copyright 2015 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.cts.verifier.camera.flashlight; 18 19 import com.android.cts.verifier.PassFailButtons; 20 import com.android.cts.verifier.R; 21 22 import android.content.Context; 23 import android.hardware.camera2.CameraManager; 24 import android.hardware.camera2.CameraCharacteristics; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.util.Log; 28 import android.view.View; 29 import android.widget.Button; 30 import android.widget.TextView; 31 32 import java.util.HashSet; 33 import java.util.HashMap; 34 35 /** 36 * This test checks the flashlight functionality by turning on and off the flashlight. After it 37 * turns on or off the flashlight, it asks for user input to verify the flashlight status. The 38 * test will pass when the user input is correct for all camera devices with a flash unit. 39 */ 40 public class CameraFlashlightActivity extends PassFailButtons.Activity { 41 42 private static final String TAG = "CameraFlashlight"; 43 44 private CameraManager mCameraManager; 45 private TestState mTestState; 46 private final HashSet<String> mPendingCameraIds = new HashSet<>(); 47 private String mCurrentCameraId; 48 49 private Button mInstructionButton; 50 private Button mOnButton; 51 private Button mOffButton; 52 private TextView mInstructionTextView; 53 private final HashSet<View> mAllButtons = new HashSet<>(); 54 // TestState -> enabled buttons 55 private final HashMap<TestState, HashSet<View>> mStateButtonsMap = new HashMap<>(); 56 57 private enum TestState { 58 NOT_STARTED, 59 TESTING_ON, 60 WAITING_ON_CALLBACK_ON, 61 RESPONDED_ON_CORRECTLY, 62 WAITING_ON_CALLBACK_OFF, 63 TESTING_OFF, 64 RESPONDED_OFF_CORRECTLY, 65 ALL_PASSED, 66 FAILED 67 } 68 69 private final View.OnClickListener mInstructionButtonListener = new View.OnClickListener() { 70 @Override 71 public void onClick(View v) { 72 switch (mTestState) { 73 case NOT_STARTED: 74 // Start testing turning on the first camera's flashlight. 75 // Fall through. 76 case RESPONDED_OFF_CORRECTLY: 77 // Current camera passed. Start testing turning on next camera's flashlight. 78 if (mPendingCameraIds.size() == 0) { 79 // Passed 80 mTestState = TestState.ALL_PASSED; 81 updateButtonsAndInstructionLocked(); 82 return; 83 } 84 85 mCurrentCameraId = (String)mPendingCameraIds.toArray()[0]; 86 mPendingCameraIds.remove(mCurrentCameraId); 87 88 try { 89 mCameraManager.setTorchMode(mCurrentCameraId, true); 90 mTestState = TestState.WAITING_ON_CALLBACK_ON; 91 } catch (Exception e) { 92 e.printStackTrace(); 93 mTestState = TestState.FAILED; 94 } 95 break; 96 97 case RESPONDED_ON_CORRECTLY: 98 // Flashlight is on and user responded correctly. 99 // Turning off the flashlight. 100 try { 101 mCameraManager.setTorchMode(mCurrentCameraId, false); 102 mTestState = TestState.WAITING_ON_CALLBACK_OFF; 103 } catch (Exception e) { 104 e.printStackTrace(); 105 mTestState = TestState.FAILED; 106 } 107 break; 108 109 case FAILED: 110 // The test failed, report failure. 111 if (mCurrentCameraId != null) { 112 try { 113 mCameraManager.setTorchMode(mCurrentCameraId, false); 114 } catch (Exception e) { 115 e.printStackTrace(); 116 Log.e(TAG, "Test failed but cannot turn off the torch"); 117 } 118 } 119 setTestResultAndFinish(false); 120 break; 121 122 case ALL_PASSED: 123 // The test passed, report pass. 124 setTestResultAndFinish(true); 125 break; 126 } 127 128 updateButtonsAndInstructionLocked(); 129 } 130 }; 131 132 private final View.OnClickListener mOnButtonListener = new View.OnClickListener() { 133 @Override 134 public void onClick(View v) { 135 // Check if user responded correctly. 136 if (mTestState == TestState.TESTING_ON) { 137 mTestState = TestState.RESPONDED_ON_CORRECTLY; 138 } else { 139 mTestState = TestState.FAILED; 140 } 141 updateButtonsAndInstructionLocked(); 142 } 143 }; 144 145 private final View.OnClickListener mOffButtonListener = new View.OnClickListener() { 146 @Override 147 public void onClick(View v) { 148 // Check if user responded correctly. 149 if (mTestState == TestState.TESTING_OFF) { 150 mTestState = TestState.RESPONDED_OFF_CORRECTLY; 151 } else { 152 mTestState = TestState.FAILED; 153 } 154 updateButtonsAndInstructionLocked(); 155 } 156 }; 157 158 private final CameraManager.TorchCallback mTorchCallback = new CameraManager.TorchCallback() { 159 @Override 160 public void onTorchModeChanged(String cameraId, boolean enabled) { 161 if (!cameraId.equals(mCurrentCameraId)) { 162 return; 163 } 164 165 // Move to next state after receiving the expected callback. 166 if (mTestState == TestState.WAITING_ON_CALLBACK_ON && enabled) { 167 mTestState = TestState.TESTING_ON; 168 } else if (mTestState == TestState.WAITING_ON_CALLBACK_OFF && !enabled) { 169 mTestState = TestState.TESTING_OFF; 170 } 171 updateButtonsAndInstructionLocked(); 172 } 173 }; 174 175 @Override 176 protected void onCreate(Bundle savedInstanceState) { 177 super.onCreate(savedInstanceState); 178 179 // initialize state -> buttons map 180 for (TestState state : TestState.values()) { 181 mStateButtonsMap.put(state, new HashSet<View>()); 182 } 183 184 mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 185 186 try { 187 String[] cameraIds = mCameraManager.getCameraIdList(); 188 for (String id : cameraIds) { 189 CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id); 190 if (info.get(CameraCharacteristics.FLASH_INFO_AVAILABLE).booleanValue() == 191 true) { 192 mPendingCameraIds.add(id); 193 } 194 } 195 mCameraManager.registerTorchCallback(mTorchCallback, new Handler()); 196 } catch (Exception e) { 197 e.printStackTrace(); 198 mTestState = TestState.FAILED; 199 updateButtonsAndInstructionLocked(); 200 return; 201 } 202 203 // Setup the UI. 204 setContentView(R.layout.camera_flashlight); 205 setPassFailButtonClickListeners(); 206 setInfoResources(R.string.camera_flashlight_test, R.string.camera_flashlight_info, -1); 207 208 mInstructionTextView = (TextView) findViewById(R.id.flash_instruction_text); 209 210 // Get the buttons and attach the listener. 211 mInstructionButton = (Button) findViewById(R.id.flash_instruction_button); 212 mInstructionButton.setOnClickListener(mInstructionButtonListener); 213 mStateButtonsMap.get(TestState.NOT_STARTED).add(mInstructionButton); 214 mStateButtonsMap.get(TestState.RESPONDED_ON_CORRECTLY).add(mInstructionButton); 215 mStateButtonsMap.get(TestState.RESPONDED_OFF_CORRECTLY).add(mInstructionButton); 216 mStateButtonsMap.get(TestState.ALL_PASSED).add(mInstructionButton); 217 mStateButtonsMap.get(TestState.FAILED).add(mInstructionButton); 218 mAllButtons.add(mInstructionButton); 219 220 mOnButton = (Button) findViewById(R.id.flash_on_button); 221 mOnButton.setOnClickListener(mOnButtonListener); 222 mStateButtonsMap.get(TestState.TESTING_ON).add(mOnButton); 223 mStateButtonsMap.get(TestState.TESTING_OFF).add(mOnButton); 224 mAllButtons.add(mOnButton); 225 226 mOffButton = (Button) findViewById(R.id.flash_off_button); 227 mOffButton.setOnClickListener(mOffButtonListener); 228 mStateButtonsMap.get(TestState.TESTING_ON).add(mOffButton); 229 mStateButtonsMap.get(TestState.TESTING_OFF).add(mOffButton); 230 mAllButtons.add(mOffButton); 231 232 View passButton = getPassButton(); 233 mStateButtonsMap.get(TestState.ALL_PASSED).add(passButton); 234 mAllButtons.add(passButton); 235 236 mTestState = TestState.NOT_STARTED; 237 updateButtonsAndInstructionLocked(); 238 } 239 240 241 private void updateButtonsAndInstructionLocked() { 242 for (View v : mAllButtons) { 243 v.setEnabled(false); 244 } 245 246 // Only enable the buttons for this state. 247 HashSet<View> views = mStateButtonsMap.get(mTestState); 248 for (View v : views) { 249 v.setEnabled(true); 250 } 251 252 switch (mTestState) { 253 case TESTING_ON: 254 case TESTING_OFF: 255 mInstructionTextView.setText(String.format( 256 getString(R.string.camera_flashlight_question_text), mCurrentCameraId)); 257 break; 258 case RESPONDED_ON_CORRECTLY: 259 case RESPONDED_OFF_CORRECTLY: 260 mInstructionTextView.setText(R.string.camera_flashlight_next_text); 261 mInstructionButton.setText(R.string.camera_flashlight_next_button); 262 break; 263 case FAILED: 264 mInstructionTextView.setText(R.string.camera_flashlight_failed_text); 265 mInstructionButton.setText(R.string.camera_flashlight_done_button); 266 break; 267 case ALL_PASSED: 268 mInstructionTextView.setText(R.string.camera_flashlight_passed_text); 269 mInstructionButton.setText(R.string.camera_flashlight_done_button); 270 break; 271 default: 272 break; 273 } 274 } 275 } 276