How to add a setMyLocationEnabled button on OSMap? - osmdroid

Can we enable a 'GotoMyLocation' button on OSMDroid like mMap.setMyLocationEnabled(true); on GoogleMap?
I didn't find such feature in MapView class.

Create one of these
org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay mylocation = new MyLocationNewOverlay(...);
Add it to your MapView
mMapView.getOverlays().add(mylocation);
Then try
mylocation.enableFollowLocation();

To set your current location use, LOCATION_SERVICE of LocationManager. This will listen your gps location and will set your center to the present location.
LocationManager myLocationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
LocationListenerProxy llp=new LocationListenerProxy(myLocationManager);
llp.startListening(gpsLocationListener, 1, 1) ;
place this code in your onCreate Activity and then define locationlistener in a different class
public final LocationListener gpsLocationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location){
textView.setText(location.getLatitude()+","+location.getLongitude());
Log.d("Location Changed >>> ", location.getLatitude()+","+location.getLongitude());
}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider){}
public void onStatusChanged(String provider, int status, Bundle extras){}
};

Related

osmdroid: Tile server which allows bulk download

I am working on an application, for which I need to be able to use map data, while offline. I have looked up how to use the CacheManager and how to download tiles referencing the SampleCacheDownloader.java.
I am using the following code to download the tiles:
CacheManager cMgr = new CacheManager(map);
BoundingBox bBox = cMgr.extendedBoundsFromGeoPoints(currentGeoPoints, 16);
cMgr.downloadAreaAsync(this, bBox, 16, 21, new CacheManager.CacheManagerCallback() {
#Override
public void onTaskComplete() {
}
#Override
public void updateProgress(int progress, int currentZoomLevel, int zoomMin, int zoomMax) {
}
#Override
public void downloadStarted() {
}
#Override
public void setPossibleTilesInArea(int total) {
}
#Override
public void onTaskFailed(int errors) {
}
});
The code works, as in starting the download. But all the tile servers, which are included in the TileSourceFactory class either throw the TileSourcePolicyException "This online tile source doesn't support bulk download" (e.g. MAPNIK and WIKIMEDIA) or fail to get the tiles, because they don't exist for the set zoom levels (e.g. USGS_SAT and USGS_TOPO).
So my question is, are there other publicly available tile servers or do I have to set up my own to be able to download tiles in bulk? Or do I have the completely wrong approach to caching the tiles included in a bounding box with set zoom levels?

Google Maps two finger pinch/stretch callbacks

In my map, I am trying to capture zoom in/out using ScaleGestureDetector but I am never receiving any callbacks to either of onScale or onScaleBegin or onScaleEnd.
In my Fragment's onCreateView, I initialize:
scaleGestureDetector = new ScaleGestureDetector(getContext(), new simpleOnScaleGestureListener());
And I implement the callbacks like so:
public class simpleOnScaleGestureListener extends
SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
startScale = detector.getScaleFactor();
Log.d(TAG, "::onScale:: " + detector.getScaleFactor());
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
Log.d(TAG, "::onScaleBegin:: " + detector.getScaleFactor());
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
Log.d(TAG, "::onScaleEnd:: " + detector.getScaleFactor());
endScale = detector.getScaleFactor();
}
Also, is it fair to assume that the callbacks will be called continuously whenever the user zooms in/out?
I was able to get past the issue of getting callbacks. Essentially, two things:
In your activity/fragment, implement, GoogleMap.OnCameraIdleListener
In onMapReady(), call mMap.setOnCameraIdleListener(this);
Hence, override onCameraIdle():
#Override
public void onCameraIdle() {
Log.i(TAG, "::onCameraIdle::" + mMap.getCameraPosition().toString());
}
to get lat/long, zoom, tilt and bearing, essentially CameraPosition.
I found a way to get radius in meters by referring to this response
VisibleRegion vr = map.getProjection().getVisibleRegion();
Location center = new Location("center");
center.setLatitude(vr.latLngBounds.getCenter().latitude);
center.setLongitude(vr.latLngBounds.getCenter().longitude);
//Location("radiusLatLng") as mentioned in google maps sample
Location farVisiblePoint = new Location("radiusLatLng");
farVisiblePoint.setLatitude(vr.farLeft.latitude);
farVisiblePoint.setLongitude(vr.farLeft.longitude);
radius = center.distanceTo(farVisiblePoint);

JavaFX - using toggle isSelected() in conditional statements

I'm building a simple sketch program using JavaFX. I want the user to be able to switch between drawing a rectangle, circle or line and I've put toggle radio buttons in the menu for these options.
Is it possible to write an if/else statement so I can write code for three different functions depending on which is selected? At the moment it will only draw lines. This is part of my code so far (sorry it's messy):
package Sketchbook;
public class Sketchbook extends Application {
final static int CANVAS_WIDTH = 800;
final static int CANVAS_HEIGHT = 600;
ColorPicker colorPicker1;
ColorPicker colorPicker2;
#Override
public void start(final Stage primaryStage) {
final Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
final GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
initDraw(graphicsContext);
canvas.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
graphicsContext.beginPath();
graphicsContext.moveTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
}
});
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
graphicsContext.lineTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
}
});
canvas.addEventHandler(MouseEvent.MOUSE_RELEASED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
}
});
Group root = new Group();
ToggleGroup toggleGroup = new ToggleGroup();
RadioButton rectangle = new RadioButton("Rectangle");
RadioButton circle = new RadioButton("Circle");
RadioButton line = new RadioButton("Line");
rectangle.setSelected(true);
rectangle.setToggleGroup(toggleGroup);
circle.setToggleGroup(toggleGroup);
line.setToggleGroup(toggleGroup);
You've pretty much already described what you need to do:
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
if (toggleGroup.getSelectedToggle() == line) {
graphicsContext.lineTo(event.getX(), event.getY());
graphicsContext.setStroke(colorPicker1.getValue());
graphicsContext.stroke();
} else if (toggleGroup.getSelectedToggle() == rectangle) {
// etc...
} // etc...
}
}
});
Obviously you may need to reorder the code a little to make sure variables are declared and initialized before you use them.

Built-in ScrollView that scrolls with head motion

Speaking "ok glass" brings up a command list that automatically scrolls based on the user's head motion.
Is there a built-in UI element in the GDK that implements this? Or will I have to write my own code that uses sensors?
I tried reimplementing parts of this. It's not as shiny as the google one, but those could serve as a starting point:
https://github.com/pscholl/glass_snippets/blob/master/lib/src/main/java/de/tud/ess/HeadListView.java
https://github.com/pscholl/glass_snippets/blob/master/lib/src/main/java/de/tud/ess/HeadScrollView.java
I went through the GDK's Developer Guides at https://developers.google.com/glass/develop/gdk/dev-guides and Reference at https://developers.google.com/glass/develop/gdk/reference/index and there's definitely no such built-in UI elements in GDK, as of XE 12 released in December 2013.
So the answer for now is yes you have to use sensors to implement that.
There is currently no native GDK UI element for scrolling a list using sensors (in fact, according to this issue, use of ListView at all appears to be discouraged).
However, I was able to get the following to work reasonably well in my app. My list is fixed at 4 elements (which helps determine how much scrolling happens), so you can tweak this accordingly (see comments).
import com.google.android.glass.media.Sounds;
import com.google.android.glass.touchpad.Gesture;
import com.google.android.glass.touchpad.GestureDetector;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.view.MotionEvent;
import android.widget.ListView;
/**
* Implements sensor-based scrolling of a ListView
*/
public class SensorListController implements SensorEventListener, GestureDetector.BaseListener {
static final String TAG = "SensorListController";
Context mContext;
ListView mList;
SensorManager mSensorManager;
private float[] mRotationMatrix = new float[16];
private float[] mOrientation = new float[9];
private float[] history = new float[2];
private float mHeading;
private float mPitch;
boolean mActive = true;
GestureDetector mGestureDetector;
public SensorListController(Context context, ListView list) {
this.mContext = context;
this.mList = list;
history[0] = 10;
history[1] = 10;
mGestureDetector = new GestureDetector(mContext);
mGestureDetector.setBaseListener(this);
}
/**
* Receive pass-through of event from View
*/
public boolean onMotionEvent(MotionEvent event) {
return mGestureDetector.onMotionEvent(event);
}
#Override
public boolean onGesture(Gesture gesture) {
switch (gesture) {
case TWO_LONG_PRESS:
// Toggle on and off accelerometer control of the list by long press
playSuccessSound();
toggleActive();
return true;
case TWO_TAP:
// Go to top of the list
playSuccessSound();
scrollToTop();
return true;
}
return false;
}
/**
* Should be called from the onResume() of Activity
*/
public void onResume() {
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR),
SensorManager.SENSOR_DELAY_UI);
}
/**
* Should be called from the onPause() of Activity
*/
public void onPause() {
mSensorManager.unregisterListener(this);
}
/**
* Toggles whether the controller modifies the view
*/
public void toggleActive() {
mActive = !mActive;
}
#Override
public void onSensorChanged(SensorEvent event) {
if (mList == null || !mActive) {
return;
}
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X,
SensorManager.AXIS_Z, mRotationMatrix);
SensorManager.getOrientation(mRotationMatrix, mOrientation);
mHeading = (float) Math.toDegrees(mOrientation[0]);
mPitch = (float) Math.toDegrees(mOrientation[1]);
float xDelta = history[0] - mHeading; // Currently unused
float yDelta = history[1] - mPitch;
history[0] = mHeading;
history[1] = mPitch;
float Y_DELTA_THRESHOLD = 0.13f;
// Log.d(TAG, "Y Delta = " + yDelta);
int scrollHeight = mList.getHeight()
/ 19; // 4 items per page, scroll almost 1/5 an item
// Log.d(TAG, "ScrollHeight = " + scrollHeight);
if (yDelta > Y_DELTA_THRESHOLD) {
// Log.d(TAG, "Detected change in pitch up...");
mList.smoothScrollBy(-scrollHeight, 0);
} else if (yDelta < -Y_DELTA_THRESHOLD) {
// Log.d(TAG, "Detected change in pitch down...");
mList.smoothScrollBy(scrollHeight, 0);
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private void scrollToTop() {
mList.smoothScrollToPosition(0);
}
private void playSuccessSound() {
// Play sound to acknowledge action
AudioManager audio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
audio.playSoundEffect(Sounds.SUCCESS);
}
}
I used the above in a ListActivity. I initialize it in onCreate(), and here is the method that initializes it:
private void initListController() {
mListView = getListView();
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.setSelector(android.R.color.transparent);
mListView.setClickable(true);
mListController = new SensorListController(this, mListView);
}
This also removes the selection indicator from view by making it transparent.
The above controller also uses two finger press to pause/resume scrolling, and a two finger tap to scroll to the top of the list (and acknowledges both these actions with a sound). Note that for these gestures to work, you will need to override onGenericMotionEvent() in your Activity and pass through the event, like:
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
// We need to pass events through to the list controller
if (mListController != null) {
return mListController.onMotionEvent(event);
}
return false;
}
Full source code for this solution can be seen on Github, and the APK can be downloaded here.

Card not showing; goes straight to home card

I am trying to show a card so I know everything up to that point works. However, when I try to display the card, it just goes straight to the home card. The card I was trying to show was just going to display what was said in the voice recognizer before but that didn't work so I just put plain text and that didn't work either. Application goes - voice trigger --> voice recognizer --> this service:
public class MedMinderService extends Service {
public String MedName;
public String voiceResults;
private static final String TAG = "ShowData";
private static final String LIVE_CARD_ID = "showdata";
public static final String PREFS_NAME = "MyPreferencesFile";
private TimelineManager mTimelineManager;
private LiveCard mLiveCard;
#Override
public void onCreate() {
super.onCreate();
mTimelineManager = TimelineManager.from(this);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId) {
String voiceResults = intent.getExtras()
.getString(RecognizerIntent.EXTRA_RESULTS);
String MedName = voiceResults; //MedName declared
SharedPreferences MedInfo = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = MedInfo.edit();
editor.putString("MedName", MedName.toString());
editor.commit();
mLiveCard = mTimelineManager.getLiveCard(LIVE_CARD_ID);
Intent i = new Intent(this, ShowDataActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
return START_STICKY;
}
}
The intent at the bottom goes to this activity:
public class ShowDataActivity extends Activity {
private LiveCard mLiveCard;
public static final String PREFS_NAME = "MyPreferencesFile";
private GestureDetector mGestureDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences MedInfo = getSharedPreferences(PREFS_NAME, 0);
Card ShowDataCard = new Card(this);
ShowDataCard.setText("IT WORKS!");
//ShowDataCard.setText(MedInfo.getString("MedName", "your medication"));
View ShowDataCardView = ShowDataCard.toView();
setContentView(ShowDataCardView);
}
The "ShowDataCard" that has been commented out is what I was origonally trying to do with the voice recognition but it wouldn't even work with the text "IT WORKS!"
Again: I am just trying to show a card with the text "IT WORKS"
thanks
The easiest way to get a live card to appear with just text is using widgets that are compatible with RemoteViews. You can find a list of them in the GDK documentation here:
https://developers.google.com/glass/develop/gdk/ui/live-cards
under the Creating low-frequency live cards section.
Here is some sample code (based on your code above) that can get that working quickly:
final String LIVE_CARD_ID = "showdata";
mLiveCard = mTimelineManager.getLiveCard(LIVE_CARD_ID);
RemoteViews remoteViews =
new RemoteViews(getPackageName(), R.layout.layout_helloglass);
mLiveCard.setViews(remoteViews);
// Make sure Glass navigates to LiveCard immediately
mLiveCard.setNonSilent(true);
mLiveCard.publish();
The layout file can look like this for layout_helloglass.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Hello, Glass!" />
</FrameLayout>
If you still want to navigate to another Activity from your LiveCard, you need to associate the Activity with a PendingIntent and then associate that PendingIntent with the LiveCard's action. This would happen immediately before the LiveCard.publish() method:
Intent i = new Intent(this, ShowCardActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(this, 0, i, 0));
That should get you up and running! Hopefully this will help.
There was a bug in the GDK Sneak Peek that prevented voice prompts from creating Services. If one inserted a Log.d() call in a Service's onStartCommand() override, they would discover that it were never called.
This bug has been fixed in the GDK Preview. This behavior should not appear again.
This question was rewritten after the GDK Preview launch to remove this outdated answer. Thanks to user Falcon for notifying me.