diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..5bd042a --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,60 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "ch.mathieubroillet.djiffchack" + compileSdk = 35 + + defaultConfig { + applicationId = "ch.mathieubroillet.djiffchack" + minSdk = 26 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation("com.github.mik3y:usb-serial-for-android:3.8.1") + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/ch/mathieubroillet/djiffchack/ExampleInstrumentedTest.kt b/app/src/androidTest/java/ch/mathieubroillet/djiffchack/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b57bfac --- /dev/null +++ b/app/src/androidTest/java/ch/mathieubroillet/djiffchack/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package ch.mathieubroillet.djiffchack + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("ch.mathieubroillet.djiffchack", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..49ec8bd --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/ch/mathieubroillet/djiffchack/Constants.kt b/app/src/main/java/ch/mathieubroillet/djiffchack/Constants.kt new file mode 100644 index 0000000..d8121e0 --- /dev/null +++ b/app/src/main/java/ch/mathieubroillet/djiffchack/Constants.kt @@ -0,0 +1,9 @@ +package ch.mathieubroillet.djiffchack + +class Constants { + companion object { +// const val INTENT_ACTION_GRANT_USB_ACCESSORY = "ch.mathieubroillet.djiffchack.USB_ACCESSORY_PERMISSION" +// const val INTENT_ACTION_GRANT_USB_DEVICE = "ch.mathieubroillet.djiffchack.USB_DEVICE_PERMISSION" + const val INTENT_ACTION_GRANT_USB_PERMISSION = "ch.mathieubroillet.djiffchack.USB_PERMISSION" + } +} \ No newline at end of file diff --git a/app/src/main/java/ch/mathieubroillet/djiffchack/MainActivity.kt b/app/src/main/java/ch/mathieubroillet/djiffchack/MainActivity.kt new file mode 100644 index 0000000..5cea06f --- /dev/null +++ b/app/src/main/java/ch/mathieubroillet/djiffchack/MainActivity.kt @@ -0,0 +1,279 @@ +package ch.mathieubroillet.djiffchack + +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.hardware.usb.UsbDevice +import android.hardware.usb.UsbDeviceConnection +import android.hardware.usb.UsbManager +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Build +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import ch.mathieubroillet.djiffchack.ui.theme.DJI_FCC_HACK_Theme +import com.hoho.android.usbserial.driver.CdcAcmSerialDriver +import com.hoho.android.usbserial.driver.ProbeTable +import com.hoho.android.usbserial.driver.UsbSerialPort +import com.hoho.android.usbserial.driver.UsbSerialProber + + +class MainActivity : ComponentActivity() { + private lateinit var usbManager: UsbManager + private var usbConnection by mutableStateOf(null as UsbDeviceConnection?) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + usbManager = getSystemService(Context.USB_SERVICE) as UsbManager + + // Register receiver to detect USB plug/unplug events + val filter = IntentFilter().apply { + addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) + addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) + addAction(Constants.INTENT_ACTION_GRANT_USB_PERMISSION) + } + ContextCompat.registerReceiver( + this, + usbReceiver, + filter, + ContextCompat.RECEIVER_NOT_EXPORTED + ) + + // Initial check for USB connection + refreshUsbConnection() + + setContent { + MainScreen(usbConnection != null, ::refreshUsbConnection, ::sendPatch) + } + } + + override fun onDestroy() { + super.onDestroy() + unregisterReceiver(usbReceiver) + } + + /** + * Refreshes the USB connection status + */ + private fun refreshUsbConnection() { + if (usbManager.deviceList.isNotEmpty()) { + val device: UsbDevice = usbManager.deviceList.values.first() + usbConnection = usbManager.openDevice(device) + + if (usbConnection == null) { + Log.d("USB_CONNECTION", "Requesting USB Permission") + requestUsbPermission(device) + } + } else { + usbConnection = null + } + } + + /** + * Handles sending the patch via USB communication + */ + private fun sendPatch() { + if (usbConnection == null) { + Toast.makeText(this, "No USB device connected!", Toast.LENGTH_SHORT).show() + return + } + + for (device in usbManager.deviceList.values) { + try { + val probeTable = ProbeTable() + probeTable.addProduct(11427, 4128, CdcAcmSerialDriver::class.java) + probeTable.addProduct(5840, 2174, CdcAcmSerialDriver::class.java) + + val usbSerialProber = UsbSerialProber(probeTable) + val usbSerialPort = usbSerialProber.probeDevice(device).ports.firstOrNull() + + if (usbSerialPort == null) { + Toast.makeText(this, "No serial port found", Toast.LENGTH_SHORT).show() + return + } + + usbSerialPort.open(usbConnection) + usbSerialPort.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE) + usbSerialPort.write( + byteArrayOf(85, 13, 4, 33, 42, 31, 0, 0, 0, 0, 1, -122, 32), + 1000 + ) + usbSerialPort.write( + byteArrayOf( + 85, 24, 4, 32, 2, 9, 0, 0, 64, 9, 39, 0, 2, 72, 0, -1, -1, 2, 0, 0, 0, 0, + -127, 31 + ), 1000 + ) + usbSerialPort.close() + } catch (e: Exception) { + Log.e("USB_PATCH", "Error sending patch: ${e.message}") + Toast.makeText(this, "Patch failed: ${e.message}", Toast.LENGTH_SHORT).show() + } + } + } + + /** + * Requests USB permission for the device + */ + private fun requestUsbPermission(device: UsbDevice) { + val permissionIntent = PendingIntent.getBroadcast( + this, + 0, + Intent(Constants.INTENT_ACTION_GRANT_USB_PERMISSION).apply { setPackage(packageName) }, + PendingIntent.FLAG_MUTABLE + ) + + usbManager.requestPermission(device, permissionIntent) + } + + + /** + * BroadcastReceiver to handle USB events + */ + private val usbReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + UsbManager.ACTION_USB_DEVICE_ATTACHED -> { + Log.d("USB_EVENT", "USB Device Connected") + refreshUsbConnection() + } + + UsbManager.ACTION_USB_DEVICE_DETACHED -> { + Log.d("USB_EVENT", "USB Device Disconnected") + refreshUsbConnection() + } + + Constants.INTENT_ACTION_GRANT_USB_PERMISSION -> { + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { + Log.d("USB_EVENT", "USB Permission Granted") + refreshUsbConnection() + } + } + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () -> Unit) { + Scaffold( + topBar = { + TopAppBar( + title = { Text("DJI FCC Hack") }, + actions = { + IconButton(onClick = onRefresh) { + Icon(Icons.Default.Refresh, contentDescription = "Refresh USB Connection") + } + IconButton(onClick = { /* Open Settings */ }) { + Icon(Icons.Default.MoreVert, contentDescription = "More Options") + } + } + ) + } + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // App Logo + Image( + painter = painterResource(id = R.drawable.dji_innovations_logo), + contentDescription = "DJI Logo", + modifier = Modifier.size(100.dp) + ) + + // USB Connection Status + Card( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + colors = CardDefaults.cardColors( + containerColor = if (usbConnected) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.errorContainer + ) + ) { + Row( + modifier = Modifier.padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(id = R.drawable.usb_c_port), + contentDescription = "USB Status", + modifier = Modifier.size(24.dp), + ) + Spacer(Modifier.width(8.dp)) + Text( + text = if (usbConnected) "Remote Connected" else "Remote Not Connected", + style = MaterialTheme.typography.bodyMedium + ) + } + } + + // Send Patch Button + Button( + onClick = onSendPatch, + shape = RoundedCornerShape(24.dp), + modifier = Modifier + .fillMaxWidth() + .height(56.dp), + enabled = usbConnected + ) { + Icon(Icons.Default.Build, contentDescription = "Patch") + Spacer(Modifier.width(8.dp)) + Text("Send FCC Patch") + } + } + } +} + + +@Preview(showBackground = true) +@Composable +fun PreviewMainScreen() { + DJI_FCC_HACK_Theme { + MainScreen(usbConnected = true, onRefresh = {}, onSendPatch = {}) + } +} \ No newline at end of file diff --git a/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Color.kt b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Color.kt new file mode 100644 index 0000000..2876c7d --- /dev/null +++ b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package ch.mathieubroillet.djiffchack.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Theme.kt b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Theme.kt new file mode 100644 index 0000000..0fce555 --- /dev/null +++ b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Theme.kt @@ -0,0 +1,57 @@ +package ch.mathieubroillet.djiffchack.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun DJI_FCC_HACK_Theme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Type.kt b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Type.kt new file mode 100644 index 0000000..3a7f581 --- /dev/null +++ b/app/src/main/java/ch/mathieubroillet/djiffchack/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package ch.mathieubroillet.djiffchack.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/dji_innovations_logo.xml b/app/src/main/res/drawable/dji_innovations_logo.xml new file mode 100644 index 0000000..9695a7f --- /dev/null +++ b/app/src/main/res/drawable/dji_innovations_logo.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/quadcopter.xml b/app/src/main/res/drawable/quadcopter.xml new file mode 100644 index 0000000..b7f1b99 --- /dev/null +++ b/app/src/main/res/drawable/quadcopter.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/res/drawable/usb.xml b/app/src/main/res/drawable/usb.xml new file mode 100644 index 0000000..5464a3d --- /dev/null +++ b/app/src/main/res/drawable/usb.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/res/drawable/usb_c_port.xml b/app/src/main/res/drawable/usb_c_port.xml new file mode 100644 index 0000000..4dd8acf --- /dev/null +++ b/app/src/main/res/drawable/usb_c_port.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..03d640e --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + dji-ffc-hack + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..f36f273 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +