Enable automatic zoom with SKZoonLevelConfiguration - android

Here is the situation, I want to set up the navigation mode to adjust the zoom to route according to the current speed. See my code:
SKZoomLevelConfiguration[] zoomConfgs = new SKZoomLevelConfiguration[4];
zoomConfgs[0] = new SKZoomLevelConfiguration(0.0f, 10.0f, 15.0f);
zoomConfgs[1] = new SKZoomLevelConfiguration(10.0f, 20.0f, 13.0f);
zoomConfgs[2] = new SKZoomLevelConfiguration(20.0f, 60.0f, 10.0f);
zoomConfgs[3] = new SKZoomLevelConfiguration(60.0f, 100.0f, 8.0f);
SKNavigationSettings navSettings = new SKNavigationSettings();
navSettings.setNavigationType(SKNavigationSettings.SKNavigationType.REAL);
navSettings.setNavigationMode(SKNavigationSettings.SKNavigationMode.CAR);
navSettings.setDistanceUnit(SKMaps.SKDistanceUnitType.DISTANCE_UNIT_KILOMETER_METERS);
navSettings.setZoomLevelConfigurations(zoomConfgs);
navSettings.setPositionerVerticalAlignment(-0.25f);
SKNavigationManager.getInstance().setNavigationListener(navListener);
SKNavigationManager.getInstance().setMapView(surfaceView);
surfaceView.getMapSettings().setMapDisplayMode(SKMapSettings.SKMapDisplayMode.MODE_3D);
SKNavigationManager.getInstance().startNavigation(navSettings);
isNavigating = true;
So the fact here is the map isn't zooming when the navigation is activated. Probably i'm doing something wrong.

In 2.5 there was an issue with this API - it was fixed for 2.6.
Here is a code snippet of how it works in 2.6:
/**
* Launches a navigation on the current route
*/
private void launchNavigation() {
if (TrackElementsActivity.selectedTrackElement != null) {
mapView.clearTrackElement(TrackElementsActivity.selectedTrackElement);
}
// get navigation settings object
SKNavigationSettings navigationSettings = new SKNavigationSettings();
// set the desired navigation settings
navigationSettings.setNavigationType(SKNavigationType.SIMULATION);
navigationSettings.setPositionerVerticalAlignment(-0.25f);
navigationSettings.setShowRealGPSPositions(false);
SKZoomLevelConfiguration[] configurations = new SKZoomLevelConfiguration[2];
configurations[0] = new SKZoomLevelConfiguration(0, 70, 10);
configurations[1] = new SKZoomLevelConfiguration(70, 100, 15);
navigationSettings.setZoomLevelConfigurations(configurations);
// get the navigation manager object
SKNavigationManager navigationManager = SKNavigationManager.getInstance();
navigationManager.setMapView(mapView);
// set listener for navigation events
navigationManager.setNavigationListener(this);
// start navigating using the settings
navigationManager.startNavigation(navigationSettings);
navigationInProgress = true;
}
Note: The speed values(km/h) set in SKZoomLevelConfigurations are correlated to the current speed(m/s) from SKNavigationState.
The onUpdateNavigationState(SKNavigationState navigationState) method provides notifications when data related to the current speed is updated.

Related

How to perform a touch and hold gesture using AccessibilityService?

Path clickPath = new Path();
clickPath.moveTo(x, y);
GestureDescription.StrokeDescription clickStroke = new GestureDescription.StrokeDescription(clickPath, 0, 1);
GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
clickBuilder.addStroke(clickStroke);
dispatchGesture(clickBuilder.build(), null, null);
With this code I can perform clicks anywhere on the screen. Is there any way to perform touch and hold gesture using AccessibilityService?
Is there any way to perform touch and hold gesture using AccessibilityService?
I think that you need decide if the gesture willContinue or not. Then, based in your code i suggest change:
GestureDescription.StrokeDescription clickStroke = new GestureDescription.StrokeDescription(clickPath, 0, 1);
To:
GestureDescription.StrokeDescription clickStroke = new GestureDescription.StrokeDescription(clickPath, 0, 1, true);
Simply, add true to last parameter of StrokeDescription. PS: this works only from Android 8+.

OSMdroid Custom and rotating icon of current location

I am using OSMdroid to show an offline map with user's current location.
1) PREFERRED - I would like to change the default icon showing current location to a custom icon. Also I need it to change its rotation based on bearing returned from GPS lets say every 5 seconds. The position of the icon should be in the center of the screen.
OR
2) possibility - rotating the map with custom current location icon fixed on the bottom of the screen.
Is there any way to do it in osmdroid?
Thanks.
1) that's been supported for a while with osmdroid. There are several my location type overlays and examples on how to use them. Depending on what version of osmdroid you're using, the mechanism to replace the default icon is a bit different.
2) there's a pull request open for osmdroid to support this feature. i'm pretty sure it allowed for the my location offset to be anywhere on the screen.
Seems like I figured out the first possibility.
I added a marker to the map which changes its position when onLocationChanged() is called. Also the map moves so the marker is in the center. Then I do marker.setRotation(bearing).
myLocationOverlay = new DirectedLocationOverlay(this);
Drawable d = ResourcesCompat.getDrawable(getResources(), R.drawable.direction_arrow, null);
Bitmap bitmap = ((BitmapDrawable) d).getBitmap();
myLocationOverlay.setDirectionArrow(bitmap);
//code to change default location icon
map.getOverlays().add(myLocationOverlay);
need to implement onLocationChanged method
#Override
public void onLocationChanged(final Location pLoc) {
long currentTime = System.currentTimeMillis();
if (mIgnorer.shouldIgnore(pLoc.getProvider(), currentTime))
return;
double dT = currentTime - mLastTime;
if (dT < 100.0) {
//Toast.makeText(this, pLoc.getProvider()+" dT="+dT, Toast.LENGTH_SHORT).show();
return;
}
mLastTime = currentTime;
GeoPoint newLocation = new GeoPoint(pLoc);
if (!myLocationOverlay.isEnabled()) {
//we get the location for the first time:
myLocationOverlay.setEnabled(true);
map.getController().animateTo(newLocation);
}
GeoPoint prevLocation = myLocationOverlay.getLocation();
myLocationOverlay.setLocation(newLocation);
myLocationOverlay.setAccuracy((int) pLoc.getAccuracy());
if (prevLocation != null && pLoc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
mSpeed = pLoc.getSpeed() * 3.6;
long speedInt = Math.round(mSpeed);
TextView speedTxt = findViewById(R.id.speed);
speedTxt.setText(speedInt + " km/h");
//TODO: check if speed is not too small
if (mSpeed >= 0.1) {
mAzimuthAngleSpeed = pLoc.getBearing();
myLocationOverlay.setBearing(mAzimuthAngleSpeed);
}
}
if (mTrackingMode) {
//keep the map view centered on current location:
map.getController().animateTo(newLocation);
map.setMapOrientation(-mAzimuthAngleSpeed);
} else {
//just redraw the location overlay:
map.invalidate();
}
if (mIsRecordingTrack) {
recordCurrentLocationInTrack("my_track", "My Track", newLocation);
}
}

CallOut popup doesn't position itself with zoom in/out

I have an Arcgis map with pins.When i tap on a pin i am showing a callout(popover)over the pins which works perfectly fine.But when i zoom in/out the map, callout does't position itself with respect to the pin on the map.How can i always show callout on top of pin while zooming in/out.
tap on pin and callout pops up
and the image where pop up moves away from pin when zoom in
Note: I have made changes to the existing sample project of Arcgis map app i.e. SymbolizingResults
Here are the changes i have made to the SymbolizingResults Activity
public class SymbolizingResults extends Activity {
MapView map;
Button queryBtn;
GraphicsLayer gl;
Callout callout;
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
map = (MapView) findViewById(R.id.map);
map.addLayer(new ArcGISTiledMapServiceLayer(
"http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));
gl = new GraphicsLayer();
gl.setRenderer(createClassBreaksRenderer());
Point p = new Point(37.6922222, -97.3372222);
HashMap<String, Object> map1 = new HashMap<String, Object>();
map1.put("NAME", "India");
PictureMarkerSymbol pic = new PictureMarkerSymbol(this,getResources().getDrawable(R.drawable.pin_dest));
Graphic gr = new Graphic(p,pic,map1);
gl.addGraphic(gr);
map.addLayer(gl);
queryBtn = (Button) findViewById(R.id.querybtn);
queryBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Sets query parameter
Query query = new Query();
query.setWhere("STATE_NAME='Kansas'");
query.setReturnGeometry(true);
String[] outfields = new String[] { "NAME", "STATE_NAME",
"POP07_SQMI" };
query.setOutFields(outfields);
query.setOutSpatialReference(map.getSpatialReference());
Query[] queryParams = { query };
AsyncQueryTask qt = new AsyncQueryTask();
qt.execute(queryParams);
}
});
// Sets 'OnSingleTapListener' so that when single tap
// happens, Callout would show 'SQMI' information associated
// with tapped 'Graphic'
map.setOnSingleTapListener(new OnSingleTapListener() {
private static final long serialVersionUID = 1L;
public void onSingleTap(float x, float y) {
if (!map.isLoaded())
return;
Point toDroppedPinPoint = map.toMapPoint(x, y);
System.out.println("X : "+toDroppedPinPoint.getX());
System.out.println("Y : "+toDroppedPinPoint.getY());
int[] uids = gl.getGraphicIDs(x, y, 2);
if (uids != null && uids.length > 0) {
int targetId = uids[0];
Graphic gr = gl.getGraphic(targetId);
callout = map.getCallout();
// Sets Callout style
callout.setStyle(R.xml.countypop);
/* String countyName = (String) gr.getAttributeValue("NAME");
String countyPop = gr.getAttributeValue("POP07_SQMI")
.toString();*/
// Sets custom content view to Callout
callout.setContent(loadView("Anshul", "India"));
callout.show(map.toMapPoint(new Point(x, y)));
} else {
if (callout != null && callout.isShowing()) {
callout.hide();
}
}
}
});
}
// Creates custom content view with 'Graphic' attributes
private View loadView(String countyName, String pop07) {
View view = LayoutInflater.from(CalloutSampleActivity.this).inflate(
R.layout.sqmi, null);
final TextView name = (TextView) view.findViewById(R.id.county_name);
name.setText(countyName + "'s SQMI");
final TextView number = (TextView) view.findViewById(R.id.pop_sqmi);
number.setText(pop07);
final ImageView photo = (ImageView) view
.findViewById(R.id.family_photo);
photo.setImageDrawable(CalloutSampleActivity.this.getResources()
.getDrawable(R.drawable.family));
return view;
}`
The trouble is this line:
callout.show(map.toMapPoint(new Point(x, y)));
Here you're saying you want to show the callout at the point that the user tapped. That's what the sample does, and in the sample it always makes sense because the sample's graphics are all polygons (i.e. counties in Kansas).
But for a point, like the pin you added, you don't want to show the callout at the tapped point. If the tapped point is a couple of pixels away from the pin, and then you zoom out, the difference can be hundreds of miles! Instead, you want to show the callout at the pin graphic's point. But you only want to do that if it's actually a point, so you need to check the graphic's geometry with instanceof.
I replaced the above line with this and it works:
Geometry graphicGeom = gr.getGeometry();
if (graphicGeom instanceof Point) {
callout.show((Point) graphicGeom);
} else {
callout.show(toDroppedPinPoint);
}
I couldn't see the code about how you are zooming in & out. But logically you should update the callout position in zoom-in & zoom-out too like you are doing in onSingleTap().

Box2d Cocos2d Android gravity not working

I'm trying to create a simple test for Box2d, Cocos2d, and Android. All I need is to put one body on the screen, and have it respond to gravity. I looked everywhere and there are good tutorials for non-Android applications but none of them has gravity on Android working. Can anyone help?
This is the code I'm using. I took it, and modified lightly from here: http://www.expobrain.net/2012/05/12/box2d-physics-simulation-on-android/
For creating the world:
World world = new World(new Vec2(2.0f, 8.0f), false);
And this is how I create the body:
public void setupBallBody() {
CGSize size = CCDirector.sharedDirector().winSize();
CGPoint pos = CGPoint.make(size.width / 1.2f, size.height / 1.2f);
// Create Dynamic Body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position.set(screenToWorld(pos));
ballBody = world.createBody(bodyDef);
MassData md = new MassData();
md.mass = 5;
ballBody.setMassData(md);
// Create Shape
CircleShape ballShape = new CircleShape();
ballShape.m_radius = SMILE_RADIUS;
// Create fixture
FixtureDef ballFixture = new FixtureDef();
ballFixture.shape = ballShape;
ballFixture.density = SMILE_DENSITY;
ballFixture.friction = SMILE_FRICTION;
ballFixture.restitution = SMILE_RESTITUTION;
// Assign fixture to Body
ballBody.createFixture(ballFixture);
// Set sprite
final CCSprite ballSprite = CCSprite.sprite("ball.jpg");
ballSprite.setPosition(pos);
addChild(ballSprite, 0);
ballBody.setUserData(ballSprite);
}
This is my "tick" method (which I'm not sure is part of what makes gravity working but I include it here for completeness.)
public void tick(float dt) {
synchronized (world) {
world.step(1/60, 10, 10);
}
// Update sprites
for (Body b = world.getBodyList(); b != null; b = b.getNext()) {
if(b == ballBody) {
CCSprite ballSprite = (CCSprite)ballBody.getUserData();
if(ballSprite != null) {
ballSprite.setPosition(worldToScreen(ballBody.getPosition())));
ballSprite.setRotation(-1.0f * (float)Math.toDegrees((ballBody.getAngle())));
}
}
}
}
My guessing here is this line may be the problem.-
world.step(1/60, 10, 10);
step function handles the bodies positions based on the time passed since last step. You're doing an integer division 1/60, which result is 0. Try 1.0f / 60.0f instead.
Otherwise, you're telling your world that 0 milliseconds passed since the last step, so bodies will always remain at their initial position.
However, it's not good practice to 'hardcode' your time step. You better pass to your world step the delta time your receiving.-
world.step(dt, 10, 10);
Also, you may simplify your loop to work for any body with an attached CCSprite, like this.-
for (Body b = world.getBodyList(); b != null; b = b.getNext()) {
CCSprite sprite = (CCSprite)b.getUserData();
if(sprite != null) {
sprite.setPosition(worldToScreen(b.getPosition())));
sprite.setRotation(-1.0f * (float)Math.toDegrees((b.getAngle())));
}
}

MapView latitudeSpan / longtitudeSpan not working

I am trying to get the bounds of my mapview but I had the problem that the latitude is always set to 0 and longtitude is always set to 360*1E6. According to this link, that is because it will only offer the right coordinates when the map is fully loaded:
Mapview getLatitudeSpan and getLongitudeSpan not working
Now, I am totally confused about the solution, I made this method which I call from the onCreate of my mainactivity (the mapview):
public int[][] getBounds()
{
GeoPoint center = this.mapView.getMapCenter();
int latitudeSpan = this.mapView.getLatitudeSpan();
int longtitudeSpan = this.mapView.getLongitudeSpan();
int[][] bounds = new int[2][2];
bounds[0][0] = center.getLatitudeE6() + (latitudeSpan/2);
bounds[0][1] = center.getLongitudeE6() + (longtitudeSpan/2);
bounds[1][0] = center.getLatitudeE6() - (latitudeSpan/2);
bounds[1][1] = center.getLongitudeE6() - (longtitudeSpan/2);
return bounds;
}
How do I make this wait for the mapview to load? I've looked in the API for postDelayed, but I cannot get it to work.
Forgive me if I am being stupid o.o'
The correct way to create a "Timer" in android is to utilize android.os.Handler:
private Handler updateHandler = new Handler();
updateHandler.postDelayed(waitForMapTimeTask, TIME_TO_WAIT_IN_MS);
private Runnable waitForMapTimeTask = new Runnable() {
public void run() {
getBounds();
// Read the bounds to see if something reasonable is returned
if (!mapIsLoaded) {
updateHandler.postDelayed(waitForMapTimeTask, TIME_TO_WAIT_IN_MS);
}
}
};

Categories

Resources