diff --git a/cmake/android/android_gradle_projects.cmake b/cmake/android/android_gradle_projects.cmake index 796d3aea5a..782a46e012 100644 --- a/cmake/android/android_gradle_projects.cmake +++ b/cmake/android/android_gradle_projects.cmake @@ -16,7 +16,7 @@ endif() set(GRADLE_VERSION "7.6.3" CACHE STRING "Gradle version") message(STATUS "Gradle version: ${GRADLE_VERSION}") -set(ANDROID_COMPILE_SDK_VERSION "26" CACHE STRING "Android compileSdkVersion") +set(ANDROID_COMPILE_SDK_VERSION "31" CACHE STRING "Android compileSdkVersion") if(ANDROID_NATIVE_API_LEVEL GREATER 21) set(ANDROID_MIN_SDK_VERSION "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android minSdkVersion") else() diff --git a/platforms/android/build_java_shared_aar.py b/platforms/android/build_java_shared_aar.py index 2a7768a2d4..e99c78ec28 100755 --- a/platforms/android/build_java_shared_aar.py +++ b/platforms/android/build_java_shared_aar.py @@ -157,7 +157,7 @@ def main(args): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Builds AAR with Java and shared C++ libs from OpenCV SDK") parser.add_argument('opencv_sdk_path') - parser.add_argument('--android_compile_sdk', default="26") + parser.add_argument('--android_compile_sdk', default="31") parser.add_argument('--android_min_sdk', default="21") parser.add_argument('--android_target_sdk', default="31") parser.add_argument('--java_version', default="1_8") diff --git a/platforms/android/build_static_aar.py b/platforms/android/build_static_aar.py index b5dc680081..c1ab4046f4 100755 --- a/platforms/android/build_static_aar.py +++ b/platforms/android/build_static_aar.py @@ -230,9 +230,9 @@ def main(args): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Builds AAR with static C++ libs from OpenCV SDK") parser.add_argument('opencv_sdk_path') - parser.add_argument('--android_compile_sdk', default="26") + parser.add_argument('--android_compile_sdk', default="31") parser.add_argument('--android_min_sdk', default="21") - parser.add_argument('--android_target_sdk', default="26") + parser.add_argument('--android_target_sdk', default="31") parser.add_argument('--java_version', default="1_8") parser.add_argument('--ndk_location', default="") parser.add_argument('--cmake_location', default="") diff --git a/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3Activity.java b/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3Activity.java index 025a74bc6f..9a4a9ea619 100644 --- a/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3Activity.java +++ b/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3Activity.java @@ -13,8 +13,11 @@ import org.opencv.android.OpenCVLoader; import org.opencv.core.Mat; import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2; +import android.Manifest; import android.annotation.SuppressLint; +import android.content.pm.PackageManager; import android.hardware.Camera.Size; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.util.Log; @@ -177,10 +180,17 @@ public class Tutorial3Activity extends CameraActivity implements CvCameraViewLis @Override public boolean onTouch(View v, MotionEvent event) { Log.i(TAG,"onTouch event"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; + requestPermissions(permissions, 1); + return false; + } + } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); String currentDateandTime = sdf.format(new Date()); - String fileName = Environment.getExternalStorageDirectory().getPath() + - "/sample_picture_" + currentDateandTime + ".jpg"; + String fileName = "sample_picture_" + currentDateandTime + ".jpg"; mOpenCvCameraView.takePicture(fileName); Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show(); return false; diff --git a/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3View.java b/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3View.java index d102cbcdef..fbc2949cec 100644 --- a/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3View.java +++ b/samples/android/tutorial-3-cameracontrol/src/org/opencv/samples/tutorial3/Tutorial3View.java @@ -1,14 +1,24 @@ package org.opencv.samples.tutorial3; import java.io.FileOutputStream; +import java.io.OutputStream; import java.util.List; +import java.util.Objects; import org.opencv.android.JavaCameraView; +import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.MediaStore; import android.util.AttributeSet; import android.util.Log; @@ -73,15 +83,36 @@ public class Tutorial3View extends JavaCameraView implements PictureCallback { mCamera.setPreviewCallback(this); // Write the image in a file (in jpeg format) - try { - FileOutputStream fos = new FileOutputStream(mPictureFileName); - - fos.write(data); - fos.close(); - - } catch (java.io.IOException e) { - Log.e("PictureDemo", "Exception in photoCallback", e); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); + new Thread(new Runnable() { + @Override + public void run() { + ContentResolver resolver = getContext().getContentResolver(); + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, mPictureFileName); + contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg"); + contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); + Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); + try { + OutputStream fos = resolver.openOutputStream(Objects.requireNonNull(imageUri)); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); + Objects.requireNonNull(fos).close(); + } catch (java.io.IOException e) { + Log.e("PictureDemo", "Exception in photoCallback", e); + } + } + }).start(); + } else { + mPictureFileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + + "/" + mPictureFileName; + try { + FileOutputStream fos = new FileOutputStream(mPictureFileName); + fos.write(data); + fos.close(); + } catch (java.io.IOException e) { + Log.e("PictureDemo", "Exception in photoCallback", e); + } } - } }