java.lang.IllegalStateException: Camera moved during a cancellation happens durning user interaction - android

I have been using google maps api v2 for around a month.
Aside from the other bugs reported in the issue tracker I came across this following odd bug.
java.lang.IllegalStateException: Camera moved during a cancellation
which happens inside a CancelableCallback that I use for the animateCamera method.
The exception is traced back to the user touch event.
I believe this happens because the user is performing an interaction with the map while the onFinish/onCancel is being called now this does not happen often however it is quite irritating.
Is there anyway around this issue? I would appreciate any help you can provide.
Here is a complete code:
public void moveMapToSearchMarker(
final T fmMarker,
final FriendlyMapGoogleMapMarkerClickListener fmMarkerClickListener,
float zoomLevel) {
CameraUpdate camUpdate = CameraUpdateFactory.newLatLngZoom(fmMarker
.getMarker().getPosition(), zoomLevel);
getGoogleMap().animateCamera(camUpdate, new CancelableCallback() {
#Override
public void onFinish() {
setMarkerOnSearchComplete(fmMarker, fmMarkerClickListener);
}
#Override
public void onCancel() {
setMarkerOnSearchComplete(fmMarker, fmMarkerClickListener);
}
});
}
private void setMarkerOnSearchComplete(T fmMarker,
FriendlyMapGoogleMapMarkerClickListener fmMarkerClickListener) {
if (!fmMarker.getMarker().isVisible())
fmMarker.getMarker().setVisible(true);
for (T lstFmMarker : this)
lstFmMarker.setSearched(false);
fmMarker.setSearched(true);
createOrUpdateSearchMarker(fmMarker.getMarker().getPosition());
fmMarkerClickListener.onFriendlyMapMarkerClick(fmMarker, this, true);
}
public void createOrUpdateSearchMarker(LatLng searchMarkerPos) {
if (searchRadiusCircle == null) {
CircleOptions cOpts = new CircleOptions();
int strokeColor = getSearchRadiusColor() + 0xEE000000;
cOpts.center(searchMarkerPos).fillColor(getSearchRadiusColor())
.strokeColor(strokeColor).radius(12).strokeWidth(2F);
searchRadiusCircle = getGoogleMap().addCircle(cOpts);
} else {
searchRadiusCircle.setVisible(true);
searchRadiusCircle.setCenter(searchMarkerPos);
}
}
public <T extends FriendlyMapMarker> boolean onFriendlyMapMarkerClick(
T fmMarker, FriendlyMapMarkerList fmMarkerList,
boolean isOnCancelableCallback) {
FriendlyMapMarkerAndList fmMapMarkerAndList = new FriendlyMapMarkerAndList<FriendlyMapMarker, FriendlyMapMarkerList>();
fmMapMarkerAndList.fmMarker = fmMarker;
fmMapMarkerAndList.fmMarkerList = fmMarkerList;
return handleMarkerClick(fmMapMarkerAndList, isOnCancelableCallback);
}
private boolean handleMarkerClick(
FriendlyMapMarkerAndList fmMapMarkerAndList,
boolean isOnCancelableCallback) {
if (fmMapMarkerAndList == null)
return false;
final FriendlyMapMarker fmMarker = fmMapMarkerAndList.fmMarker;
Marker marker = fmMarker.getMarker();
final FriendlyMapMarkerList fmMarkerList = fmMapMarkerAndList.fmMarkerList;
if (fmMarker != null) {
if (fmMarker.getClass().equals(FriendlyMapPlaceMarker.class)) {
balloonActions.setCurrentFmMarker(fmMarker);
balloonActions.setPlaceLikeButtonVisibility();
CancelableCallback onCameraCompleteMove = new CancelableCallback() {
#Override
public void onFinish() {
openActionBalloon(fmMarker, fmMarkerList);
}
#Override
public void onCancel() {
openActionBalloon(fmMarker, fmMarkerList);
}
};
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(marker.getPosition(),
1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback)
fmMarkerList.getGoogleMap()
.animateCamera(
CameraUpdateFactory.newLatLng(fmMarker
.getLatLng()), 350,
onCameraCompleteMove);
else
onCameraCompleteMove.onFinish();
fmMarker.getMarker().showInfoWindow();
LoadAsyncBalloonExtendedStatisticsResult loadAsyncBalloonStatisticsResult = new LoadAsyncBalloonExtendedStatisticsResult(
activity, marker,
(FriendlyMapPlaceMarkerList) fmMarkerList);
loadAsyncBalloonStatisticsResult
.execute(((FriendlyMapPlaceMarker) fmMarker)
.getKnownLocationID());
return true;
}
if (fmMarker.getClass().equals(FriendlyMapDiscussionMarker.class)) {
balloonActionsDiscussion.setCurrentFmMarker(fmMarker);
final FriendlyMapDiscussionMarker fmdMarker = (FriendlyMapDiscussionMarker) fmMarker;
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(fmdMarker.getMarker()
.getPosition(), 1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback) {
CameraUpdate camUpdate = CameraUpdateFactory
.newLatLng(fmdMarker.getMarker().getPosition());
fmMarkerList.getGoogleMap().animateCamera(camUpdate, 350,
new CancelableCallback() {
#Override
public void onFinish() {
openWindowInfoActionBalloon(fmMarkerList,
fmdMarker);
}
#Override
public void onCancel() {
openWindowInfoActionBalloon(fmMarkerList,
fmdMarker);
}
});
} else {
openWindowInfoActionBalloon(fmMarkerList, fmdMarker);
}
return true;
}
if (fmMarker.getClass().equals(FriendlyMapThoughtMarker.class)) {
balloonActionThought.setCurrentFmMarker(fmMarker);
balloonActionThought.setDeleteButtonVisiblity();
final FriendlyMapThoughtMarker fmtMarker = (FriendlyMapThoughtMarker) fmMarker;
LatLng camPos = Utils.getRoundedLatLng(fmMarkerList
.getGoogleMap().getCameraPosition().target, 1e5);
LatLng markerPos = Utils.getRoundedLatLng(fmtMarker.getMarker()
.getPosition(), 1e5);
if (!Utils.latLngEqualsByCoords(camPos, markerPos)
&& !isOnCancelableCallback) {
CameraUpdate camUpdate = CameraUpdateFactory
.newLatLng(fmtMarker.getMarker().getPosition());
fmMarkerList.getGoogleMap().animateCamera(camUpdate, 350,
new CancelableCallback() {
#Override
public void onFinish() {
openWindowInfoActionBalloon(fmMarkerList,
fmtMarker);
}
#Override
public void onCancel() {
openWindowInfoActionBalloon(fmMarkerList,
fmtMarker);
}
});
} else {
openWindowInfoActionBalloon(fmMarkerList, fmtMarker);
}
return true;
}
}
return false;
}
private void openWindowInfoActionBalloon(
FriendlyMapMarkerList fmMarkerList, FriendlyMapMarker fmMarker) {
Marker m = fmMarker.getMarker();
m.showInfoWindow();
openActionBalloon(fmMarker, fmMarkerList);
}
private void openActionBalloon(FriendlyMapMarker marker,
FriendlyMapMarkerList fmMarkerList) {
Projection proj = fmMarkerList.getGoogleMap().getProjection();
Point markerScreenPoint = proj.toScreenLocation(marker.getMarker()
.getPosition());
if (marker.getClass().equals(FriendlyMapPlaceMarker.class)) {
balloonActionsDiscussion.setVisibility(View.INVISIBLE);
balloonActionThought.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActions, markerScreenPoint);
} else if (marker.getClass().equals(FriendlyMapDiscussionMarker.class)) {
balloonActions.setVisibility(View.INVISIBLE);
balloonActionThought.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActionsDiscussion, markerScreenPoint);
} else if (marker.getClass().equals(FriendlyMapThoughtMarker.class)) {
balloonActionsDiscussion.setVisibility(View.INVISIBLE);
balloonActions.setVisibility(View.INVISIBLE);
setBalloonDimension(balloonActionThought, markerScreenPoint);
}
}
private void setBalloonDimension(View ballonActionView,
Point markerScreenPoint) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ballonActionView
.getLayoutParams();
int marginX = markerScreenPoint.x - (ballonActionView.getWidth() / 2);
int marginY = markerScreenPoint.y;
params.setMargins(marginX, marginY, -marginX, -marginY);
params.gravity = Gravity.NO_GRAVITY;
ballonActionView.setLayoutParams(params);
ballonActionView.setVisibility(View.VISIBLE);
}

I'd suggest posting that bug with stacktrace to the tracker.
at com.google.android.gms.maps.GoogleMap.animateCamera(Unknown Source)
at com.saipex.friendly_map.map_view_related_v2.FriendlyMapGoogleMapMarkerClickListener.handleMarkerClick(FriendlyMapGoogleMapMarkerClickListener.java:259)
at com.saipex.friendly_map.map_view_related_v2.FriendlyMapGoogleMapMarkerClickListener.onFriendlyMapMarkerClick(FriendlyMapGoogleMapMarkerClickListener.java:133)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList.setMarkerOnSearchComplete(FriendlyMapMarkerList.java:163)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList.access$0(FriendlyMapMarkerList.java:155)
at com.saipex.friendly_map.map_view_related_v2.model.FriendlyMapMarkerList$1.onCancel(FriendlyMapMarkerList.java:181)
It looks like you are trying something forbidden: animating camera in onCancel. The code would show us more.

Related

Set GIF image to Custom ImageView

I have custom ImageView for animated GIF image. i want to show GIF image, I tried but in this case it is contain url in Async instead I want to show GIF image from raw folder without using Glide. Anyone have any idea how to show image? Please guyz help to solve this problem!!!
I tried this for set raw file
new GifStaticData() {
#Override
protected void onPostExecute(Resource drawable) {
super.onPostExecute(drawable);
gifImageView.setImageResource(R.raw.earth_tilt_animation);
// Log.d(TAG, "GIF width is " + gifImageView.getGifWidth());
// Log.d(TAG, "GIF height is " + gifImageView.getGifHeight());
}
}.execute(R.raw.earth_tilt_animation);
GifStaticData.java
public class GifStaticData extends AsyncTask<Resource, Void, Resource> {
private static final String TAG = "GifDataDownloader";
#Override protected Resource doInBackground(final Resource... params) {
final Resource gifUrl = params[0];
if (gifUrl == null)
return null;
try {
// return ByteArrayHttpClient.get(gifUrl);
return gifUrl;
} catch (OutOfMemoryError e) {
Log.e(TAG, "GifDecode OOM: " + gifUrl, e);
return null;
}
}
}
GifImageView.java
public class GifImageView extends ImageView implements Runnable {
private static final String TAG = "GifDecoderView";
private GifDecoder gifDecoder;
private Bitmap tmpBitmap;
private final Handler handler = new Handler(Looper.getMainLooper());
private boolean animating;
private boolean shouldClear;
private Thread animationThread;
private OnFrameAvailable frameCallback = null;
private long framesDisplayDuration = -1L;
private OnAnimationStop animationStopCallback = null;
private final Runnable updateResults = new Runnable() {
#Override
public void run() {
if (tmpBitmap != null && !tmpBitmap.isRecycled()) {
setImageBitmap(tmpBitmap);
}
}
};
private final Runnable cleanupRunnable = new Runnable() {
#Override
public void run() {
tmpBitmap = null;
gifDecoder = null;
animationThread = null;
shouldClear = false;
}
};
public GifImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public GifImageView(final Context context) {
super(context);
}
public void setBytes(final byte[] bytes) {
gifDecoder = new GifDecoder();
try {
gifDecoder.read(bytes);
gifDecoder.advance();
} catch (final OutOfMemoryError e) {
gifDecoder = null;
Log.e(TAG, e.getMessage(), e);
return;
}
if (canStart()) {
animationThread = new Thread(this);
animationThread.start();
}
}
public long getFramesDisplayDuration() {
return framesDisplayDuration;
}
/**
* Sets custom display duration in milliseconds for the all frames. Should be called before {#link
* #startAnimation()}
*
* #param framesDisplayDuration Duration in milliseconds. Default value = -1, this property will
* be ignored and default delay from gif file will be used.
*/
public void setFramesDisplayDuration(long framesDisplayDuration) {
this.framesDisplayDuration = framesDisplayDuration;
}
public void startAnimation() {
animating = true;
if (canStart()) {
animationThread = new Thread(this);
animationThread.start();
}
}
public boolean isAnimating() {
return animating;
}
public void stopAnimation() {
animating = false;
if (animationThread != null) {
animationThread.interrupt();
animationThread = null;
}
}
public void clear() {
animating = false;
shouldClear = true;
stopAnimation();
handler.post(cleanupRunnable);
}
private boolean canStart() {
return animating && gifDecoder != null && animationThread == null;
}
public int getGifWidth() {
return gifDecoder.getWidth();
}
public int getGifHeight() {
return gifDecoder.getHeight();
}
#Override public void run() {
if (shouldClear) {
handler.post(cleanupRunnable);
return;
}
final int n = gifDecoder.getFrameCount();
do {
for (int i = 0; i < n; i++) {
if (!animating) {
break;
}
//milliseconds spent on frame decode
long frameDecodeTime = 0;
try {
long before = System.nanoTime();
tmpBitmap = gifDecoder.getNextFrame();
frameDecodeTime = (System.nanoTime() - before) / 1000000;
if (frameCallback != null) {
tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap);
}
if (!animating) {
break;
}
handler.post(updateResults);
} catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
Log.w(TAG, e);
}
if (!animating) {
break;
}
gifDecoder.advance();
try {
int delay = gifDecoder.getNextDelay();
// Sleep for frame duration minus time already spent on frame decode
// Actually we need next frame decode duration here,
// but I use previous frame time to make code more readable
delay -= frameDecodeTime;
if (delay > 0) {
Thread.sleep(framesDisplayDuration > 0 ? framesDisplayDuration : delay);
}
} catch (final Exception e) {
// suppress any exception
// it can be InterruptedException or IllegalArgumentException
}
}
} while (animating);
if (animationStopCallback != null) {
animationStopCallback.onAnimationStop();
}
}
public OnFrameAvailable getOnFrameAvailable() {
return frameCallback;
}
public void setOnFrameAvailable(OnFrameAvailable frameProcessor) {
this.frameCallback = frameProcessor;
}
public interface OnFrameAvailable {
Bitmap onFrameAvailable(Bitmap bitmap);
}
public OnAnimationStop getOnAnimationStop() {
return animationStopCallback;
}
public void setOnAnimationStop(OnAnimationStop animationStop) {
this.animationStopCallback = animationStop;
}
public interface OnAnimationStop {
void onAnimationStop();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
clear();
}
}
I had to play and pause the Gif image Glide - Cannot stop gif onClick- Getting TransitionDrawable instead of Animate/GifDrawable
The idea is to get drawable from view,checking if it is an instance of Gifdrawable and playing and pausing it.(Hoping the gif image is already playing)
Add this In OnClick of GifImageView
Drawable drawable = ((ImageView) v).getDrawable();
if (drawable instanceof GifDrawable) {
GifDrawable animatable = (GifDrawable) drawable;
if (animatable.isRunning()) {
animatable.stop();
} else {
animatable.start();
}
}
I found the solution of above problem using GifMovieView!!!
GifMovieViewer.java
public class GifMovieViewer extends Activity {
private Button btnStart;
private GifMovieView gif1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gif_movie_viewer);
gif1 = (GifMovieView) findViewById(R.id.gif1);
btnStart = (Button) findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gif1.setMovieResource(R.drawable.earth_tilt_animation);
//for pause
// gif1.setPaused(gif1.isPaused());
}
});
}
public void onGifClick(View v) {
GifMovieView gif = (GifMovieView) v;
gif.setPaused(!gif.isPaused());
}
}

Unable to implement custom touch listener on google map support fragment android

I am trying to handle events apart from the onCamerachange Listener such as knowing the event when the camera is dragged and released. For that I have taken help of a custom touch fragment and touch wrapper to manage the touch events but without success.
Here is my main activity code :
public class PickupActivity extends LocationUtils implements OnMapReadyCallback, AddressSearchAdapter.ClickListener {
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private LatLng center;
private TextView pickupMarker;
private LinearLayout markerLayout, addressBox, confirmPickupLayout;
private EditText address, pincodeText, landmarkText;
private ImageView currentLocationButton;
private LatLng latLng, latLng1;
private JSONArray addressComponents, typesArray;
String formattedAddress;
String currentLatitude, currentLongitude;
private Toolbar toolbar;
private SharedPreferenceClass preferenceClass;
private String pincode, gPlaceId, city, country, state, premise, route, enteredText, pickupLat, pickupLong, currentGplaceId;
private AddressSearchAdapter mAdapter;
private RecyclerView mRecyclerView;
private ArrayList<com.packr.classes.Address> addressArrayList = new ArrayList<>();
private JSONObject locationObject, geometryObject;
private com.packr.classes.Address mAddress;
private int pickupToastVisible = 0;
private Boolean pickupLocationSet = false, isAddressTextEmpty = false;
private Button confirmPickupButton;
private Double a, b, x, y;
/**
* Represents a geographical location.
*/
protected Location mLastLocation;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pickup);
SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
initialize();
onClick();
onSearchTextChanged();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setVisibility(View.GONE);
mRecyclerView.setLayoutManager(new MyLinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false));
mAdapter = new AddressSearchAdapter(getApplicationContext(), this);
mAdapter.setClickListener(this);
mRecyclerView.setAdapter(mAdapter);
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("Set Pickup Location");
setSupportActionBar(toolbar);
}
/**
* function to load map. If map is not created it will create it for you
* */
#Override
public void onResume() {
super.onResume();
}
public void initialize() {
confirmPickupLayout = (LinearLayout) findViewById(R.id.confirmPickupLayout);
preferenceClass = new SharedPreferenceClass(getApplicationContext());
pickupMarker = (TextView) findViewById(R.id.locationMarkertext);
markerLayout = (LinearLayout) findViewById(R.id.locationMarker);
address = (EditText) findViewById(R.id.addressText);
currentLocationButton = (ImageView) findViewById(R.id.current_location);
addressBox = (LinearLayout) findViewById(R.id.addressBox);
pincodeText = (EditText) findViewById(R.id.pincodeText);
landmarkText = (EditText) findViewById(R.id.landmarkText);
confirmPickupButton = (Button) findViewById(R.id.confirmPickup);
}
public void onClick() {
}
public void onSearchTextChanged() {
address.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 0 || s == "") {
isAddressTextEmpty = true;
if (mRecyclerView.getVisibility() == View.VISIBLE) {
mRecyclerView.setVisibility(View.GONE);
}
}
if (s.length() < 16) {
mRecyclerView.setVisibility(View.VISIBLE);
enteredText = s.toString().replace(" ", "");
if (isAddressTextEmpty) {
sendAutocompleteJsonRequest();
}
}
final List<com.packr.classes.Address> filteredModelList = filter(addressArrayList, s.toString());
mAdapter.animateTo(filteredModelList);
mRecyclerView.scrollToPosition(0);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
#Override
public void onMapReady(GoogleMap map) {
TouchableMapFragment mFragment;
mFragment = new TouchableMapFragment();
new MapStateListener(map,mFragment,this){
#Override
public void onMapTouched() {
// Map touched
L.m("touched");
}
#Override
public void onMapReleased() {
// Map released
L.m("released");
}
#Override
public void onMapUnsettled() {
// Map unsettled
L.m("unSettled");
}
#Override
public void onMapSettled() {
// Map settled
L.m("settled");
}
};
mMap = map;
map.setMyLocationEnabled(false);
currentLatitude = preferenceClass.getCurrentLatitude();
currentLongitude = preferenceClass.getCurrentLongitude();
a = Double.parseDouble(currentLatitude);
b = Double.parseDouble(currentLongitude);
latLng = new LatLng(Double.parseDouble(currentLatitude), Double.parseDouble(currentLongitude));
map.addMarker(new MarkerOptions().position(latLng).icon(BitmapDescriptorFactory
.fromResource(R.drawable.current_location_marker)));
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng).zoom(15f).tilt(0).bearing(0).build();
map.moveCamera(CameraUpdateFactory.newLatLng(latLng));
map.moveCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
address.setText(preferenceClass.getPickupAddress());
pincodeText.setText(preferenceClass.getPickupPincode());
map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
if (confirmPickupLayout.getVisibility() == View.VISIBLE) {
confirmPickupLayout.setVisibility(View.GONE);
slideOutTowardsBottom();
}
center = mMap.getCameraPosition().target;
currentLatitude = String.valueOf(center.latitude);
currentLongitude = String.valueOf(center.longitude);
latLng1 = new LatLng(center.latitude, center.longitude);
Log.e("Coordinates", String.valueOf(center.latitude) + "," + String.valueOf(center.longitude) + latLng1);
pickupMarker.setText(" Set your Location ");
if (!pickupLocationSet) {
float[] distances = new float[1];
Location.distanceBetween(center.latitude, center.longitude, a, b, distances);
System.out.println("Distance: " + distances[0]);
if (distances[0] > 1000.0) {
sendJsonRequest();
L.m("called");
a = center.latitude;
b = center.longitude;
}
}
}
});
}
public void sendJsonRequest() {
RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, getRequestUrl(), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject jsonObject) {
//console test
parseJsonResponse(jsonObject);
if (formattedAddress == null) {
address.setText("Obtaining Address");
} else {
address.setText(formattedAddress);
}
Log.e("error", jsonObject.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
if (volleyError instanceof TimeoutError || volleyError instanceof NoConnectionError) {
} else if (volleyError instanceof AuthFailureError) {
} else if (volleyError instanceof ServerError) {
} else if (volleyError instanceof NetworkError) {
} else if (volleyError instanceof ParseError) {
}
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
1000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
requestQueue.add(jsonObjectRequest);
}
public String getRequestUrl() {
return KEY_GEOCODE_URL +
currentLatitude + KEY_COMMA + currentLongitude +
KEY_SENSOR;
}
public void parseJsonResponse(JSONObject response) {
if (response != null && response.length() > 0) {
try {
JSONArray resultArray = response.getJSONArray(KEY_RESULTS);
if (resultArray.length() > 0) {
for (int i = 0; i < resultArray.length(); i++) {
JSONObject resultListObject = resultArray.getJSONObject(0);
formattedAddress = resultListObject.getString(KEY_FORMATTED_ADDRESS);
addressComponents = resultListObject.getJSONArray(KEY_ADDRESS_COMPONENTS);
gPlaceId = resultListObject.getString(KEY_PLACE_ID);
preferenceClass.savePickupGplaceId(gPlaceId);
}
if (addressComponents.length() > 0) {
for (int j = 0; j < addressComponents.length(); j++) {
JSONObject addressComponentsObject = addressComponents.getJSONObject(j);
typesArray = addressComponentsObject.getJSONArray(KEY_TYPES);
if ((typesArray.getString(0)).contentEquals(KEY_POSTAL_CODE)) {
if (!addressComponentsObject.isNull(KEY_LONG_NAME))
pincode = addressComponentsObject.getString(KEY_LONG_NAME);
pincodeText.setText(pincode);
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public String getAutocompleteRequestUrl() {
return KEY_AUTOCOMPLETE_API.concat(enteredText);
}
public void sendAutocompleteJsonRequest() {
RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, getAutocompleteRequestUrl(), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject jsonObject) {
parseJSONResponse(jsonObject);
//Calling the Snackbar
Log.e("response", jsonObject.toString());
mAdapter.setAddressArrayList(addressArrayList);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
if (volleyError instanceof TimeoutError || volleyError instanceof NoConnectionError) {
L.T(getApplicationContext(), "Something is wrong with the internet connectivity. Please try again");
} else if (volleyError instanceof AuthFailureError) {
L.T(getApplicationContext(), "Something is wrong with the internet connectivity. Please try again");
//TODO
} else if (volleyError instanceof ServerError) {
L.T(getApplicationContext(), "Something is wrong with the internet connectivity. Please try again");
//TODO
} else if (volleyError instanceof NetworkError) {
L.T(getApplicationContext(), "Something is wrong with the internet connectivity. Please try again");
//TODO
} else if (volleyError instanceof ParseError) {
L.T(getApplicationContext(), "Something is wrong with the internet connectivity. Please try again");
//TODO
}
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
1000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
}
private void parseJSONResponse(JSONObject response) {
if (response != null && response.length() > 0) {
try {
JSONArray resultArray = response.getJSONArray(KEY_RESULTS);
if (resultArray.length() > 0) {
for (int i = 0; i < resultArray.length(); i++) {
JSONObject resultListObject = resultArray.getJSONObject(i);
formattedAddress = resultListObject.getString(KEY_FORMATTED_ADDRESS);
addressComponents = resultListObject.getJSONArray(KEY_ADDRESS_COMPONENTS);
gPlaceId = resultListObject.getString(KEY_PLACE_ID);
if (resultListObject.has(KEY_LOCATION) && !(resultListObject.isNull(KEY_LOCATION))) {
locationObject = resultListObject.getJSONObject(KEY_LOCATION);
if (locationObject.has(KEY_LATITUDE) && !(locationObject.isNull(KEY_LATITUDE))) {
currentLatitude = locationObject.getString(KEY_LATITUDE);
}
if (locationObject.has(KEY_LONGITUDE) && !(locationObject.isNull(KEY_LONGITUDE))) {
currentLongitude = locationObject.getString(KEY_LONGITUDE);
}
}
if ((resultListObject.has(KEY_GEOMETRY)) && !(resultListObject.isNull(KEY_GEOMETRY))) {
geometryObject = resultListObject.getJSONObject(KEY_GEOMETRY);
if (geometryObject.has(KEY_LOCATION) && !(geometryObject.isNull(KEY_LOCATION))) {
locationObject = geometryObject.getJSONObject(KEY_LOCATION);
if (locationObject.has(KEY_LATITUDE) && !(locationObject.isNull(KEY_LATITUDE))) {
currentLatitude = locationObject.getString(KEY_LATITUDE);
}
if (locationObject.has(KEY_LONGITUDE) && !(locationObject.isNull(KEY_LONGITUDE))) {
currentLongitude = locationObject.getString(KEY_LONGITUDE);
}
}
}
if (addressComponents.length() > 0) {
for (int j = 0; j < addressComponents.length(); j++) {
JSONObject addressComponentsObject = addressComponents.getJSONObject(j);
typesArray = addressComponentsObject.getJSONArray(KEY_TYPES);
if ((typesArray.getString(0)).contentEquals(KEY_CITY)) {
if (!addressComponentsObject.isNull(KEY_LONG_NAME))
city = addressComponentsObject.getString(KEY_LONG_NAME);
} else if ((typesArray.getString(0)).contentEquals(KEY_COUNTRY)) {
if (!addressComponentsObject.isNull(KEY_LONG_NAME))
country = addressComponentsObject.getString(KEY_LONG_NAME);
} else if ((typesArray.getString(0)).contentEquals(KEY_STATE)) {
if (!addressComponentsObject.isNull(KEY_LONG_NAME))
state = addressComponentsObject.getString(KEY_LONG_NAME);
} else if ((typesArray.getString(0)).contentEquals(KEY_POSTAL_CODE)) {
if (!addressComponentsObject.isNull(KEY_LONG_NAME))
pincode = addressComponentsObject.getString(KEY_LONG_NAME);
} else if ((typesArray.getString(0)).contentEquals(KEY_PREMISE)) {
premise = addressComponentsObject.getString(KEY_LONG_NAME);
} else if ((typesArray.getString(0)).contentEquals(KEY_ROUTE)) {
route = addressComponentsObject.getString(KEY_LONG_NAME);
}
}
}
if (country.contentEquals("India") && city.contentEquals("Kolkata")) {
mAddress = new com.packr.classes.Address();
mAddress.setFormattedAddress(formattedAddress);
mAddress.setCity(city);
mAddress.setCountry(country);
mAddress.setPincode(pincode);
mAddress.setState(state);
mAddress.setStreet(premise);
mAddress.setRoute(route);
mAddress.setLatitude(currentLatitude);
mAddress.setLongitude(currentLongitude);
mAddress.setGplaceId(gPlaceId);
addressArrayList.add(mAddress);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private List<com.packr.classes.Address> filter(List<com.packr.classes.Address> models, String query) {
query = query.toLowerCase();
final List<com.packr.classes.Address> filteredModelList = new ArrayList<>();
for (com.packr.classes.Address model : models) {
final String text = model.getFormattedAddress().toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
public void slideInFromBottom() {
Animation tvAnim = AnimationUtils.loadAnimation(this, R.anim.abc_slide_in_bottom);
confirmPickupLayout.startAnimation(tvAnim);
}
public void slideOutTowardsBottom() {
Animation tvAnim = AnimationUtils.loadAnimation(this, R.anim.abc_slide_out_bottom);
confirmPickupLayout.startAnimation(tvAnim);
}
// to check whether location services are enable or not
public static boolean isLocationEnabled(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} else {
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
#Override
public void itemClicked(View view, int position) {
hideKeyboard();
confirmPickupLayout.setVisibility(View.VISIBLE);
slideInFromBottom();
mRecyclerView.setVisibility(View.GONE);
pickupLat = addressArrayList.get(position).getLatitude();
pickupLong = addressArrayList.get(position).getLongitude();
preferenceClass.savePickupLatitude(currentLatitude);
preferenceClass.savePickupLongitude(currentLongitude);
String pincode = addressArrayList.get(position).getPincode();
currentGplaceId = addressArrayList.get(position).getGplaceId();
preferenceClass.savePickupGplaceId(currentGplaceId);
latLng = new LatLng(Double.parseDouble(pickupLat), Double.parseDouble(pickupLong));
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng).zoom(15f).tilt(0).bearing(0).build();
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
address.setText(formattedAddress);
if (pincode != null) {
pincodeText.setText(pincode);
}
}
public Boolean validationCheck() {
if (address.getText().length() == 0) {
L.t(getApplicationContext(), "Please provide a pickup address");
} else if (pincodeText.getText().length() != 6) {
L.t(getApplicationContext(), "Pincode must contain 6 digits");
} else if (landmarkText.getText().length() == 0) {
L.t(getApplicationContext(), "Please provide a landmark");
} else return true;
return false;
}
private void hideKeyboard() {
// Check if no view has focus:
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
Here is the code for the custom Touch fragement. I have extended MapSupportFragment
public class TouchableMapFragment extends MapFragment {
private View mOriginalContentView;
private TouchableWrapper mTouchView;
public void setTouchListener(TouchableWrapper.OnTouchListener onTouchListener) {
mTouchView.setTouchListener(onTouchListener);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
L.m("called");
mOriginalContentView = super.onCreateView(inflater, parent,
savedInstanceState);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(mOriginalContentView);
return mTouchView;
}
#Override
public View getView() {
return mOriginalContentView;
}
}
Here is the code for the touchWrapper
public class TouchableWrapper extends FrameLayout {
public TouchableWrapper(Context context) {
super(context);
}
public void setTouchListener(OnTouchListener onTouchListener) {
this.onTouchListener = onTouchListener;
}
private OnTouchListener onTouchListener;
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onTouchListener.onTouch();
break;
case MotionEvent.ACTION_UP:
onTouchListener.onRelease();
break;
}
return super.dispatchTouchEvent(event);
}
public interface OnTouchListener {
void onTouch();
void onRelease();
}
}
Please help.

Xamarin Android Location updates not being called

I am trying to log location during an activity however I am not getting location updates. I have played around with the min refresh interval as well as the distance interval however it still doesn't work. I followed Xamarin's example for location updates but I've been banging my head against the wall as to why location updates arent working!
public class ActivityManager : Java.Lang.Object, ILocationListener, ISensorEventListener
{
private readonly LocationManager _locationManager;
private readonly SensorManager _sensorManager;
private readonly List<Location> _locationCache;
private readonly List<SensorEvent> _sensorCache;
private bool Continous { get; set; }
public ActivityManager(LocationManager locationManager, SensorManager sensorManager)
{
_locationManager = locationManager;
_sensorManager = sensorManager;
_locationCache = new List<Location>();
_sensorCache = new List<SensorEvent>();
Continous = false;
}
public void StartTrackingLocation()
{
const string provider = LocationManager.GpsProvider;
if (_locationManager.IsProviderEnabled(provider))
{
_locationManager.RequestLocationUpdates(provider, 0, 0, this);
}
}
public void StartTrackingAccelerometer()
{
var mHandlerThread = new HandlerThread("sensorThread");
mHandlerThread.Start();
var handler = new Handler(mHandlerThread.Looper);
_sensorManager.RegisterListener(this, _sensorManager.GetDefaultSensor(SensorType.Accelerometer),
SensorDelay.Normal, handler);
}
public void StopTrackingLocation()
{
_locationManager.RemoveUpdates(this);
}
public void StopTrackingAccelerometer()
{
_sensorManager.UnregisterListener(this);
}
public void StartContinousTracking()
{
_locationCache.Clear();
_sensorCache.Clear();
Continous = true;
}
public void StopContinousTracking()
{
_locationCache.Clear();
_sensorCache.Clear();
Continous = false;
}
public void ExportLocationData(string path)
{
var kml = new Kml
{
Feature = new Placemark
{
Geometry = new LineString
{
Coordinates = new CoordinateCollection(_locationCache.Select(l => new Vector {Latitude = l.Latitude, Longitude = l.Longitude}))
}
}
};
var kmlFile = KmlFile.Create(kml, true);
using (var stream = File.OpenWrite(path))
{
kmlFile.Save(stream);
}
}
public void ExportSensorData(string path)
{
var csv = new CsvWriter(new StreamWriter(path));
csv.WriteField("AccX");
csv.WriteField("AccY");
csv.WriteField("AccZ");
csv.NextRecord();
foreach (var s in _sensorCache.ToList())
{
csv.WriteField(s.Values[0]);
csv.WriteField(s.Values[1]);
csv.WriteField(s.Values[2]);
csv.NextRecord();
}
csv.Dispose();
}
public void OnLocationChanged(Location location)
{
_locationCache.Add(location);
if (!Continous) _locationCache.RemoveAll(l => location.Time - l.Time > 120000);
}
public void OnSensorChanged(SensorEvent e)
{
_sensorCache.Add(e);
if (!Continous) _sensorCache.RemoveAll(s => e.Timestamp - s.Timestamp > 120000000000);
}
public void OnProviderDisabled(string provider) { }
public void OnProviderEnabled(string provider) { }
public void OnStatusChanged(string provider, Availability status, Bundle extras) { }
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy) { }
}
Thanks in advance.
This is the implementation I have used for the Android element of a Xamarin.Forms app:
The communicating class
public class PlatformLocation : ILocation
{
private readonly global::Android.Locations.LocationManager _locationManager;
private readonly string[] _providers;
private readonly TaskCompletionSource<PfgLocationInfo> _tcs;
public PlatformLocation()
{
_locationManager = (global::Android.Locations.LocationManager)Application.Context.GetSystemService(Context.LocationService);
_providers = _locationManager.GetProviders(false).Where(s => s != global::Android.Locations.LocationManager.PassiveProvider).ToArray();
_tcs = new TaskCompletionSource<PfgLocationInfo>();
}
#region Private Methods
Task<PfgLocationInfo> StartUpdatingLocation(int timeout = 0)
{
var lastKnownGpsLocation = _locationManager.GetLastKnownLocation("gps");
if (lastKnownGpsLocation != null)
{
var pfgLocation = new PfgLocationInfo()
{
Longitude = lastKnownGpsLocation.Longitude,
Latitude = lastKnownGpsLocation.Latitude,
Timestamp = DateTime.Now,
Success = true,
Status = PfgLocationStatus.Valid
};
_tcs.TrySetResult(pfgLocation);
return _tcs.Task;
}
var lastKnownNetworkLocation = _locationManager.GetLastKnownLocation("network");
if (lastKnownNetworkLocation != null)
{
var pfgLocation = new PfgLocationInfo()
{
Longitude = lastKnownNetworkLocation.Longitude,
Latitude = lastKnownNetworkLocation.Latitude,
Timestamp = DateTime.Now,
Success = true,
Status = PfgLocationStatus.Valid
};
_tcs.TrySetResult(pfgLocation);
return _tcs.Task;
}
LocationListener listener = null;
listener = new LocationListener(
_providers.Where(_locationManager.IsProviderEnabled),
() =>
{
if (listener.Task.IsCanceled)
{
_locationManager.RemoveUpdates(listener);
}
},
timeout
);
try
{
var looper = Looper.MyLooper() ?? Looper.MainLooper;
var enabled = 0;
for (var i = 0; i < _providers.Length; ++i)
{
if (_locationManager.IsProviderEnabled(_providers[i]))
{
enabled++;
}
_locationManager.RequestLocationUpdates(_providers[i], 0, 0, listener, looper);
}
if (enabled == 0)
{
for (var i = 0; i < _providers.Length; ++i)
{
_locationManager.RemoveUpdates(listener);
}
_tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
return _tcs.Task;
}
}
catch (TaskCanceledException tcex)
{
_tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
return _tcs.Task;
}
catch (SecurityException)
{
_tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
return _tcs.Task;
}
return listener.Task;
}
#endregion
#region ILocation implementation
public Task<PfgLocationInfo> GetLocationAsync()
{
return StartUpdatingLocation();
}
public Task<PfgLocationInfo> GetLocationAsync(int timeout)
{
return StartUpdatingLocation(timeout);
}
#endregion
}
The ILocationListener implementation:
public class LocationListener : Java.Lang.Object, ILocationListener
{
private readonly HashSet<string> _activeProviders;
private readonly TaskCompletionSource<PfgLocationInfo> _completionSource = new TaskCompletionSource<PfgLocationInfo>();
private readonly Action _finishedCallback;
private readonly Timer _timer;
private readonly int _timeout;
private readonly object _locationLock = new object();
public Task<PfgLocationInfo> Task
{
get
{
return _completionSource.Task;
}
}
public LocationListener(IEnumerable<string> providers, Action finishedCallback, int timeout = -1)
{
_activeProviders = new HashSet<string>(providers);
_finishedCallback = finishedCallback;
if (timeout > 0)
{
_timeout = timeout;
_timer = new Timer(TimesUp, null, _timeout * 1000, 0);
}
}
#region Timeout Methods
void TimesUp(object state)
{
lock (_locationLock)
{
if (_completionSource.TrySetCanceled() && _finishedCallback != null)
{
_finishedCallback();
}
}
_timer.Dispose();
}
#endregion
#region ILocationListener implementation
public void OnLocationChanged(global::Android.Locations.Location location)
{
if (location != null)
{
Finish(location);
return;
}
}
public void OnProviderDisabled(string provider)
{
lock (_activeProviders)
{
if (_activeProviders.Remove(provider) && _activeProviders.Count == 0)
{
_completionSource.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
}
}
}
public void OnProviderEnabled(string provider)
{
lock (_activeProviders)
_activeProviders.Add(provider);
}
public void OnStatusChanged(string provider, Availability status, global::Android.OS.Bundle extras)
{
switch (status)
{
case Availability.Available:
OnProviderEnabled(provider);
break;
case Availability.OutOfService:
OnProviderDisabled(provider);
break;
}
}
#endregion
#region Private Methods
void Finish(global::Android.Locations.Location location)
{
var pfgLocationInfo = new PfgLocationInfo()
{
Longitude = location.Longitude,
Latitude = location.Latitude,
Timestamp = DateTime.Now,
Success = true,
Status = PfgLocationStatus.Valid
};
_completionSource.TrySetResult(pfgLocationInfo);
}
#endregion
}
The PfgLocationInfo is just a simple class for holding the results
This works exactly as required and should be relatively easy to transform to your requirements.
It turns out this was working but very intermittently. The issue appeared to be that another thread that was running was asynchronously to log the sensor data was queueing up operations which were effectively drowning out the location updates.
Removing the sensor data logging started to allow location updates to come through. This seemed strange to me as this seemed to occur despite the sensor data logging being contained in their own thread.

Show 3dmodel after tracking lost metaio sdk

I am using metaio sdk 6.0.2. i am working on metaio INSTANT_2D_GRAVITY tracking and was able to display 3d model. I want to display same 3d model when tracking is lost.but I am failing to do so. I tried by adding trackingValuesVector in onTrackingEvent of MetaioSDKCallbackHandler with no success. can anyone tell me where am I going wrong?
private TrackingValues mTrackingValues;// declared globally
private IGeometry mModel; // declared globally
private boolean mPreview=true;// declared globally
// start INSTANT_2D_GRAVITY tracking
public void onTakePicture(View v)
{
captureTrackingValues = true;
metaioSDK.startInstantTracking("INSTANT_2D_GRAVITY", new File(""), mPreview);
mPreview = !mPreview;
}
final class MetaioSDKCallbackHandler extends IMetaioSDKCallback
{
#Override
public void onInstantTrackingEvent(final boolean success,final File filePath) {
super.onInstantTrackingEvent(success, filePath);
if(mSurfaceView != null)
{
mSurfaceView.queueEvent(new Runnable() {
#Override
public void run() {
if(success)
{
if(captureTrackingValues == true)
{
metaioSDK.setTrackingConfiguration(filePath);
Log.i("Tracking value success","good");
}
}
else
{
Log.i("Tracking value failure","bad");
}
}
});
}
}
#Override
public void onTrackingEvent(TrackingValuesVector trackingValuesVector) {
super.onTrackingEvent(trackingValuesVector);
if (!trackingValuesVector.isEmpty())
{
for(int i =0;i< trackingValuesVector.size();i++)
{
if(trackingValuesVector.get(i).isTrackingState() && mModel!=null)
{
mTrackingValues = metaioSDK.getTrackingValues(i);
mModel.setCoordinateSystemID(trackingValuesVector.get(i).getCoordinateSystemID());
}
else {
if(mModel!= null && mTrackingValues != null) {
metaioSDK.setCosOffset(1, mTrackingValues);
//mChairModel.setCoordinateSystemID(0);
Log.e("TestAR","isTrackingState is null");
}
}
}
}
else{
if(mModel!= null && mTrackingValues != null) {
metaioSDK.setCosOffset(1, mTrackingValues);
//mModel.setCoordinateSystemID(0);
Log.e("TestAR","trackingValuesVector is null");
}
}
}
}
loading 3d model:
private void loadModel()
{
if (mSurfaceView != null) {
mSurfaceView.queueEvent(new Runnable() {
#Override
public void run() {
File chairModel = AssetsManager.getAssetPathAsFile(getApplicationContext(),"chair.obj");
if (chairModel != null) {
mModel = metaioSDK.createGeometry(chairModel);
mModel.setScale(3f);
mModel.setTranslation(new Vector3d(0f,0f,-60f));
mGestureHandler.addObject(mModel, 1);
mModel.setRotation(new Rotation(0f, 0.5f, 0f));
mModel.setCoordinateSystemID(1);
}
}
});
}
else
{
Log.e("exception", "msurfaceview is null");
}
}
I see that you also tried setting the model to COS 0. This should actually work, if the tracking is lost.
If you do not see the model, you would have to play around with the scale value (i.e. set a low value like 0.01) and with the Z translation value. Set a negative Z value in order to move the model away from the camera clipping plane.

Osmdroid offline mode update tiles after zoom

I'm developing an Android app that uses Osmdroid to display the maps in offline mode. I have an issue when I want to zoom in or out by pinching on the map or using the build-in zoomcontrols. When I zoom in the map tiles are not always correctly rendered and when I zoom out the sometimes there are some gray tiles in the map, sometimes everything is rendered OK. It's not related on the location displayed on the map. My map tiles are stored in an osmdroid zip-file with the Mapnik source in the folder /mnt/sdcard/osmdroid. I'm using osmdroid-3.0.7.
So, any help is welcome.
See my code below (my includes aren't included here in the code):
public class MapActivity extends OSMapActivity {
private ArrayList<String[]> mapPointData;
private ArrayList<String[]> multiData;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.map);
setABTitle(getIntent().getExtras().getStringArray("geoLoc")[0]);
actionButtonVisible(getIntent().getExtras().getBoolean("routeList"));
initLayout();
setHomePoint();
}
#Override
protected void onResume() {
super.onResume();
Prefs.clearMapPrefs(this);
}
private void initLayout() {
c = this;
// Buttons # top of the activity
doseeBN = (ImageView) findViewById(R.id.mapDoseeBN);
eatdrinkBN = (ImageView) findViewById(R.id.mapEatdrinkBN);
nightlifeBN = (ImageView) findViewById(R.id.mapNightlifeBN);
sleepBN = (ImageView) findViewById(R.id.mapSleepBN);
// The LinearLayout with the ScrollView for the Subcategories in "Do & See"
doseeLL = (LinearLayout) findViewById(R.id.doseeSubCatLL);
top10BN = (Button) findViewById(R.id.mapDoseeTop10BN);
monumentsBN = (Button) findViewById(R.id.mapDoseeMonumentsBN);
museumBN = (Button) findViewById(R.id.mapDoseeMuseumsBN);
cultureBN = (Button) findViewById(R.id.mapDoseeCultureBN);
attractionsBN = (Button) findViewById(R.id.mapDoseeAttractionBN);
shoppingBN = (Button) findViewById(R.id.mapDoseeShoppingBN);
marketBN = (Button) findViewById(R.id.mapDoseeMarketBN);
// Init of the map an mapcontroller
mapView = (MapView) findViewById(R.id.osmMV);
mapView.setTileSource(TileSourceFactory.MAPNIK);
mapController = mapView.getController();
mapController.setZoom(16);
mapView.setUseDataConnection(false);
mapView.setBuiltInZoomControls(true);
mapView.setMultiTouchControls(true);
// mapView.setDrawingCacheEnabled(true);
mapData = new ArrayList<String[]>();
mapPointData = new ArrayList<String[]>();
multiData = new ArrayList<String[]>();
}
private void setHomePoint() {
//GeoPoint centerPt = new GeoPoint(50.89489, 4.34140); // Point of Grand Place Brussels
homeLat = Double.parseDouble(getIntent().getExtras().getStringArray("geoLoc")[1]);
homeLong = Double.parseDouble(getIntent().getExtras().getStringArray("geoLoc")[2]);
GeoPoint centerPt = new GeoPoint(homeLat, homeLong);
if (checkMapRange(Double.parseDouble(getIntent().getExtras().getStringArray("geoLoc")[1]),
Double.parseDouble(getIntent().getExtras().getStringArray("geoLoc")[2]))) {
mapController.setCenter(centerPt);
Drawable marker = getResources().getDrawable(R.drawable.ic_pin_marker);
ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(new OverlayItem("Here I am!", "Hello", centerPt));
ItemizedOverlay<OverlayItem> itemOverlay =
new ItemizedIconOverlay<OverlayItem>(items, marker, null, new DefaultResourceProxyImpl(this));
mapView.getOverlays().add(itemOverlay);
mapView.invalidate();
} else {
mapController.setCenter(new GeoPoint(50.89489, 4.34140));
mapController.setZoom(11);
Action.alert(this, getResources().getString(R.string.alert_title_notinregion),
getResources().getString(R.string.alert_message_notinregion), false);
mapView.setClickable(false);
}
}
public void onClickMapPointsBN(View v) {
switch(v.getId()) {
case R.id.mapDoseeBN:
setPrefsCategory("DOSEE", doseeBN, "btn_map_dosee", "btn_map_dosee_pressed");
break;
case R.id.mapEatdrinkBN:
setPrefsCategory("EATDRINK", eatdrinkBN, "btn_map_eatdrink", "btn_map_eatdrink_pressed");
break;
case R.id.mapNightlifeBN:
setPrefsCategory("NIGHTLIFE", nightlifeBN, "btn_map_nightlife", "btn_map_nightlife_pressed");
break;
case R.id.mapSleepBN:
setPrefsCategory("SLEEP", sleepBN, "btn_map_sleep", "btn_map_sleep_pressed");
break;
}
setPOIs();
}
public void onClickDoseeListBN(View v) {
switch (v.getId()) {
case R.id.mapDoseeTop10BN:
setDosseSubCat(Definitions.doseeList[0], top10BN);
break;
case R.id.mapDoseeMuseumsBN:
setDosseSubCat(Definitions.doseeList[2], museumBN);
break;
case R.id.mapDoseeCultureBN:
setDosseSubCat(Definitions.doseeList[3], cultureBN);
break;
case R.id.mapDoseeAttractionBN:
setDosseSubCat(Definitions.doseeList[4], attractionsBN);
break;
case R.id.mapDoseeShoppingBN:
setDosseSubCat(Definitions.doseeList[5], shoppingBN);
break;
case R.id.mapDoseeMarketBN:
setDosseSubCat(Definitions.doseeList[6], marketBN);
break;
default:
setDosseSubCat(Definitions.doseeList[1], monumentsBN);
break;
}
setPOIs();
}
private void setPrefsCategory(String cat, ImageView btn, String image, String imageSelected) {
boolean sel = Prefs.getBoolean(this, "map" + cat, false);
Prefs.setBoolean(this, "map" + cat, !sel);
setCategoryImage(btn, image, imageSelected, sel);
if (cat.equalsIgnoreCase("DOSEE")) {
if (sel) {
doseeLL.setVisibility(View.GONE);
} else {
doseeLL.setVisibility(View.VISIBLE);
for (String s : Definitions.doseeList) {
if (s.equals(Definitions.doseeList[1])) {
Prefs.setBoolean(this, "mapDS_" + s, true);
} else {
Prefs.setBoolean(this, "mapDS_" + s, false);
}
}
}
setSubcategoryColor(sel);
}
}
private void setCategoryImage(ImageView btn, String image, String imageSelected, boolean selected) {
String devLang = Prefs.getString(this, "devLanguage", "en");
if (!devLang.equalsIgnoreCase("en")) {
image += "_" + devLang;
imageSelected += "_" + devLang;
}
if (selected) {
btn.setImageResource(this.getResources().getIdentifier(image, "drawable", getPackageName()));
} else {
btn.setImageResource(this.getResources().getIdentifier(imageSelected, "drawable", getPackageName()));
}
}
private void setSubcategoryColor(boolean doseeSelected) {
setDoseeSubCatTextColor(true, top10BN);
setDoseeSubCatTextColor(doseeSelected, monumentsBN);
setDoseeSubCatTextColor(true, museumBN);
setDoseeSubCatTextColor(true, cultureBN);
setDoseeSubCatTextColor(true, attractionsBN);
setDoseeSubCatTextColor(true, shoppingBN);
setDoseeSubCatTextColor(true, marketBN);
}
private void setPOIs() {
mapView.getOverlays().clear();
mapView.invalidate();
mapData.clear();
setHomePoint();
boolean selected;
for (String category : Definitions.categoryList) {
selected = Prefs.getBoolean(this, "map" + category, false);
Log.d("VB.Map", "Category: " + category + " selected: " + selected);
if (selected) {
if (category.equalsIgnoreCase("DOSEE")) {
boolean subSelected;
for (String subcategory : Definitions.doseeList) {
subSelected = Prefs.getBoolean(this, "mapDS_" + subcategory, false);
if (subSelected) {
getSqlData(category, subcategory);
}
}
} else {
getSqlData(category, null);
}
}
}
removeMapDataItems();
//mapPointData = mapData;
//multiDataLocationSelector();
setMapDataPoints();
//setMultiMapPoints();
}
private void getSqlData(String category, String subCategory) {
ArrayList<String[]> sqlData = SqlDB.db.getCategoryItems(Adjust.rewriteCategoryName(category), subCategory);
for (String[] data : sqlData) {
mapData.add(data);
}
}
private void removeMapDataItems() {
for (int i = 0; i < mapData.size(); i++) {
if ((mapData.get(i)[13].equalsIgnoreCase("")) || (mapData.get(i)[14].equalsIgnoreCase(""))) {
mapData.remove(i);
i--;
}
}
}
private void setDosseSubCat(String subCat, Button btn) {
boolean selected = Prefs.getBoolean(this, "mapDS_" + subCat, false);
Prefs.setBoolean(this, "mapDS_" + subCat, !selected);
setDoseeSubCatTextColor(selected, btn);
}
private void setDoseeSubCatTextColor(boolean selected, Button btn) {
if (selected) {
btn.setTextColor(Definitions.colorDoseeSubcat);
} else {
btn.setTextColor(Definitions.colorDoseeSubcatSelected);
}
}
private void setMapDataPoints() {
if (mapData != null) {
ArrayList<OverlayItem> mapOverlays = new ArrayList<OverlayItem>();
OverlayItem overlayItem;
for (String[] item : mapData) {
multiData.add(item);
if (existsInOverlayItems(item, mapOverlays)) {
overlayItem = new OverlayItem("-1", "", new GeoPoint(Float.parseFloat(item[13]), Float.parseFloat(item[14])));
overlayItem.setMarker(getResources().getDrawable(R.drawable.ic_pin_multiple));
} else {
overlayItem = new OverlayItem(item[0], "", new GeoPoint(Float.parseFloat(item[13]), Float.parseFloat(item[14])));
overlayItem.setMarker(getResources().getDrawable(getResources().getIdentifier(item[15], "drawable", getPackageName())));
}
mapOverlays.add(overlayItem);
}
setMapOverlays(mapOverlays);
}
}
private boolean existsInOverlayItems(String[] item, ArrayList<OverlayItem> overlayItemList) {
for (int i = 0; i < overlayItemList.size(); i++) {
if ((new GeoPoint(Double.parseDouble(item[13]), Double.parseDouble(item[14]))).equals(overlayItemList.get(i).mGeoPoint)) {
overlayItemList.remove(i);
return true;
}
}
return false;
}
private void setMapOverlays(ArrayList<OverlayItem> overlays) {
ItemizedOverlay<OverlayItem> itemOverlays = new ItemizedIconOverlay<OverlayItem>(
overlays, getResources().getDrawable(R.drawable.ic_pin_marker), new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
public boolean onItemLongPress(int arg0, OverlayItem item) {
mapOverlayItemPressed(Integer.parseInt(item.mTitle), item);
return false;
}
public boolean onItemSingleTapUp(int arg0, OverlayItem item) {
mapOverlayItemPressed(Integer.parseInt(item.mTitle), item);
return false;
}
}, new DefaultResourceProxyImpl(this));
mapView.getOverlays().add(itemOverlays);
mapView.invalidate();
}
private void mapOverlayItemPressed(int itemId, OverlayItem overlayItem) {
if (itemId == -1) {
Collect.multiPOIList.clear();
for (String[] item : multiData) {
if ((new GeoPoint(Double.parseDouble(item[13]), Double.parseDouble(item[14]))).equals(overlayItem.mGeoPoint)) {
Collect.multiPOIList.add(item);
}
}
Action.alertWithListView(this, getResources().getString(R.string.alert_title_multiplepoi), false);
} else {
SqlDB.db.getItemsById(itemId);
Bundle b = new Bundle();
b.putInt("listSelection", 0);
Action.newIntent(c, DetailActivity.class, b);
}
}
private boolean checkMapRange(double lat, double lng) {
double mapLatMax = 50.922085;
double mapLatMin = 50.781631;
double mapLongMin = 4.240723;
double mapLongMax = 4.490662;
if ((lat > mapLatMin) && (lat < mapLatMax)) {
if ((lng > mapLongMin) && (lng < mapLongMax)) {
return true;
}
}
return false;
}
}
And here the code of the OSMapActivity:
public class OSMapActivity extends ActionbarActivity {
protected Context c;
protected MapView mapView;
protected MapController mapController;
protected ArrayList<String[]> mapData;
protected ImageView doseeBN;
protected ImageView eatdrinkBN;
protected ImageView nightlifeBN;
protected ImageView sleepBN;
protected LinearLayout doseeLL;
protected Button top10BN;
protected Button monumentsBN;
protected Button museumBN;
protected Button cultureBN;
protected Button attractionsBN;
protected Button shoppingBN;
protected Button marketBN;
protected double homeLat;
protected double homeLong;
public void onClickABActionButton(View v) {
boolean actionButton = Prefs.getBoolean(this, "abActionButtonRoute", false);
if (actionButton) {
// TODO Add with current location => location manager in separate class
/*GPS.init(this);
GPS.enableGPSProvider();
GPS.enableNetworkProvider();
//Action.loadApp(this, Intent.ACTION_VIEW, Uri.parse("geo:50.89489,4.34140?daddr=Heiveld+21+Opwijk"));
Action.loadApp(this, Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?saddr=" + GPS.latitude + "," + GPS.longitude
+ "&daddr=Heiveld+21+1745+Opwijk"));
GPS.stop();*/
Action.loadMapsWithMyLocation(this, homeLat, homeLong);
} else {
Collect.dbList.clear();
for (String[] data : mapData) {
Collect.dbList.add(data);
}
// TODO Load new intent with list
Action.newIntent(this, MapListActivity.class, null);
}
}
}
Thanks for your help.
Kr
I raised an issue on version 3.0.6 about this. In the comments the authors say it was fixed on Feb 1st. As the 3.0.7 jar is dated Jan 29, I assume the fix isn't in it. I'm sticking with version 3.0.5 for now, although the cycle maps don't work in it and the tile loading can be a bit flickery. If your maps are offline though, they should load pretty fast and flicker might not be an issue.
I'm not 100% sure if this is the same problem as reported here:
OSMDroid Google Group
If so then the solution (for now) seems to be to download the current OSMDroid source and build your own .jar library.
No changes to the source are required BUT the tile loading problem is fixed.

Categories

Resources