package com.tsi.navi.activity; import android.Manifest; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.res.Configuration; import android.graphics.PointF; import android.graphics.Rect; import android.location.Location; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.annotation.UiThread; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import com.fasterxml.jackson.databind.ObjectMapper; import com.naver.maps.geometry.LatLng; import com.naver.maps.geometry.LatLngBounds; import com.naver.maps.map.CameraPosition; import com.naver.maps.map.CameraUpdate; import com.naver.maps.map.CameraUpdateParams; import com.naver.maps.map.LocationTrackingMode; import com.naver.maps.map.MapFragment; import com.naver.maps.map.NaverMap; import com.naver.maps.map.NaverMapOptions; import com.naver.maps.map.NaverMapSdk; import com.naver.maps.map.OnMapReadyCallback; import com.naver.maps.map.overlay.Align; import com.naver.maps.map.overlay.InfoWindow; import com.naver.maps.map.overlay.Marker; import com.naver.maps.map.overlay.OverlayImage; import com.naver.maps.map.util.FusedLocationSource; import com.tsi.navi.R; import com.tsi.navi.TsiNaviApplication; import com.tsi.navi.activity.dialog.AppInformationDialog; import com.tsi.navi.activity.dialog.IDialogClickListener; import com.tsi.navi.activity.dialog.MapSettingDialog; import com.tsi.navi.activity.dialog.NodeCrossDialog; import com.tsi.navi.activity.fragment.AreaCrossFragment; import com.tsi.navi.activity.fragment.DirectionNaviSignalFragment; import com.tsi.navi.activity.fragment.DirectionSignalFragment; import com.tsi.navi.activity.fragment.UserSignalFragment; import com.tsi.navi.activity.model.NodeCrossItem; import com.tsi.navi.database.DbQuery; import com.tsi.navi.databinding.ActivityMainBinding; import com.tsi.navi.dto.CpuNodeStatusDTO; import com.tsi.navi.preferences.PrefManager; import com.tsi.navi.util.BackPressedForFinish; import com.tsi.navi.util.BoundaryUtils; import com.tsi.navi.util.CameraInfo; import com.tsi.navi.util.TsiUtils; import com.tsi.navi.vo.NodeVo; import com.tsi.navi.vo.TsiGpsTrackingVo; import com.tsi.navi.websocket.NaviWebsocketClientService; import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @RequiresApi(api = Build.VERSION_CODES.R) public class MainActivity extends AppCompatActivity implements OnMapReadyCallback { private static final String TAG = MainActivity.class.getSimpleName(); private Context context; private BackPressedForFinish backPressedForFinish = null; private ActivityMainBinding binding = null; private NaverMap naverMap = null; private static final int LOCATION_PERMISSION_REQUEST_CODE = 1000; private final String[] permissions = { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }; private FusedLocationSource locationSource; private boolean dispAllSignal = false; private boolean isTrackingMode = false; private boolean isDebugMode = false; private boolean dispCvibSignal = false; private double trackingZoom; private float currSpeed = 0; private float lastBearing = -1, currBearing = -1; private float moveDist = 0; private CameraInfo cameraInfo; private BoundaryUtils mapUtils; private float carX = 0; private float carY = 0; private double tilt = 45; private float trackingDistance = 5; private float driveDistance = 8; private TsiGpsTrackingVo gpsTracking; private Location lastLocation = null; private final float[] resultDistance = {-999, -999, -999}; private String deviceId; private DbQuery dbQuery; private int overlayResourceId; private CameraUpdateParams cameraUpdateParams; private float width, height; private NodeVo selectedNode = null; private InfoWindow infoWindow; private Vector activeMarkers; private ConcurrentHashMap activeNodes; //private TsiApiService tsiApiService; private FragmentManager fragmentManager; private DirectionSignalFragment directionSignalFragment; private DirectionNaviSignalFragment directionNaviSignalFragment; private UserSignalFragment userSignalFragment; private AreaCrossFragment areaCrossFragment; private String lastTopics; private NaviWebsocketClientService naviClientService; private final AtomicBoolean moveByGps = new AtomicBoolean(false); private final ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //private NaviWebsocketClient naviClient; NaviWebsocketClientService.NaviWebsocketClientBinder naviClientBinder = (NaviWebsocketClientService.NaviWebsocketClientBinder) iBinder; naviClientService = naviClientBinder.getService(); //naviClient = naviClientService.getNaviWebsocketClient(); Toast.makeText(context, "서버 통신 시작", Toast.LENGTH_SHORT).show(); } @Override public void onServiceDisconnected(ComponentName componentName) { Toast.makeText(context, "서버 통신 연결 종료", Toast.LENGTH_SHORT).show(); } }; private class NaviWebsocketMessageListener extends BroadcastReceiver { ObjectMapper mapper = new ObjectMapper(); @Override public void onReceive(Context context, Intent intent) { String message = intent.getStringExtra("message"); try { if (message.contains("offline")) { List requests = TsiUtils.split(message, ":"); if (requests.size() == 2) { NodeVo node = TsiNaviApplication.getNodeMap().get(Long.parseLong(requests.get(0))); if (node != null) { Toast.makeText(context, node.getName() + " 는(은) 통신 OffLine 입니다.", Toast.LENGTH_SHORT).show(); } } } else { CpuNodeStatusDTO status = this.mapper.readValue(message, CpuNodeStatusDTO.class); if (directionNaviSignalFragment.isVisible() && directionNaviSignalFragment.getNodeId() == status.getA()) { directionNaviSignalFragment.updateSignal(status); } if (directionSignalFragment.isVisible() && directionSignalFragment.getNodeId() == status.getA()) { directionSignalFragment.updateSignal(status); } if (userSignalFragment.isVisible() && userSignalFragment.getNodeId() == status.getA()) { userSignalFragment.updateSignal(status, 10); } } } catch (Exception e) { Log.e(TAG, e.getMessage()); } } } private void requestTopicMessage(String topic) { try { this.naviClientService.sendMsg("topics:" + topic); this.lastTopics = topic; if (topic.equalsIgnoreCase("x")) { this.lastTopics = ""; // 교차로 신호정보 요청 취소 setSelectedNode(null); setRequestNode(null); if (this.userSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.userSignalFragment).commit(); } if (this.directionNaviSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionNaviSignalFragment).commit(); } if (this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); } } } catch (Exception e) { Log.e(TAG, "Request topic error: " + e.getMessage()); } } private class NaviWebsocketEventListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String event = intent.getStringExtra("event"); //Log.e(TAG, "onEvent: " + event); if (event.equalsIgnoreCase("open")) { naviClientService.sendMsg("group:" + deviceId); // group id send if (!lastTopics.equals("")) { requestTopicMessage(lastTopics); } //Toast.makeText(context, "서버 통신 연결", Toast.LENGTH_SHORT).show(); } else if (event.equalsIgnoreCase("close")) { Toast.makeText(context, "서버와 연결이 종료되었습니다.", Toast.LENGTH_SHORT).show(); } else if (event.equalsIgnoreCase("error")) { Toast.makeText(context, "서버와 연결 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show(); } } } private static class InfoWindowAdapter extends InfoWindow.ViewAdapter { @NonNull private final Context context; private View rootView; private ImageView icon; private TextView text; private InfoWindowAdapter(@NonNull Context context) { this.context = context; } @NonNull @Override public View getView(@NonNull InfoWindow infoWindow) { if (rootView == null) { rootView = View.inflate(context, R.layout.marker_info_window, null); icon = rootView.findViewById(R.id.icon); text = rootView.findViewById(R.id.text); } if (infoWindow.getMarker() != null) { icon.setImageResource(R.drawable.ic_place_black_24dp); text.setText((String) infoWindow.getMarker().getTag()); } else { icon.setImageResource(R.drawable.ic_app); text.setText(context.getString( R.string.format_coord, infoWindow.getPosition().latitude, infoWindow.getPosition().longitude)); } return rootView; } } @SuppressLint("NonConstantResourceId") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(this.binding.getRoot()); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 화면 꺼짐 방지 this.context = MainActivity.this; this.deviceId = PrefManager.getDeviceId(this); this.dispAllSignal = PrefManager.getDispAreaCross(this); this.dispCvibSignal = PrefManager.getDispCvibSignal(this); TsiNaviApplication.getMapConfig().loadConfig(this); //this.tsiApiService = ApiUtils.getApiService(PrefManager.getApiUrl(this)); this.trackingZoom = TsiNaviApplication.getMapConfig().getTrackingZoom(); this.tilt = TsiNaviApplication.getMapConfig().getRunTilt(); this.trackingDistance = TsiNaviApplication.getMapConfig().getRunTrackingDistance(); this.driveDistance = TsiNaviApplication.getMapConfig().getRunDriveDistance(); this.isTrackingMode = false; this.cameraInfo = new CameraInfo(this); this.mapUtils = new BoundaryUtils(this); this.gpsTracking = new TsiGpsTrackingVo(); this.backPressedForFinish = new BackPressedForFinish(this); // BackPressedForFinish 객체를 생성한다. //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); MainActivityUtils.initDatabase(this); this.dbQuery = new DbQuery(this); this.dbQuery.createDatabase(); this.dbQuery.open(); // 지도사용권한 this.locationSource = new FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE); this.binding.tvLog.setText(" "); this.binding.tvLog.setVisibility(View.INVISIBLE); this.binding.tvSpeed.setText(" "); this.fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = this.fragmentManager.beginTransaction(); this.areaCrossFragment = new AreaCrossFragment(); this.directionSignalFragment = new DirectionSignalFragment(); this.directionNaviSignalFragment = new DirectionNaviSignalFragment(); this.userSignalFragment = new UserSignalFragment(); transaction.add(R.id.frame_area_cross, areaCrossFragment, "AreaCross"); transaction.add(R.id.frame_direction_signal, this.directionSignalFragment, "DirectionSignal"); transaction.add(R.id.frame_direction_navi_signal, this.directionNaviSignalFragment, "DirectionNaviSignal"); transaction.add(R.id.frame_user_signal, this.userSignalFragment, "UserSignal"); transaction.hide(areaCrossFragment); transaction.hide(this.directionSignalFragment); transaction.hide(this.directionNaviSignalFragment); transaction.hide(this.userSignalFragment); transaction.commit(); /*this.areaCrossFragment.setOnItemClickListener(item -> { if (item != null) { requestNodeSignal(item.getNodeId(), true); } }); */ // Naver 지도객체 생성 FragmentManager fragmentManager = getSupportFragmentManager(); MapFragment mapFragment = (MapFragment)fragmentManager.findFragmentById(R.id.map); if (mapFragment == null) { mapFragment = MapFragment.newInstance(new NaverMapOptions()); fragmentManager.beginTransaction().add(R.id.map, mapFragment).commit(); } mapFragment.getMapAsync(this); startNaviWebsocketClientService(); this.binding.fabSetCurrent.setVisibility(View.INVISIBLE); this.binding.fabSetCurrent.setOnClickListener(v -> { setTrackingMode(true); }); this.binding.fabMenu.setOnClickListener(v -> { PopupMenu popup = new PopupMenu(MainActivity.this, v); final MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.bottom_menu, popup.getMenu()); MenuItem itemDispCross = popup.getMenu().findItem(R.id.menu_disp_cross); if (itemDispCross != null) { if (this.dispAllSignal) { itemDispCross.setIcon(R.drawable.ic_check_yes); } else { itemDispCross.setIcon(R.drawable.ic_check_no); } } MenuItem itemDebugMode = popup.getMenu().findItem(R.id.menu_debug_mode); if (itemDebugMode != null) { if (this.isDebugMode) { itemDebugMode.setIcon(R.drawable.ic_check_yes); } else { itemDebugMode.setIcon(R.drawable.ic_check_no); } } MenuItem itemDispCvib = popup.getMenu().findItem(R.id.menu_disp_cvib); if (itemDispCvib != null) { if (this.dispCvibSignal) { itemDispCvib.setIcon(R.drawable.ic_check_yes); } else { itemDispCvib.setIcon(R.drawable.ic_check_no); } } binding.fabMenu.setImageResource(R.drawable.ic_action_close); popup.setOnMenuItemClickListener(item -> { switch (item.getItemId()){ case R.id.menu_cross: NodeCrossDialog nodeCrossDialog = new NodeCrossDialog(MainActivity.this, new IDialogClickListener() { @Override public void onPositiveClick() { } @Override public void onNegativeClick() { } }); nodeCrossDialog.setOnDismissListener(d -> { NodeCrossItem nodeItem = nodeCrossDialog.getSelectedNode(); if (nodeItem != null) { // 교차로 선택 다이얼로그에서 교차로 선택했음 NodeVo node = TsiNaviApplication.getNodeMap().get(nodeItem.getId()); if (node != null) { naverMap.moveCamera(CameraUpdate.scrollTo(node.getLatLng())); setSelectedNode(node); setTrackingMode(false); requestSelectedNode(); } } }); nodeCrossDialog.setCanceledOnTouchOutside(true); //다이얼로그 밖에 터치했을 때 다이얼로그가 꺼짐. nodeCrossDialog.setCancelable(true); //다이얼로그 취소 가능. ( back 버튼 ) nodeCrossDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); nodeCrossDialog.show(); break; case R.id.menu_map_settings: MapSettingDialog mapSettingDialog = new MapSettingDialog(MainActivity.this, new IDialogClickListener() { @Override public void onPositiveClick() { // 설정값을 레퍼런스에 저장 TsiNaviApplication.getMapConfig().saveConfig(MainActivity.this); mapUtils.loadConfig(); trackingZoom = TsiNaviApplication.getMapConfig().getTrackingZoom(); } @Override public void onNegativeClick() { // 레퍼런스를 다시읽어 설정값 초기화 TsiNaviApplication.getMapConfig().loadConfig(MainActivity.this); } }, naverMap, mapUtils); mapSettingDialog.setCanceledOnTouchOutside(true); //다이얼로그 밖에 터치했을 때 다이얼로그가 꺼짐. mapSettingDialog.setCancelable(true); //다이얼로그 취소 가능. ( back 버튼 ) mapSettingDialog.setOnDismissListener(d -> { // 맵 설정정보 셋팅 MainActivityUtils.setupMap(naverMap, trackingZoom); /* if (TsiNaviApplication.getMapConfig().isNightMode()) { this.overlayResourceId = (this.overlayResourceId == R.drawable.ic_navi_car_on) ? R.drawable.ic_navi_car_night_on : R.drawable.ic_navi_car_night_off; } else { this.overlayResourceId = (this.overlayResourceId == R.drawable.ic_navi_car_night_on) ? R.drawable.ic_navi_car_on : R.drawable.ic_navi_car_off; } this.naverMap.getLocationOverlay().setIcon(OverlayImage.fromResource(this.overlayResourceId)); */ }); mapSettingDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); mapSettingDialog.show(); break; case R.id.menu_map_cache_delete: NaverMapSdk.getInstance(MainActivity.this).flushCache(new NaverMapSdk.CacheFlushCallback() { @Override public void onCacheFlushed() { Toast.makeText(MainActivity.this, "지도캐시초기화 완료.", Toast.LENGTH_SHORT).show(); } }); break; case R.id.menu_app_info: AppInformationDialog appInformationDialog = new AppInformationDialog(MainActivity.this, new IDialogClickListener() { @Override public void onPositiveClick() { } @Override public void onNegativeClick() { } }); appInformationDialog.setCanceledOnTouchOutside(true); //다이얼로그 밖에 터치했을 때 다이얼로그가 꺼짐. appInformationDialog.setCancelable(true); //다이얼로그 취소 가능. ( back 버튼 ) appInformationDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); appInformationDialog.show(); break; case R.id.menu_disp_cross: this.dispAllSignal = !this.dispAllSignal; PrefManager.setDispAreaCross(this.context, this.dispAllSignal); if (!this.isTrackingMode) { if (this.dispAllSignal) { if (this.selectedNode != null) { if (!this.directionNaviSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().show(this.directionNaviSignalFragment).commit(); this.directionNaviSignalFragment.setNodeCross(this.selectedNode, 10); } if (this.dispCvibSignal && !this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().show(this.directionSignalFragment).commit(); this.directionSignalFragment.setNodeCross(this.selectedNode, 10); } } } else { if (this.directionNaviSignalFragment.isVisible()) { //this.fragmentManager.beginTransaction().hide(this.directionNaviSignalFragment).commit(); this.directionNaviSignalFragment.setNodeCross(null, 10); } if (this.directionSignalFragment.isVisible()) { //this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); this.directionSignalFragment.setNodeCross(null, 10); } } } break; case R.id.menu_disp_cvib: this.dispCvibSignal = !this.dispCvibSignal; PrefManager.setDispAreaCross(this.context, this.dispCvibSignal); if (this.dispCvibSignal && this.directionNaviSignalFragment.isVisible() && !this.directionSignalFragment.isVisible()) { this.directionSignalFragment.setNodeCross(this.directionNaviSignalFragment.getNode(), this.directionNaviSignalFragment.getDirection()); this.fragmentManager.beginTransaction().show(this.directionSignalFragment).commit(); } if (!this.dispCvibSignal && this.directionSignalFragment.isVisible()) { this.directionSignalFragment.setNodeCross(this.directionNaviSignalFragment.getNode(), this.directionNaviSignalFragment.getDirection()); this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); } break; case R.id.menu_debug_mode: this.isDebugMode = !this.isDebugMode; mapUtils.setDebugMode(this.isDebugMode); mapUtils.drawBounds(null); if (!this.isDebugMode) { if (this.gpsTracking.getRequestNode() != null) { requestTopicMessage("x"); this.directionNaviSignalFragment.setNodeCross(null, 10); this.directionSignalFragment.setNodeCross(null, 10); } if (this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); } if (this.directionNaviSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionNaviSignalFragment).commit(); } } break; default: Log.e(TAG, "뭐가 클릭된거야?"); return false; } return true; }); // show icons on popup menu if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { popup.setForceShowIcon(true); } popup.setOnDismissListener(menu -> { binding.fabMenu.setImageResource(R.drawable.ic_action_menu); }); popup.show(); }); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { //https://developer.android.com/training/location/request-updates?hl=ko /*outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates); // ...*/ super.onSaveInstanceState(outState); } private void startNaviWebsocketClientService() { this.lastTopics = ""; // start service Intent intent = new Intent(this.context, NaviWebsocketClientService.class); startService(intent); // bind service Intent bindIntent = new Intent(this.context, NaviWebsocketClientService.class); bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE); // register receiver NaviWebsocketMessageListener naviClientMessageListener = new NaviWebsocketMessageListener(); IntentFilter messageFilter = new IntentFilter("com.websocket.content"); registerReceiver(naviClientMessageListener, messageFilter); NaviWebsocketEventListener naviClientEventListener = new NaviWebsocketEventListener(); IntentFilter eventFilter = new IntentFilter("com.websocket.event"); registerReceiver(naviClientEventListener, eventFilter); } //권한 받아오기 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (this.locationSource.onRequestPermissionsResult(requestCode, permissions, grantResults)) { if (!this.locationSource.isActivated()) { // 권한 거부됨 this.naverMap.setLocationTrackingMode(LocationTrackingMode.None); } else { this.naverMap.setLocationTrackingMode(LocationTrackingMode.Follow); } return; } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @SuppressLint("SetTextI18n") @UiThread @Override public void onMapReady(@NonNull @NotNull NaverMap naverMap) { this.naverMap = naverMap; this.cameraUpdateParams = new CameraUpdateParams(); this.mapUtils.setup(this.naverMap); // 네이버 맵에 locationSource 를 설정하면 위치 추적 기능을 사용 할 수 있다 this.naverMap.setLocationSource(this.locationSource); ActivityCompat.requestPermissions(this, this.permissions, LOCATION_PERMISSION_REQUEST_CODE); setMapContentPadding(); MainActivityUtils.initMap(this.naverMap); //TABS6(2560*1600). S105G(3040*1440) this.overlayResourceId = R.drawable.ic_car_red;//R.drawable.ic_navi_car_on;//TsiNaviApplication.getMapConfig().isNightMode() ? R.drawable.ic_navi_car_night_on : R.drawable.ic_navi_car_on; MainActivityUtils.initMapOverlay(this.naverMap, this.overlayResourceId, (1440 >= Math.min(this.width, this.height))); MainActivityUtils.setupMap(this.naverMap, this.trackingZoom); initNodeMarker(); setTrackingMode(true); // 도로교통공단 서울지부로 위치 이동(최초 기본 위치) //LatLng initialPosition = new LatLng(37.465913939690815, 127.04432631214559); /*CameraUpdate cameraUpdate = CameraUpdate.scrollTo(initialPosition); this.naverMap.moveCamera(cameraUpdate);*/ /*CameraPosition initialCameraPosition = new CameraPosition( initialPosition, // 위치 지정 this.trackingZoom, // 줌 레벨 this.tilt, // 기울임 각도 45 // 방향 ); this.naverMap.setCameraPosition(initialCameraPosition);*/ // 카메라의 움직임이 끝나 대기 상태가 되면 카메라 대기 이벤트가 발생합니다. // 카메라가 애니메이션 없이 움직일 때. 단, 사용자가 제스처로 지도를 움직이는 경우 // 제스처가 완전히 끝날 때까지(ACTION_UP이 발생할 때까지)는 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다. // 카메라 애니메이션이 완료될 때. 단, 카메라 애니메이션이 진행 중일 때 새로운 애니메이션이 발생하거나, // 기존 카메라 이동의 finishCallback() 또는 cancelCallback()으로 지정된 콜백 내에서 카메라 이동이 일어날 경우 // 연속적인 이동으로 간주되어 이벤트가 발생하지 않습니다. NaverMap.cancelTransitions()가 호출되어 카메라 애니메이션이 명시적으로 취소될 때. this.naverMap.addOnCameraIdleListener(() -> { if (!this.cameraInfo.equals(this.naverMap.getCameraPosition())) { this.mapUtils.initMap(); this.mapUtils.drawBounds(this.naverMap.getCameraPosition().target); } updateNodeMarker(); }); this.naverMap.addOnLocationChangeListener(location -> { //TODO Log.e(TAG, "LocationChangeListener"); /*LatLng coord = new LatLng(location); LocationOverlay locationOverlay = map.getLocationOverlay(); locationOverlay.setVisible(true); locationOverlay.setPosition(coord); locationOverlay.setBearing(location.getBearing()); map.moveCamera(CameraUpdate.scrollTo(coord));*/ this.moveByGps.set(false); this.currSpeed = location.hasSpeed() ? location.getSpeed() * 3.6F : 0.0F; // 속도 meter/sec ==> km/sec this.currBearing = location.hasBearing() ? location.getBearing() : -1; // 베어링 this.moveDist = this.lastLocation == null ? 0 : this.lastLocation.distanceTo(location); this.lastLocation = location; this.binding.tvSpeed.setText(String.valueOf((int)this.currSpeed)); // 속도값이 없거나 이동거리가 기준 이하이면 GPS 수신하지 않은것으로 처리한다. if (this.currSpeed <= 1 || this.moveDist <= 2) { this.naverMap.getLocationOverlay().setBearing(this.lastBearing); /*int disableResourceId = TsiNaviApplication.getMapConfig().isNightMode() ? R.drawable.ic_navi_car_night_off : R.drawable.ic_navi_car_off; if (overlayResourceId != disableResourceId) { this.naverMap.getLocationOverlay().setIcon(OverlayImage.fromResource(disableResourceId)); overlayResourceId = disableResourceId; }*/ //updateBounds(location); return; } /*int enabledResourceId = TsiNaviApplication.getMapConfig().isNightMode() ? R.drawable.ic_navi_car_night_on : R.drawable.ic_navi_car_on; if (overlayResourceId != enabledResourceId) { this.naverMap.getLocationOverlay().setIcon(OverlayImage.fromResource(enabledResourceId)); overlayResourceId = enabledResourceId; }*/ if (this.currBearing >= 0) { this.lastBearing = this.currBearing; } // GPS 이동한 것으로 판단. this.moveByGps.set(true); if (this.isTrackingMode) { CameraPosition gpsPosition = new CameraPosition( new LatLng(location.getLatitude(), location.getLongitude()), // 위치 지정 this.trackingZoom, // 줌 레벨 this.tilt, // 기울임 각도 this.lastBearing // 방향 ); this.naverMap.setCameraPosition(gpsPosition); } }); this.naverMap.addOnCameraChangeListener((reason, animated) -> { switch(reason) { case CameraUpdate.REASON_DEVELOPER: //REASON_DEVELOPER: 0, 개발자가 API를 호출해 카메라가 움직였음을 나타냅니다. 기본값입니다. break; case CameraUpdate.REASON_LOCATION: //REASON_LOCATION: -3, 위치 트래킹 기능으로 인해 카메라가 움직였음을 나타냅니다. break; case CameraUpdate.REASON_GESTURE: //REASON_GESTURE: -1, 사용자의 제스처로 인해 카메라가 움직였음을 나타냅니다. // == CameraUpdate.DEFAULT_ANIMATION_DURATION case CameraUpdate.REASON_CONTROL: //REASON_CONTROL: -2, 사용자의 버튼 선택으로 인해 카메라가 움직였음을 나타냅니다. setTrackingMode(false); break; } }); this.naverMap.setOnMapClickListener((point, coord) -> { if (this.infoWindow != null && this.infoWindow.isVisible()) { //마커클릭후에 지도클릭 이벤트가 먹기 때문에 여기서 처리하면 안된다.(마커클릭후에 true 리턴하면 된다) this.infoWindow.close(); } }); } private void updateBounds(Location location) { //if (location == null) return; if (location != null) { this.mapUtils.drawBounds(new LatLng(location.getLatitude(), location.getLongitude())); } else { this.mapUtils.drawBounds(this.naverMap.getCameraPosition().target); } } // 지도상에 표시되고있는 마커들 지도에서 삭제 private void freeActiveMarkers() { if (this.activeMarkers == null) { this.activeMarkers = new Vector<>(); return; } //TODO Log.e(TAG, "freeActiveMarkers: " + this.activeMarkers.size()); for (Marker activeMarker: this.activeMarkers) { activeMarker.setMap(null); } this.activeMarkers = new Vector<>(); } @SuppressLint("SetTextI18n") private void updateNodeMarkerInDrive(boolean trackingMode) { boolean isMovingByGps = this.moveByGps.getAndSet(false); //TODO Log.e(TAG, "updateNodeMarkerInDrive: " + trackingMode + ", " + isMovingByGps); //if (!trackingMode || !isMovingByGps) { if (!trackingMode && !this.isDebugMode) { //TODO Log.e(TAG, "isMovingByGps == false"); return; } /*if (this.naverMap.getCameraPosition().zoom != this.trackingZoom) { if (this.directionSignalFragment.isVisible()) { requestTopicMessage("x"); this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); } if (this.areaCrossFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.areaCrossFragment).commit(); } Log.e(TAG, "updateNodeMarkerInDrive: zoom: " + this.naverMap.getCameraPosition().zoom + ", " + this.trackingZoom); return; }*/ LatLngBounds carBounds = this.mapUtils.getCarBounds(); PointF carPos = this.mapUtils.getCarPosition(); //LatLng[] latLngBounds = this.mapUtils.getLatLngBounds(); //LatLng carLatLng = this.naverMap.getLocationOverlay().getPosition(); // 현재 차량위치 LatLng carLatLng = this.naverMap.getCameraPosition().target; // 현재 차량위치 //int signalDirectionCode = TsiNaviApplication.getDirection().getSignalDirectionCode(this.lastBearing == 0 ? this.naverMap.getCameraPosition().bearing : this.lastBearing); int signalDirectionCode = TsiNaviApplication.getDirection().getSignalDirectionCode(this.naverMap.getCameraPosition().bearing); if (signalDirectionCode == 0) { //TODO Log.e(TAG, "Direction Error: " + signalDirectionCode); return; } if (this.gpsTracking.getSignalDirCode() != signalDirectionCode) { //TODO Log.e(TAG, "Bearing different: " + this.gpsTracking.getSignalDirCode() + ", " + signalDirectionCode); this.gpsTracking.setSignalDirCode(signalDirectionCode); return; } this.gpsTracking.setSignalDirCode(signalDirectionCode); int calDirectionCode; //TODO String sLog = "--Dir: " + String.format("%3d", (int)this.lastBearing) + ", " + signalDirectionCode + ", " + String.format("%3d", (int)this.naverMap.getCameraPosition().bearing); // 진출입 노드에 대한 계산 double calBearing; double calDistance; double nearDistance = Float.MAX_VALUE; double crossDistance = Float.MAX_VALUE; NodeVo inCrossNode = null; NodeVo targetNode = null; NodeVo nearNode = null; Set inCrossNodeSet= new HashSet<>(); //TODO Log.e(TAG, "Boundary nodes: " + this.activeNodes.size() + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); boolean crossPassOffSignal = false; for (Map.Entry obj : this.activeNodes.entrySet()) { NodeVo node = obj.getValue(); PointF posNode = this.naverMap.getProjection().toScreenLocation(node.getLatLng()); Location.distanceBetween(carLatLng.latitude, carLatLng.longitude, node.getLatLng().latitude, node.getLatLng().longitude, this.resultDistance); calDistance = this.resultDistance[0]; calBearing = (this.resultDistance[1] < 0) ? (360 + this.resultDistance[1]) : this.resultDistance[1]; calDirectionCode = TsiNaviApplication.getDirection().getSignalDirectionCode(calBearing); //TODO Log.e(TAG, "calDirectionCode: " + calDirectionCode + ", " + node.getName()); if (carBounds.contains(node.getLatLng())) { // 노드 통과 영역에 포함 //TODO sLog += "\n-C: " + String.format("%3d, %d, %3d m, %s, %s", (int)calBearing, calDirectionCode, (int)calDistance, node.getDirCode(), node.getName()); if (calDistance < crossDistance) { inCrossNode = node; crossDistance = calDistance; //TODO sLog += "--Near"; } //TODO if (!node.isReal()) sLog += "--Dummy"; if (this.gpsTracking.getRequestNode() != null) { if (this.gpsTracking.getRequestNode().getNodeId() == node.getNodeId()) { if (posNode.y > carPos.y) { // 요청 신호정보가 존재하고 지금 요청 신호등을 지났으면 신호 정보 요청 취소 crossPassOffSignal = true; requestTopicMessage("x"); this.gpsTracking.setRequestNode(null); } } else { // 검지영역이 좁아서 검지역역내에 교차로가 2개 이상 검지되고 있는 경우 // 이전 요청 교차로가 현재 교차로가 아니면 요청을 취소한다. requestTopicMessage("x"); this.gpsTracking.setRequestNode(null); } } } if (this.mapUtils.contains((node.getLatLng()))) { // 진행방향 바운더리 영역내에 포함됨 //TODO sLog += "\n-N: " + String.format("%3d, %d, %3d m, %s, %s", (int)calBearing, calDirectionCode, (int)calDistance, node.getDirCode(), node.getName()); if (node.getInDirMap().contains(calDirectionCode)) { //TODO sLog += "--Match"; if (node.getInDirMap().contains(calDirectionCode) && calDistance < nearDistance) { nearNode = node; nearDistance = calDistance; //TODO sLog += "--Near"; } } //TODO if (!node.isReal()) sLog += "--Dummy"; } } if (inCrossNode != null) { // 노드를 통과 중이면 처리하는게 없다. 노드를 통과한 후에 처리하도록 한다. this.gpsTracking.setInCrossNode(inCrossNode); if (crossPassOffSignal) { // 요청 신호 정보 교차로를 지나서 요청 신호를 취소한 경우 // ====> 이부분 주석 처리하면 교차로 통과할 동안 신호정보 요청을 보내지 않는다. /* if (nearNode != null && nearNode.isReal()) { if (this.gpsTracking.getRequestNode() == null) { requestNodeSignal(nearNode.getNodeId(), signalDirectionCode); this.gpsTracking.setRequestNode(nearNode); } } */ } } else { // 노드를 통과하는 것이 아니라 도로를 주행 중인 상태 if (this.gpsTracking.getInCrossNode() != null) { // 노드를 빠져 나온 상태. 시작 노드 정보로 설정한다. this.gpsTracking.setStartNode(inCrossNode); // 노드를 빠져 나올때 근접 노드정보가 있을 경우와 없을 경우에 따라 처리 if (nearNode != null) { if (nearNode.isReal()) { if (this.gpsTracking.getRequestNode() == null || this.gpsTracking.getRequestNode().getNodeId() != nearNode.getId()) { requestNodeSignal(nearNode.getNodeId(), signalDirectionCode); this.gpsTracking.setRequestNode(nearNode); } } else { this.gpsTracking.setEndNode(nearNode); } } else { if (this.gpsTracking.getRequestNode() != null) { // 더이상 요청할 노드가 진행 방향에 존재하지 않는다. requestTopicMessage("x"); this.gpsTracking.setRequestNode(null); } } } else { // 도로 주행 if (nearNode != null) { // 진행방향에 표출할 노드가 존재하면 if (nearNode.isReal()) { if (this.gpsTracking.getRequestNode() == null || this.gpsTracking.getRequestNode().getNodeId() != nearNode.getId()) { requestNodeSignal(nearNode.getNodeId(), signalDirectionCode); this.gpsTracking.setRequestNode(nearNode); } } } else { // 진행방향에 노드가 존재하지 않음. if (this.gpsTracking.getRequestNode() != null) { requestTopicMessage("x"); this.gpsTracking.setRequestNode(null); } } } this.gpsTracking.setInCrossNode(null); } if (this.gpsTracking.getRequestNode() != null) { if (this.activeNodes.get(this.gpsTracking.getRequestNode().getNodeId()) == null) { // 요청 중인데 영역내에 없으면 취소 시킨다. requestTopicMessage("x"); this.gpsTracking.setRequestNode(null); } } //TODO this.binding.tvLog.setText(sLog); //TODO Log.e(TAG, sLog); } private void updateNodeMarker() { //Log.e(TAG, "updateNodeMarker: zoom: " + this.naverMap.getCameraPosition().zoom); updateBounds(null); int signalDirectionCode = TsiNaviApplication.getDirection().getSignalDirectionCode(this.naverMap.getCameraPosition().bearing); int runDirectionCode = TsiNaviApplication.getDirection().getSignal2RunDirection(signalDirectionCode); //TODO String sLog = "Bearing: " + (int)this.naverMap.getCameraPosition().bearing + ", " + signalDirectionCode + ", " + runDirectionCode + ", zoom:" + (int)this.naverMap.getCameraPosition().zoom; //TODO this.binding.tvLog.setText(sLog); Marker infoMarker = null; if (this.infoWindow != null) { infoMarker = this.infoWindow.getMarker(); } freeActiveMarkers(); // 메모리 관리를 위해 여기서 삭제해 준다. if (this.naverMap.getCameraPosition().zoom < 13) { /*if (this.isTrackingMode && this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); }*/ if (infoMarker != null) { this.infoWindow.close(); } return; } LatLngBounds bounds = this.naverMap.getCoveringBounds(); //LatLngBounds bounds = this.naverMap.getContentBounds(); ConcurrentHashMap activeNodes = new ConcurrentHashMap<>(); Vector activeMarkers = new Vector<>(); List nodes = MainActivityUtils.getBoundsNodes(this.dbQuery, bounds); if (nodes != null) { //TODO Log.e(TAG, "Bounds nodes: " + nodes.size() + " EA."); if (nodes.size() <= 300) { for (Long obj : nodes) { try { NodeVo node = TsiNaviApplication.getNodeMap().get(obj); if (node != null) { activeMarkers.add(node.getMarker()); activeNodes.put(node.getNodeId(), node); } } catch (Exception e) { Log.e(TAG, "updateNodeMarker: " + e.getMessage()); } } } } this.activeMarkers = activeMarkers; for (Marker activeMarker: this.activeMarkers) { if (!activeMarker.getTag().equals("x")) { activeMarker.setMap(this.naverMap); } } if (infoMarker != null) { this.infoWindow.open(infoMarker, Align.TopLeft); } if (this.isTrackingMode) { // 트래킹(드라이빙) 모드이고 조건을 만족할 경우 this.activeNodes = activeNodes; updateNodeMarkerInDrive(true); } else { // 사용자 움직임인 경우 바운더리 계산해서 영역을 다시 찾은 다음 영역에 속한 // 교차로 정보를 다시 조회해서 처리해야함 this.activeNodes = activeNodes; updateNodeMarkerInDrive(false); } } private void requestNodeSignal(long nodeId, int directionCode) { if (!this.isTrackingMode) { //return; } NodeVo node = TsiNaviApplication.getNodeMap().get(nodeId); //if (node == null) return; setRequestNode(node); this.userSignalFragment.setNodeCross(null); this.directionNaviSignalFragment.setNodeCross(node, directionCode); this.directionSignalFragment.setNodeCross(node, directionCode); requestTopicMessage(String.valueOf(nodeId)); if (this.dispCvibSignal && !this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().show(this.directionSignalFragment).commit(); } if (!this.directionNaviSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().show(this.directionNaviSignalFragment).commit(); } if (userSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.userSignalFragment).commit(); } } private void setSelectedNode(NodeVo node) { this.gpsTracking.setRequestNode(null); if (this.selectedNode != null) { // 이전 선택한 아이콘은 기본 아이콘으로 변경 this.selectedNode.marker.setIcon(OverlayImage.fromResource(R.drawable.ic_cross_normal)); } if (this.infoWindow != null && this.infoWindow.isVisible()) { // 이전 인포 윈도우 닫음 this.infoWindow.close(); } this.selectedNode = node; if (this.selectedNode != null) { // 선택한 아이콘은 선택 아이콘으로 변경 this.selectedNode.marker.setIcon(OverlayImage.fromResource(R.drawable.ic_cross_select)); // 선택한 아이콘의 인포 윈도우 오픈 this.infoWindow.open(this.selectedNode.marker, Align.TopLeft); } } private void setRequestNode(NodeVo node) { this.selectedNode = null; if (this.gpsTracking.getRequestNode() != null) { // 이전 선택한 아이콘은 기본 아이콘으로 변경 this.gpsTracking.getRequestNode().marker.setIcon(OverlayImage.fromResource(R.drawable.ic_cross_normal)); } if (this.infoWindow != null && this.infoWindow.isVisible()) { // 이전 인포 윈도우 닫음 this.infoWindow.close(); } this.gpsTracking.setRequestNode(node) ; if (this.gpsTracking.getRequestNode() != null) { // 선택한 아이콘은 선택 아이콘으로 변경 this.gpsTracking.getRequestNode().marker.setIcon(OverlayImage.fromResource(R.drawable.ic_cross_select)); // 선택한 아이콘의 인포 윈도우 오픈 this.infoWindow.open(this.gpsTracking.getRequestNode().marker, Align.TopLeft); } } private void setTrackingMode(boolean trackingMode) { if (!this.isTrackingMode && trackingMode) { requestTopicMessage("x"); this.moveByGps.set(true); } if (this.isTrackingMode && !trackingMode) { this.gpsTracking.init(); } this.isTrackingMode = trackingMode; if (trackingMode) { if (this.naverMap.getLocationTrackingMode() != LocationTrackingMode.Follow) { this.naverMap.setLocationTrackingMode(LocationTrackingMode.Follow); // Tracking Mode 설정 //binding.tvLog.setText("Follow"); /*this.cameraUpdateParams//.scrollTo(this.cameraPosition.target) .zoomTo(this.trackingZoom) .rotateTo(this.lastBearing).tiltTo(this.tilt); this.naverMap.moveCamera(CameraUpdate.withParams(this.cameraUpdateParams));*/ } this.cameraUpdateParams//.scrollTo(this.cameraPosition.target) .zoomTo(this.trackingZoom) .rotateTo(this.lastBearing).tiltTo(this.tilt); this.naverMap.moveCamera(CameraUpdate.withParams(this.cameraUpdateParams)); if (this.naverMap.getUiSettings().isZoomControlEnabled()) { this.naverMap.getUiSettings().setZoomControlEnabled(false); } if (this.binding.tvSpeed.getVisibility() == View.INVISIBLE) { this.binding.tvSpeed.setVisibility(View.VISIBLE); } if (this.lastLocation != null) { CameraPosition initialCameraPosition = new CameraPosition( new LatLng(this.lastLocation.getLatitude(), this.lastLocation.getLongitude()), // 위치 지정 this.trackingZoom, // 줌 레벨 this.tilt, // 기울임 각도 this.lastBearing // 방향 ); this.naverMap.setCameraPosition(initialCameraPosition); } if (View.VISIBLE == this.binding.fabSetCurrent.getVisibility()) { this.binding.fabSetCurrent.setVisibility(View.INVISIBLE); } if (this.infoWindow != null && this.infoWindow.isVisible()) { //마커클릭후에 지도클릭 이벤트가 먹기 때문에 여기서 처리하면 안된다. this.infoWindow.close(); } } else { if (this.naverMap.getLocationTrackingMode() != LocationTrackingMode.NoFollow) { this.naverMap.setLocationTrackingMode(LocationTrackingMode.NoFollow); this.cameraUpdateParams//.scrollTo(this.cameraPosition.target) .zoomTo(this.trackingZoom) .rotateTo(0).tiltTo(this.tilt); this.naverMap.moveCamera(CameraUpdate.withParams(this.cameraUpdateParams)); } if (!this.naverMap.getUiSettings().isZoomControlEnabled()) { this.naverMap.getUiSettings().setZoomControlEnabled(true); } if (this.binding.tvSpeed.getVisibility() == View.VISIBLE) { this.binding.tvSpeed.setVisibility(View.INVISIBLE); } if (View.VISIBLE != this.binding.fabSetCurrent.getVisibility()) { this.binding.fabSetCurrent.setVisibility(View.VISIBLE); } if (!this.userSignalFragment.isVisible()) { if (this.selectedNode != null) this.fragmentManager.beginTransaction().show(this.userSignalFragment).commit(); } if (this.dispAllSignal) { if (!this.directionNaviSignalFragment.isVisible()) { //TODO Log.e(TAG, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: " + this.selectedNode); if (this.selectedNode != null) this.fragmentManager.beginTransaction().show(this.directionNaviSignalFragment).commit(); } if (this.dispCvibSignal && !this.directionSignalFragment.isVisible()) { //TODO Log.e(TAG, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: " + this.selectedNode); if (this.selectedNode != null) this.fragmentManager.beginTransaction().show(this.directionSignalFragment).commit(); } } else { if (this.directionNaviSignalFragment.isVisible()) { //this.fragmentManager.beginTransaction().hide(this.directionNaviSignalFragment).commit(); } if (this.directionSignalFragment.isVisible()) { //this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); } } } } private void requestSelectedNode() { if (this.selectedNode != null) { this.naverMap.moveCamera(CameraUpdate.scrollTo(this.selectedNode.getLatLng())); this.userSignalFragment.setNodeCross(this.selectedNode); this.directionNaviSignalFragment.setNodeCross(this.selectedNode, 10); this.directionSignalFragment.setNodeCross(this.selectedNode, 10); requestTopicMessage(String.valueOf(this.selectedNode.getNodeId())); } } private void initNodeMarker() { // 인포 윈도우 생성 this.infoWindow = new InfoWindow(); this.infoWindow.setAnchor(new PointF(0, 1)); this.infoWindow.setOffsetX(getResources().getDimensionPixelSize(R.dimen.marker_info_window_offset_x)); this.infoWindow.setOffsetY(getResources().getDimensionPixelSize(R.dimen.marker_info_window_offset_y)); this.infoWindow.setAdapter(new InfoWindowAdapter(this)); this.infoWindow.setOnClickListener(overlay -> { if (this.selectedNode != null) { if (!this.isTrackingMode) { setTrackingMode(false); requestSelectedNode(); } } else { this.infoWindow.close(); } return true; }); // 교차로 마커 생성 for (Map.Entry obj : TsiNaviApplication.getNodeMap().entrySet()) { NodeVo node = obj.getValue(); //node.marker = MainActivityUtils.createNodeMarker(this.naverMap, node, R.drawable.ic_cross_normal, R.drawable.ic_node_small); node.marker = MainActivityUtils.createNodeMarker(null, node, R.drawable.ic_cross_normal, R.drawable.ic_node_small); if (node.isReal()) { node.marker.setOnClickListener(overlay -> { setSelectedNode(node); return true; // false 리턴하면 마커클릭 후에 지도 클릭 이벤트가 동시에 발생한다. }); } } } @Override protected void onDestroy() { super.onDestroy(); if (this.locationSource.isActivated()) { this.locationSource.deactivate(); } if (this.naviClientService.getNaviWebsocketClient().isOpen()) { this.naviClientService.getNaviWebsocketClient().close(); } this.dbQuery.close(); } @Override public void onBackPressed() { if (this.userSignalFragment.isVisible() || ( !this.isTrackingMode && this.directionSignalFragment.isVisible() || !this.isTrackingMode && this.directionSignalFragment.isVisible() ) ) { requestTopicMessage("x"); return; } /*if (this.directionSignalFragment.isVisible()) { this.fragmentManager.beginTransaction().hide(this.directionSignalFragment).commit(); setTrackingMode(true); requestTopicMessage("x"); return; }*/ this.backPressedForFinish.onBackPressed(true); } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); /*if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); }*/ setMapContentPadding(); } private void setMapContentPadding() { WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); Rect rc = wm.getCurrentWindowMetrics().getBounds(); float lWidth = rc.width(); float lHeight = rc.height(); /*@SuppressLint("WrongViewCast") FrameLayout frameMap = (FrameLayout) this.binding.getRoot().findViewById(R.id.map); if (frameMap != null) { this.width = frameMap.getWidth(); this.height = frameMap.getHeight(); Log.e(TAG, "width: " + this.width + ", height: " + this.height); }*/ //TODO Log.e(TAG, "RECT: " + rc.width() + ", " + rc.height()); float lCarX = lWidth / 2; float lCarY = (lHeight / 3) * 2; if (this.naverMap != null) { int padding = (int) (lHeight / 2); //TODO Log.e(TAG, "Rect: " + rc.toString()); //TODO Log.e(TAG, "Padding: " + padding); this.naverMap.setContentPadding(0, 0, 0, -padding); //this.naverMap.setContentPadding(100, 100, 100, 100); lCarX = (float)(this.naverMap.getContentWidth() / 2); lCarY = (float)(this.naverMap.getContentHeight() / 2); if (this.isTrackingMode) { if (this.lastLocation != null) { CameraPosition gpsPosition = new CameraPosition( new LatLng(this.lastLocation.getLatitude(), this.lastLocation.getLongitude()), // 위치 지정 this.trackingZoom, // 줌 레벨 this.tilt, // 기울임 각도 this.lastBearing // 방향 ); this.naverMap.setCameraPosition(gpsPosition); } } else { naverMap.moveCamera(CameraUpdate.scrollTo(this.naverMap.getCameraPosition().target)); } } this.width = lWidth; this.height = lHeight; this.carX = lCarX; this.carY = lCarY; this.moveByGps.set(true); } }