I've been working on a project to create a map (using googles api) where the user can longpress to place custom overlays. So far I've been able to allow the user to place one overlay, but when you go to place the second the program crashes. I suspect it's because the method attempts to reuse the same variable name? Here's the segment of code I'm using, any help as to how to achieve this would be greatly appreciated.
#Override
public void onLongPressFinished(MotionEvent e, ManagedOverlay overlay, GeoPoint point, ManagedOverlayItem item) {
if (item != null)
Toast.makeText(getApplicationContext(), "You selected..." + item.getTitle() + "!", Toast.LENGTH_LONG).show();
ManagedOverlay managedOverlay = overlayManager.createOverlay("listenerOverlay", getResources().getDrawable(R.drawable.tankicon));
managedOverlay.createItem(point, "text");
overlays.add(managedOverlay);
overlayManager.populate();
}
}
please try this one. This is used for showing multiple overlays on map view, may be it will solve the problem: https://github.com/donnfelker/android-mapviewballoons
To solve the problem I simply used the onDoubleTap method instead of the longPress. The longPress turned out to be way to problematic as it could be misinterpreted, and sometimes did not work.
The bulk of the code is still the same however.
#Override
public boolean onDoubleTap(MotionEvent e, ManagedOverlay overlay, GeoPoint point, ManagedOverlayItem item) {
ManagedOverlay managedOverlay = overlayManager.createOverlay("Location", getResources().getDrawable(R.drawable.icon));
managedOverlay.createItem(point, "place");
overlays.add(managedOverlay);
Toast.makeText(getApplicationContext(), "You selected " + managedOverlay.getName() + " !", Toast.LENGTH_LONG).show();
overlayManager.populate();
Related
There's something that android TalkBack does that I want to do too. Specifically it's to identify the view that the user touched. I made this so far:
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
//This only shows the package of the activity that the view is in, I want to identify the view itself
Toast.makeText(this, "" + event.getSource().getPackageName(), Toast.LENGTH_LONG).show();
}
}
You can get the view's id, but I think you can only access the AccessibilityNodeInfo associated with the view - I don't think you have access to the view itself. You can check the docs for more information on this.
// kotlin code
event.source.viewIdResourceName
// or
findFocusedViewInfo().viewIdResourceName
According to the docs:
Gets the fully qualified resource name of the source view's id.Note: The primary usage of this API is for UI test automation and in order to report the source view id of an AccessibilityNodeInfo the client has to set the AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS flag when configuring the AccessibilityService.
the question is not clear, but maybe this will help you:-
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source == null) {
return;
}
List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId = source.findAccessibilityNodeInfosByViewId("YOUR PACKAGE NAME:id/RESOURCE ID FROM WHERE YOU WANT DATA");
if (findAccessibilityNodeInfosByViewId.size() > 0) {
AccessibilityNodeInfo parent = (AccessibilityNodeInfo) findAccessibilityNodeInfosByViewId.get(0);
// You can also traverse the list if required data is deep in view hierarchy.
String requiredText = parent.getText().toString();
Log.i("Required Text", requiredText);
}
}
also read this tutorial
Up until a few weeks ago, my LifeCycleOwnerAwareObserver class was working fine.
It was design with the purpose of self detach on Destroy.
#Override
public void onStateChanged(#NonNull LifecycleOwner source, #NonNull Lifecycle.Event event) {
Log.d(TAG, "onStateChanged: event is: " + event.name());
Lifecycle.State state = source.getLifecycle().getCurrentState();
Log.println(Log.WARN, TAG, "onStateChanged: state is: " + state.name());
if (state.isAtLeast(INITIALIZED) && !state.equals(DESTROYED)) {
observer.get().accept(event);
} else if (state.equals(DESTROYED)) {
observer.get().accept(event);
observer.set(() -> null);
source.getLifecycle().removeObserver(this);
}
}
The idea was to build lifeCycle aware components to handle automatic unregistering.
90% of my project relies on this components...
I have not perceived any change, specially on Adapters, which listen to Fragments, the only a weird behavior I saw, where onViewCreated (an ON_START callback attaches an observer to the fragment's LifeCycleOwnerLiveData) was triggering slightly after the real onViewCreated(), but ONLY when coming back from the backStack... This is not good at all, but with some precautions it can be somewhat ignored.
But then this was the weirdest of them all...
I have a custom view (ViewParticle.class) with its own LifeCycle that implements a LifeCycleRegistry.
This code was working a few weeks ago... since I have not been testing everything constantly, I am not sure at which moment this stopped working here is the code:
private final MyLifeCycleOwner mViewLifecycleOwner = new MyLifeCycleOwner();
#Override
public void viewDestroyed() {
Lifecycle.Event event = Lifecycle.Event.ON_DESTROY;
Log.d(TAG, "viewDestroyed: event is: " + event.toString());
mViewLifecycleOwner.handleLifecycleEvent(event);
}
The receiving end:
#Override
public void viewPrepared() {
lifecycleSupplier = () -> mViewLifecycleOwner;
Lifecycle lCRef = mViewLifecycleOwner.getLifecycle();
//The callback HERE!!
lCRef.addObserver(
new LifeCycleOwnerAwareObserver(
event -> {
Log.d(TAG, "viewPrepared: event is: " + event.name());
if (event.equals(Lifecycle.Event.ON_DESTROY)) lastResponseProvider.run();
}
)
);
lifeCycleProvider.run();
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START);
}
The Logs are showing this when viewDestroyed() is executed:
D/ViewParticle: viewDestroyed: event is: ON_DESTROY
D/MyLifeCycleOwner: handleLifecycleEvent: event is: ON_DESTROY
D/LifeCycleOwnerAwareObse: onStateChanged: event is: ON_STOP
W/LifeCycleOwnerAwareObse: onStateChanged: state is: DESTROYED
D/ViewParticle: viewPrepared: event is: ON_STOP
As you can see the Event.ON_DESTROY enum is translating into:
a) Lifecycle.State.DESTROYED
b) Lifecycle.Event.ON_STOP
Which is impossible because the getStateAfter() method is as:
static State getStateAfter(Event event) {
switch (event) {
case ON_CREATE:
case ON_STOP:
return CREATED;
case ON_START:
case ON_PAUSE:
return STARTED;
case ON_RESUME:
return RESUMED;
case ON_DESTROY:
return DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException("Unexpected event value " + event);
}
Which means an Event will never differ from an State, because an State IS the product of an Event, AND what triggers/begins the callback is the Event, NOT the STATE.
This means that if the State is Destroyed, the Event MUST be ON_DESTROYED.
I cannot explain what's happening here..
I won't look too much into the issue, but at first glance the answer seems to be here:
while (!isSynced()) {
mNewEventOccurred = false;
// no need to check eldest for nullability, because isSynced does it for us.
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner);
}
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
The backwardPass(lifecycleOwner); and forwardPass(lifecycleOwner); methods, seem to work under the assumption that the mState.compareTo(newest.getValue().mState) > 0 and the mState.compareTo(mObserverMap.eldest().getValue().mState) < 0 conditions will never be greater than 1, so even if the answer is "true because it is 2", the forwardPass() method will only advance a single node in the life cycle, starting from the one of its previous value...
This behavior makes the function of the getStateAfter(Event event) method pointless.
BTW I remember this specifically giving me problems on this line:
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START);
Of my code above, this means that this in fact gave me problems before, So now the weird thing that needs clarification is why was it working fine in the first place? IDK.
The Answer is this:
#Override
public void viewDestroyed() {
Lifecycle.Event event = Lifecycle.Event.ON_STOP;
Log.d(TAG, "viewDestroyed: event is: " + event.toString());
mViewLifecycleOwner.handleLifecycleEvent(event);
Lifecycle.Event event2 = Lifecycle.Event.ON_DESTROY;
Log.d(TAG, "viewDestroyed: event is: " + event.toString());
mViewLifecycleOwner.handleLifecycleEvent(event2);
}
The requirement is that one needs to traverse the enums in order, up to the point of reaching what's desired.
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
It seems, as of now, that the only skippable enums are:
ON_RESUME and ON_PAUSE
I want to create an activity in which you can insert/remove/move/connect nodes between each others and based on them to generate a string value that would be later sent through Bluetooth to an other device.
Something like this
And the resulting string should look like:
`"do[i<0-2>]:
{case[i]:
{0:"Hello ",1:"World",2:"!"}
}"
My problem is that I have no idea how to start creating the view where the nodes will be placed and the nodes themselves
I think that the "workspace" should be just a simple empty view where you can pan and zoom in/out
But for the nodes I have no idea where to start because they need to be able to have multiple inputs/outputs... maybe I need to create a custom veiw/component but like i said :( i don't know how to start
Thanks for the help in advance!
EDIT:
I have decided to use Google's Blockly to generate the string, I have customized the block the way I need to generate the string, but I can't figure it out how to get the "code" generated as a string so I can use it later... does anyone has an idea?
Blockly for Android uses a CodeGenerationRequest.CodeGeneratorCallback to pass the code string back to the application.
See this example from the TurtleActivity:
private final CodeGenerationRequest.CodeGeneratorCallback mCodeGeneratorCallback =
new CodeGenerationRequest.CodeGeneratorCallback() {
#Override
public void onFinishCodeGeneration(final String generatedCode) {
// Sample callback.
Log.i(TAG, "generatedCode:\n" + generatedCode);
Toast.makeText(getApplicationContext(), generatedCode,
Toast.LENGTH_LONG).show();
mHandler.post(new Runnable() {
#Override
public void run() {
String encoded = "Turtle.execute("
+ JavascriptUtil.makeJsString(generatedCode) + ")";
mTurtleWebview.loadUrl("javascript:" + encoded);
}
});
}
};
I am making an application with a Google Maps on it, for Android. I have plenty of Markers on my screen and I am preparing customizable balloon for each marker when they are clicked. This means, I have information which is different according to the marker which was clicked.
I set up the contents of the View of the marker with setInfoWindowAdapter and then I override the method getInfoContents.
The problem is: This method is the general implementation of the contents of the Info Window, but each marker shall show its own information. So, as far as I understand, I have to somehow detect on getInfoContents(Marker marker) which of the markers have been clicked, in order to load from my data structures the necessary info to present on the info window. The question is: How do I identify what entity the clicked Marker 'marker' represents? I mean, having just the object Marker on getInfoContents which was triggered to show the info window, how can I detect which is the proper information to display? I though about comparing the string Title by using marker.getTitle(), but this obliges me to display a Title on the info window, which I do not want. There's also a marker.getId(), but such ID is generated by the API and I can't control it
Any ideas?
In reply to:
The question is: How do I identify what entity the clicked Marker 'marker' represents?
[...]
There's also a marker.getId(), but such ID is generated by the API and I can't control it
You can control it. The marker is returned by addMarker(), so you can get its ID and store it. Here's the code:
Map <String, Integer> markers = new HashMap<String, Integer>();
...
MarkerOptions mo = new MarkerOptions()
.icon(BitmapDescriptorFactory.fromResource(R.drawable.my_marker))
.position(new LatLng(mLat, mLon))
.flat(true)
.snippet("Click here for details")
.rotation(0)
.title(title);
When you add the marker to the map, store its ID on the container
MyClass myObject = new MyClass(lat, lon); // The class that you are rendering on the map with Markers, for example "Monument"
Marker mkr = map.addMarker(mo);
markers.put(mkr.getId(), myObject.getId());
Then when the marker is clicked, you can recover the id of "myObject" like this
map.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
public void onInfoWindowClick(Marker marker) {
int id = markers.get(marker.getId());
// Now id contains which Monument (or your preferred class) was clicked
}
});
There is a better option, and this is what google suggests:
Tag : An Object associated with the marker. For example, the Object can contain data about what the marker represents. This is easier than storing a separate Map<Marker, Object>. As another example, you can associate a String ID corresponding to the ID from a data set. Google Maps Android API neither reads nor writes this property.
Source
So you can do something like this:
for (ListItem it: mList) {
Marker mk = mMap.addMarker(new MarkerOptions().position(it.getLatLng()).title(it.getName()).snippet(it.getAddress()));
mk.setTag(it.getID());
}
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
Integer id = (Integer) marker.getTag();
return false;
}
});
You are not obligated to show title when you have it set, so you can use that and as long as you return a View from getInfoContents and not setText on any subview of that returned View with title value.
Depending on how and if you already keep references to all markers, there are alternatives, e.g. if you had List<Marker> policeMarkers and List<Marker> badGuysMarkers you can use a conditional if (policeMarkers.contains(marker)) { ... } else { ... }.
You can also keep a Map<Marker, YourMarkerRelatedDataModel> allMarkers and do YourMarkerRelatedDataModel model = allMarkers.get(marker); and use that value to differentiate.
Finally you can use Android Maps Extensions, which adds functions like Marker.setData(Object) and Object Marker.getData() to keep your model close to your markers and not create things like Map<Marker, Model>.
try this code:
#Override
public void onInfoWindowClick(final Marker marker)
{
// TODO Auto-generated method stub
if (marker.getTitle().equalsIgnoreCase("Start")) {
Toast.makeText(showMaps.this, "You have click on start -->",
Toast.LENGTH_LONG).show();
Log.e("marker.getPosition()-->", "" + marker.getPosition());
}
}
mMap.setOnMarkerClickListener{
Log.d(TAG , "easy")
return#setOnMarkerClickListener true
}
map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
public void onInfoWindowClick(Marker marker) {
double lat=marker.getPosition().latitude;
double lng=marker.getPosition().longitude;
}
});
I'm working on an android UPnP/DLNA app. I have a control point working where I can stream files from media server to renderer. I can pause/play and stop the file during playback but I cannot seem to figure out how to integrate a seekbar into the control point to show the progress of the playing file and be able to interact with the seekbar. I am using the Cling Java library to create the app. If anyone has any examples that could help me I would really appreciate it.
Thanks
I've tried to implement the SubscriptionCallback example and subscribe to LastChange
SubscriptionCallback callback = new SubscriptionCallback(service, 600) { // Timeout in seconds
public void established(GENASubscription sub) {
System.out.println("Established: " + sub.getSubscriptionId());
}
#Override
public void failed(GENASubscription sub, UpnpResponse response, Exception ex) {
System.err.println(
createDefaultFailureMessage(response, ex)
);
}
#Override
public void ended(GENASubscription sub, CancelReason reason, UpnpResponse response) {
// Reason should be null, or it didn't end regularly
}
public void eventReceived(GENASubscription sub) {
System.out.println("Event: " + sub.getCurrentSequence().getValue());
try {
lastChange = new LastChange(
new AVTransportLastChangeParser(),
sub.getCurrentValues().get("LastChange").toString()
);
} catch (Exception ex) {
log.warning("Error parsing LastChange event content: " + ex);
return;
}
Map<String, StateVariableValue> values = sub.getCurrentValues();
StateVariableValue status = values.get("Status");
System.out.println("Status is: " + status.toString());
}
public void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
System.out.println("Missed events: " + numberOfMissedEvents);
}
#Override
protected void failed(GENASubscription arg0,
UpnpResponse arg1, Exception arg2, String arg3) {
}
};
upnpService.getControlPoint().execute(callback);
Then I try to get the duration of the current playing track:
System.out.println("Duration: "+lastChange.getEventedValue(0, AVTransportVariable.CurrentTrackDuration.class).getValue());
but this returns a NullPointerException.
Any ideas???????
************UPDATE***********
I have been trying to implement Seek() but have not had success.
I have my seekbar and listener but it it keeps failing when I drag the seekbar to a new position.
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2)
{
Log.i("SEEKTIME", "time:" + arg1);
upnpService.getControlPoint().execute(new Seek(service, SeekMode.REL_TIME, arg0.toString())
{
#Override
public void success(ActionInvocation invocation)
{
//super.success(invocation);
Log.i("SEEKSUCCESS", "success seek");
}
#Override
public void failure(ActionInvocation arg0, UpnpResponse arg1, String arg2)
{
Log.i("SEEKFAIL", "fail seek");
}
});
}
Any suggestions why this would be failing
You must poll the renderer for this kind of information (see AVTransport spec chapter 2.3.1). The spec encourages polling every second, but you can easily jam up a real hardware renderer (for which DLNA is still rather a fashionable pain in the a** than a vital part of the design). Our established practice is to send GetPositionInfo() request every 2-3 seconds and treat the returned RelativeTimePosition value only as an adjustment to locally running timer. For the seekbar sizing you also need the total length of current media. Ideally the renderer will tell you automatically when you subscribe to AVTransport.LastChange. I don't know Cling specifically but a quick look shows promising example in controlpoint.SubscriptionCallback. Unfortunately with real devices, LastChange often doesn't tell you anything much. Either the values are not there at all or have a constant inert value. So you will need to poll the GetMediaInfo() again and use MediaDuration value.
As for interaction, Seek() is your friend, ideally with parameters of Unit = REL_TIME and Target = your desired time offset. Be aware that a real world renderer may not be supporting this unit (mode) of seeking. Perhaps it supports only TRACK_NR in which case the seekbar is essentialy read-only for you. Again Cling should be able to tell you allowed values of A_ARG_TYPE_SeekMode for the particular renderer.