From 9a974dded60e23d35192d3f152ef56e762004c82 Mon Sep 17 00:00:00 2001 From: vladimir-shperling Date: Thu, 4 Jan 2024 21:40:54 +0700 Subject: [PATCH] Initial commit --- .gitignore | 15 ++ app/.gitignore | 1 + app/build.gradle | 67 +++++++ app/proguard-rules.pro | 21 ++ .../lab23/InstrumentedTestTrickyHexahedron.kt | 14 ++ app/src/main/AndroidManifest.xml | 43 ++++ .../ru/myitschool/lab23/MainActivity.java | 171 ++++++++++++++++ .../drawable-v24/ic_launcher_foreground.xml | 30 +++ .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++ app/src/main/res/layout/activity_main.xml | 15 ++ app/src/main/res/layout/content_main.xml | 45 +++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/dimens.xml | 3 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/themes.xml | 26 +++ app/src/main/res/xml/file_paths.xml | 6 + .../ru/myitschool/lab23/ExampleUnitTest.java | 17 ++ build.gradle | 23 +++ gradle.properties | 21 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++++++++++++ gradlew.bat | 89 +++++++++ settings.gradle | 16 ++ 36 files changed, 1008 insertions(+) create mode 100644 .gitignore create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/ru/myitschool/lab23/InstrumentedTestTrickyHexahedron.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/ru/myitschool/lab23/MainActivity.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/content_main.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/file_paths.xml create mode 100644 app/src/test/java/ru/myitschool/lab23/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle 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..1cf76db --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,67 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk 32 + + defaultConfig { + applicationId "ru.myitschool.lab23" + minSdk 26 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + testOptions { + animationsDisabled true + } + buildFeatures { + viewBinding true + } + kotlinOptions { + jvmTarget = '11' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + + implementation "androidx.appcompat:appcompat:1.4.1" + implementation "com.google.android.material:material:1.6.0" + implementation "androidx.constraintlayout:constraintlayout:2.1.3" + + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' + implementation "androidx.navigation:navigation-fragment-ktx:$jetpack_version" + + implementation "androidx.navigation:navigation-fragment:$jetpack_version" + implementation "androidx.navigation:navigation-ui:$jetpack_version" + + androidTestImplementation "io.github.kakaocup:kakao:$kakao_version" + + implementation 'androidx.test.uiautomator:uiautomator:2.2.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.5.0-alpha05' + + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + +} 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/ru/myitschool/lab23/InstrumentedTestTrickyHexahedron.kt b/app/src/androidTest/java/ru/myitschool/lab23/InstrumentedTestTrickyHexahedron.kt new file mode 100644 index 0000000..364389b --- /dev/null +++ b/app/src/androidTest/java/ru/myitschool/lab23/InstrumentedTestTrickyHexahedron.kt @@ -0,0 +1,14 @@ +package ru.myitschool.lab23 + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters + + +@RunWith(AndroidJUnit4::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@LargeTest +class InstrumentedTestTrickyHexahedron { +} \ 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..347ead0 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/lab23/MainActivity.java b/app/src/main/java/ru/myitschool/lab23/MainActivity.java new file mode 100644 index 0000000..5da1667 --- /dev/null +++ b/app/src/main/java/ru/myitschool/lab23/MainActivity.java @@ -0,0 +1,171 @@ +package ru.myitschool.lab23; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.provider.MediaStore; +import android.widget.Button; + +import androidx.activity.ComponentActivity; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.FileProvider; + +import java.io.File; +import java.io.IOException; +import java.nio.file.NotDirectoryException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +public class MainActivity extends AppCompatActivity { + + private final long mTimeLimitSec = 60; + private final long mFileSizeLimitBytes = 1920 * 1080 * 10L; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + ActivityResultLauncher photoResultLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == Activity.RESULT_OK) { + Intent data = result.getData(); + setImage(data); + } else if (result.getResultCode() == Activity.RESULT_CANCELED) { + // TODO handle cancelled status + } + }); + + ((Button) findViewById(R.id.capture_video)).setOnClickListener(v -> + SystemCameraCall.callSystemCameraPhoto(this, + Directories.PICTURE, + "", + getPackageName(), + mTimeLimitSec, + mFileSizeLimitBytes, + photoCallback, + photoResultLauncher + ) + ); + } + + private final SystemCameraCall.CallbackVideo photoCallback = new SystemCameraCall.CallbackVideo() { + private File mTempFile; + + @Override + public File getCurrentFile() { + return mTempFile; + } + + @Override + public void setCurrentFile(File tempFile) { + mTempFile = tempFile; + } + + @Override + public void noCameraHandler() { + + } + + @Override + public void noCameraPermission() { + + } + + @Override + public void noStoragePermission() { + + } + }; + + private void setImage(Intent data) { + // TODO set image + } +} + +enum Directories { + PICTURE, + MOVIE, + OTHER +} + +class SystemCameraCall { + + public interface CallbackVideo { + // A callback interface for states + File getCurrentFile(); + + void setCurrentFile(File tempFile); + + void noCameraHandler(); + + void noCameraPermission(); + + void noStoragePermission(); + } + + /** + * @param mContext A Context (Activity) for the current component. + * @param directory Directory enum + * @param fileName The filename with prefix + * @param authority The authority of a FileProvider (applicationId) defined in the manifest + * @param videoTimeLimitSec A limit for video in seconds (not applicable to photos) + * @param sizeBytes The maximum file size + * @param callback A callback for photos and videos + * @param launcher A launcher + */ + public static void callSystemCameraPhoto(@NonNull ComponentActivity mContext, + Directories directory, + String fileName, + String authority, + Long videoTimeLimitSec, + Long sizeBytes, + CallbackVideo callback, + @NonNull ActivityResultLauncher launcher) { + // TODO check permissions + Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + /*if (videoTimeLimitSec != null && videoTimeLimitSec > 0) { + pictureIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, videoTimeLimitSec); + }*/ + if (sizeBytes != null && sizeBytes > 0) { + pictureIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeBytes); + } + if (pictureIntent.resolveActivity(mContext.getPackageManager()) != null) { + File photoFile; + try { + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", + Locale.getDefault()).format(new Date()); + String imageFileName = "IMG_" + timeStamp + "_"; + File storageDir; + if (directory.equals(Directories.PICTURE)) { + storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + } else if (directory.equals(Directories.MOVIE)) { + storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES); + } else { + throw new NotDirectoryException("unsupported directory type"); + } + photoFile = File.createTempFile(imageFileName, ".jpg", storageDir); + String imageFilePath = photoFile.getAbsolutePath(); + callback.setCurrentFile(photoFile); + } catch (IOException e) { + callback.noStoragePermission(); + return; + } + Uri photoUri = FileProvider.getUriForFile(mContext, authority + ".provider", photoFile); + pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); + launcher.launch(pictureIntent); + } else { + if (callback != null) callback.noCameraHandler(); + } + + } +} + 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/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..dacc95f --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml new file mode 100644 index 0000000..13c3e4d --- /dev/null +++ b/app/src/main/res/layout/content_main.xml @@ -0,0 +1,45 @@ + + + + + + +