From b601de49d9e9c6f7690aa729527f0bf8607ffe4b Mon Sep 17 00:00:00 2001 From: Matthew Date: Mon, 1 Jul 2024 00:12:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E5=AE=89=E8=A3=85=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E6=95=B4=E6=8E=A5=E5=8F=A3=E5=92=8C=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/cpp/MicroPhoto.cpp | 59 +++++++++++++++++++ app/src/main/cpp/PhoneDevice.cpp | 33 ++++++----- app/src/main/cpp/PhoneDevice.h | 12 ++-- app/src/main/cpp/camera2/ndkcamera.cpp | 15 +++-- app/src/main/cpp/camera2/ndkcamera.h | 2 +- .../com/xypower/mpapp/BridgeActivity.java | 17 ++++++ .../java/com/xypower/mpapp/MainActivity.java | 20 +++++-- .../com/xypower/mpapp/MicroPhotoService.java | 3 + 8 files changed, 131 insertions(+), 30 deletions(-) diff --git a/app/src/main/cpp/MicroPhoto.cpp b/app/src/main/cpp/MicroPhoto.cpp index daa72e5a..1cd4af2a 100644 --- a/app/src/main/cpp/MicroPhoto.cpp +++ b/app/src/main/cpp/MicroPhoto.cpp @@ -369,6 +369,65 @@ Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto( return JNI_TRUE; } + +extern "C" JNIEXPORT jlong JNICALL +Java_com_xypower_mpapp_MicroPhotoService_takePhoto( + JNIEnv* env, + jclass cls, jint channel, jint preset, jint cameraId, jboolean usb, jstring path) { + + if (channel < 1 || channel > 0xFF) + { + return 0; + } + + JavaVM* vm = NULL; + jint ret = env->GetJavaVM(&vm); + + CPhoneDevice* device = new CPhoneDevice(vm, NULL, "", NETID_UNSET, 0); + // device->SetListener(pTerminal); + + if (usb == JNI_TRUE) + { + device->TurnOnOtg(NULL); + } + device->TurnOnCameraPower(NULL); + + int32_t width = 1920; + int32_t height = 1080; + NdkCamera::CAMERA_PARAMS params = { 0 }; + + NdkCamera camera(0, 0, params); + int res = camera.selfTest(std::to_string(cameraId), width, height); + + // const IDevice::PHOTO_INFO& photoInfo, const vector& osds, const std::string& path + IDevice::PHOTO_INFO photoInfo(channel, preset); + photoInfo.usbCamera = (usb == JNI_TRUE) ? 1 : 0; + photoInfo.width = width; + photoInfo.height = height; + photoInfo.cameraId = cameraId; + + std::vector osds; + + const char* pathStr = env->GetStringUTFChars(path, 0); + + device->TakePhoto(photoInfo, osds, MakeString(pathStr)); + + env->ReleaseStringUTFChars(path, pathStr); + + return reinterpret_cast(device); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_xypower_mpapp_MicroPhotoService_releaseDeviceHandle( + JNIEnv* env, + jclass cls, jlong deviceHandle) { + if (deviceHandle != 0) + { + CPhoneDevice* pDevice = reinterpret_cast(deviceHandle); + delete pDevice; + } +} + extern "C" JNIEXPORT jboolean JNICALL Java_com_xypower_mpapp_MicroPhotoService_sendHeartbeat( JNIEnv* env, diff --git a/app/src/main/cpp/PhoneDevice.cpp b/app/src/main/cpp/PhoneDevice.cpp index 28f3c2ec..d852bfef 100644 --- a/app/src/main/cpp/PhoneDevice.cpp +++ b/app/src/main/cpp/PhoneDevice.cpp @@ -186,24 +186,27 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPa { ALOGE("Failed to get JNI Env"); } - m_javaService = env->NewGlobalRef(service); + if (service != NULL) + { + m_javaService = env->NewGlobalRef(service); - jclass classService = env->GetObjectClass(m_javaService); - mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(IJ)V"); - mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z"); - mUpdateCaptureScheduleMid = env->GetMethodID(classService, "updateCaptureSchedule", "(J)Z"); - mStartRecordingMid = env->GetMethodID(classService, "startRecording", "(IJIIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + jclass classService = env->GetObjectClass(m_javaService); + mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(IJ)V"); + mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z"); + mUpdateCaptureScheduleMid = env->GetMethodID(classService, "updateCaptureSchedule", "(J)Z"); + mStartRecordingMid = env->GetMethodID(classService, "startRecording", "(IJIIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - mRequestWakelockMid = env->GetMethodID(classService, "requestWakelock", "(Ljava/lang/String;J)V"); - mReleaseWakelockMid = env->GetMethodID(classService, "releaseWakelock", "(Ljava/lang/String;)V"); + mRequestWakelockMid = env->GetMethodID(classService, "requestWakelock", "(Ljava/lang/String;J)V"); + mReleaseWakelockMid = env->GetMethodID(classService, "releaseWakelock", "(Ljava/lang/String;)V"); - mGetSystemInfoMid = env->GetMethodID(classService, "getSystemInfo", "()Ljava/lang/String;"); - mInstallAppMid = env->GetMethodID(classService, "installApp", "(Ljava/lang/String;J)Z"); - mRebootMid = env->GetMethodID(classService, "reboot", "(IJ)V"); - mEnableGpsMid = env->GetMethodID(classService, "enableGps", "(Z)V"); - mRequestPositionMid = env->GetMethodID(classService, "requestPosition", "()Z"); + mGetSystemInfoMid = env->GetMethodID(classService, "getSystemInfo", "()Ljava/lang/String;"); + mInstallAppMid = env->GetMethodID(classService, "installApp", "(Ljava/lang/String;J)Z"); + mRebootMid = env->GetMethodID(classService, "reboot", "(IJ)V"); + mEnableGpsMid = env->GetMethodID(classService, "enableGps", "(Z)V"); + mRequestPositionMid = env->GetMethodID(classService, "requestPosition", "()Z"); - env->DeleteLocalRef(classService); + env->DeleteLocalRef(classService); + } if (didAttachThread) { @@ -1591,7 +1594,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat) params.push_back(mPhotoInfo.quality); bool res = false; - std::string fullPath = mPath + CTerminal::BuildPhotoFileName(mPhotoInfo); + std::string fullPath = endsWith(mPath, ".jpg") ? mPath : (mPath + CTerminal::BuildPhotoFileName(mPhotoInfo)); if (!std::filesystem::exists(std::filesystem::path(fullPath))) { bool res = cv::imwrite(fullPath.c_str(), mat, params); diff --git a/app/src/main/cpp/PhoneDevice.h b/app/src/main/cpp/PhoneDevice.h index abcf6436..23cfc185 100644 --- a/app/src/main/cpp/PhoneDevice.h +++ b/app/src/main/cpp/PhoneDevice.h @@ -213,6 +213,12 @@ public: } void UpdateSimcard(const std::string& simcard); + void TurnOnCameraPower(JNIEnv* env); + void TurnOffCameraPower(JNIEnv* env); + + void TurnOnOtg(JNIEnv* env); + void TurnOffOtg(JNIEnv* env); + protected: std::string GetFileName() const; @@ -251,12 +257,6 @@ protected: void CloseCamera2(CPhoneCamera* camera, unsigned int photoId, bool turnOffOtg); - void TurnOnCameraPower(JNIEnv* env); - void TurnOffCameraPower(JNIEnv* env); - - void TurnOnOtg(JNIEnv* env); - void TurnOffOtg(JNIEnv* env); - static void handleSignal(int sig, siginfo_t *si, void *uc); bool RegisterHandlerForSignal(int sig); void static handleTimer(union sigval v); diff --git a/app/src/main/cpp/camera2/ndkcamera.cpp b/app/src/main/cpp/camera2/ndkcamera.cpp index 2e1cd4cf..556eda86 100644 --- a/app/src/main/cpp/camera2/ndkcamera.cpp +++ b/app/src/main/cpp/camera2/ndkcamera.cpp @@ -154,7 +154,7 @@ NdkCamera::~NdkCamera() close(); } -int NdkCamera::selfTest(const std::string& cameraId, int& maxResolutionX, int& maxResolutionY) +int NdkCamera::selfTest(const std::string& cameraId, int32_t& maxResolutionX, int32_t& maxResolutionY) { camera_manager.Create(); // ACameraManager_registerAvailabilityCallback(camera_manager, &camera_manager_cb); @@ -1113,9 +1113,16 @@ void NdkCamera::on_image(const unsigned char* nv21, int nv21_width, int nv21_hei else { // Crop image - int left = (w - orgWidth) / 2; - int top = (h - orgHeight) / 2; - rgb = org(cv::Range(top, top + orgHeight), cv::Range(left, left + orgWidth)); + if (w > orgWidth && h >= orgHeight) + { + int left = (w - orgWidth) / 2; + int top = (h - orgHeight) / 2; + rgb = org(cv::Range(top, top + orgHeight), cv::Range(left, left + orgWidth)); + } + else + { + rgb = org; + } } } on_image(rgb); diff --git a/app/src/main/cpp/camera2/ndkcamera.h b/app/src/main/cpp/camera2/ndkcamera.h index 955c6d31..24b73da2 100644 --- a/app/src/main/cpp/camera2/ndkcamera.h +++ b/app/src/main/cpp/camera2/ndkcamera.h @@ -106,7 +106,7 @@ public: int open(const std::string& cameraId); void close(); - int selfTest(const std::string& cameraId, int& maxResolutionX, int& maxResolutionY); + int selfTest(const std::string& cameraId, int32_t& maxResolutionX, int32_t& maxResolutionY); void onAvailabilityCallback(const char* cameraId); void onUnavailabilityCallback(const char* cameraId); diff --git a/app/src/main/java/com/xypower/mpapp/BridgeActivity.java b/app/src/main/java/com/xypower/mpapp/BridgeActivity.java index 9a79b9f9..a6566aad 100644 --- a/app/src/main/java/com/xypower/mpapp/BridgeActivity.java +++ b/app/src/main/java/com/xypower/mpapp/BridgeActivity.java @@ -22,6 +22,7 @@ public class BridgeActivity extends AppCompatActivity { private final static String ACTION_CERT_REQ = "cert_req"; private final static String ACTION_BATTERY_VOLTAGE = "query_bv"; private final static String ACTION_RECORDING = "recording"; + private final static String ACTION_TAKE_PHOTO = "take_photo"; private final static int REQUEST_CODE_RECORDING = Camera2VideoActivity.REQUEST_CODE_RECORDING; @@ -87,6 +88,22 @@ public class BridgeActivity extends AppCompatActivity { File file = new File(path + ".tmp"); file.renameTo(new File(path)); } + } else if (TextUtils.equals(action, ACTION_TAKE_PHOTO)) { + String path = intent.getStringExtra("path"); + int channel = intent.getIntExtra("channel", 1); + int preset = intent.getIntExtra("preset", 0xFF); + boolean usb = intent.getBooleanExtra("usb", false); + int cameraId = intent.getIntExtra("cameraId", -1); + + File file = new File(path); + if (file.exists()) { + file.delete(); + } else { + FileUtils.ensureParentDirectoryExisted(path); + } + + MicroPhotoService.takePhoto(channel, preset, cameraId, usb, path); + } else if (TextUtils.equals(action, ACTION_RECORDING)) { String path = intent.getStringExtra("path"); int channel = intent.getIntExtra("channel", 1); diff --git a/app/src/main/java/com/xypower/mpapp/MainActivity.java b/app/src/main/java/com/xypower/mpapp/MainActivity.java index 6f9b0c1f..8405480d 100644 --- a/app/src/main/java/com/xypower/mpapp/MainActivity.java +++ b/app/src/main/java/com/xypower/mpapp/MainActivity.java @@ -570,7 +570,22 @@ public class MainActivity extends AppCompatActivity { } private void takePhoto(int channel, int preset, boolean photoOrVideo) { - MicroPhotoService.takePhoto(this.getApplicationContext(), channel, preset, photoOrVideo); + if (binding.btnStartServ.isEnabled()) { + String appPath = MicroPhotoContext.buildMpAppDir(getApplicationContext()); + File file = new File(appPath); + File tempFile = new File(file, "tmp"); + if (!tempFile.exists()) { + tempFile.mkdirs(); + } + File photoFile = new File(tempFile, Integer.toString(channel) + "-img.jpg"); + if (photoFile.exists()) { + photoFile.delete(); + } + + MicroPhotoService.takePhoto(channel, preset, channel - 1, (channel == 4), photoFile.getAbsolutePath()); + } else { + MicroPhotoService.takePhoto(this.getApplicationContext(), channel, preset, photoOrVideo); + } } @Override @@ -693,9 +708,6 @@ public class MainActivity extends AppCompatActivity { return 0; } - public native boolean takePhoto(int channel, int preset, String path, String fileName); - - private void gpsTake() { LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); diff --git a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java index 3af905cb..daf29379 100644 --- a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java +++ b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java @@ -1153,11 +1153,14 @@ cellSignalStrengthGsm.getDbm(); protected native long[] getPhotoTimeData2(long handler); // protected native long[] getNextScheduleItem(long handler); protected native boolean notifyToTakePhoto(long handler, int channel, int preset, long scheduleTime, boolean photoOrVideo); + protected native boolean sendHeartbeat(long handler, int signalLevel); protected native boolean reloadConfigs(long handler); protected native void updatePosition(long handler, double lon, double lat, double radius, long ts); protected native boolean uninit(long handler); protected native void recordingFinished(long handler, boolean result, String path, long videoId); + public static native long takePhoto(int channel, int preset, int cameraId, boolean usb, String path); + public static native void releaseDeviceHandle(long deviceHandle); public static native void infoLog(String log); public static native void setOtgState(boolean enabled); public static native void setCam3V3Enable(boolean enabled);