Java tutorial
package net.konyan.yangonbusonthemap; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; import com.cocoahero.android.geojson.Feature; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.MapsInitializer; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.Circle; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.maps.android.geojson.GeoJsonLayer; import com.marcoscg.easylicensesdialog.EasyLicensesDialogCompat; import net.konyan.yangonbusonthemap.adapter.BusesAdapter; import net.konyan.yangonbusonthemap.model.BusStop; import net.konyan.yangonbusonthemap.util.MyPref; import net.konyan.yangonbusonthemap.util.ObservableUtil; import net.konyan.yangonbusonthemap.util.Util; import org.json.JSONException; import org.rabbitconverter.rabbit.Rabbit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; public class HomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, OnMapReadyCallback, GoogleMap.OnMapClickListener, GoogleMap.OnMarkerClickListener, GoogleMap.OnCameraIdleListener { private final String LOG_TAG = HomeActivity.class.getSimpleName(); public static final int LANGUAGE_EN = 0x0aa; public static final int LANGUAGE_MM = 0x0bb; public static final int LANGUAGE_ZG = 0x0cc; private int language; public static final String KEY_LANGUAGE = "language"; //private final float BUS_STOP_FOUND_ZOOM = 14.5f; private final float BUS_STOP_VISIABLE_ZOOM = 14.5f; private final float DEFAULT_ZOOM = 13.8f; private final float BUS_ROUTE_ZOOM = 11.5f; //private final LatLng YANGON = new LatLng(16.8661, 96.1951); private final LatLng YANGON_SDG = new LatLng(16.798308, 96.1496143); //sdg 16.798308,96.1496143 private BottomSheetBehavior mBottomSheetBehavior; private View bottomSheet; private TextView tvBusName, tvRoadName; private RecyclerView busRecycler; private ProgressBar progressHome; private GoogleMap googleMap; private List<BusStop> allBusStops; private GeoJsonLayer layerLine; private Circle circle; private List<Marker> selectedMarkers; private List<Marker> nearByMarkers; private List<Marker> busRouteMarkers; private int currentSelectBus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); progressHome = (ProgressBar) findViewById(R.id.progress_home); language = MyPref.getInt(KEY_LANGUAGE, LANGUAGE_EN); initData(); initUi(savedInstanceState); initBanner(); } //ads public void initBanner() { AdView mAdView = (AdView) findViewById(R.id.adView_banner); AdRequest adRequest = new AdRequest.Builder() //.addTestDevice(Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID)) .build(); mAdView.loadAd(adRequest); } //initialize private void initUi(Bundle saveState) { ImageView ivMenu = (ImageView) findViewById(R.id.iv_action_menu); ivMenu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.openDrawer(GravityCompat.START); } }); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); initBottomSheet(); View view = navigationView.getHeaderView(0); RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.rg_language); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { switch (i) { case R.id.nav_radio_lan_en: language = LANGUAGE_EN; MyPref.putInt(KEY_LANGUAGE, LANGUAGE_EN); break; case R.id.nav_radio_lan_mm: language = LANGUAGE_MM; MyPref.putInt(KEY_LANGUAGE, LANGUAGE_MM); break; case R.id.nav_radio_lan_zg: language = LANGUAGE_ZG; MyPref.putInt(KEY_LANGUAGE, LANGUAGE_ZG); break; } initData(); if (nearByMarkers != null) { clearMarkers(nearByMarkers, null); } if (layerLine != null) { layerLine.removeLayerFromMap(); } if (busRouteMarkers != null) { clearMarkers(busRouteMarkers, null); currentSelectBus = -1; } mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); } }); switch (language) { case LANGUAGE_EN: ((RadioButton) view.findViewById(R.id.nav_radio_lan_en)).setChecked(true); break; case LANGUAGE_MM: ((RadioButton) view.findViewById(R.id.nav_radio_lan_mm)).setChecked(true); break; case LANGUAGE_ZG: ((RadioButton) view.findViewById(R.id.nav_radio_lan_zg)).setChecked(true); break; } if (saveState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.content_home, YangonMapFragment.newInstance(null, null)).commit(); } } private void initData() { //init data ObservableUtil.getAllBusStops(this).subscribe(new Observer<List<BusStop>>() { @Override public void onSubscribe(Disposable d) { progressHome.setVisibility(View.VISIBLE); } @Override public void onNext(List<BusStop> value) { progressHome.setVisibility(View.GONE); allBusStops = value; } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } private void initBottomSheet() { bottomSheet = findViewById(R.id.sheet_bus_stop); mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); tvBusName = (TextView) findViewById(R.id.tv_bus_stop_name); tvRoadName = (TextView) findViewById(R.id.tv_bus_stop_road); busRecycler = (RecyclerView) bottomSheet.findViewById(R.id.rc_buses); busRecycler.setAdapter(null); busRecycler.setHasFixedSize(true); busRecycler.setLayoutManager(new GridLayoutManager(this, 5)); mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_HIDDEN) { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); } else if (busRouteMarkers != null && !busRouteMarkers.isEmpty()) { clearMarkers(busRouteMarkers, null); currentSelectBus = -1; } else if (layerLine != null) { layerLine.removeLayerFromMap(); layerLine = null; } else if (nearByMarkers != null && !nearByMarkers.isEmpty()) { if (nearByMarkers != null && !nearByMarkers.isEmpty()) { clearMarkers(nearByMarkers, null); } if (selectedMarkers != null && !selectedMarkers.isEmpty()) { clearMarkers(selectedMarkers, null); } if (circle != null) { circle.remove(); } } else { super.onBackPressed(); } } ////operate @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); switch (id) { case R.id.nav_share: Util.share(this, Intent.ACTION_SEND); break; case R.id.nav_rate: Util.share(this, Intent.ACTION_VIEW); break; case R.id.nav_open_source: new EasyLicensesDialogCompat(this).setTitle("Licenses").setPositiveButton(android.R.string.ok, null) .show(); break; case R.id.nav_yrta: new AlertDialog.Builder(this).setTitle(getString(R.string.ybs)) .setMessage(getString(R.string.ybs_licence_full)) .setPositiveButton(getString(android.R.string.ok), null).create().show(); break; } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); item.setCheckable(false); return true; } @Override public void onMapReady(GoogleMap googleMap) { MapsInitializer.initialize(this); this.googleMap = googleMap; //googleMap.setMaxZoomPreference(DEFAULT_MAX_ZOOM); //googleMap.setMinZoomPreference(BUS_ROUTE_ZOOM); googleMap.setOnMapClickListener(this); googleMap.setOnMarkerClickListener(this); checkPermission(); googleMap.setMyLocationEnabled(true); googleMap.getUiSettings().setRotateGesturesEnabled(false); googleMap.getUiSettings().setTiltGesturesEnabled(false); googleMap.getUiSettings().setMapToolbarEnabled(false); googleMap.getUiSettings().setCompassEnabled(true); googleMap.getUiSettings().setMyLocationButtonEnabled(true); googleMap.setOnCameraIdleListener(this); /*googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { initData(); Log.d(LOG_TAG, "map loaded"); } });*/ googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() { @Override public void onInfoWindowClick(Marker marker) { } }); cameraUpdate(YANGON_SDG, DEFAULT_ZOOM); } @Override public void onMapClick(LatLng latLng) { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); if (nearByMarkers != null) clearMarkers(nearByMarkers, null); if (circle != null) circle.remove(); circle = googleMap.addCircle( new CircleOptions().center(latLng).radius(800).strokeColor(Color.TRANSPARENT).fillColor(0x3338bdaf)//0x10000000 //0x220000FF .strokeWidth(1)); boolean found = showFoundBusStops(latLng.latitude, latLng.longitude, language); Log.d(LOG_TAG, "first found-" + found); } @Override public boolean onMarkerClick(Marker marker) { if (selectedMarkers == null) { selectedMarkers = new ArrayList<>(); } selectedMarkers.add(marker); mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); marker.showInfoWindow(); showBusStopInfoFromMarker(marker); return true; } //operation start private boolean showFoundBusStops(double lat, double lng, int language) { //// TODO: 1/22/17 language switch with @language param String nobus = getString(R.string.message_no_bus_stop); String loading = getString(R.string.message_loading); if (language == LANGUAGE_MM) { nobus = getString(R.string.message_no_bus_stop_mm); loading = getString(R.string.message_loading_mm); } else if (language == LANGUAGE_ZG) { nobus = getString(R.string.message_no_bus_stop_mm); nobus = Rabbit.uni2zg(nobus); loading = getString(R.string.message_loading_mm); loading = Rabbit.uni2zg(loading); } List<BusStop> found = searchBusStops(lat, lng); if (found == null) { //data require //show message Toast.makeText(this, loading, Toast.LENGTH_SHORT).show(); return false; } if (found.size() < 1) { //no data found //show message //mapClickMarker.setTitle(nobus); //mapClickMarker.showInfoWindow(); Toast.makeText(this, nobus, Toast.LENGTH_SHORT).show(); return false; } else { //if (mapClickMarker != null) mapClickMarker.remove(); if (nearByMarkers == null) { nearByMarkers = new ArrayList<>(); } Log.d(LOG_TAG, "start marker init"); for (BusStop busStop : found) { String busStopName = busStop.getName_mm(); //String townshipName = busStop.getTownship_mm(); /*if (language == LANGUAGE_ZG) { busStopName = Rabbit.uni2zg(busStopName); //townshipName = Rabbit.uni2zg(townshipName); }*/ if (language == LANGUAGE_EN) { busStopName = busStop.getName_en(); //townshipName = busStop.getTownship_en(); } Marker marker = googleMap.addMarker(setMarker(new LatLng(busStop.getLat(), busStop.getLng()), busStopName, null, R.drawable.ic_action_bus_stop)); marker.setTag(busStop); nearByMarkers.add(marker); } Log.d(LOG_TAG, "finish marker init"); cameraUpdate(new LatLng(lat, lng), BUS_STOP_VISIABLE_ZOOM); return true; } } private void showBusStopInfoFromMarker(final Marker marker) { BusStop busStop = (BusStop) marker.getTag(); if (busStop == null) { return; } String busName = busStop.getName_mm(); String roadName = busStop.getRoad_mm(); String townshipName = busStop.getTownship_mm(); if (language == LANGUAGE_EN) { busName = busStop.getName_en(); roadName = busStop.getRoad_en(); townshipName = busStop.getTownship_en(); } tvBusName.setText(String.format("%s (%s)", busName, townshipName)); tvRoadName.setText(String.format("%s", roadName)); mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); ObservableUtil.getRoutes(this, busStop.getBuses()).subscribe(new Observer<List<Feature>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(List<Feature> value) { if (value != null) { initRecycler(value, marker); } } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } private void initRecycler(List<Feature> value, final Marker selectMarker) { busRecycler.setAdapter(new BusesAdapter(this, value, new BusesAdapter.BusItemClickListener() { @Override public void onItemClick(Feature bus) { //if (searchMarker != null) searchMarker.remove(); //clearMarkers(nearByMarkers, selectMarker); showRoute(bus); } })); } private void showRoute(Feature busRoute) { //final BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.ic_action_bus_stop); if (layerLine != null) layerLine.removeLayerFromMap(); if (busRouteMarkers != null) clearMarkers(busRouteMarkers, null); mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); try { currentSelectBus = busRoute.getProperties().getInt("svc_name"); String busColor = busRoute.getProperties().getString("color"); layerLine = new GeoJsonLayer(googleMap, busRoute.toJSON()); layerLine.getDefaultLineStringStyle().setColor(Color.parseColor(busColor)); layerLine.getDefaultLineStringStyle().setWidth(3); layerLine.addLayerToMap(); } catch (JSONException e) { e.printStackTrace(); } googleMap.animateCamera(CameraUpdateFactory.zoomTo(BUS_ROUTE_ZOOM + 1f)); } private List<BusStop> findAndShowBusRoute(int bus_name) { if (allBusStops == null) return null; if (busRouteMarkers == null) { busRouteMarkers = new ArrayList<>(); } else { clearMarkers(busRouteMarkers, null); } for (BusStop busStop : allBusStops) { if (busStop.getSvc_name() == bus_name) { String busStopName = busStop.getName_mm(); if (language == LANGUAGE_EN) { busStopName = busStop.getName_en(); //townshipName = busStop.getTownship_en(); } Marker marker = googleMap.addMarker(setMarker(new LatLng(busStop.getLat(), busStop.getLng()), busStopName, null, R.drawable.ic_action_bus_stop)); marker.setTag(busStop); busRouteMarkers.add(marker); } } return null; } /* * Util methods * ------------------------ * */ /* * #1 search bus-stops * */ private List<BusStop> searchBusStops(double lat, double lng) { if (allBusStops == null) return null; List<BusStop> foundBusStopMap = new ArrayList<>(); Log.d(LOG_TAG, "start search"); //start search for (BusStop busStop : allBusStops) { //find distance from current selected point float dis = distFrom((float) lat, (float) lng, busStop.getLat(), busStop.getLng()); //less estimate 1000 meter, add to found if (dis < 800) { foundBusStopMap.add(busStop); } } //return value is null, there is no data initialized. //return value size is less than 1, no data found return foundBusStopMap; } private Map<String, BusStop> searchBusStopMap(double lat, double lng) { if (allBusStops == null) return null; Map<String, BusStop> foundBusStopMap = new HashMap<>(); //start search for (BusStop busStop : allBusStops) { //find distance from current selected point float dis = distFrom((float) lat, (float) lng, busStop.getLat(), busStop.getLng()); //less estimate 1000 meter, add to found if (dis < 1000) { foundBusStopMap.put(busStop.getName_en(), busStop); } } //return value is null, there is no data initialized. //return value size is less than 1, no data found return foundBusStopMap; } /* * #2 search distance from bus stops * get from * http://stackoverflow.com/questions/837872/calculate-distance-in-meters-when-you-know-longitude-and-latitude-in-java * answer by * http://stackoverflow.com/users/1542/espen-herseth-halvorsen * */ public static float distFrom(double lat1, double lng1, double lat2, double lng2) { return distFrom((float) lat1, (float) lng1, (float) lat2, (float) lng2); } public static float distFrom(float lat1, float lng1, float lat2, float lng2) { double earthRadius = 6371000; //meters double dLat = Math.toRadians(lat2 - lat1); double dLng = Math.toRadians(lng2 - lng1); double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); float dist = (float) (earthRadius * c); return dist; } private MarkerOptions setMarker(LatLng latLng, String title, String snipped, int pic) { return new MarkerOptions().position(latLng).title(title).snippet(snipped).flat(true) .icon(BitmapDescriptorFactory.fromResource(pic)); } private void clearMarkers(List<Marker> markers, Marker remain) { if (markers == null || markers.size() < 0) return; for (Marker marker : markers) { if (!marker.equals(remain)) { marker.remove(); } } markers.clear(); } private void checkPermission() { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION }, 12); return; } } private void cameraUpdate(LatLng latLng, float zoom) { CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom); googleMap.animateCamera(cameraUpdate); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //update map } else { //show message } } @Override public void onCameraIdle() { float zoom = googleMap.getCameraPosition().zoom; Log.d(LOG_TAG, "camera idle" + zoom); if (zoom >= BUS_STOP_VISIABLE_ZOOM && currentSelectBus != -1) { findAndShowBusRoute(currentSelectBus); } else { if (busRouteMarkers != null) clearMarkers(busRouteMarkers, null); } } }