Implement 2_PROJECT_ANDROID: Gradle configuration, layout setup, and CameraX initial logic

This commit is contained in:
2026-07-05 12:29:00 +07:00
parent a3b9c24936
commit df837a4c56
6 changed files with 358 additions and 76 deletions
+13 -36
View File
@@ -5,19 +5,16 @@ plugins {
android {
namespace = "com.photobooth.app"
compileSdk = 33
compileSdk = 34
defaultConfig {
applicationId = "com.photobooth.app"
minSdk = 24
targetSdk = 33
minSdk = 26 // Android 8.0 trở lên để hỗ trợ tốt các tính năng đồ họa
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
@@ -30,48 +27,28 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "17"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
viewBinding = true // Bật ViewBinding để thao tác với giao diện dễ dàng
}
}
dependencies {
implementation("androidx.core:core-ktx:1.10.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.2")
implementation(platform("androidx.compose:compose-bom:2023.06.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
// CameraX dependencies for Sprint 1 Camera preview
val cameraVersion = "1.3.0-rc01"
// --- Thư viện CameraX Core ---
val cameraVersion = "1.3.1"
implementation("androidx.camera:camera-core:$cameraVersion")
implementation("androidx.camera:camera-camera2:$cameraVersion")
implementation("androidx.camera:camera-lifecycle:$cameraVersion")
implementation("androidx.camera:camera-view:$cameraVersion")
implementation("androidx.camera:camera-extensions:$cameraVersion")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.06.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
@@ -1,44 +1,72 @@
package com.photobooth.app
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.photobooth.app.databinding.ActivityMainBinding
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraExecutor: ExecutorService
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState: Bundle?)
setContent {
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Retro Photobooth")
}
}
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Xin quyền Camera
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Welcome to $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting("Retro Photobooth")
cameraExecutor = Executors.newSingleThreadExecutor()
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Cấu hình Kính ngắm (Preview)
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding.viewFinder.surfaceProvider)
}
// Chọn Camera Trước (Mặc định cho Photobooth)
val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, preview)
} catch (xc: Exception) {
Toast.makeText(this, "Không thể khởi động Camera", Toast.LENGTH_SHORT).show()
}
}, ContextCompat.getMainExecutor(this))
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
companion object {
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
}
}
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#121212">
<!-- Màn hình xem trước Camera -->
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="3:4"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/controlPanel" />
<!-- Bảng điều khiển phía dưới -->
<RelativeLayout
android:id="@+id/controlPanel"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#000000"
app:layout_constraintBottom_toBottomOf="parent">
<!-- Nút chụp hình -->
<ImageButton
android:id="@+id/btnCapture"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:background="@android:color/transparent"
android:src="@android:drawable/ic_menu_camera"
android:contentDescription="Capture Button" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+2 -3
View File
@@ -1,5 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
id("com.android.application") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
+1 -1
View File
@@ -13,5 +13,5 @@ dependencyResolutionManagement {
}
}
rootProject.name = "Retro Photobooth"
rootProject.name = "RetroPhotobooth"
include(":app")