I am trying to create a FollowMeMission using the DJI Phantom 4 by providing custom coordinates, similar to this post Custom coordinates on Follow me Mission DJI Mobile SDK for android
My current code looks like this:
private double lat = 48.5561726;
private double lng = 12.1138481;
private float initHeight = 10f;
private LocationCoordinate2D location;
if (getFollowMeMissionOperator().getCurrentState().toString().equals(FollowMeMissionState.READY_TO_EXECUTE.toString())){
getFollowMeMissionOperator().updateFollowingTarget(new LocationCoordinate2D(lat + 0.0001d, lng), new CommonCallbacks.CompletionCallback() {
#Override
public void onResult(DJIError djiError) {
setResultToToast("Mission updateFollowingTarget: " + (djiError == null ? "Successfully" : djiError.getDescription()));
}
});
//Toast.makeText(getApplicationContext(), "updateFollowingTarget...", Toast.LENGTH_SHORT).show();
Log.println(Log.INFO,"FOLLOW", "Before");
try{
Thread.sleep(2500);
}catch (InterruptedException e){
setResultToToast("InterruptedException!" + e.getMessage());
}
getFollowMeMissionOperator().startMission(FollowMeMission.getInstance().initUserData(lat + 0.0001d , lng, initHeight), new CommonCallbacks.CompletionCallback() {
#Override
public void onResult(DJIError djiError) {
setResultToToast("Mission Start: " + (djiError == null ? "Successfully" : djiError.getDescription()));
}});
}
else{
Toast.makeText(getApplicationContext(), getFollowMeMissionOperator().getCurrentState().toString(), Toast.LENGTH_SHORT).show();
}
I even added a 2.5 sec sleep before calling startMission() as advised in this topic http://forum.dev.dji.com/thread-33716-1-1.html
What happens is, i invoke FollowMe() and after 2.5 sec i get the message "Mission Start: Successfull", but without any callback from updateFollowingTarget(). Then nothing happens, the drone stays where it is.
What am i doing wrong? Is the way i use updateFollowingTarget() and startMission() even right?
The causes on this issue are:
1. We need use timer to updateFollowingTarget in a given frequency.
2. The moving object (following target) need provide its dynamic location.
Please refer to below code to refine it for your case:
private float initHeight = 10f;
private LocationCoordinate2D movingObjectLocation;
private AtomicBoolean isRunning = new AtomicBoolean(false);
private Subscription timmerSubcription;
private Observable<Long> timer =Observable.timer(100, TimeUnit.MILLISECONDS).observeOn(Schedulers.computation()).repeat();
private void followMeStart(){
if (getFollowMeMissionOperator().getCurrentState().toString().equals(FollowMeMissionState.READY_TO_EXECUTE.toString())){
//ToDo: You need init or get the location of your moving object which will be followed by the aircraft.
getFollowMeMissionOperator().startMission(FollowMeMission.getInstance().initUserData(movingObjectLocation.getLatitude() , movingObjectLocation.getLongitude(), initHeight), new CommonCallbacks.CompletionCallback() {
#Override
public void onResult(DJIError djiError) {
setResultToToast("Mission Start: " + (djiError == null ? "Successfully" : djiError.getDescription()));
}});
if (!isRunning.get()) {
isRunning.set(true);
timmerSubcription = timer.subscribe(new Action1<Long>() {
#Override
public void call(Long aLong) {
getFollowMeMissionOperator().updateFollowingTarget(new LocationCoordinate2D(movingObjectLocation.getLatitude(),
movingObjectLocation.getLongitude()),
new CommonCallbacks.CompletionCallback() {
#Override
public void onResult(DJIError error) {
isRunning.set(false);
}
});
}
});
}
} else{
Toast.makeText(getApplicationContext(), getFollowMeMissionOperator().getCurrentState().toString(), Toast.LENGTH_SHORT).show();
}
}
Related
This is my example where I am tapping on the map to get the tapped point coordinates and to send a search request to know more details about that place, for example, city, street. But the response is always null values.
public class MainActivity extends AppCompatActivity implements CameraListener, InputListener, Session.SearchListener {
private ActivityMainBinding binding;
private SearchManager searchManager;
private Session searchSession;
private SearchOptions searchOptions;
private MapObjectCollection mapObjectCollection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapKitFactory.setApiKey("your api key");
MapKitFactory.initialize(this);
searchOptions = new SearchOptions();
searchOptions.setSearchTypes(SearchType.GEO.value);
searchOptions.setGeometry(true);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.mapview.getMap().setNightModeEnabled((getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES);
searchManager = SearchFactory.getInstance().createSearchManager(SearchManagerType.COMBINED);
binding.mapview.getMap().addCameraListener(this);
binding.mapview.getMap().addInputListener(this);
mapObjectCollection = binding.mapview.getMap().getMapObjects();
binding.mapview.getMap().move(
new CameraPosition(new Point(55.751574, 37.573856), 11.0f, 0.0f, 0.0f),
new Animation(Animation.Type.SMOOTH, 0),
null);
}
#Override
protected void onStop() {
super.onStop();
binding.mapview.onStop();
MapKitFactory.getInstance().onStop();
}
#Override
protected void onStart() {
super.onStart();
binding.mapview.onStart();
MapKitFactory.getInstance().onStart();
}
public void submitQueryByName(String query) {
searchSession = searchManager.submit(
query,
Geometry.fromPoint(new Point(40.177200, 44.503490)),
searchOptions,
this);
}
public void submitQueryByPoint(Point point) {
searchSession = searchManager.submit(
point,
11,
searchOptions,
this);
}
#Override
public void onCameraPositionChanged(#NonNull Map map, #NonNull CameraPosition cameraPosition, #NonNull CameraUpdateReason cameraUpdateReason, boolean finished) {
Log.e("onCameraPositionChanged"," cameraPosition: "+cameraPosition+" cameraUpdateReason: "+cameraUpdateReason+" finished: "+finished);
}
#Override
public void onMapTap(#NonNull Map map, #NonNull Point point) {
MapObjectCollection mapObjects = binding.mapview.getMap().getMapObjects();
mapObjects.clear();
PlacemarkMapObject placemarkMapObject = mapObjectCollection.addPlacemark(new Point(point.getLatitude(), point.getLongitude()),
ImageProvider.fromResource(this, R.mipmap.marker_flag));
submitQueryByPoint(point);
Log.e("onMapTap", "point lat - lang: " + point.getLatitude() + " : " + point.getLongitude());
}
#Override
public void onMapLongTap(#NonNull Map map, #NonNull Point point) {
Log.e("onMapLongTap","onMapLongTap");
}
#Override
public void onSearchResponse(#NonNull Response response) {
try {
Log.e("Search", "Response: " + response);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
#Override
public void onSearchError(#NonNull Error error) {
String errorMessage = "unknown_error_message";
if (error instanceof RemoteError) {
errorMessage = "remote_error_message";
} else if (error instanceof NetworkError) {
errorMessage = "network_error_message";
}
Log.e("Response error", " error: " + errorMessage);
}
}
In the onMapTap method, I get the tapped point coordinates and send a search request by point
#Override
public void onMapTap(#NonNull Map map, #NonNull Point point) {
MapObjectCollection mapObjects = binding.mapview.getMap().getMapObjects();
mapObjects.clear();
PlacemarkMapObject placemarkMapObject = mapObjectCollection.addPlacemark(new Point(point.getLatitude(), point.getLongitude()),
ImageProvider.fromResource(this, R.mipmap.marker_flag));
submitQueryByPoint(point);
Log.e("onMapTap", "point lat - lang: " + point.getLatitude() + " : " + point.getLongitude());
}
**Response is always null values. What I do wrong?
This is a GitHub whole project for this example https://github.com/davmehrabyan/YandexMapSearch **
in my Android inside an activity I have an asynchronous call to a google maps API inside a method see the code below :
public void reverseGeocode(String lat, String lng) {
String geocodeApiUrl = getUrl(lat, lng);
GoogleService googleService = GoogleServiceBuilder.buildService(GoogleService.class);
Call<Address> geocodeRequest = googleService.geocodeAddress(geocodeApiUrl);
geocodeRequest.enqueue(new Callback<Address>() {
#Override
public void onResponse(Call<Address> call, Response<Address> response) {
if (response.errorBody() == null) {
if (response.body().getResults().length > 0) {
if (response.body().getResults()[0].getFormatted_address() != null) {
dropOffAddress = response.body().getResults()[0].getFormatted_address();
}
}
} else {
Toast.makeText(AdressPicker.this, "An error has occured", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<Address> call, Throwable t) {
Toast.makeText(AdressPicker.this, "An error has occured", Toast.LENGTH_LONG).show();
}
});
}
this method is called inside the Google map marker 's onMarkerDragEnd callback function , see code below :
#Override
public void onMarkerDragEnd(Marker marker) {
double lat = marker.getPosition().latitude;
double lng = marker.getPosition().longitude;
reverseGeocode(String.valueOf(lat), String.valueOf(lng));
marker.setSnippet(dropOffAddress);
marker.showInfoWindow();
editor.putString("dropOffAddress", dropOffAddress);
editor.putString("lat", String.valueOf(lat));
editor.putString("lng", String.valueOf(lng));
editor.apply();
}
The problem here is the first time when I move the marker the reverseGeocode method is called but it is not awaited and the onMarkerDragEnd continue its execution and puts null inside the value of the dropOffAddress variable which is intended to be displayed inside the snippet of the marker.
My question here is HOW to WAIT for the reverseGeocode method'is response inside onMarkerDragEnd before continuing executing ?
Thank you.
the only thing you. need is marker, just pass it as a parameter in your retrofit api call something like this.
public void reverseGeocode(String lat, String lng, Marker marker) {
String geocodeApiUrl = getUrl(lat, lng);
GoogleService googleService = GoogleServiceBuilder.buildService(GoogleService.class);
Call<Address> geocodeRequest = googleService.geocodeAddress(geocodeApiUrl);
geocodeRequest.enqueue(new Callback<Address>() {
#Override
public void onResponse(Call<Address> call, Response<Address> response) {
if (response.errorBody() == null) {
if (response.body().getResults().length > 0) {
if (response.body().getResults()[0].getFormatted_address() != null) {
dropOffAddress = response.body().getResults()[0].getFormatted_address();
applyGeoCode(marker)
}
}
} else {
Toast.makeText(AdressPicker.this, "An error has occured", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<Address> call, Throwable t) {
Toast.makeText(AdressPicker.this, "An error has occured", Toast.LENGTH_LONG).show();
}
});
}
now from here call a method passing the marker
public void applyGeoCode(Marker marker){
double lat = marker.getPosition().latitude;
double lng = marker.getPosition().longitude;
marker.setSnippet(dropOffAddress);
marker.showInfoWindow();
editor.putString("dropOffAddress", dropOffAddress);
editor.putString("lat", String.valueOf(lat));
editor.putString("lng", String.valueOf(lng));
editor.apply();
}
and call like this
#Override
public void onMarkerDragEnd(Marker marker) {
reverseGeocode(String.valueOf(lat), String.valueOf(lng), marker);
}
You can use CountDownLatch from the java.utils.Concurrent class.
Here is an example:
public class DoSomething {
private Address dropoffAddr;
private CountDownLatch dropoffAddrLatch = new CountDownLatch(1);
public void getAddressCallback(Address addr) {
dropoffAddr = addr;
dropoffAddrLatch.countDown();
}
#Override
public void onMarkerDragEnd(Marker marker) {
//your stuff
reverseGeocode(...); //you should call getAddressCallback once you have everything
dropOffAddrLatch.await(); //this will wait until getAddressCallBack has returned,
// you can call dropoffAddrLatch.countDown() wherever you want.
//finish your stuff
}
}
I want to get swimming data from Samsung Health App but not get any proper solution.
Below is my code.
public class SwimmingReport {
private final HealthDataStore mStore;
private SwimObserver swimObserver;
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L;
public SwimmingReport(HealthDataStore store) {
mStore = store;
}
public void start(SwimObserver listener, String strDate, JSONObject jsonObject) {
swimObserver = listener;
HealthDataObserver.addObserver(mStore, HealthConstants.Exercise.HEALTH_DATA_TYPE, new HealthDataObserver(null) {
#Override
public void onChange(String s) {
readTodaySwimData(strDate,jsonObject);
}
});
readTodaySwimData(strDate,jsonObject);
}
private void readTodaySwimData(String strDate,JSONObject jsonObject) {
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
long startTime = GlobalMethods.getEpochTime(strDate);
long endTime = startTime + ONE_DAY_IN_MILLIS;
HealthDataResolver.ReadRequest request = new HealthDataResolver.ReadRequest.Builder()
.setDataType(HealthConstants.Exercise.HEALTH_DATA_TYPE)
.setProperties(new String[]{HealthConstants.Exercise.EXERCISE_TYPE})
.setLocalTimeRange(HealthConstants.Exercise.START_TIME, HealthConstants.Exercise.TIME_OFFSET,
startTime, endTime)
.build();
try {
resolver.read(request).setResultListener(result ->{
double distance = 0.0;
try {
for (HealthData data : result) {
distance += data.getFloat(HealthConstants.Exercise.DISTANCE);
}
} finally {
result.close();
}
if (swimObserver != null) {
swimObserver.onChanged(distance,strDate,jsonObject);
}
});
} catch (Exception e) {
Log.e("=> ", "Getting step count fails.", e);
}
}
public interface SwimObserver {
void onChanged(Double distance, String date, JSONObject jsonObject);
}
}
Here is my whole source code this
I figured out on your code that you want to read distance value from the read result.
distance += data.getFloat(HealthConstants.Exercise.DISTANCE);
But you described absolutely not related property. Maybe that is the problem.
.setProperties(new String[]{HealthConstants.Exercise.EXERCISE_TYPE})
Try this.
.setProperties(new String[]{HealthConstants.Exercise.DISTANCE})
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.
I'm using the socialAuth plugin to connect a user to linkdin within my app. I have the connection set up correctly and retrieves data. However, I'm unsure how I can get my main activity to wait until the socialAuthListeners have fired and finished. I know a little about threading but I haven't used it with listeners before. Here's my code:
public class LinkdinAuth {
private static final String TAG = "TEST";
// SocialAuth Components
SocialAuthAdapter adapter;
ProgressDialog mDialog;
private Context context;
private boolean loggedIn = false;
private Bundle LinkdinData;
public LinkdinAuth(Context C){
this.context = C;
LinkdinData = new Bundle();
adapter = new SocialAuthAdapter(new ResponseListener());
}
public void adapterAuthorize(View v){
adapter.authorize(v.getContext(), Provider.LINKEDIN);
}
private final class ResponseListener implements DialogListener
{
public void onComplete(Bundle values) {
String providerName = values.getString(SocialAuthAdapter.PROVIDER);
Log.d("Main", "providername = " + providerName);
mDialog = new ProgressDialog(context);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setMessage("Loading...");
//Get profile information
adapter.getUserProfileAsync(new ProfileDataListener());
// get Job and Education information
mDialog.show();
adapter.getCareerAsync(new CareerListener());
loggedIn = true;
Log.d("Main", "LOGGED IN = " + loggedIn );
Toast.makeText(context, providerName + " connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onBack() {
Log.d("Main", "Dialog Closed by pressing Back Key");
}
#Override
public void onCancel() {
Log.d("Main", "Cancelled");
}
#Override
public void onError(SocialAuthError e) {
Log.d("Main", "Error");
e.printStackTrace();
}
}
// To receive the profile response after authentication
private final class ProfileDataListener implements SocialAuthListener<Profile> {
#Override
public void onExecute(String provider, Profile t) {
Log.d("Sign Up", "Receiving Data");
mDialog.dismiss();
Profile profileMap = t;
LinkdinData.putString("Validated ID", profileMap.getValidatedId() );
LinkdinData.putString("First Name", profileMap.getFirstName());
LinkdinData.putString("Last Name", profileMap.getLastName());
LinkdinData.putString("Email", profileMap.getEmail());
LinkdinData.putString("Country", profileMap.getCountry());
LinkdinData.putString("Language", profileMap.getLanguage());
LinkdinData.putString("Location", profileMap.getLocation());
LinkdinData.putString("Profile Image URL", profileMap.getProfileImageURL());
}
#Override
public void onError(SocialAuthError arg0) {
// TODO Auto-generated method stub
}
}
private final class CareerListener implements SocialAuthListener<Career> {
#Override
public void onExecute(String provider, Career t) {
Log.d("Custom-UI", "Receiving Data");
mDialog.dismiss();
Career careerMap = t;
//get education
Log.d("Main", "Education:");
if(careerMap.getEducations() != null){
for(Education E: careerMap.getEducations()){
Log.d("Main", "School = " +E.getSchoolName() );
Log.d("Main", "Major = " + E.getFieldOfStudy() );
Log.d("Main", "Degree = " + E.getDegree() );
Log.d("Main", "Start Date = " + E.getStartDate() );
Log.d("Main", "End Date = " + E.getEndDate() );
}
}
Log.d("SignUp", "Career");
if(careerMap.getPositions() != null){
for(Position P: careerMap.getPositions()){
LinkdinData.putString("Company Name", P.getCompanyName() );
LinkdinData.putString("Job Title", P.getTitle() );
Log.d("Main", "Industry = " + P.getIndustry() );
Log.d("Main", "Start Date = " + P.getStartDate() );
Log.d("Main", "End Date = " + P.getEndDate() );
}
}
}
#Override
public void onError(SocialAuthError e) {
}
}
public boolean isLoggedIn(){
return loggedIn;
}
public Bundle getLinkdinData(){
return LinkdinData;
}
So, as you can see. I have 2 listeners that get data after authorization goes through. And my main activity makes creates an instance, calls the adapterAuthroizeMethod and then if the user logs in a flag is set. Then getLinkedData is called. However I would like it to wait until I know the listeners have fired before calling getlinkdinData. Here's what my Main Activity does after a button press:
L.adapterAuthorize(v);
loggedInWithLinkdin = L.isLoggedIn();
Bundle B = L.getLinkdinData();
Intent i = new Intent(getBaseContext(), UserRegistration.class);
i.putExtra("linkdin bundle", B);
//startActivity(i);
Any ideas?
thanks
Well, not a recommend solution but more of a hack.
Here is what you can do.
Wrap the aync call around this construct :
AtomicBoolean done = new AtomicBoolean(false);
Global ans; // the return value holder
try{
result = someAsyncCall(query, new Thread()); // this new thread is for listener callback
result.setResultListener(result -> {
// do something with result.
ans = result.getAns() ; // set global ans
done.set(true);
synchronized (done) {
done.notifyAll(); // notify the main thread which is waiting
}
});
}
catch (Exception e ) {
Log(e);
}
synchronized (done) {
while (done.get() == false) {
done.wait(); // wait here until the listener fires
}
}
return ans; // return global ans