feat: 增加视频拍摄功能
This commit is contained in:
parent
8fc6ed7d2a
commit
e5a65e87c9
@ -84,7 +84,7 @@ dependencies {
|
|||||||
//三级选择
|
//三级选择
|
||||||
implementation 'com.airsaid.library:pickerview:1.0.3'
|
implementation 'com.airsaid.library:pickerview:1.0.3'
|
||||||
//省市区 https://github.com/Bigkoo/Android-PickerView
|
//省市区 https://github.com/Bigkoo/Android-PickerView
|
||||||
compile 'com.contrarywind:Android-PickerView:4.1.6'
|
implementation 'com.contrarywind:Android-PickerView:4.1.6'
|
||||||
implementation 'com.contrarywind:Android-PickerView:4.1.8'
|
implementation 'com.contrarywind:Android-PickerView:4.1.8'
|
||||||
/* //加载html
|
/* //加载html
|
||||||
implementation 'com.github.sendtion:XRichText:1.9.4'*/
|
implementation 'com.github.sendtion:XRichText:1.9.4'*/
|
||||||
@ -94,7 +94,7 @@ dependencies {
|
|||||||
implementation 'com.kongzue.dialog_v3x:dialog:3.2.4'
|
implementation 'com.kongzue.dialog_v3x:dialog:3.2.4'
|
||||||
//xRecyclerview下拉刷新控件
|
//xRecyclerview下拉刷新控件
|
||||||
implementation project(':xrecyclerview')
|
implementation project(':xrecyclerview')
|
||||||
//拍照功能
|
//拍照功能 https://github.com/natario1/CameraView
|
||||||
implementation 'com.otaliastudios:cameraview:2.7.0'
|
implementation 'com.otaliastudios:cameraview:2.7.0'
|
||||||
|
|
||||||
//抽屉控件 https://github.com/umano/AndroidSlidingUpPanel
|
//抽屉控件 https://github.com/umano/AndroidSlidingUpPanel
|
||||||
@ -120,4 +120,7 @@ dependencies {
|
|||||||
implementation "androidx.room:room-rxjava2:$room_version"
|
implementation "androidx.room:room-rxjava2:$room_version"
|
||||||
implementation "androidx.room:room-guava:$room_version"
|
implementation "androidx.room:room-guava:$room_version"
|
||||||
testImplementation "androidx.room:room-testing:$room_version"
|
testImplementation "androidx.room:room-testing:$room_version"
|
||||||
|
|
||||||
|
// 视频拼接 https://blog.csdn.net/u011520181/article/details/89324292
|
||||||
|
implementation 'com.googlecode.mp4parser:isoparser:1.1.21'
|
||||||
}
|
}
|
@ -38,6 +38,7 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
|
android:largeHeap="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.WhiteScreen">
|
android:theme="@style/Theme.WhiteScreen">
|
||||||
|
@ -10,6 +10,7 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
@ -18,21 +19,19 @@ import android.view.View;
|
|||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.hjq.permissions.OnPermissionCallback;
|
|
||||||
import com.hjq.permissions.Permission;
|
|
||||||
import com.hjq.permissions.XXPermissions;
|
|
||||||
import com.navinfo.outdoor.R;
|
import com.navinfo.outdoor.R;
|
||||||
import com.navinfo.outdoor.api.Constant;
|
import com.navinfo.outdoor.api.Constant;
|
||||||
import com.navinfo.outdoor.base.BaseActivity;
|
import com.navinfo.outdoor.base.BaseActivity;
|
||||||
|
|
||||||
|
import com.navinfo.outdoor.util.AWMp4ParserHelper;
|
||||||
|
import com.navinfo.outdoor.util.FileUtils;
|
||||||
import com.navinfo.outdoor.util.MyTecentLocationSource;
|
import com.navinfo.outdoor.util.MyTecentLocationSource;
|
||||||
import com.navinfo.outdoor.util.NetWorkUtils;
|
|
||||||
import com.navinfo.outdoor.util.SdkFolderCreate;
|
import com.navinfo.outdoor.util.SdkFolderCreate;
|
||||||
import com.navinfo.outdoor.util.ToastUtil;
|
|
||||||
import com.otaliastudios.cameraview.CameraException;
|
import com.otaliastudios.cameraview.CameraException;
|
||||||
import com.otaliastudios.cameraview.CameraListener;
|
import com.otaliastudios.cameraview.CameraListener;
|
||||||
import com.otaliastudios.cameraview.CameraLogger;
|
import com.otaliastudios.cameraview.CameraLogger;
|
||||||
@ -44,10 +43,14 @@ import com.otaliastudios.cameraview.VideoResult;
|
|||||||
import com.otaliastudios.cameraview.controls.Engine;
|
import com.otaliastudios.cameraview.controls.Engine;
|
||||||
import com.otaliastudios.cameraview.controls.Mode;
|
import com.otaliastudios.cameraview.controls.Mode;
|
||||||
|
|
||||||
import com.tencent.map.geolocation.TencentLocation;
|
import com.otaliastudios.cameraview.frame.Frame;
|
||||||
|
import com.otaliastudios.cameraview.frame.FrameProcessor;
|
||||||
|
import com.otaliastudios.cameraview.size.AspectRatio;
|
||||||
|
import com.otaliastudios.cameraview.size.Size;
|
||||||
|
import com.otaliastudios.cameraview.size.SizeSelector;
|
||||||
|
import com.otaliastudios.cameraview.size.SizeSelectors;
|
||||||
import com.tencent.tencentmap.mapsdk.maps.CameraUpdate;
|
import com.tencent.tencentmap.mapsdk.maps.CameraUpdate;
|
||||||
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
|
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
|
||||||
import com.tencent.tencentmap.mapsdk.maps.MapView;
|
|
||||||
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
|
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
|
||||||
import com.tencent.tencentmap.mapsdk.maps.TextureMapView;
|
import com.tencent.tencentmap.mapsdk.maps.TextureMapView;
|
||||||
import com.tencent.tencentmap.mapsdk.maps.UiSettings;
|
import com.tencent.tencentmap.mapsdk.maps.UiSettings;
|
||||||
@ -65,35 +68,60 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import static com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE;
|
import static com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE;
|
||||||
|
|
||||||
|
|
||||||
public class PictureActivity extends BaseActivity implements View.OnClickListener {
|
public class PictureActivity extends BaseActivity implements View.OnClickListener {
|
||||||
private static final CameraLogger LOG = CameraLogger.create("Picture");
|
private static final CameraLogger LOG = CameraLogger.create("Picture");
|
||||||
private CameraView camera;
|
private CameraView camera;
|
||||||
// private ImageButton capturePicture;
|
|
||||||
private long captureTime = 0;
|
private long captureTime = 0;
|
||||||
private android.widget.Button btnSwitch;
|
private android.widget.Button btnSwitch;
|
||||||
private TencentMap tencentMap;
|
private TencentMap tencentMap;
|
||||||
private MyLocationStyle locationStyle;
|
private MyLocationStyle locationStyle;
|
||||||
private TextureMapView ivMap;
|
private TextureMapView ivMap;
|
||||||
private Button captureVideo, stopVideo;
|
private CheckBox captureVideo; // 拍摄视频
|
||||||
private Button btnVideo;
|
private Button btnVideo, stopVideo;
|
||||||
private ImageView ivPic;
|
private ImageView ivPic;
|
||||||
|
private String finalVideoPath; // 摄像后最终保存的文件名
|
||||||
|
private File tmpFile; // 合并文件的临时文件路径
|
||||||
|
private Timer timer;
|
||||||
|
private CsvTimerTask timerTask; // 执行定时写入csv文件的task
|
||||||
|
private DateFormat formatter;
|
||||||
|
private final long period = 2; // 记录csv文件的间隔时间,单位为秒
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getLayout() {
|
protected int getLayout() {
|
||||||
EventBus.getDefault().register(this);
|
EventBus.getDefault().register(this);
|
||||||
|
tmpFile = new File(Constant.PICTURE_FOLDER, "temp.mp4");
|
||||||
|
formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
return R.layout.activity_picture;
|
return R.layout.activity_picture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initView() {
|
protected void initView() {
|
||||||
super.initView();
|
super.initView();
|
||||||
|
|
||||||
|
if (getIntent()!=null) {
|
||||||
|
finalVideoPath = getIntent().getStringExtra(Constant.INTENT_VIDEO_PATH);
|
||||||
|
}
|
||||||
|
if (finalVideoPath == null) {
|
||||||
|
finalVideoPath = Constant.PICTURE_FOLDER+"/final.mp4";
|
||||||
|
}
|
||||||
|
|
||||||
|
timer = new Timer();
|
||||||
|
|
||||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||||
ivMap = (TextureMapView) findViewById(R.id.iv_map);
|
ivMap = (TextureMapView) findViewById(R.id.iv_map);
|
||||||
ivPic = findViewById(R.id.iv_pic);
|
ivPic = findViewById(R.id.iv_pic);
|
||||||
@ -108,13 +136,53 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
camera = findViewById(R.id.camera);
|
camera = findViewById(R.id.camera);
|
||||||
camera.setOnClickListener(this::onClick);
|
camera.setOnClickListener(this::onClick);
|
||||||
captureVideo = findViewById(R.id.capuretVideo);
|
captureVideo = findViewById(R.id.capuretVideo);
|
||||||
captureVideo.setOnClickListener(this::onClick);
|
captureVideo.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
if (isChecked) { // 开始采集,设置按钮文字内容为“结束采集”
|
||||||
|
captureVideo.setText("暂停采集");
|
||||||
|
|
||||||
|
startTakenVideo(); // 开始采集视频
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前视频的时间,记录csv文件时使用
|
||||||
|
* */
|
||||||
|
long currentTime = AWMp4ParserHelper.getInstance().getVedioTotalTime(new File(finalVideoPath));
|
||||||
|
timerTask = new CsvTimerTask(new File(finalVideoPath+".txt"));
|
||||||
|
timerTask.setCurrentVideoTime(currentTime/1000);
|
||||||
|
|
||||||
|
// 开始采集,每隔2秒实时记录位置信息、视频时间以及设备时间
|
||||||
|
timer.schedule(timerTask, 0, period*1000);
|
||||||
|
} else {
|
||||||
|
captureVideo.setText("开始采集");
|
||||||
|
timerTask.cancel();
|
||||||
|
stopTakenVideo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
stopVideo = findViewById(R.id.btn_stop_video);
|
stopVideo = findViewById(R.id.btn_stop_video);
|
||||||
stopVideo.setOnClickListener(this::onClick);
|
stopVideo.setOnClickListener(this::onClick);
|
||||||
//拍照权限
|
//拍照权限
|
||||||
camera.setLifecycleOwner(this);
|
camera.setLifecycleOwner(this);
|
||||||
camera.setEngine(Engine.CAMERA1);
|
camera.setEngine(Engine.CAMERA1);
|
||||||
|
// camera.setVideoBitRate(5);
|
||||||
|
camera.setPreviewFrameRate(5); // 设置预览视频的帧率
|
||||||
|
|
||||||
|
// 设置视频可用的宽高size
|
||||||
|
SizeSelector width = SizeSelectors.maxWidth(1920);
|
||||||
|
SizeSelector height = SizeSelectors.maxHeight(1024);
|
||||||
|
SizeSelector dimensions = SizeSelectors.and(width, height); // Matches sizes bigger than 1000x2000.
|
||||||
|
SizeSelector ratio = SizeSelectors.aspectRatio(AspectRatio.of(1, 1), 0); // Matches 1:1 sizes.
|
||||||
|
|
||||||
|
SizeSelector result = SizeSelectors.or(
|
||||||
|
SizeSelectors.and(ratio, dimensions), // Try to match both constraints
|
||||||
|
ratio, // If none is found, at least try to match the aspect ratio
|
||||||
|
SizeSelectors.biggest() // If none is found, take the biggest
|
||||||
|
);
|
||||||
|
camera.setVideoSize(result);
|
||||||
|
camera.setVideoBitRate(3000*1024);
|
||||||
|
// camera.setAudioBitRate();
|
||||||
|
|
||||||
//设置拍照的宽高
|
//设置拍照的宽高
|
||||||
SdkFolderCreate.mkdirs(Constant.PICTURE_FOLDER);
|
SdkFolderCreate.mkdirs(Constant.PICTURE_FOLDER);
|
||||||
@ -127,12 +195,18 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
// uiSettings.setAllGesturesEnabled(false);
|
// uiSettings.setAllGesturesEnabled(false);
|
||||||
setLocMarkerStyle(); // 设置当前位置显示样式
|
setLocMarkerStyle(); // 设置当前位置显示样式
|
||||||
|
|
||||||
|
// camera.addFrameProcessor(new FrameProcessor() {
|
||||||
|
// @Override
|
||||||
|
// public void process(@NonNull Frame frame) {
|
||||||
|
// Log.e("PictureActivity", frame.getTime()+"");
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
//相机预览监听
|
//相机预览监听
|
||||||
camera.addCameraListener(new CameraListener() {
|
camera.addCameraListener(new CameraListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPictureTaken(@NonNull @NotNull PictureResult result) {
|
public void onPictureTaken(@NonNull @NotNull PictureResult result) {
|
||||||
super.onPictureTaken(result);
|
super.onPictureTaken(result);
|
||||||
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||||
String format = formatter.format(calendar.getTime());
|
String format = formatter.format(calendar.getTime());
|
||||||
@ -150,15 +224,38 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
long callbackTime = System.currentTimeMillis();
|
long callbackTime = System.currentTimeMillis();
|
||||||
captureTime = callbackTime - 300;
|
captureTime = callbackTime - 300;
|
||||||
Log.d("captureTime", captureTime + "");
|
Log.d("captureTime", captureTime + "");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//录像监听
|
//录像监听
|
||||||
@Override
|
@Override
|
||||||
public void onVideoTaken(@NonNull @NotNull VideoResult result) {
|
public void onVideoTaken(@NonNull @NotNull VideoResult result) {
|
||||||
super.onVideoTaken(result);
|
super.onVideoTaken(result);
|
||||||
Toast.makeText(PictureActivity.this, "停止摄像", Toast.LENGTH_SHORT).show();
|
Toast.makeText(PictureActivity.this, "暂停摄像", Toast.LENGTH_SHORT).show();
|
||||||
finish();
|
if (result!=null) {
|
||||||
|
File currentFile = result.getFile();
|
||||||
|
if (finalVideoPath!=null) { // 有指定的视频文件名称,合并文件
|
||||||
|
if (new File(finalVideoPath).exists()) {
|
||||||
|
List<String> spliteFileList = new ArrayList<>();
|
||||||
|
spliteFileList.add(finalVideoPath);
|
||||||
|
spliteFileList.add(currentFile.getAbsolutePath());
|
||||||
|
try {
|
||||||
|
AWMp4ParserHelper.getInstance().mergeVideos(spliteFileList, tmpFile.getAbsolutePath());
|
||||||
|
if (tmpFile.exists()) {
|
||||||
|
File finalVideoFile = new File(finalVideoPath);
|
||||||
|
finalVideoFile.delete();
|
||||||
|
currentFile.delete();
|
||||||
|
tmpFile.renameTo(finalVideoFile);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(PictureActivity.this, "视频合并失败!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("PictureActivity", e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentFile.renameTo(new File(finalVideoPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -203,20 +300,49 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
case R.id.btn_switch:
|
case R.id.btn_switch:
|
||||||
btnSwich();
|
btnSwich();
|
||||||
break;
|
break;
|
||||||
case R.id.capuretVideo:
|
// case R.id.capuretVideo:
|
||||||
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
// startTakenVideo(); // 开始拍摄视频
|
||||||
Calendar calendar = Calendar.getInstance();
|
// break;
|
||||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
|
||||||
String format = formatter.format(calendar.getTime());
|
|
||||||
//文件
|
|
||||||
File file = new File(Constant.PICTURE_FOLDER, format + ".mp4");
|
|
||||||
camera.takeVideo(file);
|
|
||||||
break;
|
|
||||||
case R.id.btn_stop_video:
|
case R.id.btn_stop_video:
|
||||||
|
this.finish();
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startTakenVideo() {
|
||||||
|
if (camera.isTakingVideo()) {
|
||||||
|
Toast.makeText(this, "已经在拍摄中...", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
String formatVideoName = formatter.format(calendar.getTime());
|
||||||
|
//文件
|
||||||
|
File file = new File(Constant.PICTURE_FOLDER, formatVideoName + ".mp4");
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
FileOutputStream fo = new FileOutputStream(file);
|
||||||
|
FileDescriptor fileDescriptor = fo.getFD();
|
||||||
|
camera.takeVideo(fileDescriptor);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
camera.takeVideo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTakenVideo() {
|
||||||
|
if (camera.isTakingVideo()) {
|
||||||
|
camera.stopVideo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Bitmap getBitMap(int resourceId) {
|
private Bitmap getBitMap(int resourceId) {
|
||||||
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId);
|
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId);
|
||||||
int width = bitmap.getWidth();
|
int width = bitmap.getWidth();
|
||||||
@ -292,6 +418,7 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
stopTakenVideo();
|
||||||
camera.destroy();
|
camera.destroy();
|
||||||
if (EventBus.getDefault().isRegistered(this)) {
|
if (EventBus.getDefault().isRegistered(this)) {
|
||||||
EventBus.getDefault().unregister(this);
|
EventBus.getDefault().unregister(this);
|
||||||
@ -315,4 +442,40 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录视频拍摄的时间及经纬度
|
||||||
|
*/
|
||||||
|
private class CsvTimerTask extends TimerTask {
|
||||||
|
private File csvFile;
|
||||||
|
private long currentVideoTime; // 记录当前的视频时间
|
||||||
|
|
||||||
|
public CsvTimerTask(File csvFile) {
|
||||||
|
this.csvFile = csvFile;
|
||||||
|
if (!csvFile.exists()) {
|
||||||
|
csvFile.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentVideoTime(long currentVideoTime) {
|
||||||
|
this.currentVideoTime = currentVideoTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// 记录当前时间、视频时间、以及当前经纬度信息
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append(formatter.format(new Date())); // 记录当前时间
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(currentVideoTime) ;// 记录视频时间
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(Constant.currentLocation.getLatitude());
|
||||||
|
sb.append(",");
|
||||||
|
sb.append(Constant.currentLocation.getLongitude());
|
||||||
|
sb.append("\r\n");
|
||||||
|
FileUtils.writeFile(csvFile.getAbsolutePath(), sb.toString(), true);
|
||||||
|
currentVideoTime = currentVideoTime+period; //
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -94,5 +94,5 @@ public class Constant {
|
|||||||
public static JobSearchBean jobSearchBean;//数据
|
public static JobSearchBean jobSearchBean;//数据
|
||||||
public static MapView treasureMap;
|
public static MapView treasureMap;
|
||||||
|
|
||||||
|
public static final String INTENT_VIDEO_PATH = "INTENT_VIDEO_PATH"; // 拍照界面指定的视频文件保存位置
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,185 @@
|
|||||||
|
package com.navinfo.outdoor.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.VideoDecoder;
|
||||||
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
|
import com.coremedia.iso.boxes.Container;
|
||||||
|
import com.googlecode.mp4parser.authoring.Movie;
|
||||||
|
import com.googlecode.mp4parser.authoring.Track;
|
||||||
|
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
|
||||||
|
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
|
||||||
|
import com.googlecode.mp4parser.authoring.tracks.AppendTrack;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Author: AlanWang4523.
|
||||||
|
* Date: 19/4/15 01:46.
|
||||||
|
* Mail: alanwang4523@gmail.com
|
||||||
|
*/
|
||||||
|
public class AWMp4ParserHelper {
|
||||||
|
private static AWMp4ParserHelper instance;
|
||||||
|
|
||||||
|
public static AWMp4ParserHelper getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new AWMp4ParserHelper();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String PREFIX_VIDEO_HANDLER = "vide";
|
||||||
|
private final static String PREFIX_AUDIO_HANDLER = "soun";
|
||||||
|
/**
|
||||||
|
* 合并视频
|
||||||
|
* @param inputVideos
|
||||||
|
* @param outputPath
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void mergeVideos(List<String> inputVideos, String outputPath) throws IOException {
|
||||||
|
List<Movie> inputMovies = new ArrayList<>();
|
||||||
|
for (String input : inputVideos) {
|
||||||
|
inputMovies.add(MovieCreator.build(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Track> videoTracks = new LinkedList<>();
|
||||||
|
List<Track> audioTracks = new LinkedList<>();
|
||||||
|
|
||||||
|
for (Movie m : inputMovies) {
|
||||||
|
for (Track t : m.getTracks()) {
|
||||||
|
if (PREFIX_AUDIO_HANDLER.equals(t.getHandler())) {
|
||||||
|
audioTracks.add(t);
|
||||||
|
}
|
||||||
|
if (PREFIX_VIDEO_HANDLER.equals(t.getHandler())) {
|
||||||
|
videoTracks.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Movie outputMovie = new Movie();
|
||||||
|
if (audioTracks.size() > 0) {
|
||||||
|
outputMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
|
||||||
|
}
|
||||||
|
if (videoTracks.size() > 0) {
|
||||||
|
outputMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
|
||||||
|
}
|
||||||
|
|
||||||
|
Container out = new DefaultMp4Builder().build(outputMovie);
|
||||||
|
|
||||||
|
FileChannel fc = new RandomAccessFile(outputPath, "rw").getChannel();
|
||||||
|
out.writeContainer(fc);
|
||||||
|
fc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取mp4视频播放时长
|
||||||
|
* */
|
||||||
|
/**
|
||||||
|
* 返回视频播放总时长
|
||||||
|
* @param vedioFile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public long getVedioTotalTime(File vedioFile){
|
||||||
|
if (!vedioFile.exists()){
|
||||||
|
Log.e("getVedioTotalTime","视频文件不存在");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
|
retriever.setDataSource(vedioFile.getAbsolutePath());
|
||||||
|
String timeString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||||
|
long time = Long.valueOf(timeString);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网络视频第一帧
|
||||||
|
*
|
||||||
|
* @param videoUrl
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public void loadFirst(String videoUrl, @NonNull ImageView cover) {
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
|
try {
|
||||||
|
//根据url获取缩略图
|
||||||
|
retriever.setDataSource(videoUrl, new HashMap());
|
||||||
|
//获得第一帧图片
|
||||||
|
bitmap = retriever.getFrameAtTime();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
//e.printStackTrace();
|
||||||
|
Log.e("zhu", e.toString());
|
||||||
|
} finally {
|
||||||
|
retriever.release();
|
||||||
|
}
|
||||||
|
if (bitmap != null) {
|
||||||
|
cover.setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* context 上下文
|
||||||
|
* uri 视频地址
|
||||||
|
* imageView 设置image
|
||||||
|
* frameTimeMicros 获取某一时间帧
|
||||||
|
*/
|
||||||
|
public void loadFirstWithGlide(final Context context, String uri, ImageView imageView, long frameTimeMicros) {
|
||||||
|
RequestOptions requestOptions = RequestOptions.frameOf(frameTimeMicros);
|
||||||
|
requestOptions.set(VideoDecoder.FRAME_OPTION, MediaMetadataRetriever.OPTION_CLOSEST);
|
||||||
|
requestOptions.transform(new BitmapTransformation() {
|
||||||
|
@Override
|
||||||
|
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
|
||||||
|
return toTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDiskCacheKey(MessageDigest messageDigest) {
|
||||||
|
try {
|
||||||
|
messageDigest.update((context.getPackageName() + "RotateTransform").getBytes("utf-8"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Glide.with(context).load(uri).apply(requestOptions).into(imageView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本地视频的第一帧
|
||||||
|
*
|
||||||
|
* @param localPath
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Bitmap getLocalVideoBitmap(String localPath) {
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
|
try {
|
||||||
|
//根据文件路径获取缩略图
|
||||||
|
retriever.setDataSource(localPath);
|
||||||
|
//获得第一帧图片
|
||||||
|
bitmap = retriever.getFrameAtTime();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
retriever.release();
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
1003
app/src/main/java/com/navinfo/outdoor/util/FileUtils.java
Normal file
1003
app/src/main/java/com/navinfo/outdoor/util/FileUtils.java
Normal file
File diff suppressed because it is too large
Load Diff
98
app/src/main/java/com/navinfo/outdoor/util/IOUtils.java
Normal file
98
app/src/main/java/com/navinfo/outdoor/util/IOUtils.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package com.navinfo.outdoor.util;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IO utils
|
||||||
|
*
|
||||||
|
* @author Vladislav Bauer
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class IOUtils {
|
||||||
|
|
||||||
|
private IOUtils() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close closable object and wrap {@link IOException} with {@link
|
||||||
|
* RuntimeException}
|
||||||
|
*
|
||||||
|
* @param closeable closeable object
|
||||||
|
*/
|
||||||
|
public static void close(Closeable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("IOException occurred. ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close closable and hide possible {@link IOException}
|
||||||
|
*
|
||||||
|
* @param closeable closeable object
|
||||||
|
*/
|
||||||
|
public static void closeQuietly(Closeable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*保存文本
|
||||||
|
* @param fileName 文件名字
|
||||||
|
* @param content 内容
|
||||||
|
* @param append 是否累加
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public static boolean saveTextValue(String fileName, String content, boolean append) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
File textFile = new File(fileName);
|
||||||
|
if (!append && textFile.exists()) textFile.delete();
|
||||||
|
|
||||||
|
FileOutputStream os = new FileOutputStream(textFile);
|
||||||
|
os.write(content.getBytes("UTF-8"));
|
||||||
|
os.close();
|
||||||
|
} catch (Exception ee) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除目录下所有文件
|
||||||
|
* @param Path 路径
|
||||||
|
*/
|
||||||
|
public static void deleteAllFile(String Path) {
|
||||||
|
|
||||||
|
// 删除目录下所有文件
|
||||||
|
File path = new File(Path);
|
||||||
|
File files[] = path.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File tfi : files) {
|
||||||
|
if (tfi.isDirectory()) {
|
||||||
|
System.out.println(tfi.getName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tfi.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
703
app/src/main/java/com/navinfo/outdoor/util/StringUtils.java
Normal file
703
app/src/main/java/com/navinfo/outdoor/util/StringUtils.java
Normal file
@ -0,0 +1,703 @@
|
|||||||
|
package com.navinfo.outdoor.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>字符串工具类,提供一些字符串相关的便捷方法</h2>
|
||||||
|
*/
|
||||||
|
public class StringUtils {
|
||||||
|
|
||||||
|
private StringUtils() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is null or its length is 0 or it is made by space
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* isBlank(null) = true;
|
||||||
|
* isBlank("") = true;
|
||||||
|
* isBlank(" ") = true;
|
||||||
|
* isBlank("a") = false;
|
||||||
|
* isBlank("a ") = false;
|
||||||
|
* isBlank(" a") = false;
|
||||||
|
* isBlank("a b") = false;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param str str
|
||||||
|
* @return if string is null or its size is 0 or it is made by space, return
|
||||||
|
* true, else return false.
|
||||||
|
*/
|
||||||
|
public static boolean isBlank(String str) {
|
||||||
|
|
||||||
|
return (str == null || str.trim().length() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is null or its length is 0
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* isEmpty(null) = true;
|
||||||
|
* isEmpty("") = true;
|
||||||
|
* isEmpty(" ") = false;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param str str
|
||||||
|
* @return if string is null or its size is 0, return true, else return
|
||||||
|
* false.
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(CharSequence str) {
|
||||||
|
|
||||||
|
return (str == null || str.length() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get length of CharSequence
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* length(null) = 0;
|
||||||
|
* length(\"\") = 0;
|
||||||
|
* length(\"abc\") = 3;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param str str
|
||||||
|
* @return if str is null or empty, return 0, else return {@link
|
||||||
|
* CharSequence#length()}.
|
||||||
|
*/
|
||||||
|
public static int length(CharSequence str) {
|
||||||
|
|
||||||
|
return str == null ? 0 : str.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* null Object to empty string
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* nullStrToEmpty(null) = "";
|
||||||
|
* nullStrToEmpty("") = "";
|
||||||
|
* nullStrToEmpty("aa") = "aa";
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param str str
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String nullStrToEmpty(Object str) {
|
||||||
|
|
||||||
|
return (str == null
|
||||||
|
? ""
|
||||||
|
: (str instanceof String ? (String) str : str.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param str str
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String capitalizeFirstLetter(String str) {
|
||||||
|
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = str.charAt(0);
|
||||||
|
return (!Character.isLetter(c) || Character.isUpperCase(c))
|
||||||
|
? str
|
||||||
|
: new StringBuilder(str.length()).append(
|
||||||
|
Character.toUpperCase(c))
|
||||||
|
.append(str.substring(1))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* encoded in utf-8
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @return 返回一个utf8的字符串
|
||||||
|
*/
|
||||||
|
public static String utf8Encode(String str) {
|
||||||
|
|
||||||
|
if (!isEmpty(str) && str.getBytes().length != str.length()) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(str, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"UnsupportedEncodingException occurred. ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param href 字符串
|
||||||
|
* @return 返回一个html
|
||||||
|
*/
|
||||||
|
public static String getHrefInnerHtml(String href) {
|
||||||
|
|
||||||
|
if (isEmpty(href)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String hrefReg = ".*<[\\s]*a[\\s]*.*>(.+?)<[\\s]*/a[\\s]*>.*";
|
||||||
|
Pattern hrefPattern = Pattern.compile(hrefReg,
|
||||||
|
Pattern.CASE_INSENSITIVE);
|
||||||
|
Matcher hrefMatcher = hrefPattern.matcher(href);
|
||||||
|
if (hrefMatcher.matches()) {
|
||||||
|
return hrefMatcher.group(1);
|
||||||
|
}
|
||||||
|
return href;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param source 字符串
|
||||||
|
* @return 返回htmL到字符串
|
||||||
|
*/
|
||||||
|
public static String htmlEscapeCharsToString(String source) {
|
||||||
|
|
||||||
|
return StringUtils.isEmpty(source)
|
||||||
|
? source
|
||||||
|
: source.replaceAll("<", "<")
|
||||||
|
.replaceAll(">", ">")
|
||||||
|
.replaceAll("&", "&")
|
||||||
|
.replaceAll(""", "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param s str
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String fullWidthToHalfWidth(String s) {
|
||||||
|
|
||||||
|
if (isEmpty(s)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] source = s.toCharArray();
|
||||||
|
for (int i = 0; i < source.length; i++) {
|
||||||
|
if (source[i] == 12288) {
|
||||||
|
source[i] = ' ';
|
||||||
|
// } else if (source[i] == 12290) {
|
||||||
|
// source[i] = '.';
|
||||||
|
}
|
||||||
|
else if (source[i] >= 65281 && source[i] <= 65374) {
|
||||||
|
source[i] = (char) (source[i] - 65248);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
source[i] = source[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param s 字符串
|
||||||
|
* @return 返回的数值
|
||||||
|
*/
|
||||||
|
public static String halfWidthToFullWidth(String s) {
|
||||||
|
|
||||||
|
if (isEmpty(s)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] source = s.toCharArray();
|
||||||
|
for (int i = 0; i < source.length; i++) {
|
||||||
|
if (source[i] == ' ') {
|
||||||
|
source[i] = (char) 12288;
|
||||||
|
// } else if (source[i] == '.') {
|
||||||
|
// source[i] = (char)12290;
|
||||||
|
}
|
||||||
|
else if (source[i] >= 33 && source[i] <= 126) {
|
||||||
|
source[i] = (char) (source[i] + 65248);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
source[i] = source[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param str 资源
|
||||||
|
* @return 特殊字符串切换
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String replaceBlanktihuan(String str) {
|
||||||
|
|
||||||
|
String dest = "";
|
||||||
|
if (str != null) {
|
||||||
|
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
|
||||||
|
Matcher m = p.matcher(str);
|
||||||
|
dest = m.replaceAll("");
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串是否为null或者是空的
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(String string) {
|
||||||
|
return string == null || "".equals(string.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串是否不为null且不为空
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
*/
|
||||||
|
public static boolean isNotEmpty(String string) {
|
||||||
|
return !isEmpty(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串数组中的所有字符串是否都为null或者是空的
|
||||||
|
*
|
||||||
|
* @param strings 给定的字符串
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(String... strings) {
|
||||||
|
boolean result = true;
|
||||||
|
for (String string : strings) {
|
||||||
|
if (isNotEmpty(string)) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串数组中是否全部都不为null且不为空
|
||||||
|
*
|
||||||
|
* @param strings 给定的字符串数组
|
||||||
|
* @return 是否全部都不为null且不为空
|
||||||
|
*/
|
||||||
|
public static boolean isNotEmpty(String... strings) {
|
||||||
|
boolean result = true;
|
||||||
|
for (String string : strings) {
|
||||||
|
if (isEmpty(string)) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果字符串是null或者空就返回""
|
||||||
|
*/
|
||||||
|
public static String filterEmpty(String string) {
|
||||||
|
return StringUtils.isNotEmpty(string) ? string : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在给定的字符串中,用新的字符替换所有旧的字符
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
* @param oldchar 旧的字符
|
||||||
|
* @param newchar 新的字符
|
||||||
|
* @return 替换后的字符串
|
||||||
|
*/
|
||||||
|
public static String replace(String string, char oldchar, char newchar) {
|
||||||
|
char chars[] = string.toCharArray();
|
||||||
|
for (int w = 0; w < chars.length; w++) {
|
||||||
|
if (chars[w] == oldchar) {
|
||||||
|
chars[w] = newchar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把给定的字符串用给定的字符分割
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
* @param ch 给定的字符
|
||||||
|
* @return 分割后的字符串数组
|
||||||
|
*/
|
||||||
|
public static String[] split(String string, char ch) {
|
||||||
|
ArrayList<String> stringList = new ArrayList<String>();
|
||||||
|
char chars[] = string.toCharArray();
|
||||||
|
int nextStart = 0;
|
||||||
|
for (int w = 0; w < chars.length; w++) {
|
||||||
|
if (ch == chars[w]) {
|
||||||
|
stringList.add(new String(chars, nextStart, w - nextStart));
|
||||||
|
nextStart = w + 1;
|
||||||
|
if (nextStart ==
|
||||||
|
chars.length) { //当最后一位是分割符的话,就再添加一个空的字符串到分割数组中去
|
||||||
|
stringList.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextStart <
|
||||||
|
chars.length) { //如果最后一位不是分隔符的话,就将最后一个分割符到最后一个字符中间的左右字符串作为一个字符串添加到分割数组中去
|
||||||
|
stringList.add(new String(chars, nextStart,
|
||||||
|
chars.length - 1 - nextStart + 1));
|
||||||
|
}
|
||||||
|
return stringList.toArray(new String[stringList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算给定的字符串的长度,计算规则是:一个汉字的长度为2,一个字符的长度为1
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
* @return 长度
|
||||||
|
*/
|
||||||
|
public static int countLength(String string) {
|
||||||
|
int length = 0;
|
||||||
|
char[] chars = string.toCharArray();
|
||||||
|
for (int w = 0; w < string.length(); w++) {
|
||||||
|
char ch = chars[w];
|
||||||
|
if (ch >= '\u0391' && ch <= '\uFFE5') {
|
||||||
|
length++;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static char[] getChars(char[] chars, int startIndex) {
|
||||||
|
int endIndex = startIndex + 1;
|
||||||
|
//如果第一个是数字
|
||||||
|
if (Character.isDigit(chars[startIndex])) {
|
||||||
|
//如果下一个是数字
|
||||||
|
while (endIndex < chars.length &&
|
||||||
|
Character.isDigit(chars[endIndex])) {
|
||||||
|
endIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char[] resultChars = new char[endIndex - startIndex];
|
||||||
|
System.arraycopy(chars, startIndex, resultChars, 0, resultChars.length);
|
||||||
|
return resultChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否全是数字
|
||||||
|
*/
|
||||||
|
public static boolean isAllDigital(char[] chars) {
|
||||||
|
boolean result = true;
|
||||||
|
for (int w = 0; w < chars.length; w++) {
|
||||||
|
if (!Character.isDigit(chars[w])) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除给定字符串中所有的旧的字符
|
||||||
|
*
|
||||||
|
* @param string 源字符串
|
||||||
|
* @param ch 要删除的字符
|
||||||
|
* @return 删除后的字符串
|
||||||
|
*/
|
||||||
|
public static String removeChar(String string, char ch) {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
for (char cha : string.toCharArray()) {
|
||||||
|
if (cha != '-') {
|
||||||
|
sb.append(cha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除给定字符串中给定位置处的字符
|
||||||
|
*
|
||||||
|
* @param string 给定字符串
|
||||||
|
* @param index 给定位置
|
||||||
|
*/
|
||||||
|
public static String removeChar(String string, int index) {
|
||||||
|
String result = null;
|
||||||
|
char[] chars = string.toCharArray();
|
||||||
|
if (index == 0) {
|
||||||
|
result = new String(chars, 1, chars.length - 1);
|
||||||
|
}
|
||||||
|
else if (index == chars.length - 1) {
|
||||||
|
result = new String(chars, 0, chars.length - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = new String(chars, 0, index) +
|
||||||
|
new String(chars, index + 1, chars.length - index);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除给定字符串中给定位置处的字符
|
||||||
|
*
|
||||||
|
* @param string 给定字符串
|
||||||
|
* @param index 给定位置
|
||||||
|
* @param ch 如果同给定位置处的字符相同,则将给定位置处的字符删除
|
||||||
|
*/
|
||||||
|
public static String removeChar(String string, int index, char ch) {
|
||||||
|
String result = null;
|
||||||
|
char[] chars = string.toCharArray();
|
||||||
|
if (chars.length > 0 && chars[index] == ch) {
|
||||||
|
if (index == 0) {
|
||||||
|
result = new String(chars, 1, chars.length - 1);
|
||||||
|
}
|
||||||
|
else if (index == chars.length - 1) {
|
||||||
|
result = new String(chars, 0, chars.length - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = new String(chars, 0, index) +
|
||||||
|
new String(chars, index + 1, chars.length - index);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = string;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的字符串进行空白过滤
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
* @return 如果给定的字符串是一个空白字符串,那么返回null;否则返回本身。
|
||||||
|
*/
|
||||||
|
public static String filterBlank(String string) {
|
||||||
|
if ("".equals(string)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定字符串中给定的区域的字符转换成小写
|
||||||
|
*
|
||||||
|
* @param str 给定字符串中
|
||||||
|
* @param beginIndex 开始索引(包括)
|
||||||
|
* @param endIndex 结束索引(不包括)
|
||||||
|
* @return 新的字符串
|
||||||
|
*/
|
||||||
|
public static String toLowerCase(String str, int beginIndex, int endIndex) {
|
||||||
|
return str.replaceFirst(str.substring(beginIndex, endIndex),
|
||||||
|
str.substring(beginIndex, endIndex)
|
||||||
|
.toLowerCase(Locale.getDefault()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定字符串中给定的区域的字符转换成大写
|
||||||
|
*
|
||||||
|
* @param str 给定字符串中
|
||||||
|
* @param beginIndex 开始索引(包括)
|
||||||
|
* @param endIndex 结束索引(不包括)
|
||||||
|
* @return 新的字符串
|
||||||
|
*/
|
||||||
|
public static String toUpperCase(String str, int beginIndex, int endIndex) {
|
||||||
|
return str.replaceFirst(str.substring(beginIndex, endIndex),
|
||||||
|
str.substring(beginIndex, endIndex)
|
||||||
|
.toUpperCase(Locale.getDefault()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定字符串的首字母转为小写
|
||||||
|
*
|
||||||
|
* @param str 给定字符串
|
||||||
|
* @return 新的字符串
|
||||||
|
*/
|
||||||
|
public static String firstLetterToLowerCase(String str) {
|
||||||
|
return toLowerCase(str, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定字符串的首字母转为大写
|
||||||
|
*
|
||||||
|
* @param str 给定字符串
|
||||||
|
* @return 新的字符串
|
||||||
|
*/
|
||||||
|
public static String firstLetterToUpperCase(String str) {
|
||||||
|
return toUpperCase(str, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将给定的字符串MD5加密
|
||||||
|
*
|
||||||
|
* @param string 给定的字符串
|
||||||
|
* @return MD5加密后生成的字符串
|
||||||
|
*/
|
||||||
|
public static String MD5(String string) {
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
char[] charArray = string.toCharArray();
|
||||||
|
byte[] byteArray = new byte[charArray.length];
|
||||||
|
for (int i = 0; i < charArray.length; i++) {
|
||||||
|
byteArray[i] = (byte) charArray[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer hexValue = new StringBuffer();
|
||||||
|
byte[] md5Bytes = MessageDigest.getInstance("MD5")
|
||||||
|
.digest(byteArray);
|
||||||
|
for (int i = 0; i < md5Bytes.length; i++) {
|
||||||
|
int val = ((int) md5Bytes[i]) & 0xff;
|
||||||
|
if (val < 16) {
|
||||||
|
hexValue.append("0");
|
||||||
|
}
|
||||||
|
hexValue.append(Integer.toHexString(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = hexValue.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串是否以一个特定的字符串开头,忽略大小写
|
||||||
|
*
|
||||||
|
* @param sourceString 给定的字符串
|
||||||
|
* @param newString 一个特定的字符串
|
||||||
|
*/
|
||||||
|
public static boolean startsWithIgnoreCase(String sourceString, String newString) {
|
||||||
|
int newLength = newString.length();
|
||||||
|
int sourceLength = sourceString.length();
|
||||||
|
if (newLength == sourceLength) {
|
||||||
|
return newString.equalsIgnoreCase(sourceString);
|
||||||
|
}
|
||||||
|
else if (newLength < sourceLength) {
|
||||||
|
char[] newChars = new char[newLength];
|
||||||
|
sourceString.getChars(0, newLength, newChars, 0);
|
||||||
|
return newString.equalsIgnoreCase(String.valueOf(newChars));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定的字符串是否以一个特定的字符串结尾,忽略大小写
|
||||||
|
*
|
||||||
|
* @param sourceString 给定的字符串
|
||||||
|
* @param newString 一个特定的字符串
|
||||||
|
*/
|
||||||
|
public static boolean endsWithIgnoreCase(String sourceString, String newString) {
|
||||||
|
int newLength = newString.length();
|
||||||
|
int sourceLength = sourceString.length();
|
||||||
|
if (newLength == sourceLength) {
|
||||||
|
return newString.equalsIgnoreCase(sourceString);
|
||||||
|
}
|
||||||
|
else if (newLength < sourceLength) {
|
||||||
|
char[] newChars = new char[newLength];
|
||||||
|
sourceString.getChars(sourceLength - newLength, sourceLength,
|
||||||
|
newChars, 0);
|
||||||
|
return newString.equalsIgnoreCase(String.valueOf(newChars));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查字符串长度,如果字符串的长度超过maxLength,就截取前maxLength个字符串并在末尾拼上appendString
|
||||||
|
*/
|
||||||
|
public static String checkLength(String string, int maxLength, String appendString) {
|
||||||
|
if (string.length() > maxLength) {
|
||||||
|
string = string.substring(0, maxLength);
|
||||||
|
if (appendString != null) {
|
||||||
|
string += appendString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查字符串长度,如果字符串的长度超过maxLength,就截取前maxLength个字符串并在末尾拼上…
|
||||||
|
*/
|
||||||
|
public static String checkLength(String string, int maxLength) {
|
||||||
|
return checkLength(string, maxLength, "…");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Html标签
|
||||||
|
*
|
||||||
|
* @param inputString
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String htmlRemoveTag(String inputString) {
|
||||||
|
if (inputString == null)
|
||||||
|
return null;
|
||||||
|
String htmlStr = inputString; // 含html标签的字符串
|
||||||
|
String textStr = "";
|
||||||
|
java.util.regex.Pattern p_script;
|
||||||
|
java.util.regex.Matcher m_script;
|
||||||
|
java.util.regex.Pattern p_style;
|
||||||
|
java.util.regex.Matcher m_style;
|
||||||
|
java.util.regex.Pattern p_html;
|
||||||
|
java.util.regex.Matcher m_html;
|
||||||
|
try {
|
||||||
|
//定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
|
||||||
|
String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";
|
||||||
|
//定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
|
||||||
|
String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";
|
||||||
|
String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
|
||||||
|
p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
|
||||||
|
m_script = p_script.matcher(htmlStr);
|
||||||
|
htmlStr = m_script.replaceAll(""); // 过滤script标签
|
||||||
|
p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
|
||||||
|
m_style = p_style.matcher(htmlStr);
|
||||||
|
htmlStr = m_style.replaceAll(""); // 过滤style标签
|
||||||
|
p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
|
||||||
|
m_html = p_html.matcher(htmlStr);
|
||||||
|
htmlStr = m_html.replaceAll(""); // 过滤html标签
|
||||||
|
textStr = htmlStr;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return textStr;// 返回文本字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -55,7 +55,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<CheckBox
|
||||||
android:id="@+id/capuretVideo"
|
android:id="@+id/capuretVideo"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -64,6 +64,10 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_marginBottom="20dp"
|
android:layout_marginBottom="20dp"
|
||||||
|
android:background="@drawable/user_style"
|
||||||
|
android:button="@null"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="@dimen/fab_margin"
|
||||||
style="@style/user_data_style"/>
|
style="@style/user_data_style"/>
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btn_stop_video"
|
android:id="@+id/btn_stop_video"
|
||||||
@ -72,6 +76,7 @@
|
|||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="结束采集"
|
android:text="结束采集"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintLeft_toRightOf="@id/capuretVideo"
|
app:layout_constraintLeft_toRightOf="@id/capuretVideo"
|
||||||
android:background="@drawable/uploding_shape"
|
android:background="@drawable/uploding_shape"
|
||||||
android:textColor="@color/colorBlue"/>
|
android:textColor="@color/colorBlue"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user