I've recently taken an interest in Android applications and I have been working on an app regarding the travelling salesman problem. My app is a kind of a trip optimizer which is meant for travelers, so that they can optionally choose a starting point and a destination/multiple destinations. Right now the app works fine.
I want to reduce/shorten this class quite a lot. if you see that a method /methods can be reduced or even erased please do not hesitate to suggest that. Any answer that rescue the class would be great :)
public class MSA extends NSA implements SRF.saveRouteDialogListener,
OnMapReadyCallback, OnCameraChangeListener, OnStreetViewPanoramaReadyCallback, OnStreetViewPanoramaChangeListener,
ConnectionCallbacks, OnStreetViewPanoramaCameraChangeListener, StreetViewPanorama.OnStreetViewPanoramaClickListener,
OnMapClickListener, OnPolylineClickListener, LocationListener, OnConnectionFailedListener, GoogleMap.OnMapLoadedCallback,
GoogleMap.OnMarkerClickListener, RadioGroup.OnCheckedChangeListener {
private GoogleMap m_routeMap;
private LocationRequest locationRequest;
private StreetViewPanorama streetViewPanorama;
private SupportStreetViewPanoramaFragment streetViewPanoramaFragment;
private int nof = 0;
private List<String> list;
private Marker[] markers;
private int markerIndex = 0;
private String rN;
private String mode = "driving";
private MC objController = new MC();
private LinkedList<List<LatLng>> listPolylines = new LinkedList<>();
private LinkedList<Polyline> polyLines = new LinkedList<>();
private SI m_objSearchInputs;
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
int index = 0;
private TextView textView;
private boolean viewPolylineInfo = false;
private int polyLineID = -1;
Location myLocation = null;
private float bearing = 0;
private int currentPositionIndex = 0;
private boolean playSubroute = false;
private boolean reset = false;
private int polyLineIdIndex = 0;
private boolean playRoute = false;
private boolean waypoint = false;
private int SV_current_index = 0;
private float bearingSV;
private boolean bearingFinished = false;
boolean showStreetView = false;
boolean polyLinesDrawn = false;
TextView currentLL;
TextView currentB;
TextView distanceTo;
TextView bearingTo;
Button beginRoute;
boolean following = false;
int bearingToPoint;
int distanceToPoint;
int polylineIndex = 0;
int pointIndex = 0;
LatLng currentLatLng;
float currentBearing;
CheckBox checkBox;
private HashMap<Integer, Integer> markerIndexToPolylineIndex = new HashMap<>();
boolean markerClicked = false;
private HashMap<Integer, Boolean> subrouteMarked = new HashMap<>();
private RadioGroup rgroup;
private List<String> routeInfoTexts = new ArrayList<>();
private boolean clearRB = false;
private LinearLayout navigationButtonBar;
private Button showTextInfo;
private Button showStreetViewButton;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLayoutInflater().inflate(R.layout.activity_map_screen, mContentLayout);
Bundle extras = getIntent().getExtras();
if(extras != null) {
m_objSearchInputs = extras.getParcelable("user_search_inputs");
list = m_objSearchInputs.m_DestinationList;
markers = new Marker[list.size()];
String commute = m_objSearchInputs.cM.toString();
ImageButton button = null;
if(commute.equals("WALK")) {
button = (ImageButton)findViewById(R.id.btnByWalk);
mode = "walking";
}
else if(commute.equals("CAR")) {
button = (ImageButton)findViewById(R.id.btnByCar);
mode = "driving";
}
objController.setMode(mode);
if(button != null) {
button.setBackgroundColor(Color.GREEN);
}
System.out.println("Go back and forth: "+m_objSearchInputs.cM.toString());
}
setInputsForSearch();
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.routeMapFragment);
mapFragment.getMapAsync(this);
rgroup = (RadioGroup)findViewById(R.id.rgroup);
rgroup.setOnCheckedChangeListener(this);
navigationButtonBar = (LinearLayout) findViewById(R.id.navigationButtonBar);
beginRoute = (Button) findViewById(R.id.btnStartNavigation);
beginRoute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int size = polyLines.get(polyLineID).getPoints().size();
LatLng latLng = polyLines.get(polyLineID).getPoints().get(size - 1);
double lat = latLng.latitude;
double lon = latLng.longitude;
String m = null;
if (mode.equals("driving")) m = "h";
if (mode.equals("walking")) m = "p";
String uri = String.format(Locale.ENGLISH, "google.navigation:q=%f,%f&mode=%s", lat, lon, m);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
}
});
textView = (TextView) findViewById(R.id.polylineInfo);
textView.setMovementMethod(new ScrollingMovementMethod());
showTextInfo = (Button)findViewById(R.id.routeInfoText);
locationRequest = new LocationRequest();
locationRequest.setInterval(1000);
locationRequest.setFastestInterval(200);
streetViewPanoramaFragment = (SupportStreetViewPanoramaFragment) getSupportFragmentManager().findFragmentById(R.id.streetviewFragment);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
@Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
streetViewPanorama = panorama;
streetViewPanorama.setOnStreetViewPanoramaChangeListener(MSA.this);
streetViewPanorama.setOnStreetViewPanoramaCameraChangeListener(MSA.this);
streetViewPanorama.setOnStreetViewPanoramaClickListener(MSA.this);
if (savedInstanceState == null) {
streetViewPanorama.setPosition(SYDNEY);
}
}
});
hideSV();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_map_screen, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return super.onOptionsItemSelected(item);
}
private void displaySaveRouteDialog() {
FragmentManager fm = getSupportFragmentManager();
SRF frag = new SRF();
frag.show(fm, "fragment_save_route");
}
@Override
public void onFinishInputDialog(String strRouteName) {
}
@Override
public void onMapReady(GoogleMap googleMap) {
m_routeMap = googleMap;
m_routeMap.setBuildingsEnabled(true);
m_routeMap.setOnMapClickListener(this);
m_routeMap.setOnPolylineClickListener(this);
m_routeMap.setOnCameraChangeListener(this);
m_routeMap.setOnMapLoadedCallback(this);
m_routeMap.setOnMarkerClickListener(this);
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
System.out.println("MY LOCATION ENABLED");
m_routeMap.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
List<String> providers = locationManager.getProviders(true);
for(String prv: providers) {
System.out.println("| " + prv);
myLocation = locationManager.getLastKnownLocation(prv);
if(myLocation != null) {
System.out.println("MYLOCATION: " + myLocation);
break;
}
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, this);
}
int i = 0;
for(String location: list) {
List<Address> addresses = null;
Geocoder geocoder = new Geocoder(this);
try{
if(location.equals("CURRENT_LOCATION")) {
addresses = geocoder.getFromLocation(myLocation.getLatitude(), myLocation.getLongitude(), 1);
String lat = myLocation.getLatitude()+"";
String lon = myLocation.getLongitude()+"";
list.set(i, new String(lat + "," + lon));
} else {
addresses = geocoder.getFromLocationName(location, 1);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
if(addresses != null) {
Address address = addresses.get(0);
LatLng latLng = new LatLng(address.getLatitude(), address.getLongitude());
markers[i++] = m_routeMap.addMarker(new MarkerOptions().position(latLng).title(location));
}
}
System.out.println("Current Location is : " + myLocation);
startCalculateThread();
}
@Override
public void onMapLoaded() {
onProceed();
showAllPolyLines();
loadRadioButtons();
}
private void loadRadioButtons() {
for(String routeInfo: routeInfoTexts) {
RadioButton rb = new RadioButton(this);
rb.setText(routeInfo);
rgroup.addView(rb);
}
}
@Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
long duration = 20;
float tilt = 30;
float bearing = 90;
StreetViewPanoramaCamera camera = new StreetViewPanoramaCamera.Builder()
.zoom(panorama.getPanoramaCamera().zoom)
.bearing(bearing)
.tilt(tilt)
.build();
panorama.setPosition(new LatLng(52.208818, 0.090587));
panorama.setStreetNamesEnabled(false);
panorama.setZoomGesturesEnabled(false);
panorama.animateTo(camera, duration);
}
@Override
public void onMapClick(LatLng point) {
if(viewPolylineInfo) {
viewPolylineInfo = false;
}
for(Polyline p: polyLines) {
p.setColor(Color.BLACK);
p.setVisible(true);
}
if(markerClicked) markerClicked = false;
clearRB = true;
navigationButtonBar.setVisibility(View.INVISIBLE);
rgroup.clearCheck();
}
@Override
public void onPolylineClick(Polyline polyline) {
int id = Integer.parseInt(polyline.getId().substring(2,3));
String[] html_instructions = objController.getHTML(id);
System.out.println("\nROUTE INSTRUCTION: ");
String message = "";
for(String html_route: html_instructions){
html_route = html_route.replaceAll( "<[^>]*>", "" );
System.out.println(html_route);
message += "-" + html_route + "\n";
}
System.out.println("\n");
if(viewPolylineInfo) {
if(id != polyLineID) {
for(Polyline p: polyLines) {
p.setColor(Color.BLACK);
}
polyline.setColor(Color.CYAN);
textView.setText(message);
} else {
for(Polyline p: polyLines) {
p.setColor(Color.BLACK);
}
viewPolylineInfo = false;
textView.setVisibility(View.INVISIBLE);
beginRoute.setVisibility(View.INVISIBLE);
checkBox.setVisibility(View.INVISIBLE);
}
} else {
textView.setVisibility(View.VISIBLE);
textView.setText(message);
polyline.setColor(Color.CYAN);
viewPolylineInfo = true;
if(id == 0 || (id > 0 && subrouteMarked.get(id-1))) {
beginRoute.setVisibility(View.VISIBLE);
checkBox.performClick();
checkBox.setVisibility(View.VISIBLE);
}
}
polyLineID = id;
}
public void viewPolylineInfo(View view){
Button b = (Button) view;
if(viewPolylineInfo) {
viewPolylineInfo = false;
b.setTextColor(Color.BLUE);
viewPolylineInfo = false;
textView.setVisibility(View.INVISIBLE);
} else {
viewPolylineInfo = true;
String[] html_instructions = objController.getHTML(polyLineID);
System.out.println("\nROUTE INSTRUCTION: ");
String message = "";
for(String html_route: html_instructions){
html_route = html_route.replaceAll( "<[^>]*>", "" );
System.out.println(html_route);
message+="-"+html_route+"\n";
}
System.out.println("\n");
b.setTextColor(Color.YELLOW);
textView.setVisibility(View.VISIBLE);
textView.setText(message);
}
}
public void onShowStreetView(View view) {
if(showStreetView){
showStreetView = false;
hideSV();
}
else{
showStreetView = true;
showSV();
}
}
private void showSV() {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.show(streetViewPanoramaFragment)
.commit();
}
private void hideSV() {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.hide(streetViewPanoramaFragment)
.commit();
}
public void onPlayRoute(View view) {
polyLineID = polyLineIdIndex;
Button button = (Button)view;
if(playRoute){
button.setText(">>");
playRoute = false;
reset = true;
} else {
streetViewPanorama.setPosition(polyLines.get(0).getPoints().get(0));
button.setText("||");
playRoute = true;
try {
Thread.sleep(1000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
animateRoute();
}
}
private void animateRoute() {
}
private void animateStreetView() {
long duration = 500;
float tilt = 0;
LatLng from = polyLines.get(0).getPoints().get(SV_current_index);
LatLng to = polyLines.get(0).getPoints().get(SV_current_index+1);
StreetViewPanoramaCamera streetViewPanoramaCamera = new StreetViewPanoramaCamera.Builder()
.zoom(streetViewPanorama.getPanoramaCamera().zoom)
.bearing(bearingSV)
.tilt(tilt)
.build();
streetViewPanorama.animateTo(streetViewPanoramaCamera, duration);
streetViewPanorama.setPosition(to);
}
private void zoomOut(LatLng target) {
CameraPosition cP = new CameraPosition.Builder()
.target(target)
.zoom(17)
.bearing(90)
.tilt(30)
.build();
currentPositionIndex = 0;
m_routeMap.animateCamera(CameraUpdateFactory.newCameraPosition(cP));
}
private void showAllMarkers() {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for(Marker marker: markers) {
builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 50);
m_routeMap.animateCamera(cu);
}
private void showAllPolyLines() {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for(Polyline polyline: polyLines) {
List<LatLng> latLngs = polyline.getPoints();
for(LatLng latLng: latLngs) {
builder.include(latLng);
}
}
LatLngBounds bounds = builder.build();
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 170);
m_routeMap.animateCamera(cu);
}
@Override
public void onCameraChange(CameraPosition cP) {
if(playSubroute || playRoute) {
if(waypoint) {
waypoint = false;
polyLineID++;
if(polyLineID == polyLines.size()) {
playRoute = false;
polyLineID = 0;
showAllMarkers();
}
else
animateRoute();
}
else
animateRoute();
}
else{
if(reset) {
reset = false;
zoomOut(cP.target);
}
}
}
@Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation streetViewPanoramaLocation) {
if(SV_current_index < 10 && playRoute) {
SV_current_index++;
System.out.println(SV_current_index);
try{
Thread.sleep(1000);
} catch (InterruptedException ie){
ie.printStackTrace();
}
animateStreetView();
}
}
@Override
public void onStreetViewPanoramaClick(StreetViewPanoramaOrientation orientation) {
Point point = streetViewPanorama.orientationToPoint(orientation);
System.out.println("CLICK: " + point.toString());
streetViewPanorama.animateTo(
new StreetViewPanoramaCamera.Builder()
.orientation(orientation)
.zoom(streetViewPanorama.getPanoramaCamera().zoom)
.build(), 1000);
}
@Override
public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera streetViewPanoramaCamera) {
System.out.println("CAMERA CHANGE: "+streetViewPanoramaCamera.bearing);
if((int)(360 + bearingSV) == (int)streetViewPanoramaCamera.bearing && !bearingFinished) {
bearingFinished = true;
animateStreetView();
}
}
@Override
public void onLocationChanged(Location location) {
currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
currentBearing = location.getBearing();
currentLL.setText("Current LatLng: "+currentLatLng.latitude+","+currentLatLng.longitude);
currentB.setText("Current Bearing: "+(int)currentBearing);
if(myLocation == null) {
System.out.println("FIRST TIME CHANGED");
}
System.out.println("LOCATION CHANGED: " + location.toString());
if(polyLinesDrawn) {
LatLng latLng = polyLines.get(polylineIndex).getPoints().get(pointIndex);
float[] result = new float[3];
Location.distanceBetween(location.getLatitude(), location.getLongitude(), latLng.latitude, latLng.longitude, result);
if(result.length > 0){
distanceToPoint = (int)result[0];
if(result.length > 1){
bearingToPoint = (result[1] < 0) ? (int)(360 + result[1]) : (int)result[1];
bearingTo.setText("Bearing: "+bearingToPoint);
}
distanceTo.setText("Distance: "+distanceToPoint+" m");
}
}
if(following) {
CameraPosition cP = new CameraPosition.Builder()
.target(currentLatLng)
.zoom(19)
.bearing(bearing)
.tilt(67)
.build();
m_routeMap.animateCamera(CameraUpdateFactory.newCameraPosition(cP));
if(distanceToPoint < 5) {
pointIndex++;
}
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
System.out.println("STATUS CHANGED");
}
@Override
public void onProviderEnabled(String provider) {
System.out.println("PROVIDER " + provider + " ENABLED");
}
@Override
public void onProviderDisabled(String provider) {
System.out.println("PROVIDER " + provider + " DISABLED");
}
@Override
public void onConnected(Bundle bundle) {
if ( ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
}
}
@Override
public void onConnectionSuspended(int i) {}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {}
@Override
public boolean onMarkerClick(Marker marker) {
if(!markerClicked) {
int id = 0;
System.out.println(marker.getId());
System.out.println(marker.getTitle());
for (int i = 0; i < markers.length; i++) {
if (markers[i].getId().equals(marker.getId())) {
id = i;
}
}
int polyLineIndex = markerIndexToPolylineIndex.get(id);
for (int i = 0; i < polyLines.size(); i++) {
if (i != polyLineIndex) {
polyLines.get(i).setVisible(false);
polyLines.get(i).setClickable(false);
}
}
markerClicked = true;
}
return false;
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(clearRB){
if(checkedId == -1){
clearRB = false;
}
}
else{
navigationButtonBar.setVisibility(View.VISIBLE);
if(checkedId != -1){
polyLineID = checkedId - 1;
for (int i = 0; i < polyLines.size(); i++) {
if (i != polyLineID) {
polyLines.get(i).setVisible(false);
polyLines.get(i).setColor(Color.BLACK);
} else {
polyLines.get(i).setColor(Color.BLUE);
polyLines.get(i).setVisible(true);
}
}
}
showAllMarkers();
}
}
private class calculateThread extends Thread {
public calculateThread(){}
@Override
public void run(){
int count = 0;
routeInfoTexts.clear();
int[][] optimizedRoute = objController.calculateTimeResult();
for(String s: list){
System.out.println("LIST: "+s);
}
for(int[] partRoute: optimizedRoute) {
int fromIndex = partRoute[0];
int toIndex = partRoute[1];
if(fromIndex == toIndex) {
break;
}
markerIndexToPolylineIndex.put(toIndex, count);
subrouteMarked.put(count, false);
System.out.println("F: "+fromIndex + " T: "+toIndex);
String origin = list.get(fromIndex);
String destination = list.get(toIndex);
System.out.println(origin+" -> "+destination);
objController.setDirectionOrigin(origin);
objController.setDirectionDestination(destination);
String polyLine = objController.fetchPolyLine();
if(polyLine.equals("NO ROUTE")){
Toast.makeText(getApplicationContext(), "Mode not supported", Toast.LENGTH_LONG).show();
System.out.println("ERROR: "+ polyLine);
count++;
if(count == nof){
break;
}
continue;
}
List<LatLng> listPolyLine = objController.decodePoly(polyLine);
listPolylines.addLast(listPolyLine);
count++;
if(count == nof){
break;
}
}
}
}
private void setInputsForSearch() {
objController.setListMatrix(list);
}
private void onProceed() {
index = 0;
markerIndex = 0;
int colorValue;
int width;
colorValue = Color.YELLOW;
width = 20;
System.out.println("SIZE: " + listPolylines.size());
for(int i = 0; i < listPolylines.size(); i++) {
Polyline p = m_routeMap.addPolyline(new PolylineOptions().addAll(listPolylines.get(i)).width(22).color(Color.parseColor("#aab1ff")).geodesic(true).clickable(true));
polyLines.add(p);
}
polyLinesDrawn = true;
}
private void clearPolyLines() {
for(Polyline p: polyLines){
p.remove();
}
polyLines.clear();
listPolylines.clear();
}
private void startCalculateThread() {
Thread thread = new calculateThread();
thread.start();
try{
thread.join();
} catch (InterruptedException ie){
ie.printStackTrace();
}
}
public void traceRouteByMode(View v) {
clearPolyLines();
ImageButton b1 = (ImageButton) findViewById(R.id.btnByWalk);
ImageButton b2 = (ImageButton) findViewById(R.id.btnByCar);
b1.setBackgroundColor(ContextCompat.getColor(getBaseContext(), R.color.primary));
b2.setBackgroundColor(ContextCompat.getColor(getBaseContext(), R.color.primary));
ImageButton button = (ImageButton) v;
button.setBackgroundColor(Color.YELLOW);
if(v.getId() == R.id.btnByWalk) {
mode = "walking";
} else if(v.getId() == R.id.btnByCar) {
mode = "driving";
}
objController.setMode(mode);
markerIndexToPolylineIndex.clear();
startCalculateThread();
for(int i = 0 ; i < routeInfoTexts.size(); i++){
RadioButton radioButton = (RadioButton)rgroup.getChildAt(i);
radioButton.setText(routeInfoTexts.get(i));
}
rgroup.clearCheck();
onProceed();
}
}