1 /* <lambda>null2 * Copyright 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 androidx.camera.integration.extensions.validation 18 19 import android.content.Context 20 import android.content.Intent 21 import android.hardware.camera2.CameraMetadata 22 import android.os.Bundle 23 import android.view.LayoutInflater 24 import android.view.Menu 25 import android.view.MenuItem 26 import android.view.View 27 import android.widget.AdapterView 28 import android.widget.BaseAdapter 29 import android.widget.ListView 30 import android.widget.TextView 31 import android.widget.Toast 32 import androidx.appcompat.app.AppCompatActivity 33 import androidx.camera.extensions.ExtensionsManager 34 import androidx.camera.integration.extensions.CameraExtensionsActivity 35 import androidx.camera.integration.extensions.IntentExtraKey.INTENT_EXTRA_KEY_CAMERA_ID 36 import androidx.camera.integration.extensions.IntentExtraKey.INTENT_EXTRA_KEY_LENS_FACING 37 import androidx.camera.integration.extensions.IntentExtraKey.INTENT_EXTRA_KEY_REQUEST_CODE 38 import androidx.camera.integration.extensions.IntentExtraKey.INTENT_EXTRA_KEY_TEST_TYPE 39 import androidx.camera.integration.extensions.R 40 import androidx.camera.integration.extensions.TestResultType.TEST_RESULT_NOT_SUPPORTED 41 import androidx.camera.lifecycle.ProcessCameraProvider 42 import androidx.concurrent.futures.await 43 import androidx.core.app.ActivityCompat 44 import androidx.lifecycle.lifecycleScope 45 import kotlinx.coroutines.launch 46 47 /** 48 * Activity to list all supported CameraX/Camera2 Extensions and camera ids combination items. 49 * 50 * Clicking a list item will launch the CameraValidationResultActivity to list the supported 51 * extension modes of the selected item. 52 */ 53 class CameraValidationResultActivity : AppCompatActivity() { 54 private lateinit var cameraProvider: ProcessCameraProvider 55 private lateinit var extensionsManager: ExtensionsManager 56 private lateinit var adapter: BaseAdapter 57 private lateinit var testResults: TestResults 58 private lateinit var cameraLensFacingMap: LinkedHashMap<String, Int> 59 private lateinit var cameraExtensionResultMap: 60 LinkedHashMap<Pair<String, String>, LinkedHashMap<Int, Pair<Int, String>>> 61 private val extensionValidationActivityRequestCode = 62 ExtensionValidationResultActivity::class.java.hashCode() % 1000 63 64 override fun onCreate(savedInstanceState: Bundle?) { 65 super.onCreate(savedInstanceState) 66 setContentView(R.layout.full_listview) 67 68 supportActionBar?.title = resources.getString(R.string.extensions_validator) 69 initialize() 70 } 71 72 private fun initialize() { 73 lifecycleScope.launch { 74 cameraProvider = 75 ProcessCameraProvider.getInstance(this@CameraValidationResultActivity).await() 76 extensionsManager = 77 ExtensionsManager.getInstanceAsync( 78 this@CameraValidationResultActivity, 79 cameraProvider 80 ) 81 .await() 82 83 testResults = TestResults.getInstance(this@CameraValidationResultActivity) 84 testResults.loadTestResults(cameraProvider, extensionsManager) 85 86 cameraLensFacingMap = testResults.getCameraLensFacingMap() 87 cameraExtensionResultMap = testResults.getCameraExtensionResultMap() 88 89 if (cameraExtensionResultMap.isEmpty()) { 90 showLoadErrorMessage() 91 return@launch 92 } 93 94 val layoutInflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 95 adapter = 96 CameraValidationResultAdapter( 97 layoutInflater, 98 cameraLensFacingMap, 99 cameraExtensionResultMap 100 ) 101 102 val listView = findViewById<ListView>(R.id.listView) 103 listView.adapter = adapter 104 listView.onItemClickListener = 105 AdapterView.OnItemClickListener { _, _, position, _ -> 106 val (testType, cameraId) = cameraExtensionResultMap.keys.elementAt(position) 107 if (!isAnyExtensionModeSupported(testType, cameraId)) { 108 Toast.makeText( 109 this@CameraValidationResultActivity, 110 "No extension mode is supported by the camera!", 111 Toast.LENGTH_SHORT 112 ) 113 .show() 114 return@OnItemClickListener 115 } 116 117 val intent = 118 Intent( 119 this@CameraValidationResultActivity, 120 ExtensionValidationResultActivity::class.java 121 ) 122 intent.putExtra(INTENT_EXTRA_KEY_TEST_TYPE, testType) 123 intent.putExtra(INTENT_EXTRA_KEY_CAMERA_ID, cameraId) 124 intent.putExtra(INTENT_EXTRA_KEY_LENS_FACING, cameraLensFacingMap[cameraId]) 125 intent.putExtra( 126 INTENT_EXTRA_KEY_REQUEST_CODE, 127 extensionValidationActivityRequestCode 128 ) 129 130 ActivityCompat.startActivityForResult( 131 this@CameraValidationResultActivity, 132 intent, 133 extensionValidationActivityRequestCode, 134 null 135 ) 136 } 137 } 138 } 139 140 private fun showLoadErrorMessage() { 141 val listView = findViewById<ListView>(R.id.listView) 142 val textView = findViewById<TextView>(R.id.textView) 143 144 listView.visibility = View.GONE 145 textView.visibility = View.VISIBLE 146 } 147 148 private fun isAnyExtensionModeSupported(testType: String, cameraId: String): Boolean { 149 cameraExtensionResultMap[Pair(testType, cameraId)]?.forEach { 150 if (it.value.first != TEST_RESULT_NOT_SUPPORTED) { 151 return true 152 } 153 } 154 return false 155 } 156 157 @Suppress("DEPRECATION") 158 @Deprecated("Deprecated in ComponentActivity") 159 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 160 super.onActivityResult(requestCode, resultCode, data) 161 162 if (requestCode != extensionValidationActivityRequestCode) { 163 return 164 } 165 166 adapter.notifyDataSetChanged() 167 } 168 169 override fun onCreateOptionsMenu(menu: Menu): Boolean { 170 menuInflater.inflate(R.menu.main_validator_menu, menu) 171 return true 172 } 173 174 override fun onOptionsItemSelected(item: MenuItem): Boolean { 175 return when (item.itemId) { 176 R.id.menu_export -> { 177 val outputFilePath = testResults.exportTestResults(contentResolver) 178 if (outputFilePath != null) { 179 Toast.makeText( 180 this, 181 "Test results have been saved in $outputFilePath!", 182 Toast.LENGTH_LONG 183 ) 184 .show() 185 } else { 186 Toast.makeText(this, "Failed to export the test results!", Toast.LENGTH_LONG) 187 .show() 188 } 189 true 190 } 191 R.id.menu_reset -> { 192 testResults.resetTestResults(cameraProvider, extensionsManager) 193 adapter.notifyDataSetChanged() 194 true 195 } 196 R.id.menu_extensions_app -> { 197 val intent = Intent(this, CameraExtensionsActivity::class.java) 198 intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK 199 startActivity(intent) 200 finish() 201 true 202 } 203 else -> super.onOptionsItemSelected(item) 204 } 205 } 206 207 companion object { 208 209 fun getLensFacingStringFromInt(lensFacing: Int): String = 210 when (lensFacing) { 211 CameraMetadata.LENS_FACING_BACK -> "BACK" 212 CameraMetadata.LENS_FACING_FRONT -> "FRONT" 213 CameraMetadata.LENS_FACING_EXTERNAL -> "EXTERNAL" 214 else -> throw IllegalArgumentException("Invalid lens facing!!") 215 } 216 } 217 } 218