Convert CameraActivity to kotlin

This commit is contained in:
Ammar Githam 2021-05-28 21:18:59 +09:00
parent f52cebf419
commit cf0c420801
1 changed files with 166 additions and 194 deletions

View File

@ -1,239 +1,211 @@
package awais.instagrabber.activities; package awais.instagrabber.activities
import android.app.Activity; import android.content.Intent
import android.content.Context; import android.content.res.Configuration
import android.content.Intent; import android.hardware.display.DisplayManager
import android.content.res.Configuration; import android.hardware.display.DisplayManager.DisplayListener
import android.hardware.display.DisplayManager; import android.media.MediaScannerConnection
import android.media.MediaScannerConnection; import android.net.Uri
import android.net.Uri; import android.os.Bundle
import android.os.Bundle; import android.util.Log
import android.util.Log; import android.view.LayoutInflater
import android.view.LayoutInflater; import android.webkit.MimeTypeMap
import android.webkit.MimeTypeMap; import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import awais.instagrabber.databinding.ActivityCameraBinding
import awais.instagrabber.utils.DirectoryUtils
import awais.instagrabber.utils.PermissionUtils
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG
import com.google.common.io.Files
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutionException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import androidx.annotation.NonNull; class CameraActivity : BaseLanguageActivity() {
import androidx.annotation.Nullable; private lateinit var binding: ActivityCameraBinding
import androidx.camera.core.CameraInfoUnavailableException; private lateinit var outputDirectory: File
import androidx.camera.core.CameraSelector; private lateinit var displayManager: DisplayManager
import androidx.camera.core.ImageCapture; private lateinit var cameraExecutor: ExecutorService
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.core.content.ContextCompat;
import com.google.common.io.Files; private var imageCapture: ImageCapture? = null
import com.google.common.util.concurrent.ListenableFuture; private var displayId = -1
private var cameraProvider: ProcessCameraProvider? = null
private var lensFacing = 0
import java.io.File; private val cameraRequestCode = 100
import java.text.SimpleDateFormat; private val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
import java.util.Locale; private val displayListener: DisplayListener = object : DisplayListener {
import java.util.concurrent.ExecutionException; override fun onDisplayAdded(displayId: Int) {}
import java.util.concurrent.ExecutorService; override fun onDisplayRemoved(displayId: Int) {}
import java.util.concurrent.Executors; override fun onDisplayChanged(displayId: Int) {
if (displayId == this@CameraActivity.displayId) {
import awais.instagrabber.databinding.ActivityCameraBinding; imageCapture?.targetRotation = binding.root.display.rotation
import awais.instagrabber.utils.DirectoryUtils;
import awais.instagrabber.utils.PermissionUtils;
import awais.instagrabber.utils.Utils;
public class CameraActivity extends BaseLanguageActivity {
private static final String TAG = CameraActivity.class.getSimpleName();
private static final int CAMERA_REQUEST_CODE = 100;
private static final String FILE_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS";
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
private ActivityCameraBinding binding;
private ImageCapture imageCapture;
private File outputDirectory;
private ExecutorService cameraExecutor;
private int displayId = -1;
private final DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(final int displayId) {}
@Override
public void onDisplayRemoved(final int displayId) {}
@Override
public void onDisplayChanged(final int displayId) {
if (displayId == CameraActivity.this.displayId) {
imageCapture.setTargetRotation(binding.getRoot().getDisplay().getRotation());
} }
} }
};
private DisplayManager displayManager;
private ProcessCameraProvider cameraProvider;
private int lensFacing;
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityCameraBinding.inflate(LayoutInflater.from(getBaseContext()));
setContentView(binding.getRoot());
Utils.transparentStatusBar(this, true, false);
displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
outputDirectory = DirectoryUtils.getOutputMediaDirectory(this, "Camera");
cameraExecutor = Executors.newSingleThreadExecutor();
displayManager.registerDisplayListener(displayListener, null);
binding.viewFinder.post(() -> {
displayId = binding.viewFinder.getDisplay().getDisplayId();
updateUi();
checkPermissionsAndSetupCamera();
});
} }
@Override override fun onCreate(savedInstanceState: Bundle?) {
protected void onResume() { super.onCreate(savedInstanceState)
super.onResume(); binding = ActivityCameraBinding.inflate(LayoutInflater.from(baseContext))
setContentView(binding.root)
Utils.transparentStatusBar(this, true, false)
displayManager = getSystemService(DISPLAY_SERVICE) as DisplayManager
outputDirectory = DirectoryUtils.getOutputMediaDirectory(this, "Camera")
cameraExecutor = Executors.newSingleThreadExecutor()
displayManager.registerDisplayListener(displayListener, null)
binding.viewFinder.post {
displayId = binding.viewFinder.display.displayId
updateUi()
checkPermissionsAndSetupCamera()
}
}
override fun onResume() {
super.onResume()
// Make sure that all permissions are still present, since the // Make sure that all permissions are still present, since the
// user could have removed them while the app was in paused state. // user could have removed them while the app was in paused state.
if (!PermissionUtils.hasCameraPerms(this)) { if (!PermissionUtils.hasCameraPerms(this)) {
PermissionUtils.requestCameraPerms(this, CAMERA_REQUEST_CODE); PermissionUtils.requestCameraPerms(this, cameraRequestCode)
} }
} }
@Override override fun onConfigurationChanged(newConfig: Configuration) {
public void onConfigurationChanged(@NonNull final Configuration newConfig) { super.onConfigurationChanged(newConfig)
super.onConfigurationChanged(newConfig);
// Redraw the camera UI controls // Redraw the camera UI controls
updateUi(); updateUi()
// Enable or disable switching between cameras // Enable or disable switching between cameras
updateCameraSwitchButton(); updateCameraSwitchButton()
} }
@Override override fun onDestroy() {
protected void onDestroy() { super.onDestroy()
super.onDestroy(); Utils.transparentStatusBar(this, false, false)
Utils.transparentStatusBar(this, false, false); cameraExecutor.shutdown()
cameraExecutor.shutdown(); displayManager.unregisterDisplayListener(displayListener)
displayManager.unregisterDisplayListener(displayListener);
} }
private void updateUi() { private fun updateUi() {
binding.cameraCaptureButton.setOnClickListener(v -> takePhoto()); binding.cameraCaptureButton.setOnClickListener { takePhoto() }
// Disable the button until the camera is set up // Disable the button until the camera is set up
binding.switchCamera.setEnabled(false); binding.switchCamera.isEnabled = false
// Listener for button used to switch cameras. Only called if the button is enabled // Listener for button used to switch cameras. Only called if the button is enabled
binding.switchCamera.setOnClickListener(v -> { binding.switchCamera.setOnClickListener {
lensFacing = CameraSelector.LENS_FACING_FRONT == lensFacing ? CameraSelector.LENS_FACING_BACK lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) CameraSelector.LENS_FACING_BACK else CameraSelector.LENS_FACING_FRONT
: CameraSelector.LENS_FACING_FRONT;
// Re-bind use cases to update selected camera // Re-bind use cases to update selected camera
bindCameraUseCases(); bindCameraUseCases()
}); }
binding.close.setOnClickListener(v -> { binding.close.setOnClickListener {
setResult(Activity.RESULT_CANCELED); setResult(RESULT_CANCELED)
finish(); finish()
}); }
} }
private void checkPermissionsAndSetupCamera() { private fun checkPermissionsAndSetupCamera() {
if (PermissionUtils.hasCameraPerms(this)) { if (PermissionUtils.hasCameraPerms(this)) {
setupCamera(); setupCamera()
return; return
} }
PermissionUtils.requestCameraPerms(this, CAMERA_REQUEST_CODE); PermissionUtils.requestCameraPerms(this, cameraRequestCode)
} }
@Override override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CAMERA_REQUEST_CODE) { if (requestCode == cameraRequestCode) {
if (PermissionUtils.hasCameraPerms(this)) { if (PermissionUtils.hasCameraPerms(this)) {
setupCamera(); setupCamera()
} }
} }
} }
private void setupCamera() { private fun setupCamera() {
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(() -> { cameraProviderFuture.addListener({
try { try {
cameraProvider = cameraProviderFuture.get(); cameraProvider = cameraProviderFuture.get()
// Select lensFacing depending on the available cameras // Select lensFacing depending on the available cameras
lensFacing = -1; lensFacing = -1
if (hasBackCamera()) { if (hasBackCamera()) {
lensFacing = CameraSelector.LENS_FACING_BACK; lensFacing = CameraSelector.LENS_FACING_BACK
} else if (hasFrontCamera()) { } else if (hasFrontCamera()) {
lensFacing = CameraSelector.LENS_FACING_FRONT; lensFacing = CameraSelector.LENS_FACING_FRONT
}
if (lensFacing == -1) {
throw new IllegalStateException("Back and front camera are unavailable");
} }
check(lensFacing != -1) { "Back and front camera are unavailable" }
// Enable or disable switching between cameras // Enable or disable switching between cameras
updateCameraSwitchButton(); updateCameraSwitchButton()
// Build and bind the camera use cases // Build and bind the camera use cases
bindCameraUseCases(); bindCameraUseCases()
} catch (ExecutionException | InterruptedException | CameraInfoUnavailableException e) { } catch (e: ExecutionException) {
Log.e(TAG, "setupCamera: ", e); Log.e(TAG, "setupCamera: ", e)
} catch (e: InterruptedException) {
Log.e(TAG, "setupCamera: ", e)
} catch (e: CameraInfoUnavailableException) {
Log.e(TAG, "setupCamera: ", e)
} }
}, ContextCompat.getMainExecutor(this))
}, ContextCompat.getMainExecutor(this));
} }
private void bindCameraUseCases() { private fun bindCameraUseCases() {
final int rotation = binding.viewFinder.getDisplay().getRotation(); val rotation = binding.viewFinder.display.rotation
// CameraSelector // CameraSelector
final CameraSelector cameraSelector = new CameraSelector.Builder() val cameraSelector = CameraSelector.Builder()
.requireLensFacing(lensFacing) .requireLensFacing(lensFacing)
.build(); .build()
// Preview // Preview
final Preview preview = new Preview.Builder() val preview = Preview.Builder() // Set initial target rotation
// Set initial target rotation .setTargetRotation(rotation)
.setTargetRotation(rotation) .build()
.build();
// ImageCapture // ImageCapture
imageCapture = new ImageCapture.Builder() imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // Set initial target rotation, we will have to call this again if rotation changes
// Set initial target rotation, we will have to call this again if rotation changes // during the lifecycle of this use case
// during the lifecycle of this use case .setTargetRotation(rotation)
.setTargetRotation(rotation) .build()
.build(); cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(this, cameraSelector, preview, imageCapture)
cameraProvider.unbindAll(); preview.setSurfaceProvider(binding.viewFinder.surfaceProvider)
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);
preview.setSurfaceProvider(binding.viewFinder.getSurfaceProvider());
} }
private void takePhoto() { private fun takePhoto() {
if (imageCapture == null) return; if (imageCapture == null) return
final File photoFile = new File(outputDirectory, SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + ".jpg"); val photoFile = File(outputDirectory, simpleDateFormat.format(System.currentTimeMillis()) + ".jpg")
final ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build(); val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
imageCapture.takePicture( imageCapture?.takePicture(
outputFileOptions, outputFileOptions,
cameraExecutor, cameraExecutor,
new ImageCapture.OnImageSavedCallback() { object : ImageCapture.OnImageSavedCallback {
@Override @Suppress("UnstableApiUsage")
public void onImageSaved(@NonNull final ImageCapture.OutputFileResults outputFileResults) { override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
final Uri uri = Uri.fromFile(photoFile); val uri = Uri.fromFile(photoFile)
//noinspection UnstableApiUsage val mimeType = MimeTypeMap.getSingleton()
final String mimeType = MimeTypeMap.getSingleton() .getMimeTypeFromExtension(Files.getFileExtension(photoFile.name))
.getMimeTypeFromExtension(Files.getFileExtension(photoFile.getName())); MediaScannerConnection.scanFile(
MediaScannerConnection.scanFile( this@CameraActivity,
CameraActivity.this, arrayOf(photoFile.absolutePath),
new String[]{photoFile.getAbsolutePath()}, arrayOf(mimeType)
new String[]{mimeType}, ) { _: String?, uri1: Uri? ->
(path, uri1) -> { Log.d(TAG, "onImageSaved: scan complete")
Log.d(TAG, "onImageSaved: scan complete"); val intent = Intent()
final Intent intent = new Intent(); intent.data = uri1
intent.setData(uri1); setResult(RESULT_OK, intent)
setResult(Activity.RESULT_OK, intent); finish()
finish();
});
Log.d(TAG, "onImageSaved: " + uri);
}
@Override
public void onError(@NonNull final ImageCaptureException exception) {
Log.e(TAG, "onError: ", exception);
} }
Log.d(TAG, "onImageSaved: $uri")
} }
);
override fun onError(exception: ImageCaptureException) {
Log.e(TAG, "onError: ", exception)
}
}
)
// We can only change the foreground Drawable using API level 23+ API // We can only change the foreground Drawable using API level 23+ API
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// // Display flash animation to indicate that photo was captured // // Display flash animation to indicate that photo was captured
@ -248,29 +220,29 @@ public class CameraActivity extends BaseLanguageActivity {
/** /**
* Enabled or disabled a button to switch cameras depending on the available cameras * Enabled or disabled a button to switch cameras depending on the available cameras
*/ */
private void updateCameraSwitchButton() { private fun updateCameraSwitchButton() {
try { try {
binding.switchCamera.setEnabled(hasBackCamera() && hasFrontCamera()); binding.switchCamera.isEnabled = hasBackCamera() && hasFrontCamera()
} catch (CameraInfoUnavailableException e) { } catch (e: CameraInfoUnavailableException) {
binding.switchCamera.setEnabled(false); binding.switchCamera.isEnabled = false
} }
} }
/** /**
* Returns true if the device has an available back camera. False otherwise * Returns true if the device has an available back camera. False otherwise
*/ */
private boolean hasBackCamera() throws CameraInfoUnavailableException { @Throws(CameraInfoUnavailableException::class)
if (cameraProvider == null) return false; private fun hasBackCamera(): Boolean {
return cameraProvider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA); return if (cameraProvider == null) false else cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
} }
/** /**
* Returns true if the device has an available front camera. False otherwise * Returns true if the device has an available front camera. False otherwise
*/ */
private boolean hasFrontCamera() throws CameraInfoUnavailableException { @Throws(CameraInfoUnavailableException::class)
if (cameraProvider == null) { private fun hasFrontCamera(): Boolean {
return false; return if (cameraProvider == null) {
} false
return cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA); } else cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) ?: false
} }
} }