commit 67a695724f6a33660caef68ad1ed49ffacb216df Author: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Wed Aug 2 13:53:07 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..fd196da --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,75 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'app.myzel394.locationtest' + compileSdk 33 + + defaultConfig { + applicationId "app.myzel394.locationtest" + minSdk 24 + targetSdk 33 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + coreLibraryDesugaringEnabled true + // Sets Java compatibility to Java 8 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion '1.5.1' + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.10.1' + implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0') + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + implementation 'androidx.activity:activity-compose:1.7.2' + implementation platform('androidx.compose:compose-bom:2022.10.00') + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.ui:ui-graphics' + implementation 'androidx.compose.ui:ui-tooling-preview' + implementation 'androidx.compose.material3:material3' + 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:2022.10.00') + androidTestImplementation 'androidx.compose.ui:ui-test-junit4' + debugImplementation 'androidx.compose.ui:ui-tooling' + debugImplementation 'androidx.compose.ui:ui-test-manifest' + + implementation 'com.google.dagger:hilt-android:2.46.1' + annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1' + implementation "androidx.hilt:hilt-navigation-compose:1.0.0" + + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' +} \ 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/app/myzel394/locationtest/ExampleInstrumentedTest.kt b/app/src/androidTest/java/app/myzel394/locationtest/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..95f3289 --- /dev/null +++ b/app/src/androidTest/java/app/myzel394/locationtest/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package app.myzel394.locationtest + +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("app.myzel394.locationtest", 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..02898e7 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/AudioRecorder.kt b/app/src/main/java/app/myzel394/locationtest/AudioRecorder.kt new file mode 100644 index 0000000..051a500 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/AudioRecorder.kt @@ -0,0 +1,102 @@ +package app.myzel394.locationtest + +import android.Manifest +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.media.MediaPlayer +import android.os.IBinder +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.runtime.* +import androidx.core.content.ContextCompat + +@Composable +fun AudioRecorder() { + val context = LocalContext.current + val launcher = rememberLauncherForActivityResult( + ActivityResultContracts.RequestPermission(), + ) { isGranted -> + } + + var service by remember { mutableStateOf(null) } + val connection = remember { + object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, binder: IBinder?) { + service = (binder as RecorderService.LocalBinder).getService().also {service -> + service.setOnStateChangeListener { + println("asd") + } + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + } + } + } + + val isRecording = service?.isRecording ?: false + + LaunchedEffect(Unit) { + Intent(context, RecorderService::class.java).also {intent -> + context.bindService(intent, connection, Context.BIND_AUTO_CREATE) + } + } + + Row { + Button( + onClick = { + // Check audio recording permission + if (context.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != android.content.pm.PackageManager.PERMISSION_GRANTED) { + launcher.launch(Manifest.permission.RECORD_AUDIO) + + return@Button + } + + if (isRecording) { + Intent(context, RecorderService::class.java).also {intent -> + intent.action = RecorderService.Actions.STOP.toString() + + context.startService(intent) + } + } else { + Intent(context, RecorderService::class.java).also {intent -> + intent.action = RecorderService.Actions.START.toString() + + ContextCompat.startForegroundService(context, intent) + context.bindService(intent, connection, Context.BIND_AUTO_CREATE) + } + } + }, + ) { + Text(text = if (isRecording) "Stop" else "Start") + } + if (!isRecording && service != null) + LazyColumn() { + val items = service!!.getRecordingFilePaths().toList() + + items(items.size) { + val path = items[it] + + Button( + onClick = { + val player = MediaPlayer().apply { + setDataSource(path) + prepare() + start() + } + } + ) { + Text(text = "Play $it") + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/MainActivity.kt b/app/src/main/java/app/myzel394/locationtest/MainActivity.kt new file mode 100644 index 0000000..0eac968 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/MainActivity.kt @@ -0,0 +1,46 @@ +package app.myzel394.locationtest + +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 app.myzel394.locationtest.ui.theme.LocationTestTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + LocationTestTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + AudioRecorder() + } + } + } + } +} + +@Composable +fun Greeting(name: String, modifier: Modifier = Modifier) { + Text( + text = "Hello $name!", + modifier = modifier + ) +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + LocationTestTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/RecorderService.kt b/app/src/main/java/app/myzel394/locationtest/RecorderService.kt new file mode 100644 index 0000000..304d857 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/RecorderService.kt @@ -0,0 +1,240 @@ +package app.myzel394.locationtest + +import android.app.Service +import android.content.Context +import android.content.Intent +import android.media.MediaRecorder +import android.os.Binder +import android.os.Build +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import androidx.compose.runtime.mutableStateOf +import androidx.core.app.NotificationCompat +import kotlinx.coroutines.NonCancellable.start +import java.io.File +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.Date + +import java.util.UUID; + +const val INTERVAL_DURATION = 30000L + +class RecorderService: Service() { + private val binder = LocalBinder() + private val handler = Handler(Looper.getMainLooper()) + + private var mediaRecorder: MediaRecorder? = null + private var onError: MediaRecorder.OnErrorListener? = null + private var onStateChange: (RecorderService.RecorderState) -> Unit = {} + + private var counter = 0 + + var recordingStart = mutableStateOf(null) + private set + var fileFolder: String? = null + private set + var bitRate: Int? = null + private set + var recordingState: RecorderState = RecorderState.IDLE + private set + + val isRecording: Boolean + get() = recordingStart.value != null + + override fun onBind(p0: Intent?): IBinder = binder + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + when (intent?.action) { + Actions.START.toString() -> { + val fileFolder = intent.getStringExtra("fileFolder") + val bitRate = intent.getIntExtra("bitRate", 320000) + + start(fileFolder, bitRate) + } + Actions.STOP.toString() -> stop() + } + + return super.onStartCommand(intent, flags, startId) + } + + fun setOnErrorListener(onError: MediaRecorder.OnErrorListener) { + this.onError = onError + } + + fun setOnStateChangeListener(onStateChange: (RecorderService.RecorderState) -> Unit) { + this.onStateChange = onStateChange + } + + // Yield all recordings from 0 to counter + fun getRecordingFilePaths() = sequence { + for (i in 0 until counter) { + yield("$fileFolder/$i.${getFileExtensions()}") + } + } + + private fun startNewRecording() { + if (!isRecording) { + return + } + + val newRecorder = createRecorder(); + + newRecorder.prepare() + + runCatching { + mediaRecorder?.let { + it.stop() + it.release() + } + } + + newRecorder.start() + mediaRecorder = newRecorder + + counter++ + handler.postDelayed(this::startNewRecording, INTERVAL_DURATION) + } + + private fun start(fileFolder: String?, bitRate: Int) { + this.fileFolder = fileFolder ?: getRandomFileFolder(this) + this.bitRate = bitRate + + // Create folder + File(this.fileFolder!!).mkdirs() + + println(this.fileFolder) + + recordingState = RecorderState.RECORDING + recordingStart.value = LocalDateTime.now() + + showNotification() + + startNewRecording() + } + + private fun stop() { + recordingState = RecorderState.IDLE + + mediaRecorder?.apply { + runCatching { + stop() + release() + } + } + recordingStart.value = null + + stopForeground(STOP_FOREGROUND_REMOVE) + stopSelf() + } + + private fun showNotification() { + if (recordingStart.value == null) { + return + } + + val notification = NotificationCompat.Builder(this, "recorder") + .setContentTitle("Recording Audio") + .setContentText("Recording audio in background") + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setOngoing(true) + .setOnlyAlertOnce(true) + .setUsesChronometer(true) + .setChronometerCountDown(false) + .setWhen(Date.from(recordingStart.value!!.atZone(ZoneId.systemDefault()).toInstant()).time) + .setShowWhen(true) + .build() + + // show notification + startForeground(getNotificationId(), notification) + + // call function 1 sec later + handler.postDelayed(this::showNotification, 1000L) + } + + // To avoid int overflow, we'll use the number of seconds since 2023-01-01 01:01:01 + private fun getNotificationId(): Int { + val offset = ZoneId.of("UTC").rules.getOffset(recordingStart.value) + + return ( + recordingStart.value!!.toEpochSecond(offset) - + LocalDateTime.of(2023, 1, 1, 1, 1).toEpochSecond(offset) + ).toInt() + } + + private fun createRecorder(): MediaRecorder { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + MediaRecorder(this) + } else { + MediaRecorder() + }.apply { + setAudioSource(MediaRecorder.AudioSource.MIC) + setOutputFile(getFilePath()) + setOutputFormat(getOutputFormat()) + setAudioEncoder(getAudioEncoder()) + setAudioEncodingBitRate(bitRate!!) + setAudioSamplingRate(getAudioSamplingRate()) + + setOnErrorListener { mr, what, extra -> + onError?.onError(mr, what, extra) + + this@RecorderService.stop() + } + } + } + + private fun getFilePath() = "${fileFolder}/${counter}.${getFileExtensions()}" + + inner class LocalBinder: Binder() { + fun getService(): RecorderService = this@RecorderService + } + + enum class Actions { + START, + STOP, + } + + enum class RecorderState { + IDLE, + RECORDING, + PAUSED, + } + + companion object { + fun getOutputFormat(): Int = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + MediaRecorder.OutputFormat.AAC_ADTS + else + MediaRecorder.OutputFormat.THREE_GPP + + fun getFileExtensions(): String = + when(getOutputFormat()) { + MediaRecorder.OutputFormat.AAC_ADTS -> "aac" + MediaRecorder.OutputFormat.THREE_GPP -> "3gp" + else -> throw Exception("Unknown output format") + } + + fun getAudioSamplingRate(): Int = + when(getOutputFormat()) { + MediaRecorder.OutputFormat.AAC_ADTS -> 96000 + MediaRecorder.OutputFormat.THREE_GPP -> 44100 + else -> throw Exception("Unknown output format") + } + + fun getAudioEncoder(): Int = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + MediaRecorder.AudioEncoder.AAC + else + MediaRecorder.AudioEncoder.AMR_NB + + fun getRandomFileFolder(context: Context): String { + // uuid + val folder = UUID.randomUUID().toString() + + return "${context.externalCacheDir!!.absolutePath}/$folder" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/RunningApp.kt b/app/src/main/java/app/myzel394/locationtest/RunningApp.kt new file mode 100644 index 0000000..67861ce --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/RunningApp.kt @@ -0,0 +1,21 @@ +package app.myzel394.locationtest + +import android.app.Application +import android.app.NotificationChannel +import android.os.Build + +class RunningApp: Application() { + override fun onCreate() { + super.onCreate() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val channel = NotificationChannel( + "recorder", + "Recorder", + android.app.NotificationManager.IMPORTANCE_LOW, + ) + val notificationManager = getSystemService(android.app.NotificationManager::class.java) + notificationManager.createNotificationChannel(channel) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/ui/theme/Color.kt b/app/src/main/java/app/myzel394/locationtest/ui/theme/Color.kt new file mode 100644 index 0000000..9741b84 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package app.myzel394.locationtest.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/app/myzel394/locationtest/ui/theme/Theme.kt b/app/src/main/java/app/myzel394/locationtest/ui/theme/Theme.kt new file mode 100644 index 0000000..8af4af4 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package app.myzel394.locationtest.ui.theme + +import android.app.Activity +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.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +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 LocationTestTheme( + 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 + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/locationtest/ui/theme/Type.kt b/app/src/main/java/app/myzel394/locationtest/ui/theme/Type.kt new file mode 100644 index 0000000..bbec797 --- /dev/null +++ b/app/src/main/java/app/myzel394/locationtest/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package app.myzel394.locationtest.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-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file 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/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..2c6acd3 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + LocationTest + \ 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..377711c --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +