I use mapbox for android (java), when it tries to access the device location it gives me an error and closes the application. This problem does not occur when I try to use the app by simulating it.
It seems that this code doesn't work.
private void enableLocationComponent(#NonNull Style loadedMapStyle) {
if (PermissionsManager.areLocationPermissionsGranted(this)) {
locationComponent = mapboxMap.getLocationComponent();
LocationComponentActivationOptions locationComponentActivationOptions =
LocationComponentActivationOptions.builder(this, loadedMapStyle)
.useDefaultLocationEngine(false)
.build();
locationComponent.activateLocationComponent(locationComponentActivationOptions);
locationComponent.setLocationComponentEnabled(true);
locationComponent.setCameraMode(CameraMode.TRACKING);
locationComponent.setRenderMode(RenderMode.COMPASS);
initLocationEngine();
} else {
permissionsManager = new PermissionsManager(this);
permissionsManager.requestLocationPermissions(this);
}
}
What is the crash message in the logcat?
Are you passing a fully loaded map style through to enableLocationComponent()?
You might have already seen them, but fyi about https://docs.mapbox.com/help/tutorials/android-location-listening/ and https://docs.mapbox.com/android/maps/examples/#device-location
Related
I'm trying to show the location of a DJI Drone on the Mapbox map and constantly update it's location.
This is what I'm doing.
private void addDroneMarker(double latitude, double longitude){
Bitmap bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.aircraft_icon)).getBitmap();
AnnotationPlugin annotationAPI = AnnotationPluginImplKt.getAnnotations(mapView);
pointAnnotationManager = PointAnnotationManagerKt.createPointAnnotationManager(annotationAPI, new AnnotationConfig());
PointAnnotationOptions pointAnnotationOptions = new PointAnnotationOptions()
.withPoint(Point.fromLngLat(longitude, latitude))
.withIconImage(bitmap);
dronePoint = pointAnnotationManager.create(pointAnnotationOptions);
}
private void updateDroneMarker(double latitude, double longitude){
dronePoint.setPoint(Point.fromLngLat(longitude, latitude));
pointAnnotationManager.update(dronePoint);
}
private void initFlightController(){
BaseProduct product = FPVApplication.getProductInstance();
if (product != null && product.isConnected()) {
if (product instanceof Aircraft) {
mFlightController = ((Aircraft) product).getFlightController();
}
}
if (mFlightController != null) {
mFlightController.setStateCallback(new FlightControllerState.Callback() {
#Override
public void onUpdate(FlightControllerState djiFlightControllerCurrentState) {
droneLocationLat = djiFlightControllerCurrentState.getAircraftLocation().getLatitude();
droneLocationLng = djiFlightControllerCurrentState.getAircraftLocation().getLongitude();
updateDroneMarker(droneLocationLat, droneLocationLng);
}
});
}
}
I create the drone annotation when the map loads and everytime the drone gives me a new location from the callback I update its location.
But my problem is, sometimes when I'm moving the map it gives me an error
Error while setting camera options : std::exception
This error could cause the application to crash with a Fatal Error
Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x787c881d0c in tid 17420 (RenderThread), pid 17347
And I realized that this error was caused by the UpdateDroneMarker (maybe because of the camera Animation), so I'm trying to find a different way to update the drones location. Hope someone could help me, thank you.
Try running on ui thread. I don't know for specific for mapbox, however callbacks from dji are not running on ui thread, so I would try that first. Otherwise you will get all kinds of strange errors.
I want to implement Google Play Games Services in my game on the libgdx engine. I tried using gdx-gamesvcs for this. But I am having trouble saving data. I understood from the example that one value is being saved, not the entire state of the game. So I decided to check it out: save and load one value using gsClient.loadGameState and gsClient.saveGameState. I deliberately deleted the game data from the device. But as a result, not only the test value changed, but many others as well. I thought that the state of the entire game is being saved, but the values obtained do not fit into the logic of the game and could not be obtained in it.
How should I use this tool and is it worth it at all, or is it better to use what libgdx itself offers?
Here is a piece of code:
if (gsClient.isSessionActive()) {
try {
gsClient.saveGameState("data", intToByteArray(testValue), 0, null);
} catch (UnsupportedOperationException unsupportedOperationException) {
}
if (gsClient.isSessionActive()) {
try {
gsClient.loadGameState("data", new ILoadGameStateResponseListener() {
#Override
public void gsGameStateLoaded(byte[] gameState) {
if (gameState != null) {
setTestValue(bytesToInt(gameState));
}
}
});
} catch (UnsupportedOperationException unsupportedOperationException) {
}
}
UPD
Yes, saving occurs both to the cloud and to the device, for saving to the device I use Preferences. I have a Google account login button in the game, it works, I have repeatedly seen this standard bar of my account level, which appears at the top when I log in. Everything is set up in the developer console too, I have an id for achievements and leaderboards. In code, I work with the client like this (In the create() method):
public IGameServiceClient gsClient;
if (gsClient == null) {
gsClient = new MockGameServiceClient(1) {
#Override
protected Array<ILeaderBoardEntry> getLeaderboardEntries() {
return null;
}
#Override
protected Array<String> getGameStates() {
return null;
}
#Override
protected byte[] getGameState() {
return new byte[0];
}
#Override
protected Array<IAchievement> getAchievements() {
return null;
}
#Override
protected String getPlayerName() {
return null;
}
};
}
gsClient.setListener(this);
gsClient.resumeSession();
Next is loading.
The exception is not caught, I removed it and everything works as before.
Well, libgdx offers no built-in cloud-save, it is hard to use it for that. :-)
You should in any case save to local AND to cloud, as the cloud is not very fast to load its state.
I can see no problem in your code besides the fact that you swallow an UnsupportedOperationException that is thrown if you did not activate cloud save feature. So the interesting question is: what happens if you don't swallow the exception, and did you intialize GpgsClient with cloud save enabled? Are you really logged in to Gpgs, and is the feature also activated in your developer console?
The main problem was that gameState was null, this arose due to the fact that you had to wait 24 hours after enabling the save function in the developer console, and the advice on clearing the memory of google play games on the test device did not help. After a while gameState began to pass the existing values, but I started having problems with the graphics flow, probably due to the asynchronous loading.
I have launched application in google play store, for that application i need to implement Immediate In app update, in order to fix the issue who are already using my application
I already tried Github examples those are Flexible updates not immediate updates.
In android developers site also i have gone through i didnt get proper example
Try below method for in-app-update for IMMEDIATE update of android app.
add below line in apps build gradle file.
implementation 'com.google.android.play:core:1.6.3'
for a better way, place this single method code in your MainActivity and call inside onCreate() method.
AppUpdateManager appUpdateManager;
private void inAppUpdate() {
// Creates instance of the manager.
appUpdateManager = AppUpdateManagerFactory.create(this);
// Returns an intent object that you use to check for an update.
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener(new OnSuccessListener<AppUpdateInfo>() {
#Override
public void onSuccess(AppUpdateInfo appUpdateInfo) {
Log.e("AVAILABLE_VERSION_CODE", appUpdateInfo.availableVersionCode()+"");
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
// For a flexible update, use AppUpdateType.FLEXIBLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Request the update.
try {
appUpdateManager.startUpdateFlowForResult(
// Pass the intent that is returned by 'getAppUpdateInfo()'.
appUpdateInfo,
// Or 'AppUpdateType.FLEXIBLE' for flexible updates.
AppUpdateType.IMMEDIATE,
// The current activity making the update request.
HomeActivity.this,
// Include a request code to later monitor this update request.
UPDATE_REQUEST_CODE);
} catch (IntentSender.SendIntentException ignored) {
}
}
}
});
appUpdateManager.registerListener(installStateUpdatedListener);
}
//lambda operation used for below listener
InstallStateUpdatedListener installStateUpdatedListener = installState -> {
if (installState.installStatus() == InstallStatus.DOWNLOADED) {
popupSnackbarForCompleteUpdate();
} else
Log.e("UPDATE", "Not downloaded yet");
};
private void popupSnackbarForCompleteUpdate() {
Snackbar snackbar =
Snackbar.make(
findViewById(android.R.id.content),
"Update almost finished!",
Snackbar.LENGTH_INDEFINITE);
//lambda operation used for below action
snackbar.setAction(this.getString(R.string.restart), view ->
appUpdateManager.completeUpdate());
snackbar.setActionTextColor(getResources().getColor(R.color.your_color));
snackbar.show();
}
courtsey here
We are using below scenario in our app for Mandatory updates.
We are maintain Current version code and latest version code in our backend database.
In Splash screen, I am calling that API to check latest version code.
Get current version code from APP.
Get latest version code from API.
If latest version code is incremental then current. We Display Update Dialog.
You have to make sure that, Once new update rollout you need to change version in backend database.
I made a geotagged social report application to report broken streets on Android. It requires location data to post a report. Either from photo's Exif, Gps sensor or set it manually from MapsPickerActivity.
I managed to make the location request using RxLocation library. There's a button that's being made enabled when the app is still getting the location from Gps. Since getting a location data from Gps might take a while, I let the user to just set a location manually at the same time. I want to stop the getGpsLocationObservable if the user pressed the button. If I don't stop the getGpsLocationObservable, I'm afraid the process would still be running and come after setting a custom location. That would be annoying.
How could I achieve that?
Here's snippets of the simplified code
Main disposable :
Disposable myDisposable = imageProcessingObservable()
.compose(getExifLocationTransformer()) //custom location button enabled here
.filter(isLocationSet -> isLocationSet)
.flatmap(x->getGpsLocationObservable());
RxLocation getGpsLocationObservable :
private Observable<String> getGpsLocationObservable(){
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setNumUpdates(1)
.setInterval(3000);
rxLocation = new RxLocation(PostActivity.this);
rxLocation.setDefaultTimeout(10, TimeUnit.SECONDS);
return rxLocation.settings()
.checkAndHandleResolution(locationRequest)
.flatMapObservable(isActivated->{
if (isActivated) {
return locationSettingsActivatedObservable();
}
else locationNotFoundObservable();
});
}
#SuppressLint("MissingPermission")
private Observable<String> locationSettingsActivatedObservable(){
return rxLocation.location().updates(locationRequest)
.map(location -> {
LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
String street = getStreetName(latLng);
return street;
})
.doOnNext(street->{
updateUI(street);
});
}
I guess it's a great use case for .amb() operator which only takes output of the observable which started emitting first and ignores all others. See http://reactivex.io/RxJava/javadoc/rx/Observable.html#amb-rx.Observable-rx.Observable-
Android 7.0 allows users (via developer options) to choose the implementation of their WebView. The user can choose the standalone WebView or use the Chrome APK to render WebViews. Reference
Since this potentially means those who use WebViews now have two different code bases to worry about, it would be useful to know which implementation is currently selected.
Is there a way to determine what WebView implementation is selected in Android 7?
Looks like this now available in Android O Preview:
Link: https://developer.android.com/preview/features/managing-webview.html
Starting in Android 7.0 (API level 24), users can choose among several
different packages for displaying web content in a WebView object.
Android O includes an API for fetching information related to the
package that is displaying web content in your app. This API is
especially useful when analyzing errors that occur only when your app
tries to display web content using a particular package's
implementation of WebView.
To use this API, add the logic shown in the following code snippet:
PackageInfo webViewPackageInfo = WebView.getCurrentWebViewPackage();
Log.d(TAG, "WebView version: " + webViewPackageInfo.versionName);
WebView.getCurrentWebViewPackage Documentation: https://developer.android.com/reference/android/webkit/WebView.html#getCurrentWebViewPackage()
To get the current Android WebView implementation and version I've created this method which should be valid for every API level.
#SuppressLint("PrivateApi")
#SuppressWarnings({"unchecked", "JavaReflectionInvocation"})
public #Nullable PackageInfo getCurrentWebViewPackageInfo() {
PackageInfo pInfo = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//starting with Android O (API 26) they added a new method specific for this
pInfo = WebView.getCurrentWebViewPackage();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//with Android Lollipop (API 21) they started to update the WebView
//as a separate APK with the PlayStore and they added the
//getLoadedPackageInfo() method to the WebViewFactory class and this
//should handle the Android 7.0 behaviour changes too
try {
Class webViewFactory = Class.forName("android.webkit.WebViewFactory");
Method method = webViewFactory.getMethod("getLoadedPackageInfo");
pInfo = (PackageInfo) method.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
} else {
//before Lollipop the WebView was bundled with the
//OS, the fixed versions can be found online, for example:
//Android 4.4 has WebView version 30.0.0.0
//Android 4.4.3 has WebView version 33.0.0.0
//etc...
}
return pInfo;
}
Then you can evaluate the result
if (pInfo != null) {
Log.d("WEBVIEW VERSION", pInfo.packageName + ", " + pInfo.versionName);
}
Remember: Immediately after an app update of WebView, a crash
could appear as described here:
https://stackoverflow.com/a/29809338/2910520, at this moment, this line webViewFactory.getMethod("getLoadedPackageInfo") of the code above would return null.
Actually there is
nothing you can do to prevent this, (this should not happen if the WebView implementation is taken from Chrome app but is not confirmed).
As a supplementary info to the answer of DataDino, for APIs below 26 here's a chunk of code that would give the desired output:
Class webViewFactory = Class.forName("android.webkit.WebViewFactory");
Method method = webViewFactory.getMethod("getLoadedPackageInfo");
PackageInfo packageInfo = (PackageInfo) method.invoke(null, null);
if ("com.android.webview".equals(packageInfo.packageName)) {
// "Android System WebView" is selected
} else {
// something else selected
// in case of chrome it would be "com.android.chrome"
}
There is an appCompat version:
WebViewCompat.getCurrentWebViewPackage(context)
dependencies {
// ...
implementation 'androidx.webkit:webkit:1.4.0' // Add to your gradle
}
public static String WebViewPackageName(Context context) {
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(context);
return webViewPackageInfo.packageName;
}