|
|
|
@ -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();
|
|
|
|
|