package im.actor.map;
import android.Manifest;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v13.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import im.actor.maps.google.R;
public class MapPickerActivity extends AppCompatActivity
implements
GoogleMap.OnMyLocationChangeListener,
AdapterView.OnItemClickListener,
GoogleMap.OnMapLongClickListener,
GoogleMap.OnMarkerClickListener, AbsListView.OnScrollListener {
private static final int PERMISSION_REQ_LOCATION = 0;
private static final String LOG_TAG = "MapPickerActivity";
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private Location currentLocation;
private LatLng geoData;
private PlaceFetchingTask fetchingTask;
private Marker currentPick;
View select;
private ListView list;
private TextView status;
private View header;
private ProgressBar loading;
private SearchView searchView;
private ImageView fullSizeButton;
private View listHolder;
private View mapHolder;
private View defineMyLocationButton;
private TextView accuranceView;
private View pickCurrent;
private HashMap<String, Marker> markers;
private ArrayList<MapItem> places;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.picker_activity_map_picker);
list = (ListView) findViewById(R.id.list);
list.setOnScrollListener(this);
list.setOnItemClickListener(this);
list.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
loading = (ProgressBar) findViewById(R.id.loading);
status = (TextView) findViewById(R.id.status);
header = findViewById(R.id.header);
listHolder = findViewById(R.id.listNearbyHolder);
mapHolder = findViewById(R.id.mapholder);
accuranceView = (TextView) findViewById(R.id.accurance);
setUpMapIfNeeded();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(false);
fullSizeButton = (ImageView) findViewById(R.id.full);
fullSizeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
togglePlacesList();
}
});
defineMyLocationButton = findViewById(R.id.define_my_location);
defineMyLocationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Location location = mMap.getMyLocation();
if (location != null) {
LatLng target = new LatLng(location.getLatitude(), location.getLongitude());
CameraPosition.Builder builder = new CameraPosition.Builder();
builder.zoom(17);
builder.target(target);
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(builder.build()));
} else {
Toast.makeText(getBaseContext(), R.string.picker_map_pick_my_wait, Toast.LENGTH_SHORT).show();
}
}
});
pickCurrent = findViewById(R.id.pick_current);
pickCurrent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (currentLocation != null) {
Intent returnIntent = new Intent();
returnIntent.putExtra("latitude", currentLocation.getLatitude());
returnIntent.putExtra("longitude", currentLocation.getLongitude());
setResult(RESULT_OK, returnIntent);
finish();
}
}
});
// we dont need these buttons
select = findViewById(R.id.select);
select.setEnabled(false);
findViewById(R.id.select_text).setEnabled(false);
select.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent returnIntent = new Intent();
returnIntent.putExtra("latitude", geoData.latitude);
returnIntent.putExtra("longitude", geoData.longitude);
setResult(RESULT_OK, returnIntent);
finish();
}
});
View cancel = findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
private int defaultHeight = 0;
protected void togglePlacesList() {
// todo animate it
if (listHolder.getVisibility() == View.GONE) {
fullSizeButton.setEnabled(false);
float startSize = findViewById(R.id.container).getHeight();
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(startSize, defaultHeight);
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new AccelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mapHolder.getLayoutParams().height = ((Float) valueAnimator.getAnimatedValue()).intValue();
mapHolder.requestLayout();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
fullSizeButton.setEnabled(true);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
valueAnimator.start();
listHolder.setVisibility(View.VISIBLE);
fullSizeButton.setImageResource(R.drawable.picker_map_fullscreen_icon);
} else {
fullSizeButton.setEnabled(false);
float endSize = findViewById(R.id.container).getHeight();
defaultHeight = mapHolder.getHeight();
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(defaultHeight, endSize);
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new AccelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mapHolder.getLayoutParams().height = ((Float) valueAnimator.getAnimatedValue()).intValue();
mapHolder.requestLayout();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
fullSizeButton.setEnabled(true);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
AlphaAnimation hideAnimation = new AlphaAnimation(1, 0);
hideAnimation.setDuration(300);
hideAnimation.setInterpolator(new AccelerateInterpolator());
hideAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
fullSizeButton.setImageResource(R.drawable.picker_map_halfscreen_icon);
listHolder.setVisibility(View.GONE);
valueAnimator.start();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
listHolder.startAnimation(hideAnimation);
}
}
@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMapAsync(googleMap -> {
mMap = googleMap;
if (mMap != null) {
setUpMap();
}
});
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.picker_map, menu);
searchView = (SearchView) menu.getItem(0).getActionView();
searchView.setIconifiedByDefault(true);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
fetchPlaces(s);
hideKeyBoard();
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
hideKeyBoard();
return false;
}
});
return true;
}
/**
* This is where we can add markers or lines, add listeners or move the camera. In this case, we
* just add a marker near Africa.
* <p/>
* This should only be called once and when we are sure that {@link #mMap} is not null.
*/
private void setUpMap() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQ_LOCATION);
im.actor.runtime.Log.d("Permissions", "MapPickerActivity.setUpMap - no permission :c");
return;
}
}
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
for (String provider : locationManager.getAllProviders()) {
currentLocation = locationManager.getLastKnownLocation(provider);
if (currentLocation != null) {
break;
}
}
if (currentLocation != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()), 14));
fetchPlaces(null);
}
mMap.setOnMyLocationChangeListener(this);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
mMap.getUiSettings().setZoomControlsEnabled(false);
mMap.getUiSettings().setCompassEnabled(false);
mMap.setMyLocationEnabled(true);
mMap.setOnMapLongClickListener(this);
mMap.setOnMarkerClickListener(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_LOCATION) {
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setUpMap();
} else {
//FIXME: if user checks "Don't ask again" button, in next open of activity, it will be finished without any notice about permissions. Need to show toast or alert dialog (with button which redirects to app info (for granting permission manually)).
finish();
}
}
}
}
private void fetchPlaces(String query) {
mMap.clear();
if (currentLocation == null) {
Toast.makeText(this, R.string.picker_map_sory_notdefined, Toast.LENGTH_SHORT).show();
return;
}
list.setAdapter(null);
status.setVisibility(View.GONE);
loading.setVisibility(View.VISIBLE);
fetchingTask = new PlaceFetchingTask(query, 50, currentLocation.getLatitude(), currentLocation.getLongitude()) {
@Override
protected void onPostExecute(Object o) {
Log.i(LOG_TAG, o.toString());
if (o instanceof ArrayList) {
loading.setVisibility(View.GONE);
status.setVisibility(View.GONE);
header.setVisibility(View.VISIBLE);
list.setVisibility(View.VISIBLE);
places = (ArrayList<MapItem>) o;
if (places.isEmpty()) {
status.setText(R.string.picker_map_nearby_empty);
} else {
list.setAdapter(new PlacesAdapter(MapPickerActivity.this, places));
showItemsOnTheMap(places);
}
} else {
places = new ArrayList<MapItem>();
list.setAdapter(null);
header.setVisibility(View.GONE);
status.setText(R.string.picker_internalerror);
Toast.makeText(MapPickerActivity.this, o.toString(), Toast.LENGTH_SHORT).show();
}
}
};
fetchingTask.execute();
}
void hideKeyBoard() {
searchView.clearFocus();
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
View focusedView = this.getCurrentFocus();
if (focusedView != null) {
InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
}
}
private void showItemsOnTheMap(ArrayList<MapItem> array) {
markers = new HashMap<String, Marker>();
for (MapItem mapItem : array) {
markers.put(mapItem.id,
mMap.addMarker(new MarkerOptions()
.position(mapItem.getLatLng())
// .title(mapItem.name)
.draggable(false)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.picker_map_marker))
));
}
}
@Override
public void onMyLocationChange(Location location) {
if (currentLocation == null) {
// do we need to attach our location on the start?
this.currentLocation = location;
fetchPlaces(null);
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 14));
}
this.currentLocation = location;
accuranceView.setText(getString(R.string.picker_map_pick_my_accuracy, (int) currentLocation.getAccuracy()));
Log.d("Location changed", location.toString());
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
MapItem mapItem = (MapItem) adapterView.getItemAtPosition(position);
Intent returnIntent = new Intent();
returnIntent.putExtra("latitude", mapItem.getLatLng().latitude);
returnIntent.putExtra("longitude", mapItem.getLatLng().longitude);
returnIntent.putExtra("street", mapItem.vicinity);
returnIntent.putExtra("place", mapItem.name);
setResult(RESULT_OK, returnIntent);
finish();
/*
select.setEnabled(true);
findViewById(R.id.select_text).setEnabled(true);
geoData = mapItem.getLatLng();
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(geoData, 16));
*/
}
@Override
public void onMapLongClick(LatLng latLng) {
select.setEnabled(true);
findViewById(R.id.select_text).setEnabled(true);
//mMap.clear();
// geoData = latLng;
if (currentPick == null) {
MarkerOptions currentPickOptions = new MarkerOptions()
.draggable(true)
.position(geoData);
//currentPick = mMap.addMarker(currentPickOptions);
} else {
//currentPick.setPosition(geoData);
}
}
@Override
public boolean onMarkerClick(Marker marker) {
if (currentPick != null)
currentPick.remove();
String placeId = null;
for (Map.Entry<String, Marker> markerIterator : markers.entrySet()) {
if (markerIterator.getValue().equals(marker)) {
placeId = markerIterator.getKey();
break;
}
}
int position = -1;
for (int i = 0; i < places.size(); i++) {
MapItem place = places.get(i);
if (place.id.equals(placeId)) {
position = i;
break;
}
}
if (position != -1) {
list.setItemChecked(position, true);
list.smoothScrollToPosition(position);
if (listHolder.getVisibility() == View.GONE) {
togglePlacesList();
}
}
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(marker.getPosition().latitude, marker.getPosition().longitude),
16));
//currentPick = marker;
return true;
}
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
switch (i) {
case SCROLL_STATE_TOUCH_SCROLL:
hideKeyBoard();
break;
}
}
@Override
public void onScroll(AbsListView absListView, int i, int i2, int i3) {
}
}