Google Analytics v4 crashes with custom global config - java

I've tried adding a custom global config file to my app but it keeps causing the app to crash. If I take out the custom gloabl config file everything works fine.
The specific version of events that leads to a crash is:
Start app, this works fine first time round
kill app using a task killer
re-load app, the app no longer starts, often just loading a black screen.
There's no log to indicate an error; the app just won't load second time round.
I've added the code i've used below, mostly copied from the google documentation
Global config addition to manifest
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="#xml/global_config" />
Global config file
<string name="ga_appName">AppName</string>
<string name="ga_appVersion">Version1.1.0</string>
<!--Remember to set to WARNING log level for production -->
<string name="ga_logLevel">verbose</string>
<!--time before hit is sent to google -->
<integer name="ga_dispatchPeriod">30</integer>
<!--Remember to set to FALSE for production version-->
<bool name="ga_dryRun">true</bool>
Tracker code in Application class
HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();
public enum TrackerName {
APP_TRACKER,
}
// creates analytics tracker
public synchronized Tracker getTracker(TrackerName trackerId) {
if (!mTrackers.containsKey(trackerId)) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
Tracker t = analytics.newTracker(R.xml.app_tracker);
t.enableAdvertisingIdCollection(true);
mTrackers.put(trackerId, t);
}
return mTrackers.get(trackerId);
}
Code to init tracker in BaseActivity class
((MyApplication) getApplication()).getTracker(MyApplication.TrackerName.APP_TRACKER);
I'm at a bit of a loss to fix this with no log output and quite sparse documentation so any help would be much appreciated!
Thanks

After some experimenting I found a way round the problem. I removed the global_config.xml and took away its reference in the manifest file.
Instead I set the global config parameters in the getTracker method
// creates analytics tracker
public synchronized Tracker getTracker(TrackerName trackerId) {
if (!mTrackers.containsKey(trackerId)) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
analytics.setDryRun(true);
analytics.setLocalDispatchPeriod(1000);
analytics.getLogger().setLogLevel(com.google.android.gms.analytics.Logger.LogLevel.VERBOSE);
Tracker t = analytics.newTracker(R.xml.app_tracker);
t.enableAdvertisingIdCollection(true);
mTrackers.put(trackerId, t);
}
return mTrackers.get(trackerId);
}
The app now runs fine with custom global configs and no crashes!

Related

Audio Stops Recording After a Minute

I am trying to do WebRTC, all is working fine but there seems to be an issue, that is, if the screen remains off for more than a minute the audio stops recording, meaning the audio from device stops until I switch the screen on once again.
What I have tried?
1) I have tried setting webSettings.setMediaPlaybackRequiresUserGesture(false); it does no good to the problem.
2) I have also tried adding a wakelock in the activity in which I am doing WebRTC but it also didn't work.
Here are the permissions declared in Manifest:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Here in activity, I am granting permission for the microphone in WebChromeClient:
#Override
public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources());
}
What I want?
I want to be able to continue call without disrupting the user to turn screen back on again. Please point me in right direction.
Thanks!
Update: I tried loading the WebRTC url in Chrome and the same thing is happening, that is, audio stops recording from my device.
Update 2: Adding log when audio stops coming from the device.
2019-08-06 17:18:47.266 4332-22405/? V/APM_AudioPolicyManager: getAudioPolicyConfig: audioParam;outDevice
2019-08-06 17:18:47.266 4332-22405/? V/APM_AudioPolicyManager: getNewOutputDevice() selected device 2
2019-08-06 17:18:47.266 4332-22405/? V/APM_AudioPolicyManager: ### curdevice : 2
2019-08-06 17:18:47.307 4332-22405/? V/APM_AudioPolicyManager: AudioPolicyManager:setRecordSilenced(uid:99066, silenced:1)
2019-08-06 17:18:47.308 4332-22405/? V/APM_AudioPolicyManager: AudioPolicyManager:setRecordSilenced(uid:11556, silenced:1)
Update 3: Tried initializing WebView in a Foreground Service still same result.
Update 4: Tried a demo call on https://appr.tc/ using Chrome(76.0.3809.132). Observed the same result.
Update 5: Tried a demo call using Firefox and it worked FLAWLESSLY which lets me thinking that is it a Chromium bug?
Update 6: Filled a bug report
Android will automatically destroy your activity on a few minutes after leaving foreground that will cause the audio recording to turn off.
I have working with webrtc on android, if you want to create call and video call with webrtc on Android, I suggest to use native webrtc and implement everything related to webrtc on foreground service. Foreground service will ensure your recorder and camera to keep running event when activity is destroyed.
For reference, here the google sample for implementing webrtc native
https://webrtc.googlesource.com/src/+/master/examples/androidapp/src/org/appspot/apprtc
You should work on keeping the screen on in that activity during the call and prevent if from dimming.
Use this:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
and after your call is done:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Check your Chrome/Android version due to this issue with WebRTC on Android:
Issue 513633: WebRTC call in Chrome on Android will be cut off 1 min after screen off
WebRTC is supported by default in Chrome so... it should work.
BTW, if you dont't need WebRtc or want try to implement in a background service...
Interest readings:
1 - recording-when-screen-off
As the post says, keep in mind:
To call:
startForeground();
Use START_STICKY:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
2 - how to implement a recorder
As the post says, keep in mind permissions:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Background services with Apache Cordova
With cordova and a webview you need to use a plugin to run code in background as a service too.
Take a look at this link:
cordova plugin
Another choice with Cordova is to do your own plugin like this:
custom plugin - background video recorder
Obviously, it's no usual task, because all your implementation, it's just a WebView. Which very hard to align with such long living task and lifecycle inside Android. For ex. every VoIP application we did, had services in background, to keep connection alive, with wake locks. This was only one way to ensure about stability of the call.
However, I think you could try to do the same. By managing your WebView work inside Service. For this purpose, you could consider moving some calling logic into another view, and starting new Service and creation new Window. This will ensure your Window will be alive, during all the lifecycle of the Service.
Smth like.
public class ServiceWithWebView extends Service {
#Override
public void onCreate() {
super.onCreate();
final WindowManager windowManager = (WindowManager)
getSystemService(WINDOW_SERVICE);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);
final LinearLayout view = new LinearLayout(this);
view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout
.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
WebView wv = new WebView(this);
wv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout
.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
view.addView(wv);
wv.loadUrl("http://google.com");
windowManager.addView(view, params);
}
}
It is possible that the problem is in battery optimization. The device cleans up the background processes and finds there your audio recording screen working on the background. try to add the app to the list of Battery Best Performance list. Search how to do that on your device.
For my case even important background tasks as accessibility service is forced to stop under that battery optimization algorithm. To allow my service to work all the time, the user should add the app to the whitelist of battery best performance rule.
I hope it can help you.

Android NDK throwning signal SIGSEGV: invalid address after getting GoogleSignInClient in Activity via JNI

I'm developing an add-on to the Android port of the LÖVE 2D game framework to provide connectivity to Google Play Games Services from the games code. The most part of the framework is written in C++. It features a LuaVM with simplified bridges to SDL2 to access anything it needs.
To access Google Play Games Services from the Lua code that is running in the LuaVM, I have to add a native C++ module that contains entry points and wrapper classes. From there I redirect calls into the android.cpp from which I have to use the JNI to access the functions in my main Activity, since I have to sign in the player using the Java package com.google.android.gms.auth.api.signin.
This bridge works as expected. When the app is loading I initialise it like so:
love2d-rich-android/love/src/jni/love/src/modules/mobsvc/config_MobSvc.h:
static const bool MOBSVC_REQUIRED = false; // Force login into Google Play Games Services
love2d-rich-android/love/src/jni/love/src/modules/mobsvc/MobSvc.cpp:
MobSvc::MobSvc()
{
love::android::mobSvcInit(MOBSVC_REQUIRED);
}
^- The module will be constructed on start of the app.
love2d-rich-android/love/src/jni/love/src/common/android.h:
void mobSvcInit(bool required);
love2d-rich-android/love/src/jni/love/src/common/android.cpp:
void mobSvcInit(bool required)
{
bool inp1 = required;
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz (env->GetObjectClass(activity));
jmethodID methodID = env->GetMethodID(clazz, "mobSvcInit", "(Z)V");
jboolean jinp1 = (jboolean) inp1;
env->CallVoidMethod(activity, methodID, jinp1);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(clazz);
}
love2d-rich-android/love/src/main/java/org/love2d/android/RichGameActivity.java:
public void mobSvcInit(boolean required) {
// Specify if skipping of the login should be impossible.
mobSvcRequired = required;
// Determine if Google Play Games Services is installed on the device.
PackageManager pm = context.getPackageManager();
boolean isKindle = (Build.MANUFACTURER.equals("Amazon") && Build.MODEL.equals("Kindle Fire")) || Build.MODEL.startsWith("KF");
try
{
PackageInfo info = pm.getPackageInfo(!isKindle ? "com.android.vending" : "com.amazon.venezia", PackageManager.GET_ACTIVITIES);
String label = (String) info.applicationInfo.loadLabel(pm);
mobSvcAvailable = (label != null && !label.equals("Market"));
}
catch (PackageManager.NameNotFoundException e)
{
mobSvcAvailable = false;
}
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
.requestEmail()
.build();
// Build a GoogleSignInClient with the options specified by gso.
mobSvcSignInClient = GoogleSignIn.getClient(this, gso);
Log.d("RichGameActivity","Play Games Services initialised.");
}
The code will pass, it will be executed. However the line mobSvcSignInClient = GoogleSignIn.getClient(this, gso); causes it to crash on ANativeWindow_fromSurface(env, s); in the function Android_JNI_GetNativeWindow in the file love2d-rich-android/love/src/jni/SDL2-2.0.5/src/core/android/SDL_android.c, afterwards, which is a JNI operation done by the SDL2 framework:
If the line is removed, everything keeps running without issue. For closer inspection the repository is available here: https://bitbucket.org/MartyMaro/love2d-rich-android/src/c5ad59b16a8b7f9fcc267a9f56e03de959c30b05/?at=MobSvc
I think this issue is not SDL2 related tho, because in a later step I went ahead and tried to make sure the code is called on the UI thread. Without digging to much into how the LuaVM and the LÖVE framework work, I've implemented the bridge for the module, so I can trigger the code above from Lua itself. So, the way things are called is the same, however the execution of the code is way later when the VM is already running and all the LÖVE modules are initialised and the code is executed in the UI thread for sure.
Now the exception is in the NDK bundle's jni.h (~/Library/Android/sdk/ndk-bundle/sysroot/usr/include/jni.h):
The fault address seem to be the same and JNI (so the NDK) plays a role in both cases, so I believe getting the sign-in client of Google causes the NDK to fail on the next JNI operation. I need a proper way to handle this situation without causing any issues. I'm glad for anything ideas how to solve this issue.
So I moved my code to the onStart of my Activity to get rid of the whole NDK dependency just to find out that I get a NoClassDefFoundError exception on runtime. After playing around I saw that I implemented an older version of auth in my gradle files.
Changed it to the recent one in my gradle file:
api 'com.google.android.gms:play-services-auth:16.0.0'
And the exception was not thrown. After that my JNI call does work. It turns out the exception was just higher in my stack and the NDK cannot handle such exception properly, so I just get a common invalid address exception.
If you have similar issues, try to get the latest libs before you try something else.

How to store a HashMap in Firebase for offline use

I have a Map:
Map<String, String> noidung = new HashMap<>();
The Map receives data from Firebase and I show them in a Gridview. Everything worked well.
But when the phone goes offline, I want the data I have loaded to remain on the Gridview.
My idea is to store the Map noidung to a file (I think SharedPreference) to use offline. I have tried very much solutions but failed.
Take a look at this:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
From the documentation:
Firebase apps automatically handle temporary network interruptions for you. Cached data will still be available while offline and your writes will be resent when network connectivity is recovered. Enabling disk persistence allows our app to also keep all of its state even after an app restart. We can enable disk persistence with just one line of code.
https://firebase.google.com/docs/database/android/offline-capabilities
In addition, you can keep specific locations in sync:
DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");
scoresRef.keepSynced(true);
Setting persistence enabled has to be the very first call to the Firebase API. So before you do any queries/etc. A good location is in your Application subclass:
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Don't forget to update your manifest accordingly:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="my.package" >
...
<application android:name=".MainApplication">
...
</application>
</manifest>
It's really that easy. And that is what Firebase makes so awesome :-)

Retrieving geo location in my app is far less accurate than what Google Maps app shows in the same time on my device

In my app, I've tried two ways of accessing location:
a) Using LocationManager and GPS_PROVIDER. I accept location to be processed if it has accuracy 50 or less. App receives location however most of the time receives no location at all - while Google Maps when I start it to try it out gets my location constantly and more precise than my app.
Here are parts of the source related to this:
Start to listen to locations:
// in service class, function to start listening for locations.
// class implements android.location.LocationListener interface
this.locman = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
if( !this.locman.isProviderEnabled(LocationManager.GPS_PROVIDER) ){
Log.d("","GPS is not enabled");
}else{
this.locman.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged( this.locman.getLastKnownLocation(LocationManager.GPS_PROVIDER) );
}
android.location.LocationListener implementation of onLocationChanged function:
#Override
public void onLocationChanged(Location location)
{
... showing provided Location on the map
}
in manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
This can give me relatively frequent updates, but sometimes has huge gaps. I believe maybe it's problem with connecting with enough satellites, however if I open Google Maps in the same time - it works flawlessly. No time gaps between location updates, and more precise than what I am getting here.
I thought it may be needed to use LocationClient and LocationRequest instead, counting that maybe Google Play API may have some internal interpolation / prediction / whatever that improves precision.
b) Using GooglePlay API with LocationClient and LocationRequest. I've installed Google Play SDK, and also tried Google's sample apps. Here is my code related to this:
// in service class, function to start listening for locations.
// class implements com.google.android.gms.location.LocationListener,
// com.google.android.gms.common.ConnectionResult.OnConnectionFailedListener and
// com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks interface
this.locclient = new LocationClient(this.getApplicationContext(),this,this);
this.locclient.connect();
implementation of onConnected:
#Override
public void onConnected(Bundle dataBundle)
{
LocationRequest req = LocationRequest.create();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setInterval(2000); // 2 sec
req.setFastestInterval(16); // 60 fps
this.locclient.requestLocationUpdates(req, this);
}
And of course onConnectionFailed and onDisconnected is implemented and breakpointed - never gets in, while onConnected is called.
Implementation of com.google.android.gms.location.LocationListener:
#Override
public void onLocationChanged(Location location)
{
... showing provided Location on the map
}
In this case, I get updates immediately, however off for like 200m or more.
In desperation, I tried MyLocation app that is on Google Play and it shows SAME OFFSET!
When I try Google Maps, in the same time, it shows absolute accuracy like 5-6m the most.
Important notice: I am located in Shanghai, China. Not sure if this is related in any way.
How is it possible to have such huge offset between Google Maps and Google's own example of location service (MyLocationDemoActivity.java, provided in google_play_services/samples/maps/)?? To clarify: Google's map demo provided with Google Play Services sample codes, also shows SAME OFFSET (~200m) away from my real location, while in the same time Google Maps app shows precise location.
I'm using Nexus 4 as development platform.
Compiler is ADT (Eclipse). All up-to-date.
Really hope for some quick breakthrough from anyone here!!! Thanks in advance!
P.S.
I have now tried to use LocationRequest.PRIORITY_NO_POWER as setting for location request, to have my app get location update only when another app requested it. I've then started Google Maps, and switched back to my app. It immediately received location. I've copied long/lat into http://maps.googleapis.com/maps/api/staticmap?center=31.229179,121.422615&zoom=16&format=png&sensor=false&size=640x640&maptype=roadmap to test it out, and it is showing SAME OFFSET. While Google Maps on my phone shows exact location.
Is it possible that maps from Google have offset? Or that there is an offset to long/lat received?
I don't have enough reputation to comment yet so I'm writing an answer.
This is most likely related to the China GPS offset problem. The Chinese government insists on not allowing users to record accurate GPS data in some scenarios ("national security something blah blah") and force companies like Apple/Google to abide by the local laws.
Here is a link with some good information on the topic:
http://www.sinosplice.com/life/archives/2013/07/16/a-more-complete-ios-solution-to-the-china-gps-offset-problem
As in above answer, offset is because of China government regulation. However people managed to get transform used at least by GoogleMaps and HEREMaps. It is here written in C#.
Using that you can convert real coordinates to transformed ones with maximum 20 meters error. There are also more accurate implementations.
If you don't want to modify your software, you can use something based on this. It is my simple Xposed module to convert coordinates for all applications using LocationManager.

Android GPS does not work until restart on new phones

I have posted about this issue before, and found a few other people who have had the same issue with no solutions found.
I am developing an Android app that submits a JSON query to a server with the obtained GPS coordinates and geocoded Zip Code. For brand new users that have never downloaded the app, GPS does not work whatsoever. It is not until rebooting the phone that GPS will work. After installing the app and then rebooting, the GPS will work every time without problem, even if they restart again.
There is precious little information on this issue, and the only issue I have found refers to using Google Play Location Services, with no further details. Has anyone else had this issue? My development is completely halted until this issue can be resolved.
EDIT:
Here is the link to the MainActivity.java file that calls the geopositioning functions.
Here is the link to the MyLocation.java file that contains the actual logic for multiple sources of geolocation
I have no doubt that there are much better ways of doing GPS. I'm very new to Android development, so any help on this front is very much appreciated.
EDIT 2:
I have wiped my phone with a factory reset, and started from scratch. I still cannot replicate the issue on this device, only on phones using the app for the very first time prior to a restart.
Looks like you're registering both the GPS and NETWORK providers to listen for a location for 10 seconds, and when the timer goes off after 10 seconds you try to get the most recent location from both providers.
There are a few things going on here.
First, you seem to be listening for updates in the wrong method. Your two listeners should look like:
LocationListener locationListenerGps = new LocationListener() {
// This will never be called, its not part of the LocationListener interface - http://developer.android.com/reference/android/location/LocationListener.html
/* public void onStatusChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
} */
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
public void onLocationChanged(Location location) {
// This is the correct method to receive location callbacks
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
Second, I'd use the ScheduledThreadPoolExecutor or Handler instead of Timer.
From the Timer docs:
Prefer ScheduledThreadPoolExecutor for new code...This class does not offer guarantees about the real-time nature of task scheduling.
If a reboot is required to get the app working, its likely something to do with the Timer not firing after 10 seconds. Note that this doesn't necessarily mean that GPS itself isn't working.
Handler should do the job and it's designed for Android, so I'd suggest using it. It looks like:
Handler handler = new Handler();
handler.postDelayed(getLastLocation, 10000);
...and your GetLastLocation would change to:
Runnable getLastLocation = new Runnable() {
#Override
public void run() {
...
}
}
...and your cancel() and other methods would need to reference the Handler.
Also, note that you're declaring the Location object in your MainActivity with a provider type of NETWORK_PROVIDER, and then setting the lat/long in that object.
public Location mUserCoordinates = new Location(LocationManager.NETWORK_PROVIDER);
So, the location type in MainActivity will always appear to be of NETWORK_PROVIDER, no matter the actual source.
Also, doesn't look like your MainActivity needs to implement LocationListener, as its never registered with the LocationManager.
Finally, instead of using two listeners for GPS and NETWORK, I would suggest using the Fused location provider in Google Play Services, as discussed here:
http://developer.android.com/training/location/receive-location-updates.html
You'll be limited to devices Android 2.2 and up with Google Play Services installed, but in my opinion its worth it to avoid dealing with some of the eccentricities of location in the platform and managing more than one provider. For more about Fused location provider and how it differs from listening directly to GPS and NETWORK providers, see this 2013 Google I/O presentation - Beyond the Blue Dot: New Features in Android Location
Why do you use Google Play Services Location API?
The only new feature provided by Play Services is Geofencing. From your answer i assume that you don't want to use Geofencing but just "usual" location requests.
The Android platform provides a great API for such requests which does not requires Google Play Services. I never had the problem you described when using it.
Note that although Google claims the Play Services to be better than the Android API, this is not true since API 9 (Android 2.3), as long as you use the newer LocationManager.requestLocationUpdates methodes that don't require a provider to be specified.
See: http://developer.android.com/guide/topics/location/strategies.html
I had the same issue with the regular Location API earlier. I swiched to Play Services, and it seemed to work. Lately sometimes I experience this issue again with Google Play Services. It is really strange, and based on my experience the probelem is system-wide, so when my app couldn't find location, than the Google Maps app couldn't eather. Note that I use Cyanogenmod, so it can be some bug within it.

Categories

Resources