diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..08653eade --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,40 @@ +name: Run Gradle Build on PRs +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v2 + with: + distribution: temurin + java-version: 11 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + gradle-version: 7.4.2 + + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r21e + + - name: Execute Gradle Build Release + run: ./gradlew clean build assembleRelease --parallel -x lint + + - name: Upload + if: github.ref_name == 'release' + uses: actions/upload-artifact@v4 + with: + name: Build Artifacts (${{ matrix.os }}) + path: app/build/outputs/apk/release/ diff --git a/.gitignore b/.gitignore index b219993c2..5982fd762 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ bin/classes bin/res bin/jarlist.cache *.cache +.DS_Store # Local configuration file (sdk path, etc) local.properties @@ -55,6 +56,8 @@ build !.idea/fileColors.xml !.idea/encodings.xml !.idea/gradle.xml +!.idea/modules.xml +!.idea/modules/*.xml !.idea/runConfigurations/*.xml !.idea/inspectionProfiles/*.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 96cc43efa..b589d56e9 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,22 +1,6 @@ - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index da16de338..493d293d4 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,9 +1,9 @@ + diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 0fbe4b750..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d8..000000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index a6bdc99dd..d09c0f65d 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ If you want to use Android Studio(unfortunately NDK supporting on Android Studio 5. Android Studio raise some errors but just ignore now. Android Studio generate `local.properties` file. Please open `local.properties` and add `ndk.dir` key to the end of the file. The contents of the file looks like this. ``` sdk.dir={path to Android SDK on your storage} -ndk.dir={path to Android SDK on your storage} +ndk.dir={path to Android NDK on your storage} ``` Please replace actual path to SDK and NDK on your storage. Of course you can make `local.properties` by manually instead of using automatically generated ones by Android Studio. diff --git a/UVCCamera.iml b/UVCCamera.iml index e9836a27d..757acfb3b 100644 --- a/UVCCamera.iml +++ b/UVCCamera.iml @@ -1,19 +1,12 @@ - - - - - - - - + + + - + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 3287a8720..6b881ebec 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,20 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - repositories { -// google() - maven { url 'https://maven.google.com' } - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' - } + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.2.1' + } } allprojects { - repositories { -// google() - maven { url 'https://maven.google.com' } + repositories { + maven { url 'https://raw.github.com/saki4510t/libcommon/master/repository/' } jcenter() - maven { url 'http://raw.github.com/saki4510t/libcommon/master/repository/' } - } + google() + } } task clean(type: Delete) { @@ -26,9 +24,9 @@ task clean(type: Delete) { ext { supportLibVersion = '27.1.1' // variable that can be referenced to keep support libs consistent commonLibVersion= '2.12.4' - versionBuildTool = '27.0.3' - versionCompiler = 27 - versionTarget = 27 + versionCompiler = 34 + versionTarget = 34 + minTargetVersion = 30 versionNameString = '1.0.0' javaSourceCompatibility = JavaVersion.VERSION_1_8 javaTargetCompatibility = JavaVersion.VERSION_1_8 diff --git a/gradle.properties b/gradle.properties index 2c1f15099..f30eb8d10 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m -org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..13372aef5 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17daf5c34..aa991fcea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Oct 02 16:16:11 JST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/gradlew b/gradlew index 91a7e269e..9d82f7891 100755 --- a/gradlew +++ b/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/libuvccamera/build.gradle b/libuvccamera/build.gradle index 6025fe8c2..d95f9e811 100644 --- a/libuvccamera/build.gradle +++ b/libuvccamera/build.gradle @@ -25,8 +25,7 @@ apply plugin: 'com.android.library' import org.apache.tools.ant.taskdefs.condition.Os android { - compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool + compileSdk versionCompiler compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { } defaultConfig { - minSdkVersion 14 + minSdkVersion minTargetVersion targetSdkVersion versionTarget } @@ -58,13 +57,16 @@ tasks.withType(JavaCompile) { String getNdkBuildPath() { Properties properties = new Properties() - properties.load(project.rootProject.file('local.properties').newDataInputStream()) - def ndkBuildingDir = properties.getProperty("ndk.dir") - def ndkBuildPath = ndkBuildingDir + def ndkBuildPath = ""; + def ndkBuildingDir = ""; + if (project.rootProject.file("local.properties").exists()) { + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + ndkBuildingDir = properties.getProperty("ndk.dir") + '/' + } if (Os.isFamily(Os.FAMILY_WINDOWS)) { - ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd' + ndkBuildPath = ndkBuildingDir + 'ndk-build.cmd' } else { - ndkBuildPath = ndkBuildingDir + '/ndk-build' + ndkBuildPath = ndkBuildingDir + 'ndk-build' } return ndkBuildPath } @@ -86,7 +88,6 @@ clean.dependsOn 'ndkClean' dependencies { implementation fileTree(dir: new File(buildDir, 'libs'), include: '*.jar') - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/libuvccamera/src/main/AndroidManifest.xml b/libuvccamera/src/main/AndroidManifest.xml index 8a2f33f49..730106ed7 100644 --- a/libuvccamera/src/main/AndroidManifest.xml +++ b/libuvccamera/src/main/AndroidManifest.xml @@ -26,8 +26,4 @@ android:versionCode="2" android:versionName="1.1" > - - diff --git a/libuvccamera/src/main/java/com/serenegiant/common/BaseActivity.java b/libuvccamera/src/main/java/com/serenegiant/common/BaseActivity.java index 89262ca26..96783e699 100644 --- a/libuvccamera/src/main/java/com/serenegiant/common/BaseActivity.java +++ b/libuvccamera/src/main/java/com/serenegiant/common/BaseActivity.java @@ -26,15 +26,18 @@ import android.Manifest; import android.annotation.SuppressLint; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.StringRes; -import android.support.v7.app.AppCompatActivity; +import android.app.Activity; import android.util.Log; import android.widget.Toast; +import com.serenegiant.dialog.MessageDialogFragment; import com.serenegiant.dialog.MessageDialogFragmentV4; import com.serenegiant.utils.BuildCheck; import com.serenegiant.utils.HandlerThreadHandler; @@ -44,7 +47,7 @@ * Created by saki on 2016/11/18. * */ -public class BaseActivity extends AppCompatActivity +public class BaseActivity extends Activity implements MessageDialogFragmentV4.MessageDialogListener { private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること @@ -277,11 +280,15 @@ protected void checkPermissionResult(final int requestCode, final String permiss * @return true 外部ストレージへの書き込みパーミッションが有る */ protected boolean checkPermissionWriteExternalStorage() { - if (!PermissionCheck.hasWriteExternalStorage(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, - R.string.permission_title, R.string.permission_ext_storage_request, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); - return false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { + return Environment.isExternalStorageManager() || Environment.isExternalStorageEmulated(); + } else { + if (!PermissionCheck.hasWriteExternalStorage(this)) { + MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, + R.string.permission_title, R.string.permission_ext_storage_request, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); + return false; + } } return true; } @@ -293,7 +300,7 @@ protected boolean checkPermissionWriteExternalStorage() { */ protected boolean checkPermissionAudio() { if (!PermissionCheck.hasAudio(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING, + MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING, R.string.permission_title, R.string.permission_audio_recording_request, new String[]{Manifest.permission.RECORD_AUDIO}); return false; @@ -308,7 +315,7 @@ protected boolean checkPermissionAudio() { */ protected boolean checkPermissionNetwork() { if (!PermissionCheck.hasNetwork(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_NETWORK, + MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_NETWORK, R.string.permission_title, R.string.permission_network_request, new String[]{Manifest.permission.INTERNET}); return false; @@ -323,7 +330,7 @@ protected boolean checkPermissionNetwork() { */ protected boolean checkPermissionCamera() { if (!PermissionCheck.hasCamera(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_CAMERA, + MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_CAMERA, R.string.permission_title, R.string.permission_camera_request, new String[]{Manifest.permission.CAMERA}); return false; diff --git a/libuvccamera/src/main/java/com/serenegiant/common/BaseFragment.java b/libuvccamera/src/main/java/com/serenegiant/common/BaseFragment.java index cdb07fe4c..4318bda8b 100644 --- a/libuvccamera/src/main/java/com/serenegiant/common/BaseFragment.java +++ b/libuvccamera/src/main/java/com/serenegiant/common/BaseFragment.java @@ -27,7 +27,9 @@ import android.annotation.SuppressLint; import android.app.Fragment; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; @@ -285,11 +287,15 @@ protected void checkPermissionResult(final int requestCode, final String permiss * @return true 外部ストレージへの書き込みパーミッションが有る */ protected boolean checkPermissionWriteExternalStorage() { - if (!PermissionCheck.hasWriteExternalStorage(getActivity())) { - MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, - com.serenegiant.common.R.string.permission_title, com.serenegiant.common.R.string.permission_ext_storage_request, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); - return false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) { + return Environment.isExternalStorageManager() || Environment.isExternalStorageEmulated(); + } else { + if (!PermissionCheck.hasWriteExternalStorage(getActivity())) { + MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, + R.string.permission_title, R.string.permission_ext_storage_request, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); + return false; + } } return true; } diff --git a/libuvccamera/src/main/java/com/serenegiant/usb/USBMonitor.java b/libuvccamera/src/main/java/com/serenegiant/usb/USBMonitor.java index 722dd3613..abfd37a70 100644 --- a/libuvccamera/src/main/java/com/serenegiant/usb/USBMonitor.java +++ b/libuvccamera/src/main/java/com/serenegiant/usb/USBMonitor.java @@ -43,6 +43,7 @@ import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; +import android.os.Build; import android.os.Handler; import android.text.TextUtils; import android.util.Log; @@ -167,11 +168,21 @@ public synchronized void register() throws IllegalStateException { if (DEBUG) Log.i(TAG, "register:"); final Context context = mWeakContext.get(); if (context != null) { - mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); + mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); // ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); - context.registerReceiver(mUsbReceiver, filter); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // For Android 13 (API level 33) and above, use receiver flags + context.registerReceiver(mUsbReceiver, filter, Context.RECEIVER_NOT_EXPORTED); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // For Android 12 (API level 31) and above + context.registerReceiver(mUsbReceiver, filter); + } else { + // For older versions of Android + context.registerReceiver(mUsbReceiver, filter); + } } // start connection check mDeviceCounts = 0; @@ -660,7 +671,11 @@ public static final String getDeviceKeyName(final UsbDevice device, final String if (useNewAPI && BuildCheck.isAndroid5()) { sb.append("#"); if (TextUtils.isEmpty(serial)) { - sb.append(device.getSerialNumber()); sb.append("#"); // API >= 21 + try { + sb.append(device.getSerialNumber()); + sb.append("#"); + } // API >= 21 & targetSdkVersion has to be <= 28 + catch(SecurityException ignore) {} } sb.append(device.getManufacturerName()); sb.append("#"); // API >= 21 sb.append(device.getConfigurationCount()); sb.append("#"); // API >= 21 diff --git a/libuvccamera/src/main/jni/Application.mk b/libuvccamera/src/main/jni/Application.mk index c6f7c2e1b..01b07c4b4 100644 --- a/libuvccamera/src/main/jni/Application.mk +++ b/libuvccamera/src/main/jni/Application.mk @@ -26,7 +26,7 @@ # Note: Supporting GCC on NDK is already deprecated and GCC will be removed from NDK soon. #NDK_TOOLCHAIN_VERSION := 4.9 -APP_PLATFORM := android-14 -APP_ABI := armeabi armeabi-v7a x86 mips +APP_PLATFORM := android-21 +APP_ABI := armeabi-v7a arm64-v8a #APP_OPTIM := debug APP_OPTIM := release diff --git a/libuvccamera/src/main/jni/UVCCamera/UVCPreview.cpp b/libuvccamera/src/main/jni/UVCCamera/UVCPreview.cpp index 02c1a60b8..391d82f45 100644 --- a/libuvccamera/src/main/jni/UVCCamera/UVCPreview.cpp +++ b/libuvccamera/src/main/jni/UVCCamera/UVCPreview.cpp @@ -845,7 +845,7 @@ void UVCPreview::do_capture_surface(JNIEnv *env) { */ void UVCPreview::do_capture_callback(JNIEnv *env, uvc_frame_t *frame) { ENTER(); - + pthread_mutex_lock(&capture_mutex); if (LIKELY(frame)) { uvc_frame_t *callback_frame = frame; if (mFrameCallbackObj) { @@ -872,5 +872,6 @@ void UVCPreview::do_capture_callback(JNIEnv *env, uvc_frame_t *frame) { SKIP: recycle_frame(callback_frame); } + pthread_mutex_unlock(&capture_mutex); EXIT(); } diff --git a/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c b/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c index 86265959e..0d52e7384 100644 --- a/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c +++ b/libuvccamera/src/main/jni/libusb/libusb/os/android_usbfs.c @@ -1311,10 +1311,10 @@ static int android_initialize_device(struct libusb_device *dev, priv->descriptors_len = 0; priv->fd = 0; memset(desc, 0, sizeof(desc)); - if (!lseek(fd, 0, SEEK_SET)) { - // ディスクリプタを読み込んでローカルキャッシュする - int length = read(fd, desc, sizeof(desc)); - LOGD("Device::init read returned %d errno %d\n", length, errno); + if (!lseek(fd, 0, SEEK_SET)) { + // ディスクリプタを読み込んでローカルキャッシュする + int length = read(fd, desc, sizeof(desc)); + LOGD("Device::init read returned %d errno %d\n", length, errno); if (length > 0) { priv->fd = fd; priv->descriptors = usbi_reallocf(priv->descriptors, length); @@ -1383,36 +1383,36 @@ int android_generate_device(struct libusb_context *ctx, struct libusb_device **d int r = 0; *dev = NULL; - /* FIXME: session ID is not guaranteed unique as addresses can wrap and - * will be reused. instead we should add a simple sysfs attribute with - * a session ID. */ + /* FIXME: session ID is not guaranteed unique as addresses can wrap and + * will be reused. instead we should add a simple sysfs attribute with + * a session ID. */ session_id = busnum << 8 | devaddr; - LOGD("allocating new device for %d/%d (session %ld)", busnum, devaddr, session_id); - *dev = usbi_alloc_device(ctx, session_id); // この時点で参照カウンタ=1 - if (UNLIKELY(!dev)) { - RETURN(LIBUSB_ERROR_NO_MEM, int); - } - - r = android_initialize_device(*dev, busnum, devaddr, fd); - if (UNLIKELY(r < 0)) { - LOGE("initialize_device failed: ret=%d", r); - goto out; - } - r = usbi_sanitize_device(*dev); - if (UNLIKELY(r < 0)) { - LOGE("usbi_sanitize_device failed: ret=%d", r); - goto out; - } + LOGD("allocating new device for %d/%d (session %ld)", busnum, devaddr, session_id); + *dev = usbi_alloc_device(ctx, session_id); // この時点で参照カウンタ=1 + if (UNLIKELY(!dev)) { + RETURN(LIBUSB_ERROR_NO_MEM, int); + } + + r = android_initialize_device(*dev, busnum, devaddr, fd); + if (UNLIKELY(r < 0)) { + LOGE("initialize_device failed: ret=%d", r); + goto out; + } + r = usbi_sanitize_device(*dev); + if (UNLIKELY(r < 0)) { + LOGE("usbi_sanitize_device failed: ret=%d", r); + goto out; + } out: - if (UNLIKELY(r < 0)) { - libusb_unref_device(*dev); // ここで参照カウンタが0になって破棄される - *dev = NULL; - } else { - usbi_connect_device(*dev); - } + if (UNLIKELY(r < 0)) { + libusb_unref_device(*dev); // ここで参照カウンタが0になって破棄される + *dev = NULL; + } else { + usbi_connect_device(*dev); + } - RETURN(r, int); + RETURN(r, int); } @@ -2726,6 +2726,9 @@ static int handle_iso_completion(struct libusb_device_handle *handle, // XXX add usbi_mutex_lock(&itransfer->lock); for (i = 0; i < num_urbs; i++) { + if(tpriv->iso_urbs == NULL){ + return LIBUSB_TRANSFER_ERROR; + } if (urb == tpriv->iso_urbs[i]) { urb_idx = i + 1; break; @@ -2926,7 +2929,13 @@ static int reap_for_handle(struct libusb_device_handle *handle) { usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status, urb->actual_length); - + + // if not check status, will crash when target > 27 + // current error status is -108 + if(urb->status == -108){ + return LIBUSB_ERROR_OTHER; + } + switch (transfer->type) { case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return handle_iso_completion(handle, itransfer, urb); diff --git a/usbCameraCommon/build.gradle b/usbCameraCommon/build.gradle index 92ed5a9d9..243d56c74 100644 --- a/usbCameraCommon/build.gradle +++ b/usbCameraCommon/build.gradle @@ -24,8 +24,7 @@ apply plugin: 'com.android.library' android { - compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool + compileSdk versionCompiler compileOptions { sourceCompatibility javaSourceCompatibility @@ -33,7 +32,7 @@ android { } defaultConfig { - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget } @@ -48,7 +47,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraCommon/src/main/AndroidManifest.xml b/usbCameraCommon/src/main/AndroidManifest.xml index 67c59eab7..95180b680 100644 --- a/usbCameraCommon/src/main/AndroidManifest.xml +++ b/usbCameraCommon/src/main/AndroidManifest.xml @@ -21,4 +21,5 @@ ~ may have a different license, see the respective files. --> - + + diff --git a/usbCameraCommon/src/main/java/com/serenegiant/encoder/MediaAudioEncoder.java b/usbCameraCommon/src/main/java/com/serenegiant/encoder/MediaAudioEncoder.java index a6a9010f6..ba6d07fba 100644 --- a/usbCameraCommon/src/main/java/com/serenegiant/encoder/MediaAudioEncoder.java +++ b/usbCameraCommon/src/main/java/com/serenegiant/encoder/MediaAudioEncoder.java @@ -27,6 +27,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; +import android.annotation.SuppressLint; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaCodec; @@ -37,16 +38,16 @@ import android.util.Log; public class MediaAudioEncoder extends MediaEncoder implements IAudioEncoder { - private static final boolean DEBUG = true; // TODO set false on release + private static final boolean DEBUG = true; // TODO set false on release private static final String TAG = "MediaAudioEncoder"; private static final String MIME_TYPE = "audio/mp4a-latm"; - private static final int SAMPLE_RATE = 44100; // 44.1[KHz] is only setting guaranteed to be available on all devices. - private static final int BIT_RATE = 64000; - public static final int SAMPLES_PER_FRAME = 1024; // AAC, bytes/frame/channel - public static final int FRAMES_PER_BUFFER = 25; // AAC, frame/buffer/sec + private static final int SAMPLE_RATE = 44100; // 44.1[KHz] is only setting guaranteed to be available on all devices. + private static final int BIT_RATE = 64000; + public static final int SAMPLES_PER_FRAME = 1024; // AAC, bytes/frame/channel + public static final int FRAMES_PER_BUFFER = 25; // AAC, frame/buffer/sec - private AudioThread mAudioThread = null; + private AudioThread mAudioThread = null; public MediaAudioEncoder(final MediaMuxerWrapper muxer, final MediaEncoderListener listener) { super(muxer, listener); @@ -55,52 +56,52 @@ public MediaAudioEncoder(final MediaMuxerWrapper muxer, final MediaEncoderListen @Override protected void prepare() throws IOException { if (DEBUG) Log.v(TAG, "prepare:"); - mTrackIndex = -1; - mMuxerStarted = mIsEOS = false; - // prepare MediaCodec for AAC encoding of audio data from inernal mic. - final MediaCodecInfo audioCodecInfo = selectAudioCodec(MIME_TYPE); - if (audioCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } + mTrackIndex = -1; + mMuxerStarted = mIsEOS = false; + // prepare MediaCodec for AAC encoding of audio data from inernal mic. + final MediaCodecInfo audioCodecInfo = selectAudioCodec(MIME_TYPE); + if (audioCodecInfo == null) { + Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); + return; + } if (DEBUG) Log.i(TAG, "selected codec: " + audioCodecInfo.getName()); - final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1); + final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1); audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO); audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); -// audioFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); +// audioFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); // audioFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs ); if (DEBUG) Log.i(TAG, "format: " + audioFormat); - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - mMediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - mMediaCodec.start(); - if (DEBUG) Log.i(TAG, "prepare finishing"); - if (mListener != null) { - try { - mListener.onPrepared(this); - } catch (final Exception e) { - Log.e(TAG, "prepare:", e); - } - } + mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); + mMediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); + mMediaCodec.start(); + if (DEBUG) Log.i(TAG, "prepare finishing"); + if (mListener != null) { + try { + mListener.onPrepared(this); + } catch (final Exception e) { + Log.e(TAG, "prepare:", e); + } + } } - @Override + @Override protected void startRecording() { super.startRecording(); // create and execute audio capturing thread using internal mic if (mAudioThread == null) { - mAudioThread = new AudioThread(); + mAudioThread = new AudioThread(); mAudioThread.start(); } } @Override - protected void release() { + protected void release() { mAudioThread = null; super.release(); - } + } private static final int[] AUDIO_SOURCES = new int[] { MediaRecorder.AudioSource.DEFAULT, @@ -112,9 +113,10 @@ protected void release() { * Thread to capture audio data from internal mic as uncompressed 16bit PCM data * and write them to the MediaCodec encoder */ - private class AudioThread extends Thread { - @Override - public void run() { + private class AudioThread extends Thread { + @Override + @SuppressLint("MissingPermission") + public void run() { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); // THREAD_PRIORITY_URGENT_AUDIO int cnt = 0; final int min_buffer_size = AudioRecord.getMinBufferSize( @@ -132,7 +134,7 @@ public void run() { if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { audioRecord.release(); audioRecord = null; - } + } } } catch (final Exception e) { audioRecord = null; @@ -197,37 +199,37 @@ public void run() { } } if (DEBUG) Log.v(TAG, "AudioThread:finished"); - } - } - - /** - * select the first codec that match a specific MIME type - * @param mimeType - * @return - */ - private static final MediaCodecInfo selectAudioCodec(final String mimeType) { - if (DEBUG) Log.v(TAG, "selectAudioCodec:"); - - MediaCodecInfo result = null; - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); -LOOP: for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (DEBUG) Log.i(TAG, "supportedType:" + codecInfo.getName() + ",MIME=" + types[j]); - if (types[j].equalsIgnoreCase(mimeType)) { - if (result == null) { - result = codecInfo; - break LOOP; - } - } - } - } - return result; - } + } + } + + /** + * select the first codec that match a specific MIME type + * @param mimeType + * @return + */ + private static final MediaCodecInfo selectAudioCodec(final String mimeType) { + if (DEBUG) Log.v(TAG, "selectAudioCodec:"); + + MediaCodecInfo result = null; + // get the list of available codecs + final int numCodecs = MediaCodecList.getCodecCount(); +LOOP: for (int i = 0; i < numCodecs; i++) { + final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); + if (!codecInfo.isEncoder()) { // skipp decoder + continue; + } + final String[] types = codecInfo.getSupportedTypes(); + for (int j = 0; j < types.length; j++) { + if (DEBUG) Log.i(TAG, "supportedType:" + codecInfo.getName() + ",MIME=" + types[j]); + if (types[j].equalsIgnoreCase(mimeType)) { + if (result == null) { + result = codecInfo; + break LOOP; + } + } + } + } + return result; + } } diff --git a/usbCameraCommon/src/main/java/com/serenegiant/usbcameracommon/AbstractUVCCameraHandler.java b/usbCameraCommon/src/main/java/com/serenegiant/usbcameracommon/AbstractUVCCameraHandler.java index b368a1cfc..22ba3da78 100644 --- a/usbCameraCommon/src/main/java/com/serenegiant/usbcameracommon/AbstractUVCCameraHandler.java +++ b/usbCameraCommon/src/main/java/com/serenegiant/usbcameracommon/AbstractUVCCameraHandler.java @@ -23,6 +23,7 @@ package com.serenegiant.usbcameracommon; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; @@ -31,6 +32,7 @@ import android.media.AudioManager; import android.media.MediaScannerConnection; import android.media.SoundPool; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.Looper; @@ -65,7 +67,7 @@ import java.util.concurrent.CopyOnWriteArraySet; abstract class AbstractUVCCameraHandler extends Handler { - private static final boolean DEBUG = true; // TODO set false on release + private static final boolean DEBUG = true; // TODO set false on release private static final String TAG = "AbsUVCCameraHandler"; public interface CameraCallback { @@ -515,7 +517,7 @@ public void handleCaptureStill(final String path) { if (DEBUG) Log.v(TAG_THREAD, "handleCaptureStill:"); final Activity parent = mWeakParent.get(); if (parent == null) return; - mSoundPool.play(mSoundId, 0.2f, 0.2f, 0, 0, 1.0f); // play shutter sound + mSoundPool.play(mSoundId, 0.2f, 0.2f, 0, 0, 1.0f); // play shutter sound try { final Bitmap bitmap = mWeakCameraView.get().captureStillImage(); // get buffered output stream for saving a captured still image as a file on external storage. @@ -544,16 +546,16 @@ public void handleStartRecording() { if (DEBUG) Log.v(TAG_THREAD, "handleStartRecording:"); try { if ((mUVCCamera == null) || (mMuxer != null)) return; - final MediaMuxerWrapper muxer = new MediaMuxerWrapper(".mp4"); // if you record audio only, ".m4a" is also OK. + final MediaMuxerWrapper muxer = new MediaMuxerWrapper(".mp4"); // if you record audio only, ".m4a" is also OK. MediaVideoBufferEncoder videoEncoder = null; switch (mEncoderType) { - case 1: // for video capturing using MediaVideoEncoder + case 1: // for video capturing using MediaVideoEncoder new MediaVideoEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener); break; - case 2: // for video capturing using MediaVideoBufferEncoder + case 2: // for video capturing using MediaVideoBufferEncoder videoEncoder = new MediaVideoBufferEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener); break; - // case 0: // for video capturing using MediaSurfaceEncoder + // case 0: // for video capturing using MediaSurfaceEncoder default: new MediaSurfaceEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener); break; @@ -700,27 +702,37 @@ public void onStopped(final MediaEncoder encoder) { /** * prepare and load shutter sound for still image capturing */ - @SuppressWarnings("deprecation") - private void loadShutterSound(final Context context) { - // get system stream type using reflection - int streamType; - try { - final Class audioSystemClass = Class.forName("android.media.AudioSystem"); - final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); - streamType = sseField.getInt(null); - } catch (final Exception e) { - streamType = AudioManager.STREAM_SYSTEM; // set appropriate according to your app policy - } - if (mSoundPool != null) { - try { - mSoundPool.release(); - } catch (final Exception e) { - } - mSoundPool = null; - } - // load shutter sound from resource - mSoundPool = new SoundPool(2, streamType, 0); - mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); + @SuppressLint("SoonBlockedPrivateApi") + protected void loadShutterSound(final Context context) { + // Define a default stream type + int streamType = AudioManager.STREAM_SYSTEM; + + // Conditionally handle reflection based on the Android version + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) { // API 32 is Android 12L + try { + // Use reflection only for older versions + final Class audioSystemClass = Class.forName("android.media.AudioSystem"); + final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); + streamType = sseField.getInt(null); + } catch (final Exception e) { + // If reflection fails, fall back to STREAM_SYSTEM + streamType = AudioManager.STREAM_SYSTEM; + } + } + + // Clean up existing SoundPool instance if necessary + if (mSoundPool != null) { + try { + mSoundPool.release(); + } catch (final Exception e) { + // Handle the exception (optional) + } + mSoundPool = null; + } + + // Initialize the SoundPool and load the shutter sound + mSoundPool = new SoundPool(2, streamType, 0); + mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); } @Override diff --git a/usbCameraTest/build.gradle b/usbCameraTest/build.gradle index da5a1c139..55d8e8008 100644 --- a/usbCameraTest/build.gradle +++ b/usbCameraTest/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest" - minSdkVersion 14 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest/src/main/AndroidManifest.xml b/usbCameraTest/src/main/AndroidManifest.xml index a2abf49a9..dcc18c307 100644 --- a/usbCameraTest/src/main/AndroidManifest.xml +++ b/usbCameraTest/src/main/AndroidManifest.xml @@ -31,7 +31,8 @@ android:theme="@style/AppTheme" > + android:label="@string/app_name" + android:exported="true"> diff --git a/usbCameraTest/src/main/res/layout/activity_main.xml b/usbCameraTest/src/main/res/layout/activity_main.xml index 5ca52e562..cde370285 100644 --- a/usbCameraTest/src/main/res/layout/activity_main.xml +++ b/usbCameraTest/src/main/res/layout/activity_main.xml @@ -34,7 +34,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:background="#ff000000" /> + android:background="@null" /> + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest0/build.gradle b/usbCameraTest0/build.gradle index cc233b045..ee17236c9 100644 --- a/usbCameraTest0/build.gradle +++ b/usbCameraTest0/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest0" - minSdkVersion 14 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest0/src/main/AndroidManifest.xml b/usbCameraTest0/src/main/AndroidManifest.xml index 015e549fc..ab263c4dc 100644 --- a/usbCameraTest0/src/main/AndroidManifest.xml +++ b/usbCameraTest0/src/main/AndroidManifest.xml @@ -31,7 +31,8 @@ android:theme="@style/AppTheme" > + android:label="@string/app_name" + android:exported="true"> diff --git a/usbCameraTest0/src/main/res/values/dimens.xml b/usbCameraTest0/src/main/res/values/dimens.xml index 9c8e51ac3..68161865d 100644 --- a/usbCameraTest0/src/main/res/values/dimens.xml +++ b/usbCameraTest0/src/main/res/values/dimens.xml @@ -23,6 +23,7 @@ --> + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest2/build.gradle b/usbCameraTest2/build.gradle index 6d7160fa7..a75390083 100644 --- a/usbCameraTest2/build.gradle +++ b/usbCameraTest2/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest2" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest2/src/main/AndroidManifest.xml b/usbCameraTest2/src/main/AndroidManifest.xml index 34e65a862..13d8b9bab 100644 --- a/usbCameraTest2/src/main/AndroidManifest.xml +++ b/usbCameraTest2/src/main/AndroidManifest.xml @@ -33,7 +33,8 @@ android:theme="@style/AppTheme" > + android:label="@string/app_name" + android:exported="true"> diff --git a/usbCameraTest2/src/main/res/layout/activity_main.xml b/usbCameraTest2/src/main/res/layout/activity_main.xml index ae26b4037..131bb9ca4 100644 --- a/usbCameraTest2/src/main/res/layout/activity_main.xml +++ b/usbCameraTest2/src/main/res/layout/activity_main.xml @@ -27,7 +27,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff000000" - tools:context="com.serenegiant.usbcameratest.MainActivity" + tools:context="com.serenegiant.usbcameratest2.MainActivity" tools:ignore="MergeRootFrame" > + android:background="@null" /> - + + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest3/build.gradle b/usbCameraTest3/build.gradle index 71d65ef70..34f1e9ad0 100644 --- a/usbCameraTest3/build.gradle +++ b/usbCameraTest3/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest3" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest3/src/main/AndroidManifest.xml b/usbCameraTest3/src/main/AndroidManifest.xml index 7b60fda08..c93c69464 100644 --- a/usbCameraTest3/src/main/AndroidManifest.xml +++ b/usbCameraTest3/src/main/AndroidManifest.xml @@ -37,7 +37,8 @@ + android:label="@string/app_name" + android:exported="true"> diff --git a/usbCameraTest3/src/main/res/values/dimens.xml b/usbCameraTest3/src/main/res/values/dimens.xml index 790540d2d..522af662f 100644 --- a/usbCameraTest3/src/main/res/values/dimens.xml +++ b/usbCameraTest3/src/main/res/values/dimens.xml @@ -24,6 +24,7 @@ + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest4/build.gradle b/usbCameraTest4/build.gradle index 8b9f98b7f..aedb6d838 100644 --- a/usbCameraTest4/build.gradle +++ b/usbCameraTest4/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest4" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 9 versionName "3.00" @@ -51,12 +50,9 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" - implementation("com.serenegiant:common:${commonLibVersion}") { - exclude module: 'support-v4' - } + implementation("com.serenegiant:common:${commonLibVersion}") implementation project(':libuvccamera') implementation project(':usbCameraCommon') } diff --git a/usbCameraTest4/src/main/AndroidManifest.xml b/usbCameraTest4/src/main/AndroidManifest.xml index 9fc8b5aa3..76ba38790 100644 --- a/usbCameraTest4/src/main/AndroidManifest.xml +++ b/usbCameraTest4/src/main/AndroidManifest.xml @@ -39,7 +39,8 @@ + android:launchMode="singleTask" + android:exported="true"> @@ -57,7 +58,8 @@ + android:process=":uvcservice" + android:exported="true"> diff --git a/usbCameraTest4/src/main/java/com/serenegiant/service/CameraServer.java b/usbCameraTest4/src/main/java/com/serenegiant/service/CameraServer.java index 21f6a3c5b..f57bad958 100644 --- a/usbCameraTest4/src/main/java/com/serenegiant/service/CameraServer.java +++ b/usbCameraTest4/src/main/java/com/serenegiant/service/CameraServer.java @@ -27,10 +27,12 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import android.annotation.SuppressLint; import android.content.Context; import android.media.AudioManager; import android.media.MediaScannerConnection; import android.media.SoundPool; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -61,13 +63,13 @@ public final class CameraServer extends Handler { private int mFrameWidth = DEFAULT_WIDTH, mFrameHeight = DEFAULT_HEIGHT; - private static class CallbackCookie { + private static class CallbackCookie { boolean isConnected; } - private final RemoteCallbackList mCallbacks + private final RemoteCallbackList mCallbacks = new RemoteCallbackList(); - private int mRegisteredCallbackCount; + private int mRegisteredCallbackCount; private RendererHolder mRendererHolder; private final WeakReference mWeakThread; @@ -317,7 +319,7 @@ private static final class CameraThread extends Thread { private static final String TAG_THREAD = "CameraThread"; private final Object mSync = new Object(); private boolean mIsRecording; - private final WeakReference mWeakContext; + private final WeakReference mWeakContext; private int mEncoderSurfaceId; private int mFrameWidth, mFrameHeight; /** @@ -594,31 +596,42 @@ public void onStopped(final MediaEncoder encoder) { } }; + + /** * prepare and load shutter sound for still image capturing */ - @SuppressWarnings("deprecation") - private void loadShutterSound(final Context context) { - if (DEBUG) Log.d(TAG_THREAD, "loadShutterSound:"); - // get system stream type using refrection - int streamType; - try { - final Class audioSystemClass = Class.forName("android.media.AudioSystem"); - final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); - streamType = sseField.getInt(null); - } catch (final Exception e) { - streamType = AudioManager.STREAM_SYSTEM; // set appropriate according to your app policy - } - if (mSoundPool != null) { - try { - mSoundPool.release(); - } catch (final Exception e) { - } - mSoundPool = null; - } - // load sutter sound from resource - mSoundPool = new SoundPool(2, streamType, 0); - mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); + @SuppressLint("SoonBlockedPrivateApi") + protected void loadShutterSound(final Context context) { + // Define a default stream type + int streamType = AudioManager.STREAM_SYSTEM; + + // Conditionally handle reflection based on the Android version + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) { // API 32 is Android 12L + try { + // Use reflection only for older versions + final Class audioSystemClass = Class.forName("android.media.AudioSystem"); + final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); + streamType = sseField.getInt(null); + } catch (final Exception e) { + // If reflection fails, fall back to STREAM_SYSTEM + streamType = AudioManager.STREAM_SYSTEM; + } + } + + // Clean up existing SoundPool instance if necessary + if (mSoundPool != null) { + try { + mSoundPool.release(); + } catch (final Exception e) { + // Handle the exception (optional) + } + mSoundPool = null; + } + + // Initialize the SoundPool and load the shutter sound + mSoundPool = new SoundPool(2, streamType, 0); + mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); } @Override diff --git a/usbCameraTest5/build.gradle b/usbCameraTest5/build.gradle index b51c7260e..fc51fef58 100644 --- a/usbCameraTest5/build.gradle +++ b/usbCameraTest5/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest5" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest5/src/main/AndroidManifest.xml b/usbCameraTest5/src/main/AndroidManifest.xml index 9d8ca8dc9..60087082f 100644 --- a/usbCameraTest5/src/main/AndroidManifest.xml +++ b/usbCameraTest5/src/main/AndroidManifest.xml @@ -36,7 +36,8 @@ android:theme="@style/AppTheme" > + android:label="@string/app_name" + android:exported="true"> diff --git a/usbCameraTest5/src/main/res/values/dimens.xml b/usbCameraTest5/src/main/res/values/dimens.xml index 790540d2d..522af662f 100644 --- a/usbCameraTest5/src/main/res/values/dimens.xml +++ b/usbCameraTest5/src/main/res/values/dimens.xml @@ -24,6 +24,7 @@ + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest6/build.gradle b/usbCameraTest6/build.gradle index d24f32692..630bfaeb2 100644 --- a/usbCameraTest6/build.gradle +++ b/usbCameraTest6/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest6" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 8 versionName "3.00" @@ -51,7 +50,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest6/src/main/AndroidManifest.xml b/usbCameraTest6/src/main/AndroidManifest.xml index 7bdc7d8aa..d6ee4b1da 100644 --- a/usbCameraTest6/src/main/AndroidManifest.xml +++ b/usbCameraTest6/src/main/AndroidManifest.xml @@ -37,7 +37,8 @@ + android:screenOrientation="sensorLandscape" + android:exported="true"> diff --git a/usbCameraTest6/src/main/res/values/dimens.xml b/usbCameraTest6/src/main/res/values/dimens.xml index 790540d2d..522af662f 100644 --- a/usbCameraTest6/src/main/res/values/dimens.xml +++ b/usbCameraTest6/src/main/res/values/dimens.xml @@ -24,6 +24,7 @@ + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest7/build.gradle b/usbCameraTest7/build.gradle index eba53a822..acde75357 100644 --- a/usbCameraTest7/build.gradle +++ b/usbCameraTest7/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest7" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 9 versionName "3.00" @@ -53,7 +52,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" implementation("com.serenegiant:common:${commonLibVersion}") { diff --git a/usbCameraTest7/src/main/AndroidManifest.xml b/usbCameraTest7/src/main/AndroidManifest.xml index 4047ece96..71cf5600d 100644 --- a/usbCameraTest7/src/main/AndroidManifest.xml +++ b/usbCameraTest7/src/main/AndroidManifest.xml @@ -37,7 +37,8 @@ + android:screenOrientation="sensorLandscape" + android:exported="true"> diff --git a/usbCameraTest7/src/main/res/values/dimens.xml b/usbCameraTest7/src/main/res/values/dimens.xml index 790540d2d..522af662f 100644 --- a/usbCameraTest7/src/main/res/values/dimens.xml +++ b/usbCameraTest7/src/main/res/values/dimens.xml @@ -24,6 +24,7 @@ + 24sp 16dp 16dp 48dp diff --git a/usbCameraTest8/build.gradle b/usbCameraTest8/build.gradle index 94d049ff5..b2bdedcdf 100644 --- a/usbCameraTest8/build.gradle +++ b/usbCameraTest8/build.gradle @@ -25,7 +25,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion versionCompiler - buildToolsVersion versionBuildTool compileOptions { sourceCompatibility javaSourceCompatibility @@ -34,7 +33,7 @@ android { defaultConfig { applicationId "com.serenegiant.usbcameratest8" - minSdkVersion 18 + minSdkVersion minTargetVersion targetSdkVersion versionTarget versionCode 1 versionName "1.0" @@ -53,7 +52,6 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) - implementation "com.android.support:support-v4:${supportLibVersion}" implementation "com.android.support:support-annotations:${supportLibVersion}" androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { @@ -61,9 +59,7 @@ dependencies { }) testImplementation 'junit:junit:4.12' - implementation("com.serenegiant:common:${commonLibVersion}") { - exclude module: 'support-v4' - } + implementation("com.serenegiant:common:${commonLibVersion}") implementation project(':libuvccamera') implementation project(':usbCameraCommon') } diff --git a/usbCameraTest8/src/main/AndroidManifest.xml b/usbCameraTest8/src/main/AndroidManifest.xml index 99bca5aa2..62aef2222 100644 --- a/usbCameraTest8/src/main/AndroidManifest.xml +++ b/usbCameraTest8/src/main/AndroidManifest.xml @@ -1,28 +1,29 @@ + ~ UVCCamera + ~ library and sample to access to UVC web camera on non-rooted Android device + ~ + ~ Copyright (c) 2014-2017 saki t_saki@serenegiant.com + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + ~ All files in the folder are under this Apache License, Version 2.0. + ~ Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder + ~ may have a different license, see the respective files. + --> + xmlns:tools="http://schemas.android.com/tools" + package="com.serenegiant.usbcameratest8"> @@ -38,7 +39,9 @@ + android:label="@string/app_name" + android:exported="true" + tools:ignore="DiscouragedApi"> diff --git a/usbCameraTest8/src/main/res/values/dimens.xml b/usbCameraTest8/src/main/res/values/dimens.xml index f353c0d9d..e0619e297 100644 --- a/usbCameraTest8/src/main/res/values/dimens.xml +++ b/usbCameraTest8/src/main/res/values/dimens.xml @@ -23,6 +23,7 @@ + 24sp 16dp 16dp