diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3209b316..26300344 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
+
+ android:exported="false"
+ android:screenOrientation="landscape" />
enabled != 0))
{
// TODO
+ XYLOG(XYLOG_SEVERITY_DEBUG, "Start init ncnn");
ncnn_init();
std::string paramFile = m_appPath + (APP_PATH_RECOG_PARAM);
std::string binFile = m_appPath + (APP_PATH_RECOG_BIN);
diff --git a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java
index e4a845e7..43a034f2 100644
--- a/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java
+++ b/app/src/main/java/com/xypower/mpapp/MicroPhotoService.java
@@ -42,6 +42,7 @@ import android.os.SystemClock;
import androidx.core.app.NotificationCompat;
import androidx.core.content.FileProvider;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
@@ -57,6 +58,7 @@ import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.InetAddressUtils;
import com.xypower.common.MicroPhotoContext;
+import com.xypower.mpapp.video.VideoActivity;
import java.io.File;
import java.io.FileOutputStream;
@@ -130,6 +132,7 @@ public class MicroPhotoService extends Service {
protected long mNativeHandle = 0;
private AlarmReceiver mAlarmReceiver = null;
+ private AlarmReceiver mLocalMsgReceiver = null;
private ScreenActionReceiver mScreenaAtionReceiver = null;
private NetworkChangedReceiver mNetworkChangedReceiver = null;
@@ -165,11 +168,11 @@ public class MicroPhotoService extends Service {
mAlarmReceiver = new AlarmReceiver(this);
IntentFilter intentFilter = new IntentFilter(ACTION_HEARTBEAT);
intentFilter.addAction(ACTION_TAKE_PHOTO);
- intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY);
- intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY);
- intentFilter.addAction(ACTION_MSG_BROADCAST);
- intentFilter.addAction(ACTION_VIDEO_FINISHED);
- intentFilter.addAction(ACTION_STOP);
+ // intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY);
+ // intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY);
+ // intentFilter.addAction(ACTION_MSG_BROADCAST);
+ // intentFilter.addAction(ACTION_VIDEO_FINISHED);
+ // intentFilter.addAction(ACTION_STOP);
// intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
getApplicationContext().registerReceiver(mAlarmReceiver, intentFilter, Context.RECEIVER_EXPORTED | Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
@@ -178,6 +181,20 @@ public class MicroPhotoService extends Service {
// registerRe
}
+ {
+ mLocalMsgReceiver = new AlarmReceiver(this);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_HEARTBEAT);
+ intentFilter.addAction(ACTION_TAKE_PHOTO);
+ intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY);
+ intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY);
+ intentFilter.addAction(ACTION_MSG_BROADCAST);
+ intentFilter.addAction(ACTION_VIDEO_FINISHED);
+ intentFilter.addAction(ACTION_STOP);
+
+ LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver (mLocalMsgReceiver, intentFilter);
+ }
+
{
mNetworkChangedReceiver = new NetworkChangedReceiver(this);
IntentFilter filter = new IntentFilter();
@@ -226,6 +243,8 @@ public class MicroPhotoService extends Service {
getApplicationContext().unregisterReceiver(mScreenaAtionReceiver);
getApplicationContext().unregisterReceiver(mNetworkChangedReceiver);
+ LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalMsgReceiver);
+
for(Map.Entry entry : mWakeLocks.entrySet()) {
try {
PowerManager.WakeLock wl = entry.getValue();
@@ -387,6 +406,8 @@ public class MicroPhotoService extends Service {
}
}
}
+
+ // Will be called fron native
private void registerHeartbeatTimer(int duration) {
int orgHeartbeatDuration = mHeartbeatDuration;
mHeartbeatDuration = duration;
@@ -412,36 +433,42 @@ public class MicroPhotoService extends Service {
private static void registerPhotoTimer(Context context, long scheduleTime, long takingTime, long timeout, List schedules) {
// 创建延迟意图
- Intent alarmIntent = new Intent();
- alarmIntent.setAction(ACTION_TAKE_PHOTO);
+ Intent intent = new Intent();
+ intent.setAction(ACTION_TAKE_PHOTO);
int cnt = schedules.size();
- alarmIntent.putExtra(EXTRA_PARAM_SCHEDULES, cnt);
+ intent.putExtra(EXTRA_PARAM_SCHEDULES, cnt);
StringBuilder channelStr = new StringBuilder();
long val = 0;
for (int idx = 0; idx < cnt; idx++) {
val = schedules.get(idx).longValue();
- alarmIntent.putExtra(EXTRA_PARAM_SCHEDULE + idx, schedules.get(idx).longValue());
+ intent.putExtra(EXTRA_PARAM_SCHEDULE + idx, schedules.get(idx).longValue());
channelStr.append("(" + ((val & 0XFF0000) >> 16) + "-" + Long.toString (((val & 0XFF00) >> 8), 16).toUpperCase() + ") ");
}
- alarmIntent.putExtra(EXTRA_PARAM_TIME, scheduleTime);
- alarmIntent.putExtra(EXTRA_PARAM_TAKING_TIME, takingTime);
+ intent.putExtra(EXTRA_PARAM_TIME, scheduleTime);
+ intent.putExtra(EXTRA_PARAM_TAKING_TIME, takingTime);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ if (timeout == 0) {
+ // LocalBroadcast
+ LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
+ localBroadcastManager.sendBroadcast(intent);
+ } else {
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
- try {
- alarmManager.cancel(pendingIntent);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
+ try {
+ alarmManager.cancel(pendingIntent);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
- long currentTimeMillis = System.currentTimeMillis();
- Date date = new Date(currentTimeMillis + timeout);
- String dateStr = (String) DateFormat.format("MM-dd kk:mm:ss", date);
- Log.d(TAG, "PhotoTimer Reg: " + dateStr + " currentTimeMillis=" + currentTimeMillis + " timeout=" + timeout + " CH-PR=" + channelStr.toString());
+ long currentTimeMillis = System.currentTimeMillis();
+ Date date = new Date(currentTimeMillis + timeout);
+ String dateStr = (String) DateFormat.format("MM-dd kk:mm:ss", date);
+ Log.d(TAG, "PhotoTimer Reg: " + dateStr + " currentTimeMillis=" + currentTimeMillis + " timeout=" + timeout + " CH-PR=" + channelStr.toString());
- alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, pendingIntent);
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, pendingIntent);
+ }
}
private void registerPhotoTimer(long scheduleTime, long timeout, List schedules) {
@@ -451,10 +478,8 @@ public class MicroPhotoService extends Service {
public void startRecording(int cameraId, long videoId, int duration, int width, int height, int quality) {
Context context = getApplicationContext();
- Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.xypower.mvapp");
- if (intent == null) {
- return;
- }
+ Intent intent = new Intent(this, VideoActivity.class);
+
intent.putExtra("cameraId", cameraId);
intent.putExtra("videoId", videoId);
intent.putExtra("duration", duration);
@@ -462,8 +487,8 @@ public class MicroPhotoService extends Service {
intent.putExtra("height", height);
intent.putExtra("quality", quality);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- context.startActivity(intent);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
}
protected boolean updateCaptureSchedule(long startTime) {
@@ -502,33 +527,15 @@ public class MicroPhotoService extends Service {
schedules.add(Long.valueOf(val));
- registerPhotoTimer(context, 0, ts, 100, schedules);
+ registerPhotoTimer(context, 0, ts, 0, schedules);
}
public static void sendHeartbeat(Context context) {
-
- Intent alarmIntent = new Intent();
-
- // if(Build.VERSION.SDK_INT >= 26) {
- // alarmIntent.addFlags(0x01000000);
- //}
- // String className = AlarmReceiver.class.getName();
- // alarmIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- // context.startService(alarmIntent);
-
- // alarmIntent.setComponent(new ComponentName(context.getPackageName(), className));
- // alarmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // alarmIntent.setPackage(context.getPackageName());
- alarmIntent.setAction(ACTION_HEARTBEAT_MANUALLY);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
-
- // context.sendBroadcast(alarmIntent);
- // context.sendBroadcast(alarmIntent);
- // LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
- // localBroadcastManager.sendBroadcast(alarmIntent);
-
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
- alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 100, pendingIntent);
+ Intent intent = new Intent();
+ intent.setAction(ACTION_HEARTBEAT_MANUALLY);
+ // PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+ LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
+ localBroadcastManager.sendBroadcast(intent);
}
@Override
diff --git a/app/src/main/java/com/xypower/mpapp/video/VideoActivity.java b/app/src/main/java/com/xypower/mpapp/video/VideoActivity.java
index 328aefce..19139346 100644
--- a/app/src/main/java/com/xypower/mpapp/video/VideoActivity.java
+++ b/app/src/main/java/com/xypower/mpapp/video/VideoActivity.java
@@ -1,7 +1,9 @@
package com.xypower.mpapp.video;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import android.content.Intent;
import android.os.Bundle;
import com.xypower.mpapp.R;
@@ -14,8 +16,30 @@ public class VideoActivity extends AppCompatActivity {
setContentView(R.layout.activity_video);
if (null == savedInstanceState) {
+ Bundle bundle = new Bundle();
+ Intent intent = getIntent();
+
+ int duration = intent.getIntExtra("duration", 0);
+ if (intent.hasExtra("cameraId")) {
+ bundle.putInt("cameraId", intent.getIntExtra("cameraId", 0));
+ }
+ if (intent.hasExtra("videoId")) {
+ bundle.putLong("videoId", intent.getLongExtra("videoId", 0));
+ }
+
+ bundle.putInt("duration", duration);
+ String act = intent.getStringExtra("action");
+ if (act != null) {
+ bundle.putString("action", act);
+ }
+
+ bundle.putInt("width", intent.getIntExtra("width", 0));
+ bundle.putInt("height", intent.getIntExtra("height", 0));
+
+ Fragment fragment = VideoFragment.newInstance();
+ fragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.container, VideoFragment.newInstance())
+ .replace(R.id.container, fragment)
.commit();
}
}
diff --git a/app/src/main/java/com/xypower/mpapp/video/VideoFragment.java b/app/src/main/java/com/xypower/mpapp/video/VideoFragment.java
index edbef909..0f62297b 100644
--- a/app/src/main/java/com/xypower/mpapp/video/VideoFragment.java
+++ b/app/src/main/java/com/xypower/mpapp/video/VideoFragment.java
@@ -3,8 +3,10 @@ package com.xypower.mpapp.video;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Matrix;
@@ -28,7 +30,9 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.legacy.app.FragmentCompat;
import androidx.legacy.app.FragmentCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
@@ -42,6 +46,7 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
+import com.xypower.mpapp.MicroPhotoService;
import com.xypower.mpapp.R;
import java.io.File;
@@ -58,7 +63,10 @@ import java.util.concurrent.TimeUnit;
* Use the {@link VideoFragment#newInstance} factory method to
* create an instance of this fragment.
*/
-public class VideoFragment extends Fragment implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
+public class VideoFragment extends Fragment implements View.OnClickListener, MediaRecorder.OnInfoListener, FragmentCompat.OnRequestPermissionsResultCallback {
+
+ public static final String ACTION_FINISH = "com.xypower.mvapp.ACT_FINISH";
+ public static final String ACTION_MP_VIDEO_FINISHED = "com.xypower.mpapp.ACT_V_FINISHED";
private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
@@ -88,6 +96,10 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);
}
+ private String mCameraId;
+ private long mVideoId = 0;
+ private int mDuration = 0;
+
/**
* An {@link AutoFitTextureView} for camera preview.
*/
@@ -169,6 +181,8 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
*/
private Handler mBackgroundHandler;
+ private Handler mMainHandler;
+
/**
* A {@link Semaphore} to prevent the app from exiting before closing the camera.
*/
@@ -212,6 +226,49 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
private String mNextVideoAbsolutePath;
private CaptureRequest.Builder mPreviewBuilder;
+ public void onInfo(MediaRecorder mr, int what, int extra) {
+ if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
+ Log.v(TAG, "Recording Maximum Duration Reached");
+ final Runnable quitRunnable = new Runnable() {
+ @Override
+ public void run() {
+ getActivity().finish();
+ }
+ };
+
+ if (mIsRecordingVideo) {
+ stopRecordingVideo();
+ Log.i(TAG, "Stop recording");
+
+ mMainHandler.post(quitRunnable);
+ }
+ }
+ }
+
+ private void broadcastVideoFile(boolean result, String path) {
+ if (mDuration <= 0) {
+ return;
+ }
+
+ Context context = getContext();
+ String receiverName = MicroPhotoService.AlarmReceiver.class.getName();
+ String packageName = context.getPackageName();
+
+ Intent intent = new Intent(ACTION_MP_VIDEO_FINISHED);
+ // intent.setPackage(packageName);
+ intent.putExtra("result", result);
+ intent.putExtra("path", path);
+ intent.putExtra("videoId", mVideoId);
+
+ // intent.setComponent(new ComponentName(packageName, receiverName));
+
+ Log.i(TAG, "Notify recording videoId=" + Long.toString(mVideoId) + " " + path);
+ LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(getContext().getApplicationContext());
+ localBroadcastManager.sendBroadcast(intent);
+
+ context.sendBroadcast(intent);
+ }
+
public static Fragment newInstance() {
return new VideoFragment();
}
@@ -277,12 +334,37 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
mButtonVideo = (Button) view.findViewById(R.id.video);
mButtonVideo.setOnClickListener(this);
view.findViewById(R.id.info).setOnClickListener(this);
+
+ mMainHandler = new Handler();
+
+ Bundle argument = getArguments();
+ if (argument != null) {
+ mCameraId = Integer.toString(argument.getInt("CameraId", 0));
+ mVideoId = argument.getLong("videoId", 0);
+ mDuration = argument.getInt("duration", 0);
+ }
+
+ Log.i(TAG, "Recv recording request CameraId=" + mCameraId + " videoId=" + Long.toString(mVideoId));
}
@Override
public void onResume() {
super.onResume();
startBackgroundThread();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ if (!mIsRecordingVideo) {
+ Log.i(TAG, "Start recording duration=" + Integer.toString(mDuration));
+ startRecordingVideo();
+ }
+ }
+ };
+
+ if (mDuration > 0) {
+ mMainHandler.postDelayed(runnable, 1000);
+ }
+
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
@@ -414,9 +496,10 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
}
configureTransform(width, height);
mMediaRecorder = new MediaRecorder();
+ mMediaRecorder.setOnInfoListener(this);
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
- Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
+ // Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
activity.finish();
} catch (NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
@@ -477,7 +560,8 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Activity activity = getActivity();
if (null != activity) {
- Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
+ broadcastVideoFile(false, "");
+ // Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
}
}, mBackgroundHandler);
@@ -543,7 +627,12 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
if (null == activity) {
return;
}
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ try {
+ // mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ } catch (Exception ex) {
+
+ }
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
if (mNextVideoAbsolutePath == null || mNextVideoAbsolutePath.isEmpty()) {
@@ -555,6 +644,9 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ if (mDuration > 0) {
+ mMediaRecorder.setMaxDuration(mDuration * 1000);
+ }
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
switch (mSensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
@@ -568,9 +660,18 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
}
private String getVideoFilePath(Context context) {
- final File dir = context.getExternalFilesDir(null);
- return (dir == null ? "" : (dir.getAbsolutePath() + "/"))
- + System.currentTimeMillis() + ".mp4";
+ // final File dir = context.getExternalFilesDir(null);
+ String path = Environment.getExternalStorageDirectory().getAbsolutePath();
+ if (!path.endsWith(File.separator)) {
+ path += File.separator;
+ }
+ path += context.getPackageName() + File.separator;
+ File file = new File(path);
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ path += System.currentTimeMillis() + ".mp4";
+ return path;
}
private void startRecordingVideo() {
@@ -621,7 +722,8 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Activity activity = getActivity();
if (null != activity) {
- Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
+ broadcastVideoFile(false, "");
+ // Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
}
}, mBackgroundHandler);
@@ -648,9 +750,10 @@ public class VideoFragment extends Fragment implements View.OnClickListener, Fra
Activity activity = getActivity();
if (null != activity) {
- Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath,
- Toast.LENGTH_SHORT).show();
- Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);
+ // Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath, Toast.LENGTH_SHORT).show();
+ // Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);
+
+ broadcastVideoFile(true, mNextVideoAbsolutePath);
}
mNextVideoAbsolutePath = null;
startPreview();