viewList) {
- this.viewList = viewList;
- }
-
- public int getCount() {
- return viewList.size();
- }
-
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
-
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
- }
-
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View) object);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/askey/widget/CustomTextView.java b/app/src/main/java/com/d160/view/CustomTextView.java
old mode 100755
new mode 100644
similarity index 95%
rename from app/src/main/java/com/askey/widget/CustomTextView.java
rename to app/src/main/java/com/d160/view/CustomTextView.java
index e6bee87..d4be60b
--- a/app/src/main/java/com/askey/widget/CustomTextView.java
+++ b/app/src/main/java/com/d160/view/CustomTextView.java
@@ -1,4 +1,4 @@
-package com.askey.widget;
+package com.d160.view;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -7,7 +7,7 @@
import android.util.AttributeSet;
import android.widget.TextView;
-import com.askey.record.R;
+import com.d160.wa034.R;
@SuppressLint("AppCompatCustomView")
public class CustomTextView extends TextView {
diff --git a/app/src/main/java/com/d160/view/mFragmentBackHandler.java b/app/src/main/java/com/d160/view/mFragmentBackHandler.java
new file mode 100644
index 0000000..7cc3dff
--- /dev/null
+++ b/app/src/main/java/com/d160/view/mFragmentBackHandler.java
@@ -0,0 +1,5 @@
+package com.d160.view;
+
+public interface mFragmentBackHandler {
+ boolean onBackPressed();
+}
diff --git a/app/src/main/java/com/askey/widget/HomeListen.java b/app/src/main/java/com/d160/view/mHomeListen.java
similarity index 58%
rename from app/src/main/java/com/askey/widget/HomeListen.java
rename to app/src/main/java/com/d160/view/mHomeListen.java
index 7c99b04..ee56239 100644
--- a/app/src/main/java/com/askey/widget/HomeListen.java
+++ b/app/src/main/java/com/d160/view/mHomeListen.java
@@ -1,56 +1,49 @@
-package com.askey.widget;
+package com.d160.view;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-/**
- * Home按键监听类 使用说明: 1、初始化HomeListen HomeListen homeListen = new HomeListen( this
- * ); homeListen.setOnHomeBtnPressListener( new setOnHomeBtnPressListener(){
- *
- * @Override public void onHomeBtnPress( ){ // 按下Home按键回调 }
- * @Override public void onHomeBtnLongPress( ){ // 长按Home按键回调 } });
- *
- * 2、在onResume方法中启动HomeListen广播: homeListen.start();
- *
- * 3、在onPause方法中停止HomeListen广播: homeListen.stop( );
- */
+public class mHomeListen {
+ private final Context mContext;
+ private final IntentFilter mHomeBtnIntentFilter;
+ private final HomeBtnReceiver mHomeBtnReceiver;
+ private boolean isRun = false;
+ private OnHomeBtnPressListener mOnHomeBtnPressListener = null;
-public class HomeListen {
- private Context mContext = null;
- private IntentFilter mHomeBtnIntentFilter = null;
- private OnHomeBtnPressLitener mOnHomeBtnPressListener = null;
- private HomeBtnReceiver mHomeBtnReceiver = null;
-
- public HomeListen(Context context) {
+ public mHomeListen(Context context) {
mContext = context;
mHomeBtnReceiver = new HomeBtnReceiver();
mHomeBtnIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
}
- public void setOnHomeBtnPressListener(OnHomeBtnPressLitener onHomeBtnPressListener) {
+ public void setOnHomeBtnPressListener(OnHomeBtnPressListener onHomeBtnPressListener) {
mOnHomeBtnPressListener = onHomeBtnPressListener;
}
public void start() {
- try{
+ isRun = true;
+ try {
mContext.registerReceiver(mHomeBtnReceiver, mHomeBtnIntentFilter);
- }catch (Exception e){
-
+ } catch (Exception e) {
+ e.printStackTrace();
}
}
public void stop() {
- try{
- mContext.unregisterReceiver(mHomeBtnReceiver);
- }catch (Exception e){
-
+ try {
+ if (null != mHomeBtnReceiver && isRun)
+ mContext.unregisterReceiver(mHomeBtnReceiver);
+ } catch (Exception e) {
+ e.printStackTrace();
}
+ isRun = false;
}
public void receive(Intent intent) {
String action = intent.getAction();
+
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra("reason");
if (null != reason) {
@@ -67,7 +60,7 @@ public void receive(Intent intent) {
}
}
- public interface OnHomeBtnPressLitener {
+ public interface OnHomeBtnPressListener {
void onHomeBtnPress();
void onHomeBtnLongPress();
diff --git a/app/src/main/java/com/askey/widget/mListAdapter.java b/app/src/main/java/com/d160/view/mListAdapter.java
similarity index 89%
rename from app/src/main/java/com/askey/widget/mListAdapter.java
rename to app/src/main/java/com/d160/view/mListAdapter.java
index fdfb05d..809eb81 100644
--- a/app/src/main/java/com/askey/widget/mListAdapter.java
+++ b/app/src/main/java/com/d160/view/mListAdapter.java
@@ -1,4 +1,4 @@
-package com.askey.widget;
+package com.d160.view;
import android.view.View;
import android.view.ViewGroup;
@@ -8,7 +8,7 @@
public class mListAdapter extends BaseAdapter {
- private ArrayList arrayList;
+ private final ArrayList arrayList;
public mListAdapter(ArrayList arrayList) {
this.arrayList = arrayList;
diff --git a/app/src/main/java/com/askey/widget/mLog.java b/app/src/main/java/com/d160/view/mLog.java
similarity index 60%
rename from app/src/main/java/com/askey/widget/mLog.java
rename to app/src/main/java/com/d160/view/mLog.java
index fa6ee4d..4a44b27 100644
--- a/app/src/main/java/com/askey/widget/mLog.java
+++ b/app/src/main/java/com/d160/view/mLog.java
@@ -1,4 +1,4 @@
-package com.askey.widget;
+package com.d160.view;
public enum mLog {
v, d, i, w, e
diff --git a/app/src/main/java/com/d160/view/mLogMsg.java b/app/src/main/java/com/d160/view/mLogMsg.java
new file mode 100644
index 0000000..e6d3fff
--- /dev/null
+++ b/app/src/main/java/com/d160/view/mLogMsg.java
@@ -0,0 +1,26 @@
+package com.d160.view;
+
+import com.d160.wa034.Utils;
+
+import java.util.*;
+
+public class mLogMsg {
+ public long run;
+ public Date date;
+ public String msg;
+ public mLog type;
+
+ public mLogMsg(String msg) {
+ this.run = Utils.getIsRun();
+ this.date = Calendar.getInstance().getTime();
+ this.msg = msg;
+ this.type = mLog.d;
+ }
+
+ public mLogMsg(String msg, mLog type) {
+ this.run = Utils.getIsRun();
+ this.date = Calendar.getInstance().getTime();
+ this.msg = msg;
+ this.type = type;
+ }
+}
diff --git a/app/src/main/java/com/d160/wa034/CameraActivity.java b/app/src/main/java/com/d160/wa034/CameraActivity.java
new file mode 100644
index 0000000..aac2124
--- /dev/null
+++ b/app/src/main/java/com/d160/wa034/CameraActivity.java
@@ -0,0 +1,30 @@
+package com.d160.wa034;
+
+import android.annotation.*;
+import android.content.*;
+import android.os.*;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import java.util.Objects;
+
+public class CameraActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_camera);
+ if (null == savedInstanceState) {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.container, CameraFragment.newInstance())
+ .commit();
+ }
+ }
+
+ public static class BootUpReceiver extends BroadcastReceiver {
+ @SuppressLint("UnsafeProtectedBroadcastReceiver")
+ public void onReceive(Context context, Intent intent) {
+ context.startActivity(RestartActivity.createIntent(Objects.requireNonNull(context)));
+ }
+ }
+}
diff --git a/app/src/main/java/com/d160/wa034/CameraFragment.java b/app/src/main/java/com/d160/wa034/CameraFragment.java
new file mode 100644
index 0000000..a5a47f2
--- /dev/null
+++ b/app/src/main/java/com/d160/wa034/CameraFragment.java
@@ -0,0 +1,1248 @@
+package com.d160.wa034;
+
+import android.annotation.*;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.*;
+import android.content.pm.*;
+
+import java.text.*;
+
+import android.graphics.*;
+import android.hardware.camera2.*;
+import android.media.*;
+import android.os.*;
+import android.util.*;
+import android.view.*;
+import android.widget.*;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.*;
+import androidx.fragment.app.*;
+
+import com.d160.view.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.*;
+
+import static android.os.Looper.getMainLooper;
+import static java.lang.System.gc;
+import static com.d160.wa034.Utils.*;
+
+public class CameraFragment extends Fragment implements mFragmentBackHandler {
+
+ public static final String TAG = "com.d160.b030";
+ public static final String configName = "BurnInTestConfig.ini";
+ public static final String logName = "BurnInTestLog.ini";
+ public static final String CONFIG_TITLE = "[BurnIn_Config]";
+ public static final String LOG_TITLE = "[BurnIn_Log]";
+ public static final String firstCamera = "0", secondCamera = "1", thirdCamera = "2";
+ public static final int delay_3 = 3000, delay_60 = 60000;
+ public static MediaPlayer mp;
+ //-------------------------------------------------------------------------------
+ public static final boolean Open_f_Camera = true, Open_s_Camera = false, Open_t_Camera = false;
+ public static final boolean Open_Audio = false;
+ //TODO 是否啟用keepScreen
+ public static boolean keepScreen = true;
+ //TODO 是否啟用preview
+ public static boolean preview = false;
+ //TODO 是否使用SD_Mode
+ public static boolean SD_Mode = true;
+ //TODO 是否啟用onPause
+ public static boolean autoPause = false;
+ //TODO 是否啟用重啟功能
+ public static boolean autoRestart = true;
+ //TODO 是否啟用60s停止錄影
+ public static boolean autoStopRecord = true;
+ //-------------------------------------------------------------------------------
+ public static boolean extraRecordStatus = true, onRestart = false;
+ public static long onRun = 0, onSuccess = 0, onFail = 0, onReset = 0;
+ //-------------------------------------------------------------------------------
+ private BroadcastReceiver batteryReceiver = null;
+ private Handler mainHandler;
+ private Size mPreviewSize = null;
+ private mHomeListen home;
+ private Timer recordTimer = null, alarmTimer = null;
+ private long recordValue = 0, alarmValue = 0;
+ private mTimerTask recordTask = null;
+ private mAlarmTask alarmTask = null;
+
+ public static CameraFragment newInstance() {
+ return new CameraFragment();
+ }
+
+ public static void checkFile(String path) {
+ try {
+ File video = new File(path);
+ int frameRate = 0;
+ if (video.exists()) {
+ try {
+ frameRate = getFrameRate(video);
+ } catch (Exception ignored) {
+ if (null != videoLogList)
+ videoLogList.add(new mLogMsg("CheckFile error.", mLog.e));
+ }
+ if (frameRate != 0) Success++;
+ else Fail++;
+ } else {
+ Fail++;
+ }
+ if (null != videoLogList) {
+ videoLogList.add(new mLogMsg("CheckFile:(" + path.split("/")[3] +
+ ") video_frameRate:(" + frameRate + ") video_success/fail:(" + getSuccess() + "/" + getFail() +
+ ") app_reset:(" + getReset() + ")", mLog.i));
+ Log.e(TAG, "CheckFile:(video_frameRate:(" + frameRate + ") video_success/fail:(" + getSuccess() + "/" + getFail() +
+ ") app_reset:(" + getReset() + ")");
+ }
+ } catch (Exception ignored) {
+ if (null != videoLogList)
+ videoLogList.add(new mLogMsg("CheckFile error.", mLog.e));
+ Fail++;
+ }
+ }
+
+ private static int getFrameRate(File file) {
+ int frameRate = 0;
+ if (!getSDPath().equals("")) {
+ try {
+ MediaExtractor extractor;
+ FileInputStream fis;
+ try {
+ fis = new FileInputStream(file);
+ extractor = new MediaExtractor();
+ extractor.setDataSource(fis.getFD());
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("getFrameRate failed on MediaExtractor.<============ Crash here", mLog.e));
+ return 0;
+ }
+ int numTracks = extractor.getTrackCount();
+ for (int i = 0; i < numTracks; i++) {
+ MediaFormat format = extractor.getTrackFormat(i);
+ if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+ try {
+ frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("getFrameRate failed on MediaExtractor.<============ Crash here", mLog.e));
+ }
+ }
+ }
+ extractor.release();
+ fis.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("getFrameRate failed.<============ Crash here", mLog.e));
+ }
+ } else {
+ videoLogList.add(new mLogMsg("getFrameRate failed " + NO_SD_CARD + ".", mLog.e));
+ }
+ return frameRate;
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ public static void saveLog(Context context, boolean reFormat, boolean kill) {
+ if (null != videoLogList)
+ if (!getSDPath().equals("")) {
+ String version = context.getString(R.string.app_name);
+ StringBuilder logString = new StringBuilder();
+ assert videoLogList != null;
+ File file = new File(getLogPath(), logName);
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ if (!file.exists()) {
+ logString = new StringBuilder(LOG_TITLE + version + "\r\n");
+ try {
+ boolean create = file.createNewFile();
+ if (null != videoLogList) {
+ if (!create)
+ videoLogList.add(new mLogMsg("Create file failed.", mLog.w));
+ else
+ videoLogList.add(new mLogMsg("Create the log file.", mLog.w));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ if (null != videoLogList)
+ videoLogList.add(new mLogMsg("Create file failed.", mLog.w));
+ }
+ }
+ if (null != videoLogList)
+ try {
+ for (mLogMsg logs : videoLogList) {
+ // ex: 2020-03-25 19:46:55 run:0 -> logs.msg
+ logString.append(dateFormat.format(logs.date))
+ .append(" run:").append(logs.run)
+ .append(" -> ").append(logs.msg)
+ .append("\r\n");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ FileOutputStream output = new FileOutputStream(file, !reFormat);
+ output.write(logString.toString().getBytes());
+ output.close();
+ videoLogList.clear();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ isError = true;
+ isSave = !getSDPath().equals("");
+ }
+ if (kill)
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ // TODO onCreateView
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ isRun = 0;
+ videoLogList = new ArrayList<>();
+ //#onCreateView -> #onViewCreated -> #onActivityCreated -> #onResume
+ setProp();
+ return inflater.inflate(R.layout.fragment_camera, container, false);
+ }
+
+ private void setProp() {
+ try {
+ //TODO adb shell setprop persist.logd.logpersistd.size 1024
+ //TODO adb shell setprop persist.logd.logpersistd logcatd
+ if (!SystemProperties.get("persist.logd.logpersistd").equals("logcatd")) {
+ Log.e(TAG, "persist.logd.logpersistd.size: 1024");
+ SystemProperties.set("persist.logd.logpersistd.size", "1024");
+ Log.e(TAG, "persist.logd.logpersistd: logcatd");
+ SystemProperties.set("persist.logd.logpersistd", "logcatd");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("logcatd error.", mLog.e));
+ new Handler(getMainLooper()).post(() -> saveLog(getContext(), false, false));
+ }
+ }
+
+ // TODO onViewCreated
+ @SuppressLint("HandlerLeak")
+ public void onViewCreated(@NonNull final View view, Bundle savedInstanceState) {
+ Log.e(TAG, "#onViewCreated");
+ videoLogList.add(new mLogMsg("#onViewCreated", mLog.v));
+ if (checkPermission(Objects.requireNonNull(getContext()))) {
+ showPermission();
+ } else {
+ initial();
+ if (!autoPause)
+ startBackgroundThread();
+ }
+ }
+
+ private void initial() {
+ setHomeListener();
+ checkConfigFile(getContext());
+ Activity activity = getActivity();
+ isSave = !getSDPath().equals("");
+ Log.e(TAG, "#initial");
+ videoLogList.add(new mLogMsg("#initial", mLog.v));
+ checkSdCardFromFileList();
+ Objects.requireNonNull(activity).findViewById(R.id.cancel).setOnClickListener((View v) -> {
+ isCancel();
+ });
+ activity.findViewById(R.id.record).setOnClickListener((View v) -> isRecordStart(false));
+ ((TextView) activity.findViewById(R.id.record_status)).setText(getSDPath().equals("") ? "Error" : "Ready");
+ videoLogList.add(new mLogMsg("#initial complete", mLog.v));
+ onRun = activity.getIntent().getIntExtra(EXTRA_VIDEO_RUN, 0);
+ onFail = activity.getIntent().getIntExtra(EXTRA_VIDEO_FAIL, 0);
+ onReset = activity.getIntent().getIntExtra(EXTRA_VIDEO_RESET, 0);
+ onSuccess = activity.getIntent().getIntExtra(EXTRA_VIDEO_SUCCESS, 0);
+ isInitReady = true;
+// extraRecordStatus = activity.getIntent().getBooleanExtra(EXTRA_VIDEO_RECORD, false);
+
+ if (onReset != 0)
+ videoLogList.add(new mLogMsg("#noReset:" + onReset, mLog.v));
+ }
+
+ private void isCancel() {
+ videoLogList.add(new mLogMsg("@cancel", mLog.v));
+ stopRecordAndSaveLog(true);
+ }
+
+ private void isRecordStart(boolean auto) {
+ if (!isError && isSave) {
+ if (isCameraReady) {
+ if (!isRecord) {
+ if (!auto)
+ videoLogList.add(new mLogMsg("@Start record", mLog.v));
+ else
+ videoLogList.add(new mLogMsg("#Start record", mLog.v));
+ isRecord = true;
+ if (extraRecordStatus) {
+ isRun = onRun;
+ Success = onSuccess;
+ Fail = onFail;
+ } else {
+ onReset = 0;
+ isRun = 0;
+ Success = 0;
+ Fail = 0;
+ }
+ for (String CameraId : allCamera) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ cameraFile.set(id, "");
+ if (isOpenCamera.get(id))
+ cameraFilePath.get(id).clear();
+ }
+ extraRecordStatus = true;
+ if (!isError && isSave) {
+ videoLogList.add(new mLogMsg("#------------------------------", mLog.v));
+ videoLogList.add(new mLogMsg("#takeRecord FrameRate: default", mLog.v));
+ int delay = 0;
+ for (String CameraId : allCamera) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (isOpenCamera.get(id)) {
+ new Handler(getMainLooper()).postDelayed(() -> recordHandler.get(id).obtainMessage().sendToTarget(), delay);
+ delay += 500;
+ }
+ }
+ saveLog(getContext(), false, false);
+ } else {
+ stopRecordAndSaveLog(false);
+ showDialogLog(false);
+ }
+ } else {
+ if (!auto)
+ videoLogList.add(new mLogMsg("@Stop record", mLog.v));
+ else
+ videoLogList.add(new mLogMsg("#Stop record", mLog.v));
+ new Handler(getMainLooper()).post(() -> stopRecord(!auto));
+ }
+ } else {
+ showDialogLog(false);
+ videoLogList.add(new mLogMsg("#Camera is not ready.", mLog.v));
+ }
+ } else {
+ stopRecordAndSaveLog(false);
+ showDialogLog(false);
+ }
+ }
+
+ public boolean onBackPressed() {
+ videoLogList.add(new mLogMsg("@back", mLog.v));
+ stopRecordAndSaveLog(true);
+ return false;
+ }
+
+
+ // TODO onResume 螢幕開啟
+ public void onResume() {
+ super.onResume();
+ if (!checkPermission(Objects.requireNonNull(getContext()))) {
+ if (autoPause && isInitReady) {
+ Log.e(TAG, "#onResume");
+ videoLogList.add(new mLogMsg("#onResume", mLog.v));
+ startBackgroundThread();
+ }
+ } else {
+ showPermission();
+ }
+ }
+
+ // TODO onPause 螢幕關閉
+ public void onPause() {
+ if (autoPause && !checkPermission(Objects.requireNonNull(getContext())) && isInitReady) {
+ Log.e(TAG, "#onPause");
+ videoLogList.add(new mLogMsg("#onPause", mLog.v));
+ if (isRecord)
+ isRecordStart(true);
+ stopBackgroundThread();
+ saveLog(getContext(), false, false);
+ }
+ super.onPause();
+ }
+
+ private void showPermission() {
+ videoLogList.add(new mLogMsg("#showPermission", mLog.v));
+ // We don't have permission so prompt the user
+ List permissions = new ArrayList<>();
+ permissions.add(permission.get(0));
+ permissions.add(permission.get(1));
+ permissions.add(permission.get(2));
+ requestPermissions(permissions.toArray(new String[0]), 0);
+ }
+
+ private boolean checkPermission(@NonNull Context context) {
+ videoLogList.add(new mLogMsg("#checkPermission", mLog.v));
+ return permission(context, permission.get(0)) || permission(context, permission.get(1)) || permission(context, permission.get(2));
+ }
+
+ private boolean permission(@NonNull Context context, String mp) {
+ return ActivityCompat.checkSelfPermission(context, mp) != PackageManager.PERMISSION_GRANTED;
+ }
+
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode == 0) {
+ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // 許可授權
+ initial();
+ startBackgroundThread();
+ } else {
+ // 沒有權限
+ showPermission();
+ videoLogList.add(new mLogMsg("#no permissions!", mLog.e));
+ }
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
+ @SuppressLint("HandlerLeak")
+ private void startBackgroundThread() {
+ mainHandler = new Handler(getMainLooper());
+ if (keepScreen)
+ Objects.requireNonNull(getActivity()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ else
+ Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ for (String CameraId : allCamera) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (isOpenCamera.get(id)) {
+ thread.set(id, new HandlerThread(threadString.get(id)));
+ thread.get(id).start();
+ backgroundHandler.set(id, new Handler(thread.get(id).getLooper()));
+ try {
+ setCamera(CameraId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("setCallback " + CameraId + " is error.", mLog.w));
+ }
+ if (textureView.get(id).isAvailable())
+ openCamera(CameraId);
+ else
+ textureView.get(id).setSurfaceTextureListener(new mSurfaceTextureListener(CameraId));
+ }
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.addAction("start");
+ filter.addAction("close");
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ getActivity().registerReceiver(batteryReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (Objects.equals(intent.getAction(), Intent.ACTION_BATTERY_CHANGED)) { //Battery
+ Log.e(TAG, "Battery:" + intent.getIntExtra("level", 0) + "%");
+ videoLogList.add(new mLogMsg("Battery:" + intent.getIntExtra("level", 0) + "%", mLog.e));
+ saveLog(getContext(), false, false);
+ }
+ String str = intent.getAction();
+ if (str.equals("start")) {
+ isRecordStart(false);
+ }
+ if (str.equals("close")) {
+ isCancel();
+ }
+ }
+ }, filter);
+ new Handler(getMainLooper()).postDelayed(() -> {
+ if (autoPause || extraRecordStatus)
+ isRecordStart(true);
+ saveLog(getContext(), false, false);
+ }, delay_3);
+ }
+
+ private void stopBackgroundThread() {
+ Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (batteryReceiver != null)
+ getActivity().unregisterReceiver(batteryReceiver);
+ for (String CameraId : allCamera) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ thread.get(id).quitSafely();
+ try {
+ thread.get(id).join();
+ thread.set(id, null);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ backgroundHandler.get(id).removeCallbacks(thread.get(id));
+ backgroundHandler.set(id, null);
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private void startRecord(String CameraId) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (!isError) {
+ Log.e(TAG, "startRecord " + CameraId);
+ try {
+ if (isCameraOne(CameraId)) {
+ checkSdCardFromFileList();
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ checkConfigFile(getContext());
+ if (recordTimer == null) {
+ onRun = getIsRun();
+ onFail = getFail();
+ onSuccess = getSuccess();
+ recordValue = 0;
+ recordTask = new mTimerTask(recordValue);
+ recordTimer = new Timer(true);
+ ((TextView) getActivity().findViewById(R.id.record_timer)).setText("0");
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Recording");
+
+ }
+ if (isFinish != 999) {
+ if (alarmTimer == null) {
+ alarmValue = (isFinish - onRun) * 60;
+ alarmTask = new mAlarmTask(alarmValue);
+ alarmTimer = new Timer(true);
+ } else {
+ ((TextView) getActivity().findViewById(R.id.record_alarm)).setText("");
+ }
+ } else {
+ ((TextView) getActivity().findViewById(R.id.record_alarm)).setText("Loop testing..");
+ }
+ });
+ CameraManager manager = (CameraManager) Objects.requireNonNull(getActivity())
+ .getSystemService(Context.CAMERA_SERVICE);
+ mPreviewSize = Objects.requireNonNull(manager.getCameraCharacteristics(CameraId)
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP))
+ .getOutputSizes(SurfaceTexture.class)[0];
+ }
+ try {
+ closePreviewSession(CameraId);
+ } catch (Exception e) {
+ errorMessage("closePreviewSession error.", true, e);
+ }
+ SurfaceTexture texture = null;
+ try {
+ texture = textureView.get(id).getSurfaceTexture();
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("getSurfaceTexture" + CameraId + " is error."));
+ }
+ if (null == texture) {
+ Log.e(TAG, "Run " + isRun + " texture is null, return");
+ return;
+ }
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ Surface surface = new Surface(texture);
+ List surfaces = new ArrayList<>();
+ CaptureRequest.Builder mPreviewBuilder;
+ CameraDevice mCameraDevice;
+ Surface recorderSurface;
+ mCameraDevice = cameraDevice.get(id);
+ mediaRecorder.set(id, setUpMediaRecorder(CameraId));
+ recorderSurface = mediaRecorder.get(id).getSurface();
+ surfaces.add(surface);
+ surfaces.add(recorderSurface);
+ if (mCameraDevice != null) {
+ mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ mPreviewBuilder.addTarget(surface);
+ mPreviewBuilder.addTarget(recorderSurface);
+ try {
+ mCameraDevice.createCaptureSession(surfaces,
+ new CameraCaptureSession.StateCallback() {
+ public void onConfigured(@NonNull CameraCaptureSession session) {
+ try {
+ if (isCameraOne(CameraId)) {
+ recordTimer.schedule(recordTask, 1000, 1000);
+ if (isFinish != 999)
+ alarmTimer.schedule(alarmTask, 1000, 1000);
+ }
+
+ previewSession.set(id, session);
+ updatePreview(mPreviewBuilder, session, backgroundHandler.get(id));
+ if (null != mediaRecorder.get(id)) {
+ try {
+ mp = MediaPlayer.create(getContext(), R.raw.v_0189);
+ mp.setOnCompletionListener(MediaPlayer::release);
+ mp.start();
+ }catch (Exception e){
+ videoLogList.add(new mLogMsg("MediaPlayer error", mLog.v));
+ }
+ mediaRecorder.get(id).start();
+ codeDate.set(id, getCalendarTime());
+ Message msg = stopRecordHandler.get(id).obtainMessage();
+ msg.obj = codeDate.get(id);
+ int delay = 0;
+ if (!isCameraOne(CameraId)) {
+ for (String c : allCamera) {
+ delay += id * 600;
+ if (c.equals(CameraId))
+ break;
+ }
+ }
+ if (autoStopRecord)
+ stopRecordHandler.get(id).sendMessageDelayed(msg, delay_60 + delay);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Camera " + CameraId + " can't record. <============ Crash here", false, e);
+ }
+ }
+
+ public void onConfigureFailed(@NonNull CameraCaptureSession Session) {
+ errorMessage("Camera " + CameraId + " Record onConfigureFailed.", true, null);
+ }
+ }, backgroundHandler.get(id));
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Camera " + CameraId + " CameraCaptureSession.StateCallback() error. <============ Crash here", true, e);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Camera " + CameraId + " startRecord error. <============ Crash here", true, e);
+ }
+ } else {
+ if (autoRestart) {
+ new Handler(getMainLooper()).postDelayed(this::restartApp, delay_3);
+ }
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private void stopRecord(String date, String CameraId) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ try {
+ if (date.equals(codeDate.get(id))) {
+ isRun++;
+ videoLogList.add(new mLogMsg("#stopRecord " + CameraId, mLog.v));
+ Log.e(TAG, isRun + " stopRecord " + CameraId);
+ if (isCameraOne(CameraId))
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ if (recordTimer != null) {
+ recordTimer.cancel();
+ recordTimer = null;
+ }
+ if (isFinish != 999)
+ if (alarmTimer != null) {
+ alarmTimer.cancel();
+ alarmTimer = null;
+ }
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Stop");
+ });
+ codeDate.set(id, getCalendarTime());
+ try {
+ closeMediaRecorder(CameraId);
+ checkAndClear(CameraId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Check file is fail. <============ Crash here", true, e);
+ }
+ if (isFinish == 999 || isRun < isFinish) {
+ startRecord(CameraId);
+ } else {
+ isRecordStart(true);
+ }
+ if (isError || !isSave) {
+ isRun = 0;
+ isFinish = 0;
+ isRecord = false;
+ ((TextView) Objects.requireNonNull(getActivity()).findViewById(R.id.record_status)).setText("Error");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Camera " + CameraId + " stopRecord error. <============ Crash here", true, e);
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private void stopRecord(boolean reset) {
+ try {
+ if (!isError && isSave) { // noError, isSave
+ if (!reset) {
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ if (getFail() + getReset() == 0) {
+ videoLogList.add(new mLogMsg("#Pass"));
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Pass");
+ } else {
+ videoLogList.add(new mLogMsg("#Fail"));
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Fail " + getFail() + getReset());
+ }
+ });
+ new Handler(getMainLooper()).postDelayed(() -> showDialogLog(true), delay_3 / 3);
+ }
+ for (String CameraId : allCamera) { // 遍例Camera
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (isOpenCamera.get(id)) { // 檢查OpenCamera
+ videoLogList.add(new mLogMsg("#stopRecord " + CameraId, mLog.v));
+ Log.e(TAG, isRun + " stopRecord " + CameraId);
+ if (isCameraOne(CameraId))
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ if (recordTimer != null) {
+ recordTimer.cancel();
+ recordTimer = null;
+ }
+ if (isFinish != 999)
+ if (alarmTimer != null) {
+ alarmTimer.cancel();
+ alarmTimer = null;
+ }
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Stop");
+ });
+ codeDate.set(id, getCalendarTime());
+ try {
+ closeMediaRecorder(CameraId);
+ checkAndClear(CameraId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("Check file is fail. <============ Crash here", true, e);
+ }
+ }
+ }
+ }
+ isRun = 0;
+ isFinish = 0;
+ isRecord = false;
+ videoLogList.add(new mLogMsg("#Complete"));
+ videoLogList.add(new mLogMsg("#------------------------------", mLog.v));
+ saveLog(getContext(), false, false);
+ if (!reset) {
+ extraRecordStatus = false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("stopRecord all camera error. <============ Crash here", true, e);
+ }
+ }
+
+ private void checkAndClear(String CameraId) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ try {
+ if (isRecord)
+ if (isOpenCamera.get(id) && null != cameraFilePath.get(id)) {
+ for (String f : cameraFilePath.get(id)) {
+ checkFile(f);
+ }
+ cameraFilePath.get(id).clear();
+ }
+ gc();
+ } catch (Exception e) {
+ videoLogList.add(new mLogMsg("CheckFile " + CameraId + " error.", mLog.e));
+ }
+ }
+
+ private void showDialogLog(boolean end) {
+ videoLogList.add(new mLogMsg("#Log_show", mLog.v));
+ View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_getlog, null);
+ final AlertDialog dialog = new AlertDialog.Builder(getContext(), R.style.Theme_AppCompat_NoActionBar)
+ .setView(view).setCancelable(true).create();
+
+ view.findViewById(R.id.dialog_button_2).setOnClickListener((View vs) -> { // ok
+ videoLogList.add(new mLogMsg("@Log_ok", mLog.v));
+ dialog.dismiss();
+ });
+ ArrayList list = new ArrayList<>();
+ if (isSave)
+ if (end) {
+ if (getFail() + getReset() == 0) {
+ list.add("#Pass");
+ } else {
+ list.add("#Fail");
+ }
+ list.add("CheckFile -> video_success/fail:(" + getSuccess() + "/" + getFail() + ") app_reset:(" + getReset() + ")");
+ } else
+ list.add("App Version:" + this.getString(R.string.app_name));
+ else list.add(NO_SD_CARD);
+
+ if (!errorMessage.equals(""))
+ list.add(errorMessage);
+ else {
+ for (String CameraId : allCamera) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (isOpenCamera.get(id) && !isCameraOpened.get(id))
+ list.add("Camera Access error, Please check camera " + CameraId + ". <============ Crash here");
+ }
+ }
+ if (list.size() > 0) {
+ ArrayList items = new ArrayList<>();
+ for (String s : list) {
+ @SuppressLint("InflateParams") View item_layout = LayoutInflater.from(getContext()).inflate(R.layout.style_text_item, null);
+ ((CustomTextView) item_layout.findViewById(R.id.customTextView)).setText(s);
+ items.add(item_layout);
+ }
+ ((ListView) view.findViewById(R.id.dialog_listview)).setAdapter(new mListAdapter(items));
+// ((ListView) view.findViewById(R.id.dialog_listview)).setSelection(items.size() - 1);
+ }
+ dialog.show();
+ }
+
+ boolean checkFile(String file, AtomicReferenceArray list) {
+ if (file.equals(list.get(0)))
+ return false;
+ else if (file.equals(list.get(1)))
+ return false;
+ return !file.equals(list.get(2));
+ }
+
+ public void onDestroy() {
+ super.onDestroy();
+ try {
+ closeCamera();
+ stopBackgroundThread();
+ for (String CameraId : allCamera) {
+ closeStateCallback(CameraId);
+ closePreviewSession(CameraId);
+ closeMediaRecorder(CameraId);
+ }
+ stopBackgroundThread();
+ if (null != home)
+ home.stop();
+ saveLog(getContext(), false, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("onDestroy error.", false, e);
+ }
+ }
+
+ @SuppressLint("MissingPermission")
+ private void openCamera(String CameraId) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ videoLogList.add(new mLogMsg("#Open Camera" + CameraId + ".", mLog.w));
+ Log.e(TAG, "camera ID: " + CameraId);
+ try {
+ CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
+ mPreviewSize = Objects.requireNonNull(manager.getCameraCharacteristics(CameraId)
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP))
+ .getOutputSizes(SurfaceTexture.class)[0];
+ Log.e(TAG, "camera " + CameraId + " is open");
+ manager.openCamera(CameraId, stateCallback.get(id), mainHandler);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (isLastCamera(CameraId))
+ isCameraReady = true;
+ }
+ }
+
+ private void closeCamera() {
+ isCameraReady = false;
+ Log.e(TAG, "camera is close");
+ for (String CameraId : allCamera) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ try {
+ if (null != cameraDevice.get(id)) {
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ try {
+ cameraDevice.get(id).close();
+ cameraDevice.set(id, null);
+ Thread.sleep(300); //TODO 防止 Camera error, 不過會慢很多
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+ }
+ }
+ }
+
+ private void stopRecordAndSaveLog(boolean kill) {
+ if (isRecord)
+ new Handler(getMainLooper()).post(() -> stopRecord(true));
+ saveLog(getContext(), false, kill);
+ }
+
+ @SuppressLint("HandlerLeak")
+ private void setCamera(String CameraId) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ textureView.set(id, Objects.requireNonNull(getActivity()).findViewById(view_id.get(id)));
+ cameraFilePath.set(id, new ArrayList<>());
+ codeDate.set(id, getCalendarTime());
+ stateCallback.set(id, setCallback(CameraId));
+ videoLogList.add(new mLogMsg("setCallback " + CameraId + ".", mLog.w));
+ recordHandler.set(id, new Handler(getMainLooper()) {
+ public void handleMessage(Message msg) {
+ try {
+ startRecord(CameraId);
+ videoLogList.add(new mLogMsg("startRecord " + CameraId + ".", mLog.w));
+ } catch (Exception e) {
+ videoLogList.add(new mLogMsg("startRecord " + CameraId + " is error.", mLog.w));
+ e.printStackTrace();
+ }
+ }
+ });
+ stopRecordHandler.set(id, new Handler(getMainLooper()) {
+ public void handleMessage(Message msg) {
+ if (isRecord)
+ try {
+ stopRecord(msg.obj.toString(), CameraId);
+ videoLogList.add(new mLogMsg("stopRecord " + CameraId + ".", mLog.w));
+ } catch (Exception e) {
+ videoLogList.add(new mLogMsg("stopRecord " + CameraId + " is error.", mLog.w));
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ @SuppressLint("SetTextI18n")
+ private void errorMessage(String msg, boolean reset, Exception e) {
+ if (e != null)
+ Log.e(TAG, e.toString());
+ isSave = !getSDPath().equals("");
+ isError = true;
+ isRecord = false;
+ Objects.requireNonNull(getActivity()).runOnUiThread(() ->
+ ((TextView) getActivity().findViewById(R.id.record_status)).setText("Error"));
+ if (null != videoLogList)
+ videoLogList.add(new mLogMsg(msg, mLog.e));
+ errorMessage = msg;
+ new Handler(getMainLooper()).post(() -> stopRecordAndSaveLog(false));
+ if (reset) {
+ new Handler(getMainLooper()).postDelayed(this::restartApp, delay_3);
+ }
+ }
+
+ private void restartApp() {
+ onRestart = true;
+ onReset++;
+ Context context = getContext();
+ Intent intent = RestartActivity.createIntent(Objects.requireNonNull(context));
+ intent.putExtra(EXTRA_VIDEO_RUN, onRun);
+ intent.putExtra(EXTRA_VIDEO_FAIL, onFail);
+ intent.putExtra(EXTRA_VIDEO_RESET, onReset);
+ intent.putExtra(EXTRA_VIDEO_SUCCESS, onSuccess);
+ intent.putExtra(EXTRA_VIDEO_RECORD, extraRecordStatus);
+ context.startActivity(intent);
+ }
+
+ private void closeStateCallback(String CameraId) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ try {
+ if (null != stateCallback.get(id)) {
+ stateCallback.get(id).onDisconnected(cameraDevice.get(id));
+ stateCallback.set(id, null);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closeStateCallback" + CameraId + " is error.", true, e);
+ }
+ }
+
+ private void closePreviewSession(String CameraId) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ try {
+ if (null != previewSession.get(id)) {
+ previewSession.get(id).close();
+ previewSession.set(id, null);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closePreviewSession" + CameraId + " is error.", false, e);
+ }
+ }
+
+ private void closeMediaRecorder(String CameraId) {
+ /* this function will error with camera changed. */
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ if (null != mediaRecorder.get(id)) {
+ try {
+ try {
+ mediaRecorder.get(id).stop();
+ mediaRecorder.get(id).release();
+ } catch (RuntimeException stopException) {
+ // handle cleanup here
+ videoLogList.add(new mLogMsg("stop MediaRecorder " + CameraId + " is error."));
+ }
+ mediaRecorder.set(id, null);
+ videoLogList.add(new mLogMsg("Record " + CameraId + " finish."));
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("stop MediaRecorder " + CameraId + " is error."));
+ }
+ }
+ }
+
+ private MediaRecorder setUpMediaRecorder(String CameraId) {
+ /* this function will error with camera changed. */
+ CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ int kbps = 1000;
+ String file;
+ MediaRecorder mediaRecorder = null;
+ try {
+ if (!getSDPath().equals("")) {
+ String name = getCalendarTime(CameraId) + ".mp4";
+ file = getSDPath() + name;
+ videoLogList.add(new mLogMsg("Create: " + name, mLog.w));
+ cameraFile.set(id, file + "");
+ cameraFilePath.get(id).add(file);
+ mediaRecorder = new MediaRecorder();
+ if (Open_Audio) videoLogList.add(new mLogMsg("#audio"));
+ if (Open_Audio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+// mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
+ mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+ if (Open_Audio) mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
+ if (Open_Audio) mediaRecorder.setAudioEncodingBitRate(96 * kbps);
+ mediaRecorder.setVideoEncodingBitRate(2000 * kbps);
+ if (Open_Audio) {
+ mediaRecorder.setAudioChannels(2);
+ mediaRecorder.setAudioSamplingRate(44100);
+ }
+ mediaRecorder.setVideoFrameRate(50);
+ mediaRecorder.setOutputFile(file);
+ mediaRecorder.prepare();
+ } else {
+ errorMessage("MediaRecorder error. " + NO_SD_CARD + " <============ Crash here", false, null);
+ return null;
+ }
+ } catch (Exception e) {
+ errorMessage("MediaRecorder " + CameraId + " error. <============ Crash here", false, e);
+ }
+ return mediaRecorder;
+ }
+
+ private void showToast(final String text) {
+ final Activity activity = getActivity();
+ if (activity != null) {
+ activity.runOnUiThread(() -> Toast.makeText(activity, text, Toast.LENGTH_SHORT).show());
+ }
+ }
+
+ private void checkSdCardFromFileList() {
+ isSave = !getSDPath().equals("");
+ if (isSave) {
+ try {
+ StatFs stat = new StatFs(getSDPath());
+ long sdAvailSize = stat.getAvailableBlocksLong() * stat.getBlockSizeLong();
+ double gigaAvailable = (sdAvailSize >> 30);
+ Log.e(TAG, "Size:" + gigaAvailable + " gb");
+ if (gigaAvailable < sdData) {
+ videoLogList.add(new mLogMsg("SD Card is Full."));
+ ArrayList tmp = new ArrayList<>();
+ File[] fileList = new File(getSDPath()).listFiles();
+ for (File file : fileList) {
+ if (!file.isDirectory() && Utils.getFileExtension(file.toString()).equals("mp4"))
+ if (checkFile(file.toString(), cameraFile))
+ tmp.add(file.toString());
+ }
+ if (tmp.size() >= 6) {
+ Object[] list = tmp.toArray();
+ Arrays.sort(list);
+ for (int i = 0; i < 6; i++)
+ delete((String) (list != null ? list[i] : null), SD_Mode);
+ checkSdCardFromFileList();
+ } else {
+ isError = true;
+ videoLogList.add(new mLogMsg("MP4 video file not found. <============ Crash here"));
+ errorMessage("error: At least " + sdData + "gb memory needs to be available to record, please check the SD Card free space.", false, null);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ if (!getSDPath().equals("")) {
+ errorMessage("error: At least " + sdData + "gb memory needs to be available to record, please check the SD Card free space.", false, null);
+ } else {
+ errorMessage(NO_SD_CARD, false, null);
+ }
+ }
+ } else {
+ errorMessage(NO_SD_CARD, false, null);
+ }
+ }
+
+ private void setHomeListener() {
+ try {
+ home = new mHomeListen(getContext());
+ home.setOnHomeBtnPressListener(new mHomeListen.OnHomeBtnPressListener() {
+ public void onHomeBtnPress() {
+ videoLogList.add(new mLogMsg("@home", mLog.v));
+ stopRecordAndSaveLog(true);
+ }
+
+ public void onHomeBtnLongPress() {
+ videoLogList.add(new mLogMsg("@recent", mLog.v));
+ stopRecordAndSaveLog(true);
+ }
+ });
+ home.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private CameraDevice.StateCallback setCallback(String CameraId) {
+ CameraDevice.StateCallback callback;
+ try {
+ callback = new CameraDevice.StateCallback() {
+ final int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+
+ public void onOpened(@NonNull CameraDevice cameraDevice) {
+ Log.e(TAG, "onOpened Camera " + CameraId);
+ try {
+ isCameraOpened.set(id, true);
+ Utils.cameraDevice.set(id, cameraDevice);
+ takePreview(CameraId);
+ videoLogList.add(new mLogMsg("Camera " + CameraId + " is opened.", mLog.i));
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closeCameraDevices " + CameraId + " close error.", true, e);
+ }
+ }
+
+ public void onDisconnected(@NonNull CameraDevice cameraDevice) {
+ Log.e(TAG, "onDisconnected Camera " + CameraId);
+ try {
+ isCameraOpened.set(id, false);
+ Utils.cameraDevice.get(id).close();
+ videoLogList.add(new mLogMsg("Camera " + CameraId + " is disconnected.", mLog.w));
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closeCameraDevices " + CameraId + " close error.", true, e);
+ }
+ }
+
+ public void onError(@NonNull CameraDevice cameraDevice, int error) {
+ Log.e(TAG, "onError Camera " + CameraId);
+ try {
+ isCameraOpened.set(id, false);
+ Utils.cameraDevice.get(id).close();
+ videoLogList.add(new mLogMsg("Camera " + CameraId + " is disconnected.", mLog.w));
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closeCameraDevices " + CameraId + " close error.", true, e);
+ }
+ errorMessage("Camera " + CameraId + " is error. <============ Crash here", true, null);
+ }
+ };
+ return callback;
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("closeCameraDevices " + CameraId + " close error.", true, e);
+ }
+ return null;
+ }
+
+ private void takePreview(String CameraId) {
+ int id = CameraId.equals(allCamera.get(0)) ? 0 : 1;
+ Log.e(TAG, "takePreview " + CameraId);
+ videoLogList.add(new mLogMsg("Preview " + CameraId + " Camera.", mLog.i));
+ try {
+ SurfaceTexture texture = null;
+ try {
+ texture = textureView.get(id).getSurfaceTexture();
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("takePreview " + CameraId + " error. <============ Crash here", true, e);
+ }
+ assert texture != null;
+ // We configure the size of default buffer to be the size of camera preview we want.
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ Surface surface = new Surface(texture);
+ CaptureRequest.Builder mPreviewBuilder;
+ // We set up a CaptureRequest.Builder with the output Surface.
+ mPreviewBuilder = cameraDevice.get(id).createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mPreviewBuilder.addTarget(surface);
+ // Here, we create a CameraCaptureSession for camera preview.
+ cameraDevice.get(id).createCaptureSession(Collections.singletonList(surface),
+ new CameraCaptureSession.StateCallback() {
+ public void onConfigured(@NonNull CameraCaptureSession session) {
+ try {
+ // When the session is ready, we start displaying the preview.
+ previewSession.set(id, session);
+ updatePreview(mPreviewBuilder, previewSession.get(id), backgroundHandler.get(id));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void onConfigureFailed(
+ @NonNull CameraCaptureSession cameraCaptureSession) {
+ Objects.requireNonNull(getActivity()).runOnUiThread(() ->
+ errorMessage("Preview " + CameraId + " onConfigureFailed", true, null));
+ }
+ }, backgroundHandler.get(id));
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected void updatePreview(CaptureRequest.Builder mPreviewBuilder, CameraCaptureSession mPreviewSession, Handler backgroundHandler) {
+ try {
+ mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+ mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
+ } catch (Exception e) {
+ e.printStackTrace();
+ errorMessage("setCaptureRequest error.", true, e);
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private class mTimerTask extends TimerTask {
+ long value;
+
+ public mTimerTask(long value) {
+ this.value = value;
+ }
+
+ public void run() {
+ Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+ try {
+ value += 1;
+ ((TextView) getActivity().findViewById(R.id.record_timer)).setText(value + "");
+ if (autoStopRecord && value >= 65) {
+ errorMessage("Application has timed out.", true, null);
+ }
+ } catch (Exception ignored) {
+ }
+ });
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private class mAlarmTask extends TimerTask {
+ long value;
+
+ public mAlarmTask(long value) {
+ this.value = value;
+ }
+
+ @SuppressLint("DefaultLocale")
+ public void run() {
+ try {
+ value -= 1;
+ long uptime = value;
+ long hour = TimeUnit.SECONDS.toHours(uptime);
+ uptime -= TimeUnit.HOURS.toSeconds(hour);
+ long min = TimeUnit.SECONDS.toMinutes(uptime);
+ uptime -= TimeUnit.MINUTES.toSeconds(min);
+ long sec = uptime;
+ Objects.requireNonNull(getActivity()).runOnUiThread(() ->
+ ((TextView) getActivity().findViewById(R.id.record_alarm)).setText(String.format("%02d:%02d:%02d", hour, min, sec)));
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ private class mSurfaceTextureListener implements TextureView.SurfaceTextureListener {
+ String cameraId;
+
+ public mSurfaceTextureListener(String cameraId) {
+ this.cameraId = cameraId;
+ }
+
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ openCamera(cameraId);
+ }
+
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+ }
+
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ return false;
+ }
+
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+ }
+ }
+}
diff --git a/app/src/main/java/com/d160/wa034/Config.java b/app/src/main/java/com/d160/wa034/Config.java
new file mode 100644
index 0000000..29fecd1
--- /dev/null
+++ b/app/src/main/java/com/d160/wa034/Config.java
@@ -0,0 +1,29 @@
+package com.d160.wa034;
+
+import android.content.Context;
+
+import static com.d160.wa034.CameraFragment.*;
+import static com.d160.wa034.Utils.*;
+
+public class Config {
+
+ protected Context context;
+ protected int numberOfRuns = defaultRun;
+
+ public Config(Context context) {
+ this.context = context;
+ }
+
+ public Config(Context context, int isRuns) {
+ this.context = context;
+ this.numberOfRuns = isRuns;
+ }
+
+ protected String[] config() {
+ return new String[]{
+ CONFIG_TITLE+ context.getString(R.string.app_name) + "\r\n",
+ "#Total number of runs (1 record is 1 min)\r\n",
+ "numberOfRuns = " + numberOfRuns + "\r\n"
+ };
+ }
+}
diff --git a/app/src/main/java/com/askey/record/restartActivity.java b/app/src/main/java/com/d160/wa034/RestartActivity.java
similarity index 79%
rename from app/src/main/java/com/askey/record/restartActivity.java
rename to app/src/main/java/com/d160/wa034/RestartActivity.java
index 5b8c41d..9bdbced 100644
--- a/app/src/main/java/com/askey/record/restartActivity.java
+++ b/app/src/main/java/com/d160/wa034/RestartActivity.java
@@ -1,11 +1,10 @@
-package com.askey.record;
+package com.d160.wa034;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
+import android.app.*;
+import android.content.*;
+import android.os.*;
-public class restartActivity extends Activity {
+public class RestartActivity extends Activity {
public static final String EXTRA_MAIN_PID = "RestartActivity.main_pid";
public static final String EXTRA_VIDEO_RUN = "RestartActivity.run";
public static final String EXTRA_VIDEO_FAIL = "RestartActivity.fail";
@@ -15,37 +14,36 @@ public class restartActivity extends Activity {
public static Intent createIntent(Context context) {
Intent intent = new Intent();
- intent.setClassName(context.getPackageName(), restartActivity.class.getName());
+ intent.setClassName(context.getPackageName(), RestartActivity.class.getName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // メインプロセスの PID を Intent に保存しておく
intent.putExtra(EXTRA_MAIN_PID, android.os.Process.myPid());
return intent;
}
-
+
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // 1. メインプロセスを Kill する
Intent intent = getIntent();
int mainPid = intent.getIntExtra(EXTRA_MAIN_PID, -1);
int EXTRA_RUN = intent.getIntExtra(EXTRA_VIDEO_RUN, 0);
int EXTRA_RESET = intent.getIntExtra(EXTRA_VIDEO_RESET, 0);
int EXTRA_FAIL = getIntent().getIntExtra(EXTRA_VIDEO_FAIL, 0);
int EXTRA_SUCCESS = getIntent().getIntExtra(EXTRA_VIDEO_SUCCESS, 0);
+
boolean EXTRA_RECORD = intent.getBooleanExtra(EXTRA_VIDEO_RECORD, false);
android.os.Process.killProcess(mainPid);
// 2. MainActivity を再起動する
Context context = getApplicationContext();
Intent restartIntent = new Intent(Intent.ACTION_MAIN);
- restartIntent.setClassName(context.getPackageName(), VideoRecordActivity.class.getName());
+ restartIntent.setClassName(context.getPackageName(), CameraActivity.class.getName());
restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
restartIntent.putExtra(EXTRA_VIDEO_RUN, EXTRA_RUN);
restartIntent.putExtra(EXTRA_VIDEO_RESET, EXTRA_RESET);
restartIntent.putExtra(EXTRA_VIDEO_FAIL, EXTRA_FAIL);
restartIntent.putExtra(EXTRA_VIDEO_SUCCESS, EXTRA_SUCCESS);
+
restartIntent.putExtra(EXTRA_VIDEO_RECORD, EXTRA_RECORD);
context.startActivity(restartIntent);
- // 3. RestartActivity を終了する
finish();
android.os.Process.killProcess(android.os.Process.myPid());
}
diff --git a/app/src/main/java/com/d160/wa034/Utils.java b/app/src/main/java/com/d160/wa034/Utils.java
new file mode 100644
index 0000000..28d5c58
--- /dev/null
+++ b/app/src/main/java/com/d160/wa034/Utils.java
@@ -0,0 +1,369 @@
+package com.d160.wa034;
+
+import android.Manifest;
+import android.annotation.*;
+import android.content.Context;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.media.*;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.view.*;
+
+import com.d160.view.*;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import static android.os.Environment.*;
+import static com.d160.wa034.CameraFragment.*;
+
+@SuppressLint("StaticFieldLeak")
+public class Utils {
+ //-------------------------------------------------------------------------------
+ public static final String EXTRA_VIDEO_RUN = "RestartActivity.run";
+ public static final String EXTRA_VIDEO_FAIL = "RestartActivity.fail";
+ public static final String EXTRA_VIDEO_RESET = "RestartActivity.reset";
+ public static final String EXTRA_VIDEO_RECORD = "RestartActivity.record";
+ public static final String EXTRA_VIDEO_SUCCESS = "RestartActivity.success";
+ //-------------------------------------------------------------------------------
+ public static final String NO_SD_CARD = "SD card is not available!";
+ public static final int defaultRun = 480;
+ public static final double sdData = 3;
+ public static long isFinish = defaultRun, isRun = 0, Success = 0, Fail = 0;
+ public static ArrayList videoLogList = null;
+ public static boolean isInitReady = false, isCameraReady = true, isRecord = false,
+ isError = false, isSave = false;
+ public static String errorMessage = "";
+ //-------------------------------------------------------------------------------
+ public static List allCamera = Arrays.asList(firstCamera);
+ public static AtomicReferenceArray isOpenCamera = new AtomicReferenceArray<>(new Boolean[]{Open_f_Camera});
+ public static AtomicIntegerArray view_id = new AtomicIntegerArray(new int[]{R.id.view0});
+ public static AtomicReferenceArray threadString = new AtomicReferenceArray<>(new String[]{"CameraPreview0", "CameraPreview1"});
+ public static AtomicReferenceArray permission = new AtomicReferenceArray<>(new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE});
+ public static AtomicReferenceArray cameraFile = new AtomicReferenceArray<>(new String[]{"", ""});
+ public static AtomicReferenceArray isCameraOpened = new AtomicReferenceArray<>(new Boolean[]{false, false});
+ public static AtomicReferenceArray> cameraFilePath = new AtomicReferenceArray>(new ArrayList[2]);
+ public static AtomicReferenceArray codeDate = new AtomicReferenceArray<>(new String[2]);
+ public static AtomicReferenceArray textureView = new AtomicReferenceArray<>(new TextureView[2]);
+ public static AtomicReferenceArray cameraDevice = new AtomicReferenceArray<>(new CameraDevice[2]);
+ public static AtomicReferenceArray previewSession = new AtomicReferenceArray<>(new CameraCaptureSession[2]);
+ public static AtomicReferenceArray stateCallback = new AtomicReferenceArray<>(new CameraDevice.StateCallback[2]);
+ public static AtomicReferenceArray mediaRecorder = new AtomicReferenceArray<>(new MediaRecorder[2]);
+ public static AtomicReferenceArray thread = new AtomicReferenceArray<>(new HandlerThread[2]);
+ public static AtomicReferenceArray backgroundHandler = new AtomicReferenceArray<>(new Handler[2]);
+ public static AtomicReferenceArray recordHandler = new AtomicReferenceArray<>(new Handler[2]);
+ public static AtomicReferenceArray stopRecordHandler = new AtomicReferenceArray<>(new Handler[2]);
+ //-------------------------------------------------------------------------------
+
+ public static String getLogPath() {
+ return getPath() + "DCIM/";
+ }
+
+ //TODO Default Path
+ public static String getPath() {
+ return getStorageDirectory().getPath() + "/emulated/0/";
+ }
+
+ public static String getSDPath() {
+ String path = "";
+ if (SD_Mode) {
+ try {
+ long start = (System.currentTimeMillis() / 1000) % 60;
+ long end = start + 10;
+ Runtime run = Runtime.getRuntime();
+ String cmd = "ls /storage";
+ Process pr = run.exec(cmd);
+ InputStreamReader input = new InputStreamReader(pr.getInputStream());
+ BufferedReader buf = new BufferedReader(input);
+ String line;
+ while ((line = buf.readLine()) != null) {
+ if (!line.equals("self") && !line.equals("emulated") && !line.equals("enterprise") && !line.contains("sdcard")) {
+ path = "/storage/" + line + "/";
+ break;
+ }
+ if ((System.currentTimeMillis() / 1000) % 60 > end) {
+ videoLogList.add(new mLogMsg("getSDPath time out.", mLog.e));
+ break;
+ }
+ }
+ buf.close();
+ input.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ path = getPath();
+ }
+ return path;
+ }
+
+ public static long getIsRun() {
+ return isRun;
+ }
+
+ public static long getSuccess() {
+ return Success;
+ }
+
+ public static long getFail() {
+ return Fail;
+ }
+
+ public static long getReset() {
+ return onReset;
+ }
+
+ public static boolean isInteger(String s, boolean zero) {
+ try {
+ if (Integer.parseInt(s) <= (zero ? 0 : -1)) {
+ return false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public static void setTestTime(int min) {
+ if (min == 999) {
+ Log.e(TAG, "setRecord time: 999.");
+ videoLogList.add(new mLogMsg("setRecord time: 999 times.", mLog.d));
+ } else {
+ Log.e(TAG, "setRecord time: " + min + " min.");
+ videoLogList.add(new mLogMsg("setRecord time: " + min + " min.", mLog.d));
+ }
+ isFinish = min;
+ }
+
+ public static void checkConfigFile(Context context) {
+ videoLogList.add(new mLogMsg("#checkConfigFile", mLog.v));
+ if (!getPath().equals("")) {
+ isSave = true;
+ File file = new File(getLogPath(), configName);
+ if (!file.exists()) {
+ try {
+ if (file.createNewFile())
+ videoLogList.add(new mLogMsg("Create the config.", mLog.w));
+ else
+ videoLogList.add(new mLogMsg("Failed to create the config.", mLog.w));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ writeConfigFile(context, file, new Config(context).config());
+ } else {
+ if (!isCameraReady) {
+ videoLogList.add(new mLogMsg("Find the config file.", mLog.e));
+ videoLogList.add(new mLogMsg("#------------------------------", mLog.v));
+ }
+ checkConfigFile(context, new File(getLogPath(), configName));
+ }
+ } else {
+ isSave = false;
+ }
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ public static void checkConfigFile(Context context, File file) {
+ try {
+ String input = readConfigFile(context, file);
+ boolean reformat = true, update = true;
+ if (input.length() > 0) {
+ String[] read = input.split("\r\n");
+ int target = 0, t;
+ String title = CONFIG_TITLE;
+ String code = "numberOfRuns = ";
+ for (String s : read)
+ if (s.contains(title)) {
+ target++;
+ t = s.indexOf(title) + title.length();
+ title = s.substring(t);
+ } else if (s.contains(code)) {
+ target++;
+ t = s.indexOf(code) + code.length();
+ code = s.substring(t);
+ }
+ if (target == 2) {
+ reformat = false;
+ if (title.equals(context.getString(R.string.app_name))) {
+ update = false;
+ } else {
+ Log.e(TAG, "Config is updated.");
+ videoLogList.add(new mLogMsg("Config is updated.", mLog.e));
+ reformat = true;
+ }
+ if (isInteger(code.split("\n")[0], true)) {
+ int min = Integer.parseInt(code.split("\n")[0]);
+ if (min <= 0) {
+ Log.e(TAG, "The test time must be a positive number.");
+ videoLogList.add(new mLogMsg("The test time must be a positive number.", mLog.e));
+ reformat = true;
+ } else {
+ setTestTime(min);
+ }
+ } else {
+ Log.e(TAG, "Unknown Record Times.");
+ videoLogList.add(new mLogMsg("Unknown Record Times.", mLog.e));
+ reformat = true;
+ }
+ } else {
+ Log.e(TAG, "target != 2 & Config is reset.");
+ }
+ }
+ if (update) {
+ StringBuilder logString = new StringBuilder(LOG_TITLE + context.getString(R.string.app_name) + "\r\n");
+ videoLogList.add(new mLogMsg("Reformat the Log file.", mLog.e));
+ for (mLogMsg logs : videoLogList) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ logString.append(dateFormat.format(logs.date)).append(" run:")
+ .append(logs.run).append(" -> ").append(logs.msg).append("\r\n");
+ }
+ try {
+ FileOutputStream output = new FileOutputStream(new File(getLogPath(), logName), false);
+ output.write(logString.toString().getBytes());
+ output.close();
+ videoLogList.clear();
+ } catch (Exception e) {
+ e.printStackTrace();
+ videoLogList.add(new mLogMsg("Write LOG failed. <============ error here", mLog.e));
+ }
+ }
+ if (reformat) {
+ reformatConfigFile(context, file);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ reformatConfigFile(context, file);
+ }
+ }
+
+ public static void reformatConfigFile(Context context, File file) {
+ writeConfigFile(context, file, new Config(context).config());
+ videoLogList.add(new mLogMsg("Reformat the Config file.", mLog.e));
+ }
+
+ public static String readConfigFile(Context context, File file) {
+ String tmp = "";
+ try {
+ byte[] buffer = new byte[100];
+ int length;
+ FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ while ((length = bis.read(buffer)) != -1) {
+ bytes.write(buffer, 0, length);
+ }
+ tmp += bytes.toString();
+ bytes.close();
+ bis.close();
+ fis.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ isError = true;
+ videoLogList.add(new mLogMsg("Read failed. <============ Crash here", mLog.e));
+ saveLog(context, false, false);
+ errorMessage = "Read failed. <============ Crash here";
+ videoLogList.add(new mLogMsg("Read failed.", mLog.e));
+ tmp += ("App Version:" + context.getString(R.string.app_name) + "\r\n");
+ tmp += ("Read failed. <============ Crash here");
+ return tmp;
+ }
+ return tmp;
+ }
+
+ public static void writeConfigFile(Context context, File file, String[] str) {
+ StringBuilder tmp = new StringBuilder();
+ for (String s : str)
+ tmp.append(s);
+ try {
+ FileOutputStream output = new FileOutputStream(file);
+ output.write(tmp.toString().getBytes());
+ output.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ isError = true;
+ videoLogList.add(new mLogMsg("Write failed. <============ Crash here", mLog.e));
+ saveLog(context, false, false);
+ errorMessage = "Write failed. <============ Crash here";
+ }
+ }
+
+ public static void updateConfigFile(Context context, File file, int min){
+ Log.e(TAG, "setConfig time: " + min + " min.");
+// videoLogList.add(new mLogMsg("set Config file. "+isRun+" ", mLog.e));
+ writeConfigFile(context, file, new Config(context, min).config());
+ }
+
+ @SuppressLint({"DefaultLocale", "SimpleDateFormat"})
+ public static String getCalendarTime() {
+ Calendar calendar = Calendar.getInstance();
+ return new SimpleDateFormat("HHmmss").format(calendar.getTime()) + "";
+ }
+
+ @SuppressLint({"DefaultLocale", "SimpleDateFormat"})
+ public static String getCalendarTime(String cameraId) {
+ Calendar calendar = Calendar.getInstance();
+ String cm = "c";
+ switch (cameraId) {
+ case firstCamera:
+ cm = "f";
+ break;
+ case secondCamera:
+ cm = "s";
+ break;
+ case thirdCamera:
+ cm = "t";
+ break;
+ }
+ return "v" + new SimpleDateFormat("yyyyMMddHHmmss").format(calendar.getTime()) + cm;
+ }
+
+ public static String getFileExtension(String fullName) {
+ String fileName = new File(fullName).getName();
+ int dotIndex = fileName.lastIndexOf('.');
+ return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
+ }
+
+ public static boolean isCameraOne(String cameraId) {
+// if (isOpenCamera.get(0))
+ return cameraId.equals(allCamera.get(0));
+// else if (isOpenCamera.get(1))
+// return cameraId.equals(allCamera.get(1));
+// else
+// return cameraId.equals(allCamera.get(2));
+ }
+
+ public static boolean isLastCamera(String cameraId) {
+// if (isOpenCamera.get(2))
+// return cameraId.equals(allCamera.get(2));
+// else if (isOpenCamera.get(1))
+// return cameraId.equals(allCamera.get(1));
+// else
+ return cameraId.equals(allCamera.get(0));
+ }
+
+ public static void delete(String path, boolean SdMode) {
+ File video = new File(path);
+ try {
+ if (!path.equals("")) {
+ if (video.exists()) {
+ if (SdMode)
+ videoLogList.add(new mLogMsg("Delete: " + path.split("/")[3], mLog.w));
+ else
+ videoLogList.add(new mLogMsg("Delete: " + path.split("/")[5], mLog.w));
+ boolean del = video.delete();
+ if (!del)
+ videoLogList.add(new mLogMsg("Video delete failed.", mLog.e));
+ } else {
+ videoLogList.add(new mLogMsg("Video not find.", mLog.e));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_camera.xml b/app/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..965947f
--- /dev/null
+++ b/app/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,7 @@
+
diff --git a/app/src/main/res/layout/activity_video_record.xml b/app/src/main/res/layout/activity_video_record.xml
deleted file mode 100644
index 04cf1ff..0000000
--- a/app/src/main/res/layout/activity_video_record.xml
+++ /dev/null
@@ -1,192 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_camera.xml b/app/src/main/res/layout/fragment_camera.xml
new file mode 100644
index 0000000..c26ee4c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_camera.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/layout_setting.xml b/app/src/main/res/layout/layout_setting.xml
deleted file mode 100644
index 29d355b..0000000
--- a/app/src/main/res/layout/layout_setting.xml
+++ /dev/null
@@ -1,245 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/style_setting_item.xml b/app/src/main/res/layout/style_setting_item.xml
old mode 100755
new mode 100644
index a64e085..33e498b
--- a/app/src/main/res/layout/style_setting_item.xml
+++ b/app/src/main/res/layout/style_setting_item.xml
@@ -13,7 +13,7 @@
android:background="@drawable/bg_rounded_white"
android:gravity="center">
-
-
-
- CDR9020_QTR(v1.7.6)
+ CDRB030_BurnIn(v1.1)
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
deleted file mode 100644
index 1243d8f..0000000
--- a/app/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/build.gradle b/build.gradle
index dfd946d..58312f2 100755
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
buildscript {
repositories {
google()
jcenter()
-
+
}
dependencies {
- //noinspection GradleDependency
+ //noinspection AndroidGradlePluginVersion,GradleDependency
classpath 'com.android.tools.build:gradle:3.5.3'
}
}
@@ -16,7 +15,6 @@ allprojects {
repositories {
google()
jcenter()
-
}
}
diff --git a/gradle.properties b/gradle.properties
index 82618ce..df358a1 100755
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,15 +1,3 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-
-
+org.gradle.parallel=true
+android.useAndroidX=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 62e02ba..ba34cc6 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+
diff --git a/script/0.brunIn-install.bat b/script/0.brunIn-install.bat
new file mode 100644
index 0000000..b23a1ce
--- /dev/null
+++ b/script/0.brunIn-install.bat
@@ -0,0 +1,2 @@
+adb wait-for-device
+adb install app-debug.apk
\ No newline at end of file
diff --git a/script/1.brunIn-open.bat b/script/1.brunIn-open.bat
new file mode 100644
index 0000000..46c5ea7
--- /dev/null
+++ b/script/1.brunIn-open.bat
@@ -0,0 +1,2 @@
+adb wait-for-device
+adb shell am start com.d160.wa034/.CameraActivity
\ No newline at end of file
diff --git a/script/2.brunIn-close.bat b/script/2.brunIn-close.bat
new file mode 100644
index 0000000..adb840b
--- /dev/null
+++ b/script/2.brunIn-close.bat
@@ -0,0 +1,2 @@
+adb wait-for-device
+adb shell am broadcast -a close
\ No newline at end of file
diff --git a/script/AdbWinApi.dll b/script/AdbWinApi.dll
new file mode 100644
index 0000000..7abe26c
Binary files /dev/null and b/script/AdbWinApi.dll differ
diff --git a/script/AdbWinUsbApi.dll b/script/AdbWinUsbApi.dll
new file mode 100644
index 0000000..e7a6de1
Binary files /dev/null and b/script/AdbWinUsbApi.dll differ
diff --git a/script/BurnInTestConfig.ini b/script/BurnInTestConfig.ini
new file mode 100644
index 0000000..bf6e620
--- /dev/null
+++ b/script/BurnInTestConfig.ini
@@ -0,0 +1,3 @@
+[BurnIn_Config]CDRB030_BurnIn(v1.1)
+#Total number of runs (1 record is 1 min)
+numberOfRuns = 480
diff --git a/script/README.txt b/script/README.txt
new file mode 100644
index 0000000..eae773b
--- /dev/null
+++ b/script/README.txt
@@ -0,0 +1,15 @@
+
+ CDRB030_BurnIn 指令使用說明
+
+ 0.brunIn-install.bat 安裝App
+
+ 1.brunIn-open.bat 開啟App -> 自動錄影, 測試結束會顯示結果
+
+ 2.brunIn-close.bat 結束App
+
+ 其他指令
+ brunIn-(start&stop).bat 開始/停止錄影, 手動停止不會顯示結果
+
+ brunIn-取出logs.bat 取出Logd及Config
+
+ brunIn-寫入config.bat 修改BurnInTestConfig 後使用之Push指令
diff --git a/script/adb.exe b/script/adb.exe
new file mode 100644
index 0000000..dd233d8
Binary files /dev/null and b/script/adb.exe differ
diff --git a/script/app-debug.apk b/script/app-debug.apk
new file mode 100644
index 0000000..fe75c2a
Binary files /dev/null and b/script/app-debug.apk differ
diff --git a/script/brunIn-(start&stop).bat b/script/brunIn-(start&stop).bat
new file mode 100644
index 0000000..3b62924
--- /dev/null
+++ b/script/brunIn-(start&stop).bat
@@ -0,0 +1,2 @@
+adb wait-for-device
+adb shell am broadcast -a start
\ No newline at end of file
diff --git "a/script/brunIn-\345\217\226\345\207\272logs.bat" "b/script/brunIn-\345\217\226\345\207\272logs.bat"
new file mode 100644
index 0000000..26a5cc5
--- /dev/null
+++ "b/script/brunIn-\345\217\226\345\207\272logs.bat"
@@ -0,0 +1,21 @@
+adb wait-for-device
+adb root
+adb shell getprop ro.boot.serialno > serno.txt
+set /p SERNO=