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