diff --git a/app/build.gradle b/app/build.gradle index 4d4059c..4134a89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,16 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' +} +//apply plugin: 'com.android.application' +//apply plugin: 'kotlin-android' +//apply plugin: 'kotlin-kapt' +//apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 32 - buildToolsVersion '29.0.2' + compileSdkVersion 31 +// buildToolsVersion '29.0.2' //ndkVersion '23.0.7123448' defaultConfig { @@ -53,6 +58,9 @@ android { pickFirst 'lib/x86_64/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' } + buildFeatures { + viewBinding true + } } //efs { // //是否对启动过程进程插桩的开关,如果使用自动集成监控则必须开启 @@ -96,7 +104,6 @@ dependencies { implementation 'com.gyf.immersionbar:immersionbar:3.0.0' implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0' - //网络框架 implementation 'com.lzy.net:okgo:3.0.4' implementation 'com.lzy.net:okrx2:2.0.2' @@ -123,6 +130,8 @@ dependencies { implementation 'com.github.bumptech.glide:glide:4.8.0' //弹窗 https://github.com/kongzue/DialogV3 implementation 'com.kongzue.dialog_v3x:dialog:3.2.4' + implementation "com.kongzue.dialogx:DialogX:0.0.47" + implementation "com.kongzue.dialogx.style:DialogXMIUIStyle:0.0.47" //xRecyclerview下拉刷新控件 implementation project(':xrecyclerview') //拍照功能 https://github.com/natario1/CameraView diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 36b06e9..b9295b7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -145,8 +145,13 @@ + + + trackLocRemovables/*用户轨迹图标marker*/; + private boolean isMapSlide = false; // 地图是否为靠在侧边的小图模式 + private ImageView ivZoomAdd/*zoom放大*/, ivZoomDel/*zoom缩小*/, ivLocation/*定位按钮*/, + ivPicRoadImage/*道路拍摄水平线*/, ivPicVideoImage/*视频拍摄水平线*/; + private View layerMapController; + private ImageView btnSwitch; // 切换地图大小的按钮 + private ViewGroup layerChange; // 切换地图和相机的父控件 + private BitmapDescriptor pileDescriptor = BitmapDescriptorFactory + .fromResource(R.drawable.circle); + private TencentMarkerUtils tencentMarkerUtils; + private List removables; // 地图上渲染的网络获取的道路任务 + private List removablesLocality; // 地图上渲染的本地道路任务 + private HashMap> removableHashMap; + private List roadLinkEntityList/*请求到的待匹配道路数据*/, roadMatchEntityList/*已匹配起始点的道路数据*/; + private int satelliteCount; // 卫星颗数 + private static double MATCH_START_BUFFER_DISTANCE=50e-5; // 匹配起点用到的buffer距离,此处5米使用简易判断 + private static double MATCH_BUFFER_DISTANCE=30e-5; // 匹配途经点用到的buffer距离,此处5米使用简易判断 + private static float /*UNMATCH_GIVE_UP_DISTANCE_BUFFER = 0.2f*//*放弃的距离匹配阈值*//*, */MATCH_CONFIRM_FINISH_BUFFER=0.75f/*完全匹配的距离阈值*/; + private static int /*UNMATCH_BUFFER_START_BUFFER = 5*//*匹配开始后连续未匹配的个数*//*,*/ UNMATCH_BUFFER_MIDDLE_BUFFER = 20/*匹配过程中连续未匹配的个数*/; + // private static float UNMATCH_COUNT_BUFFER = UNMATCH_GIVE_UP_DISTANCE_BUFFER/(1-UNMATCH_GIVE_UP_DISTANCE_BUFFER); + private final String tmpPicFoldPath = Constant.PICTURE_FOLDER+"/tmp"; + private LocationRecorderDao recorderDao; + private PoiDao poiDao; + private SimpleDateFormat picFormatter = new SimpleDateFormat("yyyyMMdd HHmmss"); + private Button btnClearMatch, btnStopPicture; + private Point lastPositionPoint; // 最近一次的定位,用来过滤距离较近的点位 + private static int BRIGHTNESS=40, FRAMENESS=30; + private Button btnSetting; + private Switch locationSwitch; + private boolean locationEnable=true; + private ImageView imgViewSettingHook; // 调起隐藏设置的按钮 + private Point oldCurrentLocation = null; // 记录上一次的位置信息 + private MediaPlayer mediaPlayer; + private ImageView imgNaviDistance/*自动规划到距离最近的数据开关*/, imgRoadDirection; // 道路方向匹配开关 + private Polyline currentNaviLine; // 当前界面上正显示的导航路径线,重绘路径时需要清除此前已绘制的路径 + private boolean startMatchEnableDirection = true; // 是否启用方向匹配起点 + private Logger logger; + private ImageView imgLocationType; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + SharedPreferences sharedPreferences = getSharedPreferences("pic", Context.MODE_PRIVATE); + BRIGHTNESS = sharedPreferences.getInt("brightness", 40); + FRAMENESS = sharedPreferences.getInt("framness", 30); + + // 设置当前界面亮度为40% + setWindowBrightness(BRIGHTNESS); + // 初始化提示音播放器 + mediaPlayer=MediaPlayer.create(this, R.raw.ding); + // 启动GPS定位 + LocationLifeCycle.getInstance().startGPSLocation(); + } + + @Override + protected int getLayout() { + EventBus.getDefault().register(this); + return R.layout.activity_auto_take_pictures; + } + + @SuppressLint("SimpleDateFormat") + @Override + protected void initView() { + super.initView(); + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } + + layerChange = findViewById(R.id.layer_change); + systemTTS = SystemTTS.getInstance(AutoTakePicture4PoiVideoActivity.this); + tvMapView = findViewById(R.id.text_map_view); + tvMapView.setOnClickListener(this); + ivZoomAdd = findViewById(R.id.iv_zoom_add); + ivZoomAdd.setOnClickListener(this); + layerMapController = findViewById(R.id.layer_map_controller); + ivZoomDel = findViewById(R.id.iv_zoom_del); + ivZoomDel.setOnClickListener(this); + ivLocation = findViewById(R.id.iv_location); + ivLocation.setOnClickListener(this); + camera = findViewById(R.id.camera); + camera.setSnapshotMaxWidth(1920); + camera.setSnapshotMaxHeight(1440); + camera.setOnClickListener(this); + btnSwitch = findViewById(R.id.btn_switch); + btnSwitch.setOnClickListener(this); + ivPicRoadImage = findViewById(R.id.iv_pic_road); + ivPicVideoImage = findViewById(R.id.iv_pic_video); + btnClearMatch = findViewById(R.id.clear_all_match_data); + btnStopPicture = findViewById(R.id.btn_stop_picture); + imgNaviDistance = findViewById(R.id.img_navi_distance); + imgRoadDirection = findViewById(R.id.img_road_direction); + imgRoadDirection.setSelected(true); + imgLocationType = findViewById(R.id.img_location_type); + imgLocationType.setOnClickListener(this::onClick); + + //获取地图 + tencentMap = tvMapView.getMap(); + //获取地图UI 设置对象 + UiSettings uiSettings = tencentMap.getUiSettings(); + //设置logo的大小 + uiSettings.setLogoScale(0.7f); + uiSettings.setRotateGesturesEnabled(false);//禁止地图旋转手势. + uiSettings.setTiltGesturesEnabled(false);//禁止倾斜手势. + setLocMarkerStyle(LOCATION_TYPE_LOCATION_ROTATE); + tencentMap.setLocationSource(new MyTecentLocationSource(this)); + tencentMap.setMyLocationEnabled(true); + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(dm); + FrameLayout.LayoutParams layoutParamsMap = (FrameLayout.LayoutParams) tvMapView.getLayoutParams();//相机的宽高 + layoutParamsMap.width = dm.widthPixels / 3; + layoutParamsMap.height = dm.heightPixels / 3; + tvMapView.setLayoutParams(layoutParamsMap); + + ivPicRoadImage.setVisibility(View.VISIBLE); + ivPicVideoImage.setVisibility(View.GONE); + + trackLocRemovables = new ArrayList<>(); + + // 清空所有匹配的数据 + btnClearMatch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (roadMatchEntityList!=null&&!roadMatchEntityList.isEmpty()) { + cancelReciverTask(roadMatchEntityList) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer() { + @Override + public void accept(PoiEntity poiEntity) throws Exception { + + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, throwable.getMessage(), Toast.LENGTH_SHORT).show(); + } + }, new Action() { + @Override + public void run() throws Exception { + // 重新刷新地图 + initRoadLine2Map(); + // 执行结束后清空已匹配列表 + roadMatchEntityList.clear(); + } + }); + } + } + }); + + btnStopPicture.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + + btnSetting = findViewById(R.id.btn_setting); + btnSetting.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CustomDialog.show(new OnBindView(R.layout.camera_setting) { + @Override + public void onBind(CustomDialog dialog, View v) { + EditText startDistance = v.findViewById(R.id.edt_camera_setting_start_distance); + startDistance.setText(MATCH_START_BUFFER_DISTANCE*100000+""); + + EditText midDistance = v.findViewById(R.id.edt_camera_setting_mid_distance); + midDistance.setText(MATCH_BUFFER_DISTANCE*100000+""); + +// EditText startCount = v.findViewById(R.id.edt_camera_setting_start_count); +// startCount.setText(UNMATCH_BUFFER_START_BUFFER+""); + + EditText midCount = v.findViewById(R.id.edt_camera_setting_mid_count); + midCount.setText(UNMATCH_BUFFER_MIDDLE_BUFFER+""); + +// EditText unmatchPecent = v.findViewById(R.id.edt_camera_setting_unmatch_pecent); +// unmatchPecent.setText(UNMATCH_GIVE_UP_DISTANCE_BUFFER+""); + + EditText matchPecent = v.findViewById(R.id.edt_camera_setting_match_pecent); + matchPecent.setText(MATCH_CONFIRM_FINISH_BUFFER+""); + + Button btnConfirm = v.findViewById(R.id.btn_camera_setting_confirm); + btnConfirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!startDistance.getText().toString().isEmpty()) { + MATCH_START_BUFFER_DISTANCE = Double.parseDouble(startDistance.getText().toString())/100000; + } + if (!midDistance.getText().toString().isEmpty()) { + MATCH_BUFFER_DISTANCE = Double.parseDouble(midDistance.getText().toString())/100000; + } +// if (!startCount.getText().toString().isEmpty()) { +// UNMATCH_BUFFER_START_BUFFER = Integer.parseInt(startCount.getText().toString()); +// } + if (!midCount.getText().toString().isEmpty()) { + UNMATCH_BUFFER_MIDDLE_BUFFER = Integer.parseInt(midCount.getText().toString()); + } +// if (!unmatchPecent.getText().toString().isEmpty()) { +// UNMATCH_GIVE_UP_DISTANCE_BUFFER = Float.parseFloat(unmatchPecent.getText().toString()); +// } + if (!matchPecent.getText().toString().isEmpty()) { + MATCH_CONFIRM_FINISH_BUFFER = Float.parseFloat(matchPecent.getText().toString()); + } + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, "设置完成", Toast.LENGTH_SHORT).show(); + dialog.dismiss(); + } + }); + } + }).setFullScreen(true); + } + }); + locationSwitch = findViewById(R.id.location_switch); + locationSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + locationEnable = isChecked; + } + }); + + imgViewSettingHook = findViewById(R.id.image_view); + imgViewSettingHook.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (btnSetting.isShown()) { + return; + } + settingHookClickCount++; + if(lastClickTime > 0){ + long secondClickTime = System.currentTimeMillis();//距离上次开机时间 + long dtime = secondClickTime - lastClickTime; + if(dtime <800){ + if (settingHookClickCount>8) { + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, "打开设置功能", Toast.LENGTH_SHORT).show(); + btnSetting.setVisibility(View.VISIBLE); + locationSwitch.setVisibility(View.VISIBLE); + imgRoadDirection.setVisibility(View.VISIBLE); + } else { + if (settingHookClickCount>3) { + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, "再点击"+(9-settingHookClickCount)+"下打开设置功能", Toast.LENGTH_SHORT).show(); + } + } + } else{ + lastClickTime = 0; + settingHookClickCount = 1; + } + } + lastClickTime = System.currentTimeMillis(); + } + }); + + imgNaviDistance.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + imgNaviDistance.setSelected(!imgNaviDistance.isSelected()); + if (view.isSelected()) { + // 开始自动匹配 + if (roadMatchEntityList.isEmpty()) { + navi2NearestPoiEntity(); + } + } else { + if (currentNaviLine!=null) { + currentNaviLine.remove(); + } + } + } + }); + + imgRoadDirection.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + view.setSelected(!view.isSelected()); + startMatchEnableDirection = view.isSelected(); + } + }); + } + private long lastClickTime = 0; + private int settingHookClickCount = 1; + + + @Override + protected void initData() { + super.initData(); + tencentMarkerUtils = new TencentMarkerUtils(); + removables = new ArrayList<>();//存储网络数据的marker数据(线,面,点) + removablesLocality = new ArrayList<>();//存储本地的marker数据(线,面,点) + removableHashMap = new HashMap<>();//key wkt value :存储的数据类型 + roadLinkEntityList = new ArrayList<>(); + roadMatchEntityList = new ArrayList<>(); + recorderDao = PoiDatabase.getInstance(AutoTakePicture4PoiVideoActivity.this).getRecorderDao(); + poiDao = PoiDatabase.getInstance(AutoTakePicture4PoiVideoActivity.this).getPoiDao(); + + camera.setMode(Mode.PICTURE); + initCameraSize(); + tencentMap.addOnMapLoadedCallback(new TencentMap.OnMapLoadedCallback() { + @Override + public void onMapLoaded() { + tencentMap.setMapFrameRate(30); + initRoadLine2Map(); // 获取道路任务,渲染在地图上 + } + }); + + tencentMap.setOnMapClickListener(new TencentMap.OnMapClickListener() { + @Override + public void onMapClick(LatLng latLng) { + Message msg = handler.obtainMessage(0x105); + msg.obj = TencentLocationObtain.obtainTecentLocation(latLng); + handler.sendMessage(msg); + } + }); + + tencentMap.addTencentMapGestureListener(new TencentMapGestureListener() { + @Override + public boolean onDoubleTap(float v, float v1) { + return false; + } + + @Override + public boolean onSingleTap(float v, float v1) { + return false; + } + + @Override + public boolean onFling(float v, float v1) { + return false; + } + + @Override + public boolean onScroll(float v, float v1) { + return false; + } + + @Override + public boolean onLongPress(float v, float v1) { + return false; + } + + @Override + public boolean onDown(float v, float v1) { + setLocMarkerStyle(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); + return false; + } + + @Override + public boolean onUp(float v, float v1) { + return false; + } + + @Override + public void onMapStable() { + + } + }); + camera.addCameraListener(new CameraListener() { + @Override + public void onPictureTaken(@NonNull PictureResult result) { + super.onPictureTaken(result); + if (camera == null || camera.getSnapshotSize()==null) { + return; + } + // 获取照片数据 + if (result != null && result.getData() != null && result.getData().length > 0) { + super.onPictureTaken(result); + System.out.println("收到拍照按钮jieguo:"+result.getSize().toString()); + // 道路拍照必须为横向拍照 + // TODO 测试时先解除竖向拍摄检查 + if (Objects.requireNonNull(camera.getSnapshotSize()).getWidth() < camera.getSnapshotSize().getHeight()) { + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this, "不允许竖向拍摄..."); + systemTTS.playText("不允许竖向拍摄"); + return; + } + + File tmpPicFolder = new File(tmpPicFoldPath); + if (!tmpPicFolder.exists()) { + tmpPicFolder.mkdirs(); + } + String currentName = System.currentTimeMillis()+""; + File picFile = new File(tmpPicFolder.getAbsolutePath(), currentName); + synchronized (picFile) { + // 生成点位marker + addTrackMarker(); + result.toFile(picFile, new FileCallback() { + @Override + public void onFileReady(@Nullable File file) { + // 在数据库中记录照片、轨迹位置以及卫星颗数 + LocationRecorder recorder = new LocationRecorder(); + recorder.setTime(Long.parseLong(file.getName())); + // 记录主定位方式 + recorder.setTencentLocationX(LocationLifeCycle.getInstance().getMainLocation().getLongitude()); + recorder.setTencentLocationY(LocationLifeCycle.getInstance().getMainLocation().getLatitude()); + // 记录辅助定位方式 + MyLocation gpsLocation = LocationLifeCycle.getInstance().getReferenceLocation(); + if (gpsLocation!=null) { + recorder.setGpsLocationX(gpsLocation.getLongitude()); + recorder.setGpsLocationY(gpsLocation.getLatitude()); + } + recorder.setBearing(LocationLifeCycle.getInstance().getMainLocation().getBearing()); + recorder.setImgFileName(file.getAbsolutePath()); + recorder.setRssi(GPSUtils.getInstance(AutoTakePicture4PoiVideoActivity.this).getSateliteCount()); + recorder.setSatelliteCount(GPSUtils.getInstance(AutoTakePicture4PoiVideoActivity.this).getSateliteCount()); + Observable.just(recorder).observeOn(Schedulers.io()) + .filter(roadMatchEntity -> roadMatchEntity!=null) + .subscribe(new Consumer() { + @Override + public void accept(LocationRecorder locationRecorder) throws Exception { + recorderDao.insertLocationRecorder(recorder); + } + }); + } + }); + } + } + } + }); + + SharedPreferences spf = getSharedPreferences("MatchEntity", Context.MODE_PRIVATE); + Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); + String matchedData = spf.getString("match-data", null); + if (matchedData!=null) { + List dataList = gson.fromJson(matchedData, new TypeToken>(){}.getType()); + roadMatchEntityList.addAll(dataList); + } + // 清空缓存数据 + spf.edit().remove("match-data"); + spf.edit().commit(); + } + + /** + * 根据网络数据和本地数据库数据,更新地图上渲染的道路任务 + * */ + private void initRoadLine2Map() { + if (Constant.USHERED != null) { + // 刷新筛选的本地数据 + tencentMarkerUtils.initLocalMarker(AutoTakePicture4PoiVideoActivity.this, tencentMap, removablesLocality, removableHashMap, new TencentMarkerUtils.MarkerInitCallback() { + @Override + public void onMarkerInit(Map> removableHashMap, List uploadByNet, List listData) { + + } + }); + } + if (LocationLifeCycle.getInstance().getMainLocation() != null) { //筛选从服务器获取到的数据 + // 注意,此处只获取道路数据 + tencentMarkerUtils.initNetMarkerList(AutoTakePicture4PoiVideoActivity.this, LocationLifeCycle.getInstance().getTencentLocation(), tencentMap, removables, + "3"/*只获取poi录像数据*/,"0"/*只获取未领取的数据*/, removableHashMap, 50, new TencentMarkerUtils.MarkerInitCallback() { + + @Override + public void onMarkerInit(Map> removableHashMap, List uploadByNet, + List listData) { + // 根据获取到的网络数据,整理数据的起终点数据,方便接下来自动捕捉数据 + roadLinkEntityList.clear(); + if (listData!=null) { + listData.stream().forEach( + it -> { + String geometryStr = Geohash.getInstance().decode(it.getGeo()); + Geometry geometry = GeometryTools.createGeometry(geometryStr); + RoadMatchEntity roadMatchEntity = new RoadMatchEntity(); + roadMatchEntity.setId(it.getId()); + roadMatchEntity.setDataDetail(it); + roadMatchEntity.setGeometry((LineString) geometry); +// roadMatchEntity.setBuffer(geometry.buffer(MATCH_BUFFER_DISTANCE).toString()); + // 实时设置当前任务的起始角度 + if (geometry instanceof LineString) { + LineString lineString = (LineString) geometry; + // 计算前两个点的坐标角度 + // 获取当前数据的前两个点的方向 + Coordinate[] coordinates = lineString.getCoordinates(); + // 循环取出当前数据的坐标点,为防止出现重复点,需要循环做判断 + Coordinate[] lineCoordinates = new Coordinate[2]; + lineCoordinates[0] = coordinates[0]; + lineCoordinates[1] = coordinates[0]; + for (Coordinate c: coordinates) { + if (c.x!=lineCoordinates[0].x&&c.y!=lineCoordinates[0].y) { + lineCoordinates[1] = c; + break; + } + } + if (lineCoordinates[0]!=lineCoordinates[1]) { + double dataBearing = getBearing(lineCoordinates[0].x, lineCoordinates[1].x, lineCoordinates[0].y, lineCoordinates[1].y); + roadMatchEntity.setAngle(dataBearing); + } + roadMatchEntity.setsPoint(lineString.getStartPoint().toString()); + roadMatchEntity.setePoint(lineString.getEndPoint().toString()); + } + roadLinkEntityList.add(roadMatchEntity); + } + ); + // 如果当前自动规划打开且没有正在匹配的任务,自动规划下一条最近的任务 + if (imgNaviDistance.isSelected()&&roadMatchEntityList.isEmpty()) { + navi2NearestPoiEntity(); + } + } + } + }); + } else { + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this, "未开启定位服务"); + } + } + + Observer receiveObserver = new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(PoiEntity poiEntity) { + write2Log("领取任务成功:", poiEntity.getId()); + } + + @Override + public void onError(Throwable e) { + systemTTS.playText("注意,领取任务失败!"); + if (AutoTakePicture4PoiVideoActivity.this!=null) { + write2Log("领取任务失败:", e.getMessage()+",网络状态-:"+ NetWorkUtils.getNetworkTypeName(AutoTakePicture4PoiVideoActivity.this)); + } + } + + @Override + public void onComplete() { + initRoadLine2Map(); + } + }; + + /** + * 开始自动匹配 + * */ + private double minDistance = MATCH_START_BUFFER_DISTANCE; // 最小距离,需要在匹配过程点时判断哪个任务是距离最小的 + private void startMatchRoadLink(Point currentPoint) { + if (roadLinkEntityList == null/*没有需要匹配的道路数据*/ || currentPoint == null/*没有位置信息*/) { + write2Log("开始匹配:", "roadLinkEntityList == null:"+(roadLinkEntityList == null)+",currentPoint == null:"+(currentPoint == null)); + return; + } + double[] speedAndBearing = getSpeedAndBearing(currentPoint); + double currentSpeed = speedAndBearing[0]; // 当前速度 + double currentBearing = speedAndBearing[1]; // 当前方向 + double matchMiddleDistance = MATCH_BUFFER_DISTANCE; + // 如果速度大于70,则动态调整起点捕捉范围 + if (currentSpeed>=70) { + matchMiddleDistance = MATCH_BUFFER_DISTANCE*1.5; + } + // 此处开始匹配起点 + write2Log("开始匹配起点位置:", "currentLocation:"+currentPoint.toString()+",可匹配数据个数:"+roadLinkEntityList.size()); + List matchStartList = roadLinkEntityList.stream() + // 筛选当前任务与起点距离 + .filter(it-> { + if (GeometryTools.createGeometry(it.getsPoint()).distance(currentPoint) { + if (startMatchEnableDirection) { + double dataBearing = it.getAngle(); + if (Math.abs(dataBearing-currentBearing)<=90 || Math.abs(dataBearing-currentBearing)>=270) { + return true; + } else { + // 根据方向判定无法匹配 + write2Log("方向不匹配:", "currentBearing:"+currentBearing+",数据角度:"+dataBearing+",数据id:"+it.getDataDetail().getId()); + return false; + } + } else { + return true; + } + }) + // 判断筛选出的数据是否已经在匹配列表中,如果不存在,需要自动领取该任务、记录开始采集时间 + .filter( + o -> { + if (roadMatchEntityList.stream().noneMatch(roadMatchEntity -> o.getId()==roadMatchEntity.getId())) { + return true; // 如果列表中不存在当前数据,不过滤,断点使用,增加return + } else { + return false; + } + }) + .collect(Collectors.toList()); + if (matchStartList!=null&&!matchStartList.isEmpty()) { + // 存在新匹配到的数据 + matchStartList.stream().forEach( + roadMatchEntity -> { + // 记录开始采集时间 + roadMatchEntity.setStartMatchTime(System.currentTimeMillis()); + // TODO:自动发送请求领取任务 + receiverRoadTask(roadMatchEntity).subscribe(receiveObserver); + }); + + // 语音提醒 + if (roadMatchEntityList.isEmpty()) { + // 当前没有已匹配的数据,提示用户“叮~捕捉任务” + mediaPlayer.start(); + systemTTS.playText("捕捉任务"); + } else { + // 当前存在已匹配的任务,有新匹配的任务,提示“叮~任务拍摄中” + mediaPlayer.start(); + systemTTS.playText("任务拍摄中"); + } + + // 将匹配到的数据加入到已匹配列表中 + roadMatchEntityList.addAll(matchStartList); + } else { + write2Log("匹配起点数据为空:", "当前位置为:"+currentPoint.toString()+"当前角度:"+currentBearing); + } + + // 尝试用当前位置点匹配已经匹配到的roadLink,如果能匹配到,需要将该点记录,如果无法匹配,则需要评估已匹配的link是否需要被剔除 + minDistance = MATCH_START_BUFFER_DISTANCE; // 使用距离起终点的最大阈值初始化最小距离 + if (!roadMatchEntityList.isEmpty()) { + // 因为单个点位只能匹配一条任务,需要获取当前点位距离所有任务最近的距离 + roadMatchEntityList.stream().forEach(it->{ + double currentDistance = GeometryTools.createGeometry(it.getGeometry()).distance(currentPoint); + it.setCurrentLineDistance(currentDistance); + if (currentDistance<=minDistance) { + minDistance = currentDistance; + } + }); + + List unMatchList = new ArrayList<>(); + Map finishEntityMap = new HashMap<>(); + double finalMatchMiddleDistance = matchMiddleDistance; + roadMatchEntityList.stream().forEach( + roadMatchEntity -> { + double currentDistance = roadMatchEntity.getCurrentLineDistance(); + boolean isMatch=currentDistance<= finalMatchMiddleDistance; // 当前点位是否可以和link匹配到 + if (isMatch) { // 可以匹配到 + if (roadMatchEntity.getCurrentLineDistance()<=minDistance) { // 并且该条数据还是最近的点, 将当前点位匹配到此任务下(注意,当距离完全相等时,同一点位可能同时匹配到多个任务) + if (roadMatchEntity.getMatchPointList().size() == 0) { // 可以匹配到,并且从未匹配过,更新任务的开始时间 + roadMatchEntity.setStartMatchTime(System.currentTimeMillis()); + } + // 更新连续匹配的个数 + roadMatchEntity.setMatchCount(roadMatchEntity.getMatchCount()+1); + // 匹配到最近的任务,将当前点加入到已匹配道路中 + roadMatchEntity.getMatchPointList().add(new MyCoordinate(currentPoint.getX(), currentPoint.getY())); + // 如果连续匹配个数大于1(可以连成线),更新已匹配长度 + if (roadMatchEntity.getMatchCount()>1) { + roadMatchEntity.setMatchedLength( + roadMatchEntity.getMatchedLength() + + + // 加上最后两个点的长度 + GeometryTools.getLineStringByMyCoordinate(roadMatchEntity.getMatchPointList().subList(roadMatchEntity.getMatchPointList().size()-2, roadMatchEntity.getMatchPointList().size())).getLength() + ); + } + } else { // 在阈值内,但是并非最近的点 + roadMatchEntity.setMatchCount(0); // 连续匹配个数置为0 + } + roadMatchEntity.setUnMatchCount(0); // 有匹配的数据,则连续未匹配个数归0(即使不是最近的数据,在阈值内即认为可匹配,未匹配点数也置为0) + + double currentEndDistance = currentPoint.distance(GeometryTools.createGeometry(roadMatchEntity.getePoint())); // 当前距离终点的距离 + // 记录本次的匹配距离,如果本次匹配距离大于上一次,且上一次匹配终点时间不为0(说明已经提前匹配到终点了),则结束匹配,否则继续等待匹配,设置过EndMathchTime的数据即为可以结束匹配的数据,下一次如果未匹配,也可以结束 + if (roadMatchEntity.getEndMathchTime()>0/*endMatchTime不为0,说明该数据已经匹配到终点*/&¤tEndDistance>roadMatchEntity.getLastEndDistance()) { + finishEntityMap.put(roadMatchEntity.getId(), roadMatchEntity); + // 更新终点时间为距离终点逐渐变大时的时间 + roadMatchEntity.setEndMathchTime(System.currentTimeMillis()); + } + // 匹配距离超过指定阈值,认为该条数据可完成,记录当前位置与终点的距离,当距离从小变大时,完成该任务 + if (roadMatchEntity.getMatchPointList().size()>=2&&roadMatchEntity.getMatchedLength()/roadMatchEntity.getLength()>=MATCH_CONFIRM_FINISH_BUFFER) { + roadMatchEntity.setEndMathchTime(System.currentTimeMillis()); + // 匹配到终点后,记录该条数据的最新一次匹配距离,当下一次匹配距离大于当前距离,则认为该数据完全匹配,结束匹配 + roadMatchEntity.setLastEndDistance(currentEndDistance); + } + //=============如果在匹配范围内,但是该数据并非最近的点,不需要记录匹配,也无需增加未匹配点的个数 + } else { // 无法匹配 + // 更新连续无法匹配的点位个数 + roadMatchEntity.setUnMatchCount(roadMatchEntity.getUnMatchCount()+1); + // 有未匹配的数据,连续匹配个数也归0 + roadMatchEntity.setMatchCount(0);// 设置连续匹配的数据个数为0 + roadMatchEntity.getUnMatchPointList().add(new MyCoordinate(currentPoint.getX(), currentPoint.getY())); + // 当连续未匹配个数大于等于20个时,该任务被认为可以结束(舍弃或完成-需根据匹配到的数据长度与任务长度做对比) + if (roadMatchEntity.getUnMatchCount()>=UNMATCH_BUFFER_MIDDLE_BUFFER) { // 连续未匹配大于阈值时 + List matchPointList = roadMatchEntity.getMatchPointList(); + if (matchPointList == null || matchPointList.size()<2) { // 已匹配的点位不足2个,无法计算长度,直接放弃该任务 + unMatchList.add(roadMatchEntity); + } else { + if (roadMatchEntity.getMatchedLength()/roadMatchEntity.getLength()>=MATCH_CONFIRM_FINISH_BUFFER) { // 已匹配距离与任务长度距离比例超过指定阈值,该任务可完成 + roadMatchEntity.setEndMathchTime(System.currentTimeMillis()); + finishEntityMap.put(roadMatchEntity.getId(), roadMatchEntity); + } else { + unMatchList.add(roadMatchEntity); + } + } + } + } + } + ); + + + if (!finishEntityMap.isEmpty()) { + // 过滤掉已完成的link + for (RoadMatchEntity finishEntity: finishEntityMap.values()) { + roadMatchEntityList.remove(finishEntity); + } + // TODO 完成的entity数据,需要自动生成对应的数据,还需要自动复制对应的照片,通知服务器采集完成 + finishRoadTask(finishEntityMap); + // 只有在没有正在拍摄的任务,所有任务都拍摄完成时才会提示 + if (roadMatchEntityList.isEmpty()) { + // 语音提示用户 + mediaPlayer.start(); + systemTTS.playText("拍摄完成"); + } + } + + if (!unMatchList.isEmpty()) { + cancelReciverTask(unMatchList).subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + // 过滤需要舍弃的link + for (RoadMatchEntity unMatchEntity: unMatchList) { + roadMatchEntityList.remove(unMatchEntity); + } + } + + @Override + public void onNext(PoiEntity poiEntity) { + + } + + @Override + public void onError(Throwable e) { + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onComplete() { + // 重新刷新地图 + initRoadLine2Map(); + } + }); + } + } + // 如果当前已经不存在正在采集的数据,则停止记录经纬度和拍照 + if (roadMatchEntityList.isEmpty()) { + stopRecordLocation(); + } else { + startRecordLocation(); + } + } + + /** + * 导航到最近的道路任务 + * */ + @RequiresApi(api = Build.VERSION_CODES.N) + private void navi2NearestPoiEntity() { + if (roadLinkEntityList == null || roadLinkEntityList.isEmpty()) { + SystemTTS.getInstance(this).playText("附近当前没有可匹配的任务"); + return; + } + // RxJava处理,子线程中做后台计算路径规划 + Geometry currentGeometry = GeometryTools.createGeometry(new double[]{LocationLifeCycle.getInstance().getMainLocation().getLongitude(), LocationLifeCycle.getInstance().getMainLocation().getLatitude()}); + Observable.create( + new ObservableOnSubscribe() { + @Override + public void subscribe(ObservableEmitter emitter) throws Exception { + RoadMatchEntity minRoadLink = roadLinkEntityList.stream() + // 过滤已经匹配到的数据 + .filter(roadMatchEntity -> { + if (roadMatchEntityList.contains(roadMatchEntity)) { + return false; + } + return true; + }) + .min((t1, t2) -> { + // 判断距离用户当前位置的距离 + JobSearchBean.BodyBean.ListBean bean1 = t1.getDataDetail(); + JobSearchBean.BodyBean.ListBean bean2 = t2.getDataDetail(); + // 转换geo + Geometry geometry1 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean1.getGeo())); + Geometry geometry2 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean2.getGeo())); + if (currentGeometry.distance(geometry1)>currentGeometry.distance(geometry2)) { + return 1; + } else if (currentGeometry.distance(geometry1)() { + @Override + public void accept(RoadMatchEntity minRoadLink) throws Exception { + JobSearchBean.BodyBean.ListBean bean = minRoadLink.getDataDetail(); + Coordinate endPoint = GeometryTools.createGeometry(Geohash.getInstance().decode(bean.getGeo())).getCoordinates()[0]; + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this, "已为您规划距离最近的任务路径:"+bean.getName()); + // 跳转到对应的导航界面 + try { + if (Constant.currentNaviType == null) { + NaviUtils.getInstance().selectNaviType(AutoTakePicture4PoiVideoActivity.this, new NaviUtils.SelectNaviTypeListener() { + @Override + public void selectNaviType(Constant.NAV_TYPE nav_type) { + // 显示导航类型选择的对话框 + Constant.currentNaviType = nav_type; + try { + tencentNaviManager = NaviUtils.getInstance().searchRouteOnly(AutoTakePicture4PoiVideoActivity.this, Constant.currentNaviType, new NaviPoi(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()), new NaviPoi(endPoint.getY(), endPoint.getX()), routeSearchCallback); + } catch (Exception e) { + e.printStackTrace(); + com.github.lazylibrary.util.ToastUtils.showToast(AutoTakePicture4PoiVideoActivity.this, e.getMessage()); + } + } + }); + } else { + // 已选择导航方式 + tencentNaviManager = NaviUtils.getInstance().searchRouteOnly(AutoTakePicture4PoiVideoActivity.this, Constant.currentNaviType, new NaviPoi(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()), new NaviPoi(endPoint.getY(), endPoint.getX()), routeSearchCallback); + } + } catch (Exception e) { + e.printStackTrace(); + com.github.lazylibrary.util.ToastUtils.showToast(AutoTakePicture4PoiVideoActivity.this, e.getMessage()); + } + } + }); + } + + private TencentNaviManager tencentNaviManager; + TencentRouteSearchCallback routeSearchCallback = new TencentRouteSearchCallback() { + @Override + public void onRouteSearchFailure(int i, String s) { + + } + + @Override + public void onRouteSearchSuccess(ArrayList arrayList) { + currentNaviLine = drawNaviLine(arrayList.get(0)); + } + + @Override + public void onCalcRouteSuccess(CalcRouteResult calcRouteResult) { + } + + @Override + public void onCalcRouteFailure(CalcRouteResult calcRouteResult) { + + } + }; + + /** + * 绘制导航线路 + * */ + private Polyline drawNaviLine(RouteData routeData) { + if (currentNaviLine!=null) { + currentNaviLine.remove(); + } + Polyline polyline = NaviUtils.getInstance().addRoutes(routeData, tencentMap); + NaviUtils.getInstance().zoomToRoute(AutoTakePicture4PoiVideoActivity.this, routeData, tencentMap); + if (tencentNaviManager!=null) { +// if (Constant.currentNaviType == Constant.NAV_TYPE.CAR) { +// } else if (Constant.currentNaviType == Constant.NAV_TYPE.RIDE) { +// +// } else { +// +// } + tencentNaviManager.setNaviCallback(new TencentNaviCallback() { + @Override + public void onStartNavi() { + + } + + @Override + public void onStopNavi() { + polyline.remove(); + } + + @Override + public void onOffRoute() { + + } + + @Override + public void onRecalculateRouteSuccess(int i, ArrayList arrayList) { + } + + @Override + public void onRecalculateRouteSuccessInFence(int i) { + + } + + @Override + public void onRecalculateRouteFailure(int i, int i1, String s) { + + } + + @Override + public void onRecalculateSuccess(CalcRouteResult calcRouteResult) { + + } + + @Override + public void onRecalculateFailure(CalcRouteResult calcRouteResult) { + + } + + @Override + public void onRecalculateRouteStarted(int i) { + + } + + @Override + public void onRecalculateRouteCanceled() { + + } + + @Override + public void onArrivedDestination() { + polyline.remove(); + } + + @Override + public void onPassedWayPoint(int i) { + + } + + @Override + public void onUpdateRoadType(int i) { + + } + + @Override + public void onUpdateParallelRoadStatus(ParallelRoadStatus parallelRoadStatus) { + + } + + @Override + public void onUpdateAttachedLocation(AttachedLocation attachedLocation) { + + } + + @Override + public void onFollowRouteClick(String s, ArrayList arrayList) { + + } + + @Override + public int onVoiceBroadcast(NaviTts naviTts) { + return 0; + } + + @Override + public void onEnterIdleSection(IdleRangeInfo idleRangeInfo) { + + } + }); + } + return polyline; + } + + /** + * 清除导航的路线 + * */ + private void clearNaviLine(Polyline polyline) { + polyline.remove(); + } + + /** + * 初始化领取任务的管理栈 + * */ + private Observable receiverRoadTask(RoadMatchEntity entity) { + write2Log("开始领取任务:", entity.getId()+""); + return Observable.just(entity).subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()) + .filter(roadMatchEntity -> roadMatchEntity!=null) + .map(new Function() { + @Override + public PoiEntity apply(RoadMatchEntity roadMatchEntity) throws Exception { + + PoiEntity poiEntity = translateRoadMatchEntity(roadMatchEntity); + // 首先发送领取任务的请求 + OkGoBuilder okGoBuilder = OkGoBuilder + .getInstance() + .time(30) + .Builder(AutoTakePicture4PoiVideoActivity.this) + .url(HttpInterface.RECEIVED_ROAD_TASK + "/" + entity.getDataDetail().getId()) + .cls(TaskByNetBean.class) + .params(new HttpParams()) + .token(Constant.ACCESS_TOKEN); + Response response = okGoBuilder.getSynchronization(); + Gson gson = new Gson(); + String body = response.body().string(); + TaskByNetBean taskByNetBean = gson.fromJson(body, TaskByNetBean.class); + Log.d("AutoTake:", body); + if (taskByNetBean.getCode() == 200) { + // 继续保存 + TaskByNetBean.BodyBean listBean = taskByNetBean.getBody(); + if (listBean != null) { + PoiEntity taskIdPoiEntity = PoiDatabase.getInstance(AutoTakePicture4PoiVideoActivity.this).getPoiDao() + .getTaskIdPoiEntity(poiEntity.getTaskId()); + if (taskIdPoiEntity == null) {//数据库没有这条数据 + PoiEntity poiListEntity = new PoiEntity(); + poiListEntity.setTaskId(poiEntity.getTaskId()); + poiListEntity.setName(listBean.getName()); + poiListEntity.setMemo(listBean.getMemo()); + poiListEntity.setCreateTime(listBean.getEndDate()); + poiListEntity.setAddress(listBean.getAddress()); + poiListEntity.setType(listBean.getType()); + poiListEntity.setPrecision(String.valueOf(listBean.getPrice())); + poiListEntity.setIsExclusive(listBean.getIsExclusive()); + poiListEntity.setTaskStatus(1); + poiListEntity.setGeoWkt(listBean.getGeo()); + String encodeStr = listBean.getGeo(); + String geo = Geohash.getInstance().decode(encodeStr); + // 生成对应的x和y poiEntity.setX + GeometryTools.obitainPoiEntityXY(geo, poiListEntity); + InsertAndUpdateUtils.getInstance().insertOrUpdate(AutoTakePicture4PoiVideoActivity.this, poiListEntity); + } + } + } else if (taskByNetBean.getCode() == 230) { // Token过期 + systemTTS.playText("注意,Token过期,请重新登陆!"); + write2Log("领取任务失败:", "Token过期:"+taskByNetBean.getMessage()); + FlushTokenUtil.flushToken(AutoTakePicture4PoiVideoActivity.this); + Message msg = handler.obtainMessage(0x103); + msg.obj = entity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } else { + systemTTS.playText("注意,领取任务失败!"); + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this,taskByNetBean.getMessage()); + write2Log("领取任务失败:", "领取失败:"+taskByNetBean.getMessage()); + Message msg = handler.obtainMessage(0x103); + msg.obj = entity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } + return poiEntity; + } + } + ) + .observeOn(AndroidSchedulers.mainThread()); + } + + /** + * 取消领取任务 + * */ + private Observable cancelReciverTask(List cancelMatchLinkList) { + return Observable.fromIterable(cancelMatchLinkList) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.computation()) + .filter(roadMatchEntity -> roadMatchEntity!=null) + .flatMap(roadMatchEntity -> { + PoiEntity poiEntity = poiDao.getTaskIdPoiEntity(roadMatchEntity.getId()); + if (poiEntity!=null) { + return sendCancelRequest(poiEntity); + } else { + return Observable.empty(); + } + }) + .observeOn(AndroidSchedulers.mainThread()); + } + + private Observable sendCancelRequest(PoiEntity origin) { + return Observable.just(origin) + .subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()) + .map(new Function() { + @Override + public PoiEntity apply(PoiEntity poiEntity) throws Exception { + if (poiEntity!=null) { + HttpParams httpParams = new HttpParams(); + httpParams.put("taskIds", poiEntity.getTaskId()); + httpParams.put("auditIds", ""); + OkGoBuilder okGoBuilder = OkGoBuilder.getInstance() + .time(30) + .Builder(AutoTakePicture4PoiVideoActivity.this) + .url(HttpInterface.UNRECEIVED_POLYGON_TASK) + .cls(UnPolygonTaskBean.class) + .params(httpParams) + .token(Constant.ACCESS_TOKEN); + Response synchronization = okGoBuilder.getSynchronization(); + try { + String bodyString = synchronization.body().string(); + Gson gson = new Gson(); + UnPolygonTaskBean response = gson.fromJson(bodyString, UnPolygonTaskBean.class); + if (response.getCode() == 200) { + PoiDatabase.getInstance(AutoTakePicture4PoiVideoActivity.this).getPoiDao().deletePoiEntity(poiEntity); + // 不需要删除照片,自动采集时照片是临时保存在tmp目录下 + } else if (response.getCode() == 230) { + FlushTokenUtil.flushToken(AutoTakePicture4PoiVideoActivity.this); + Message msg = handler.obtainMessage(0x106); + msg.obj = poiEntity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } else { + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this, response.getMessage()); + Message msg = handler.obtainMessage(0x106); + msg.obj = poiEntity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } + return poiEntity; + } catch (IOException e) { + throw e; + } + } else { + throw new Exception(""); + } + } + }); + } + + private PoiEntity translateRoadMatchEntity(RoadMatchEntity roadMatchEntity) { + PoiEntity poiListEntity = new PoiEntity(); + JobSearchBean.BodyBean.ListBean listBean = roadMatchEntity.getDataDetail(); + poiListEntity.setTaskId(listBean.getId()); + poiListEntity.setGeoWkt(listBean.getGeo()); + poiListEntity.setName(listBean.getName()); + poiListEntity.setAddress(listBean.getAddress()); + poiListEntity.setTelPhone(listBean.getTelephone()); + poiListEntity.setPrecision(listBean.getPrice() + ""); + poiListEntity.setDist(listBean.getDist() + ""); + poiListEntity.setDescribe(listBean.getMemo()); + poiListEntity.setCreateTime(listBean.getEndDate()); + poiListEntity.setType(listBean.getType()); + poiListEntity.setRecord_way(listBean.getCanReceived()); + poiListEntity.setIsExclusive(listBean.getIsExclusive()); + String beanGeo = listBean.getGeo(); + String geo = Geohash.getInstance().decode(beanGeo); + // 生成对应的x和y poiEntity.setX + GeometryTools.obitainPoiEntityXY(geo, poiListEntity); + return poiListEntity; + } + + /** + * 结束采集,对照片归档 + * */ + private int finishTaskCount = 0; + private boolean wantBack = false; // 用户是否想要退出当前界面,如果当前有正在处理的图片转移任务,会阻挡用户退出,此时该值状态置为true,当照片处理完后,可以对话框提示用户退出 + private void finishRoadTask(Map finishEntityMap) { + if (finishEntityMap!=null&&!finishEntityMap.isEmpty()) { + finishTaskCount++; + + Observable.fromIterable(finishEntityMap.values()) + .subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()) + .filter(roadMatchEntity -> roadMatchEntity!=null) + .map(roadMatchEntity -> { + // 判断是否已领取,未领取则调用领取数据接口 + PoiEntity poiEntity = poiDao.getTaskIdPoiEntity(roadMatchEntity.getId()); + if (poiEntity == null) { + // 数据库中不存在,尝试再次领取 + InsertAndUpdateUtils.getInstance().insertOrUpdate(AutoTakePicture4PoiVideoActivity.this, translateRoadMatchEntity(roadMatchEntity)); + // 调用网络领取任务 + receiverRoadTask(roadMatchEntity).subscribe(receiveObserver); + } + + List recorderList = recorderDao.getLocationRecorderByTime(roadMatchEntity.getStartMatchTime(), roadMatchEntity.getEndMathchTime()); + File recorderFolder = new File(Constant.PICTURE_FOLDER+"/"+poiEntity.getId()); + if (!recorderFolder.exists()) { + recorderFolder.mkdirs(); + } + // 编辑paper.txt + // 复制图片文件 + File paperFile = new File(recorderFolder.getAbsolutePath(), "paper.txt"); + for (int i = 0; i < recorderList.size(); i++) { + File originImg = new File(recorderList.get(i).getImgFileName()); + File destFile = new File(recorderFolder.getAbsolutePath()+"/"+i+".jpg"); + if (!destFile.exists()) { + FileUtils.copyFile(originImg.getAbsolutePath(), destFile.getAbsolutePath()); + } + FileUtils.writeFile(paperFile.getAbsolutePath(), recorderList.get(i).toString(picFormatter ,i), true); + } + + return poiEntity; + }) + .doOnNext(poiEntity -> { + // 网络提交数据 + if (poiEntity!=null) { + // 提交数据,更新状态 + roadSaveWork(poiEntity); + /*poiEntity.setTaskStatus(3); + InsertAndUpdateUtils.getInstance().insertOrUpdate(AutoTakePictureActivity.this, poiEntity);*/ + finishEntityMap.remove(poiEntity.getTaskId()); + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .onErrorResumeNext(Observable.empty()) + .subscribe(new Consumer() { + @Override + public void accept(PoiEntity poiEntity) { +// // 已经处理过该任务,将其从finish列表中移除 +// if (poiEntity!=null) { +// finishEntityMap.remove(poiEntity.getTaskId()); +// } + + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) { + // 此处异常可能是服务返回的数据无法解析,但http正常返回了,因此可能为程序问题,不再重复尝试上报 + systemTTS.playText("注意,领取任务失败!"); + XLog.e("完成失败:"+throwable.getMessage()); + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this, throwable.getMessage()); + finishTaskCount--; + if (finishTaskCount == 0) { + showExitDialog(true); + } + } + }, new Action() { + @Override + public void run() throws Exception { + // 重新绘制网络任务和本地任务 + initRoadLine2Map(); + finishTaskCount--; + if (finishTaskCount == 0) { + showExitDialog(false); + } + } + }); + } + } + + private void showExitDialog(boolean hasError) { + StringBuilder dialogMessage = new StringBuilder("任务数据处理完成,是否退出当前界面"); + if (hasError) { + dialogMessage.append("(注意,其中有部分任务处理失败)"); + } + MessageDialog.show("退出当前界面", dialogMessage) + .setOkButton("确定", new OnDialogButtonClickListener() { + @Override + public boolean onClick(MessageDialog dialog, View v) { + dialog.dismiss(); + AutoTakePicture4PoiVideoActivity.this.finish(); + return false; + } + }) + .setCancelButton("取消", new OnDialogButtonClickListener() { + @Override + public boolean onClick(MessageDialog dialog, View v) { + dialog.dismiss(); + wantBack = false; + return false; + } + }) + .show(); + } + + private void roadSaveWork(PoiEntity poiEntity) throws IOException { + // 设置当前数据状态为本地保存 + poiEntity.setTaskStatus(2); + // 更新数据库中状态 + InsertAndUpdateUtils.getInstance().insertOrUpdate(AutoTakePicture4PoiVideoActivity.this, poiEntity); + + HttpParams httpParams = new HttpParams(); + httpParams.put("taskId", poiEntity.getTaskId()); + httpParams.put("name", poiEntity.getName()); + httpParams.put("address", poiEntity.getAddress()); + httpParams.put("workType", 0); + httpParams.put("memo", poiEntity.getMemo()); + // 增加对应九天平台的参数 + httpParams.put("existence", 0); + httpParams.put("description", ""); + + OkGoBuilder okGoBuilder = OkGoBuilder.getInstance() + .time(30) + .Builder(AutoTakePicture4PoiVideoActivity.this) + .url(HttpInterface.ROAD_TASK_SUBMIT) + .cls(RoadSaveBean.class) + .params(httpParams) + .token(Constant.ACCESS_TOKEN); + Response synchronization = okGoBuilder.getSynchronization(); + Gson gson = new Gson(); + RoadSaveBean submitBean = gson.fromJson(synchronization.body().string(), RoadSaveBean.class); + if (submitBean.getCode() == 200) { + Integer body = submitBean.getBody(); + if (body != null && body != 0) { + poiEntity.setBodyId(body); + poiEntity.setTaskStatus(3); + // 更新数据库中状态 + InsertAndUpdateUtils.getInstance().insertOrUpdate(AutoTakePicture4PoiVideoActivity.this, poiEntity); + } else { + Message obtain1 = Message.obtain(); + obtain1.what = Constant.NEST_WORD_REGISTER; + obtain1.obj = "道路:" + poiEntity.getName() + " 保存本地失败"; + EventBus.getDefault().post(obtain1); + } + } else if (submitBean.getCode() == 230) { // Token过期 + systemTTS.playText("注意,Token过期,请重新登陆!"); + FlushTokenUtil.flushToken(AutoTakePicture4PoiVideoActivity.this); + Message msg = handler.obtainMessage(0x104); + msg.obj = poiEntity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } else { + systemTTS.playText("注意,领取任务失败!"); + ToastUtils.Message(AutoTakePicture4PoiVideoActivity.this,submitBean.getMessage()); + Message msg = handler.obtainMessage(0x104); + msg.obj = poiEntity; + handler.sendMessageDelayed(msg, 10*1000); // 10秒后重试 + } + } + + /** + * 开始记录位置信息 + * */ + private void startRecordLocation() { + // 只有以前不记录照片,此刻才需要发送新的消息开始拍摄 + if (!handler.hasMessages(0x101)) { + handler.sendEmptyMessage(0x101); + } + } + /** + * 停止记录位置信息 + * */ + private void stopRecordLocation() { + if (handler.hasMessages(0x101)) { + handler.removeMessages(0x101); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_switch: +// handler.sendEmptyMessageDelayed(0x102, 2000);// 利用handler延迟发送更改状态信息 + benSwitch(); + break; + case R.id.iv_zoom_add://放大 + CameraUpdate cameraUpdateIn = CameraUpdateFactory.zoomIn(); + tencentMap.animateCamera(cameraUpdateIn); + setLocMarkerStyle(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); + break; + case R.id.iv_zoom_del://缩小 + CameraUpdate cameraUpdateOut = CameraUpdateFactory.zoomOut(); + tencentMap.animateCamera(cameraUpdateOut); + setLocMarkerStyle(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); + break; + case R.id.iv_location://定位: + if (LocationLifeCycle.getInstance().getMainLocation() != null) { + CameraUpdate cameraSigma = CameraUpdateFactory + .newCameraPosition(new CameraPosition(new LatLng(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()), //中心点坐标,地图目标经纬度 + 17, //目标缩放级别 + 0, //目标倾斜角[0.0 ~ 45.0] (垂直地图时为0) + 0)); //目标旋转角 0~360° (正北方为0) + tencentMap.animateCamera(cameraSigma); + } + // 设置当前地图的定位显示模式为跟随 + setLocMarkerStyle(LOCATION_TYPE_LOCATION_ROTATE); + break; + case R.id.img_location_type: // 切换定位方式 + imgLocationType.setSelected(!imgLocationType.isSelected()); + if (imgLocationType.isSelected()) { // 选中状态,切换为GPS为主定位 + LocationLifeCycle.getInstance().setMainLocationFrom(LocationLifeCycle.LOCATION_FROM.ORIGIN); + } else { + LocationLifeCycle.getInstance().setMainLocationFrom(LocationLifeCycle.LOCATION_FROM.TENCENT); + } + break; + } + } + + private Bitmap getBitMap() { + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.locaiton_auto_pictures); + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + int newWidth = 55; + int newHeight = 55; + float widthScale = ((float) newWidth) / width; + float heightScale = ((float) newHeight) / height; + Matrix matrix = new Matrix(); + matrix.postScale(widthScale, heightScale); + bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); + return bitmap; + } + + /*设置定位图标样式*/ + private void setLocMarkerStyle(int type) { + MyLocationStyle locationStyle = new MyLocationStyle(); + //LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER + locationStyle = locationStyle.myLocationType(type); + //创建图标 + BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(getBitMap()); + locationStyle.icon(bitmapDescriptor); + //设置定位圆形区域的边框宽度; + locationStyle.fillColor(getResources().getColor(android.R.color.transparent)); + locationStyle.strokeWidth(1); + tencentMap.setMyLocationStyle(locationStyle); + if (LOCATION_TYPE_LOCATION_ROTATE == type) { + ivLocation.setEnabled(false); + } else { + ivLocation.setEnabled(true); + } + } + + public void benSwitch() { + FrameLayout.LayoutParams layoutParamsMap = (FrameLayout.LayoutParams) tvMapView.getLayoutParams();//地图的宽高 + int heightMap = tvMapView.getMeasuredHeight(); + int widthMap = tvMapView.getMeasuredWidth(); + FrameLayout.LayoutParams layoutParamsCamera = (FrameLayout.LayoutParams) camera.getLayoutParams();//相机的宽高 + int heightCamera = camera.getMeasuredHeight(); + int widthCamera = camera.getMeasuredWidth(); + layerChange.removeAllViews(); + if (widthMap > widthCamera) { + layoutParamsCamera.width = widthMap; + layoutParamsCamera.height = heightMap; + layoutParamsMap.height = heightCamera; + layoutParamsMap.width = widthCamera; + camera.setLayoutParams(layoutParamsCamera); + tvMapView.setLayoutParams(layoutParamsMap); + layerChange.addView(camera); + layerChange.addView(tvMapView); + initMapBig(); + } else { + layoutParamsMap.height = heightCamera; + layoutParamsMap.width = widthCamera; + layoutParamsCamera.height = heightMap; + layoutParamsCamera.width = widthMap; + camera.setLayoutParams(layoutParamsCamera); + tvMapView.setLayoutParams(layoutParamsMap); + layerChange.addView(tvMapView); + layerChange.addView(camera); + initMapShort(); + } + } + + //小图 + private void initMapBig() { + isMapSlide = false; + layerMapController.setVisibility(View.GONE); + setLocMarkerStyle(LOCATION_TYPE_LOCATION_ROTATE); + // 道路水平方向图标显示 + ivPicRoadImage.setVisibility(View.VISIBLE); + } + + //大图 + private void initMapShort() { + isMapSlide = true; + layerMapController.setVisibility(View.VISIBLE); + setLocMarkerStyle(LOCATION_TYPE_LOCATION_ROTATE); + // 道路水平方向图标不显示 + ivPicRoadImage.setVisibility(View.GONE); + } + + @Override + protected void onStart() { + super.onStart(); + tvMapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + camera.open(); + tvMapView.onResume(); + camera.setPreviewFrameRate(FRAMENESS); +// CameraOptions cameraOptions = camera.getCameraOptions(); +// if (FRAMENESS>=cameraOptions.getPreviewFrameRateMinValue()&&FRAMENESS<=cameraOptions.getPreviewFrameRateMaxValue()) { +// camera.setPreviewFrameRate(FRAMENESS); +// } else { +// camera.setPreviewFrameRate(0); +// } + } + + /** + * 设置相机的拍照size + * */ + private void initCameraSize() { + SizeSelector maxWidth = SizeSelectors.maxWidth(1920); + SizeSelector maxHeight = SizeSelectors.maxHeight(1440); + SizeSelector minWidth = SizeSelectors.minWidth(1440); + SizeSelector minHeight = SizeSelectors.minHeight(1080); + SizeSelector maxDimensions = SizeSelectors.and(maxWidth, maxHeight); // Matches sizes bigger than 1000x2000. + SizeSelector minDimensions = SizeSelectors.and(minWidth, minHeight); // Matches sizes bigger than 1000x2000. + SizeSelector verticalRatio = SizeSelectors.aspectRatio(AspectRatio.of(1080, 1920), 0.2f); // Matches 1:1 sizes. + SizeSelector horzentalRatio = SizeSelectors.aspectRatio(AspectRatio.of(1920, 1080), 0.2f); // Matches 1:1 sizes. + + SizeSelector result = SizeSelectors.or( + SizeSelectors.and(verticalRatio, maxDimensions, minDimensions), // Try to match both constraints + SizeSelectors.and(horzentalRatio, maxDimensions, minDimensions), // Try to match both constraints + verticalRatio, // If none is found, at least try to match the aspect ratio + horzentalRatio, // If none is found, at least try to match the aspect ratio + SizeSelectors.biggest() // If none is found, take the biggest + ); + camera.setPictureSize(result); + camera.setPreviewStreamSize(result); + /** + * app:cameraPictureSizeAspectRatio="1920:1080" + * app:cameraPictureSizeBiggest="true" + * app:cameraPictureSizeMaxArea="3686400" + * app:cameraPictureSizeMaxHeight="1920" + * app:cameraPictureSizeMaxWidth="1920" + * app:cameraPictureSizeMinArea="1166400" + * app:cameraPictureSizeMinHeight="1080" + * app:cameraPictureSizeMinWidth="1080" + * app:cameraPictureSizeSmallest="true" + * */ + } + + @Override + protected void onRestart() { + super.onRestart(); + this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + tvMapView.onRestart(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + Message obtain = Message.obtain(); + obtain.what = Constant.PICTURE_VIDEO_WORD; + obtain.obj = true; + EventBus.getDefault().post(obtain); + } + + @Override + protected void onPause() { + super.onPause(); + tvMapView.onPause(); + camera.close(); + } + + @Override + protected void onStop() { + super.onStop(); + tvMapView.onStop(); + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + stopRecordLocation(); + camera.destroy(); + tvMapView.onDestroy(); + trackLocRemovables.stream().forEach(it->it.remove()); + trackLocRemovables.clear(); + if (EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().unregister(this); + } + if (roadMatchEntityList!=null&&!roadLinkEntityList.isEmpty()) { + // roadMatchEntity已匹配数据如果存在,缓存 + SharedPreferences.Editor editor = getSharedPreferences("MatchEntity", Context.MODE_PRIVATE).edit(); + Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); + editor.putString("match-data", gson.toJson(roadMatchEntityList)); + editor.commit(); + } + if (mediaPlayer!=null) { + mediaPlayer.release(); + } + // 退出后切换主定位模式为腾讯定位 + LocationLifeCycle.getInstance().setMainLocationFrom(LocationLifeCycle.LOCATION_FROM.TENCENT); + LocationLifeCycle.getInstance().stopGPSLocation(); + } + + @Override + public void onBackPressed() { + if (finishTaskCount>0) { + MessageDialog.show("提示", "后台正在处理已拍摄完成的任务,请稍后再退出当前界面"); + wantBack = true; + return; + } + MessageDialog.show("提示", "退出自动采集模式?", "是", "否") + .setOkButton(new OnDialogButtonClickListener() { + @Override + public boolean onClick(BaseDialog baseDialog, View v) { + stopRecordLocation(); + Observable.create(new ObservableOnSubscribe() { + @Override + public void subscribe(ObservableEmitter emitter) throws Exception { + // 查询所有已领取的任务,在返回前全部自动取消领取这些任务 + List receivedPoiEntityList = poiDao.getPoiEntityByTaskStatus(1, 4); + if (receivedPoiEntityList!=null&&!receivedPoiEntityList.isEmpty()) { + receivedPoiEntityList.stream().forEach(poiEntity -> { + emitter.onNext(poiEntity); + }); + } + emitter.onComplete(); + } + }).subscribeOn(Schedulers.io()) + .flatMap( + poiEntity -> { + if (poiEntity!=null) { + return sendCancelRequest(poiEntity); + } else { + return Observable.empty(); + } + } + ) + .filter(poiEntity -> poiEntity!=null) + .observeOn(AndroidSchedulers.mainThread()) + .doFinally(new Action() { + @Override + public void run() throws Exception { + showLoadingDialog("正在删除缓存照片..."); + } + }) + .observeOn(Schedulers.io()) + .doOnComplete(new Action() { + @Override + public void run() throws Exception { + // 删除缓存目录 + FileUtils.deleteFile(tmpPicFoldPath); + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .doFinally(new Action() { + @Override + public void run() throws Exception { + showLoadingDialog("正在删除缓存照片..."); + } + }) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + showLoadingDialog("正在取消已领取的任务..."); + } + + @Override + public void onNext(PoiEntity o) { + + } + + @Override + public void onError(Throwable e) { + Toast.makeText(AutoTakePicture4PoiVideoActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); + AutoTakePicture4PoiVideoActivity.this.finish(); + } + + @Override + public void onComplete() { +// // 重新刷新地图 +// initRoadLine2Map(); + // 通知主界面刷新 + Message obtains = Message.obtain(); + obtains.what = Constant.JOB_WORD_MONITOR; + obtains.obj = true; + EventBus.getDefault().post(obtains); + + dismissLoadingDialog(); + // 执行结束后清空已匹配列表 + roadMatchEntityList.clear(); + AutoTakePicture4PoiVideoActivity.this.finish(); + } + }); + return false; + } + }); + } + + /** + * 添加轨迹点 + */ + public void addTrackMarker() { + LatLng latLng = null; + latLng = new LatLng(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()); +// if (GPSUtils.getInstance(AutoTakePictureActivity.this).getSateliteCount() != 0) { +// latLng = new LatLng(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()); +// } else { +// if (gpsLocation == null) { +// latLng = new LatLng(LocationLifeCycle.getInstance().getMainLocation().getLatitude(), LocationLifeCycle.getInstance().getMainLocation().getLongitude()); +// } else { +// double[] doubles = Gps.toGCJ02Point(gpsLocation.getLatitude(), gpsLocation.getLongitude()); +// latLng = new LatLng(doubles[0],doubles[1]); +// } +// } + Marker marker = tencentMap.addMarker(new MarkerOptions(latLng) + .icon(pileDescriptor) + .alpha(0.9f) + .flat(true) + .clockwise(false)); + trackLocRemovables.add(marker); + } + + // 设置当前界面亮度 + private void setWindowBrightness(int brightness) { +// Window window = getWindow(); +// WindowManager.LayoutParams lp = window.getAttributes(); +// lp.screenBrightness = brightness / 255.0f; +// window.setAttributes(lp); + } + + + private Handler handler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(@NonNull Message msg) { + if (msg.what == 0x101) { + System.out.println("收到拍照按钮请求"); + camera.takePictureSnapshot(); + handler.sendEmptyMessageDelayed(0x101, 500); + } else if (msg.what == 0x102) { + } else if (msg.what == 0x103) { + RoadMatchEntity roadMatchEntity = (RoadMatchEntity) msg.obj; + receiverRoadTask(roadMatchEntity).subscribe(receiveObserver); + } else if (msg.what == 0x104) { + PoiEntity poiEntity = (PoiEntity) msg.obj; + try { + roadSaveWork(poiEntity); + } catch (Exception e) { + + } + } else if (msg.what == 0x105) { // 测试用例,当用户点击地图时,会自动返回当前点击位置 + if (locationEnable) { + return false; + } + TencentLocation tencentLocation = (TencentLocation) msg.obj; + if (tencentMap != null && !isMapSlide) { + CameraUpdate cameraSigma = CameraUpdateFactory.newCameraPosition(new CameraPosition( + new LatLng(tencentLocation.getLatitude(), tencentLocation.getLongitude()), //中心点坐标,地图目标经纬度 + 17, //目标缩放级别 + 0, //目标倾斜角 + 0)); //目标旋转角 0~360° (正北方为0) + tencentMap.animateCamera(cameraSigma); + } + // 判断当前点位和上一个点位的距离,如果距离过近,忽略该点 + Point currentPoint = (Point) GeometryTools.createGeometry(new LatLng(tencentLocation.getLatitude(), tencentLocation.getLongitude())); + if (lastPositionPoint!=null&&lastPositionPoint.distance(currentPoint)<3e-7) { // 如果当前点小于最小距离阈值,过滤该数据 + return false; + } + lastPositionPoint = currentPoint; + startMatchRoadLink(currentPoint); + } else if (msg.what == 0x106) { + PoiEntity poiEntity = (PoiEntity) msg.obj; + try { + sendCancelRequest(poiEntity).subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(PoiEntity poiEntity) { + + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } catch (Exception e) { + + } + } + return false; + } + }); + + private double[] getSpeedAndBearing(Point currentPoint) { + double[] speedAndBearing = new double[2]; + + double bearing = 0; +// if (Constant.currentLocation.getDirection() != 0) { +// bearing = (float) Constant.currentLocation.getDirection(); +// } else { +// // 使用上一个点和当前点位的向量计算方向 +// if (oldCurrentLocation!=null&&oldCurrentLocation.getLatitude()!=Constant.currentLocation.getLatitude()&&oldCurrentLocation.getLongitude()!=Constant.currentLocation.getLongitude()) { +// bearing = getBearing(oldCurrentLocation.getLongitude(), Constant.currentLocation.getLongitude(), oldCurrentLocation.getLatitude(), Constant.currentLocation.getLatitude()); +// } +// } + // 使用上一个点和当前点位的向量计算方向 + if (oldCurrentLocation!=null&&oldCurrentLocation.getX()!=currentPoint.getX()&&oldCurrentLocation.getY()!=currentPoint.getY()) { + bearing = getBearing(oldCurrentLocation.getX(), currentPoint.getX(), oldCurrentLocation.getY(), currentPoint.getY()); + } + + float speed = LocationLifeCycle.getInstance().getMainLocation().getSpeed();//米/秒 + if (speed != 0) { + speed = (speed * 3600 / 1000);//km/h + } else { + if (oldCurrentLocation != null) { + LatLng startLatLng = new LatLng(oldCurrentLocation.getY(), oldCurrentLocation.getX());//旧的坐标 + LatLng endLatLng = new LatLng(currentPoint.getY(), currentPoint.getX());//新的坐标 + double geometry = GeometryTools.distanceToDouble(startLatLng, endLatLng);//米 + speed = (float) (geometry * 3600 / 1000); + } + } + oldCurrentLocation = currentPoint; + speedAndBearing[0] = speed; + speedAndBearing[1] = bearing; + + return speedAndBearing; + } + + private double getBearing(double startLongitude, double endLongitude, double startLatitude, double endLatitude) { + double x = endLongitude - startLongitude; + double y = endLatitude - startLatitude; + double angle = Math.atan(x / y)*180/Math.PI; + if((x>0&&y<0)||(x<0&&y<0)){ + angle=angle+180; + } + angle = (angle+720)%360; + return angle; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMessageMainThread(Message msg) { + if (msg.what == Constant.EVENT_WHAT_LOCATION_CHANGE) { // 用户位置更新 + if (!locationEnable) { + write2Log("onEventMessageMainThread", "关闭了获取GPS定位开关"); + return; + } + TencentLocation tencentLocation = (TencentLocation) msg.obj; +// if (tencentMap != null && ivLocation!=null && !ivLocation.isEnabled()) { // 当定位按钮禁用, +// CameraUpdate cameraSigma = CameraUpdateFactory.newCameraPosition(new CameraPosition( +// new LatLng(tencentLocation.getLatitude(), tencentLocation.getLongitude()), //中心点坐标,地图目标经纬度 +// 17, //目标缩放级别 +// 0, //目标倾斜角 +// 0)); //目标旋转角 0~360° (正北方为0) +// tencentMap.animateCamera(cameraSigma); +// } + // 判断当前点位和上一个点位的距离,如果距离过近,忽略该点 + Point currentPoint = (Point) GeometryTools.createGeometry(new LatLng(tencentLocation.getLatitude(), tencentLocation.getLongitude())); + if (lastPositionPoint!=null&&lastPositionPoint.distance(currentPoint)<5e-7) { // 如果当前点小于最小距离阈值,过滤该数据 + write2Log("onEventMessageMainThread", "距离上一点位距离过近:currentPoint-"+currentPoint.toString()+"lastPositionPoint:"+lastPositionPoint.toString()); + return; + } + lastPositionPoint = currentPoint; + startMatchRoadLink(currentPoint); + } + } + private void write2Log(String tag, String log) { + if (logger == null) { + Printer filePrinter = new FilePrinter // 打印日志到文件的打印器 + .Builder(Constant.LOG_FOLDER) // 指定保存日志文件的路径 + .fileNameGenerator(new DateFileNameGenerator() { + ThreadLocal mLocalDateFormat = new ThreadLocal() { + + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd", Locale.US); + } + }; + @Override + public boolean isFileNameChangeable() { + return true; + } + + @Override + public String generateFileName(int logLevel, long timestamp) { + SimpleDateFormat sdf = mLocalDateFormat.get(); + sdf.setTimeZone(TimeZone.getDefault()); + return "AutoTakePicture-"+sdf.format(new Date(timestamp)); + } + }) // 指定日志文件名生成器,默认为 ChangelessFileNameGenerator("log") + .flattener(new ClassicFlattener()) + .build(); + logger = XLog.printers(filePrinter).build(); + } + logger.v(null, tag, log); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java b/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java index 7520939..5316df4 100644 --- a/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java +++ b/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java @@ -49,12 +49,11 @@ import com.github.lazylibrary.util.NetWorkUtils; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.kongzue.dialog.interfaces.OnDialogButtonClickListener; -import com.kongzue.dialog.util.BaseDialog; -import com.kongzue.dialog.util.DialogSettings; -import com.kongzue.dialog.v3.CustomDialog; -import com.kongzue.dialog.v3.MessageDialog; -import com.kongzue.dialog.v3.WaitDialog; +import com.kongzue.dialogx.dialogs.CustomDialog; +import com.kongzue.dialogx.dialogs.MessageDialog; +import com.kongzue.dialogx.interfaces.BaseDialog; +import com.kongzue.dialogx.interfaces.OnBindView; +import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener; import com.lzy.okgo.OkGo; import com.lzy.okgo.model.HttpParams; import com.navinfo.outdoor.R; @@ -269,7 +268,6 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic EventBus.getDefault().register(this); } - this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); layerChange = findViewById(R.id.layer_change); systemTTS = SystemTTS.getInstance(AutoTakePictureActivity.this); tvMapView = findViewById(R.id.text_map_view); @@ -361,7 +359,7 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic btnSetting.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - CustomDialog.show(AutoTakePictureActivity.this, R.layout.camera_setting, new CustomDialog.OnBindView() { + CustomDialog.show(new OnBindView(R.layout.camera_setting) { @Override public void onBind(CustomDialog dialog, View v) { EditText startDistance = v.findViewById(R.id.edt_camera_setting_start_distance); @@ -405,7 +403,7 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic MATCH_CONFIRM_FINISH_BUFFER = Float.parseFloat(matchPecent.getText().toString()); } Toast.makeText(AutoTakePictureActivity.this, "设置完成", Toast.LENGTH_SHORT).show(); - dialog.doDismiss(); + dialog.dismiss(); } }); } @@ -1406,18 +1404,19 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic if (hasError) { dialogMessage.append("(注意,其中有部分任务处理失败)"); } - MessageDialog.show(AutoTakePictureActivity.this, "退出当前界面", dialogMessage) - .setOkButton("确定", new OnDialogButtonClickListener() { + MessageDialog.show("退出当前界面", dialogMessage) + .setOkButton("确定", new OnDialogButtonClickListener() { @Override - public boolean onClick(BaseDialog baseDialog, View v) { + public boolean onClick(MessageDialog dialog, View v) { + dialog.dismiss(); AutoTakePictureActivity.this.finish(); return false; } }) - .setCancelButton("取消", new OnDialogButtonClickListener() { + .setCancelButton("取消", new OnDialogButtonClickListener() { @Override - public boolean onClick(BaseDialog baseDialog, View v) { - baseDialog.doDismiss(); + public boolean onClick(MessageDialog dialog, View v) { + dialog.dismiss(); wantBack = false; return false; } @@ -1732,13 +1731,13 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic @Override public void onBackPressed() { - DialogSettings.style = DialogSettings.STYLE.STYLE_IOS; if (finishTaskCount>0) { - MessageDialog.show(this, "提示", "后台正在处理已拍摄完成的任务,请稍后再退出当前界面"); + MessageDialog.show("提示", "后台正在处理已拍摄完成的任务,请稍后再退出当前界面"); wantBack = true; return; } - MessageDialog.show(this, "提示", "退出自动采集模式?", "是", "否").setOnOkButtonClickListener(new OnDialogButtonClickListener() { + MessageDialog.show("提示", "退出自动采集模式?", "是", "否") + .setOkButton(new OnDialogButtonClickListener() { @Override public boolean onClick(BaseDialog baseDialog, View v) { stopRecordLocation(); diff --git a/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java b/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java index c355cf1..6508fae 100644 --- a/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java +++ b/app/src/main/java/com/navinfo/outdoor/api/UserApplication.java @@ -10,6 +10,9 @@ import android.util.Log; import androidx.lifecycle.ProcessLifecycleOwner; +import com.kongzue.dialogx.DialogX; +import com.kongzue.dialogx.style.MIUIStyle; +import com.kongzue.dialogx.style.MaterialStyle; import com.lzy.okgo.OkGo; import com.lzy.okgo.cache.CacheEntity; import com.lzy.okgo.cache.CacheMode; @@ -62,7 +65,10 @@ public class UserApplication extends Application { config.setDeviceId(deviceID); // 或者设置开发者自己的的设备号config.setDeviceId(xxxxxxxx); TencentNavi.init(this, config); - + // 初始化对话框组件 + DialogX.init(this); + DialogX.globalStyle = new MIUIStyle(); + DialogX.globalTheme = DialogX.THEME.LIGHT; } public static UserApplication getUserApplication() { diff --git a/app/src/main/java/com/navinfo/outdoor/base/BaseFragment.java b/app/src/main/java/com/navinfo/outdoor/base/BaseFragment.java index 4bfb675..5a49bee 100644 --- a/app/src/main/java/com/navinfo/outdoor/base/BaseFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/base/BaseFragment.java @@ -23,15 +23,8 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import com.navinfo.outdoor.R; -import com.kongzue.dialog.interfaces.OnBackClickListener; -import com.kongzue.dialog.v3.WaitDialog; -import com.navinfo.outdoor.R; -import com.navinfo.outdoor.activity.HomeActivity; import com.navinfo.outdoor.activity.WebActivity; -import com.navinfo.outdoor.http.HttpInterface; -import com.navinfo.outdoor.util.BackHandlerHelper; import com.navinfo.outdoor.util.FragmentBackHandler; -import com.navinfo.outdoor.util.NetWorkUtils; import java.util.HashMap; import java.util.Map; @@ -82,7 +75,7 @@ public abstract class BaseFragment extends Fragment implements FragmentBackHandl } protected T findViewById(@IdRes int id) { - return Objects.requireNonNull(getView()).findViewById(id); + return requireView().findViewById(id); } protected void debounce(View view) { @@ -99,7 +92,7 @@ public abstract class BaseFragment extends Fragment implements FragmentBackHandl if (alertDialog != null) { alertDialog.dismiss(); } - alertDialog = new AlertDialog.Builder(Objects.requireNonNull(getActivity())).create(); + alertDialog = new AlertDialog.Builder(requireActivity()).create(); Objects.requireNonNull(alertDialog.getWindow()).setBackgroundDrawable(new ColorDrawable()); alertDialog.setCancelable(false); alertDialog.setOnKeyListener((dialog, keyCode, event) -> { diff --git a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java index 205d902..d9f3799 100644 --- a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java @@ -53,9 +53,13 @@ import com.kongzue.dialog.util.BaseDialog; import com.kongzue.dialog.util.DialogSettings; import com.kongzue.dialog.v3.MessageDialog; import com.kongzue.dialog.v3.ShareDialog; +import com.kongzue.dialogx.dialogs.PopMenu; +import com.kongzue.dialogx.interfaces.OnIconChangeCallBack; +import com.kongzue.dialogx.interfaces.OnMenuItemClickListener; import com.lzy.okgo.model.HttpParams; import com.lzy.okgo.model.Progress; import com.navinfo.outdoor.R; +import com.navinfo.outdoor.activity.AutoTakePicture4PoiVideoActivity; import com.navinfo.outdoor.activity.AutoTakePictureActivity; import com.navinfo.outdoor.activity.FragmentManagement; import com.navinfo.outdoor.activity.WebActivity; @@ -313,8 +317,37 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen @RequiresApi(api = Build.VERSION_CODES.N) @Override public void onClick(View v) { - Intent autoMatchIntent = new Intent(getContext(), AutoTakePictureActivity.class); - startActivity(autoMatchIntent); + PopMenu.show(v, new String[]{"道路任务", "POI录像"}) + .setOverlayBaseView(true) + .setAlignGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL) + .setOnIconChangeCallBack(new OnIconChangeCallBack() { + @Override + public int getIcon(PopMenu dialog, int index, String menuText) { + switch (index){ + case 0: + return R.drawable.marker_road_show; + case 1: + return R.drawable.marker_poi_video_show; + default: + break; + } + return 0; + } + }) + .setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onClick(PopMenu dialog, CharSequence text, int index) { + if (index == 0) { // 自动捕捉道路任务 + Intent autoMatchIntent = new Intent(getContext(), AutoTakePictureActivity.class); + startActivity(autoMatchIntent); + } else if (index == 1) { + Intent autoMatchIntent = new Intent(getContext(), AutoTakePicture4PoiVideoActivity.class); + startActivity(autoMatchIntent); + } + return false; + } + }); + // // 设置亮度和摄像机刷新率 // CustomDialog.show((AppCompatActivity) getActivity(), R.layout.camera_setting_pre, new CustomDialog.OnBindView() { // @Override diff --git a/app/src/main/res/layout/activity_picture.xml b/app/src/main/res/layout/activity_picture.xml index 119113d..db5459d 100644 --- a/app/src/main/res/layout/activity_picture.xml +++ b/app/src/main/res/layout/activity_picture.xml @@ -132,7 +132,7 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@+id/btn_switch" - android:background="@color/whiteAlpha50" + android:background="@color/white50" android:padding="@dimen/default_widget_padding" android:textColor="@color/colorRead" android:format="00:00:00" diff --git a/app/src/main/res/layout/camera_setting.xml b/app/src/main/res/layout/camera_setting.xml index 7a23c59..a67b3e1 100644 --- a/app/src/main/res/layout/camera_setting.xml +++ b/app/src/main/res/layout/camera_setting.xml @@ -2,7 +2,7 @@