I am developing an app to be used on a specific tablet running Android 7.0. I'm using a Service to send periodic DatagramPackets. I can only use mobile networks. I check the connectivity status using ConnectivityManager, NetworkInfo and DetailedState. I get the network state with this code:
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
DetailedState networkState = activeNetwork.getDetailedState();
If the tablet is plugged in and the screen is on or off, I get CONNECTED state.
If the tabled is unplugged and the screen is on, I get CONNECTED state.
If the tabled is unplugged and the screen is off, I get BLOCKED state.
In my tablet the Data Saver is off. Just in case, I have run tests to verify there are no restrictions when the screen turns off, cm.getRestrictBackgroundStatus() always returns 1, which is RESTRICT_BACKGROUND_STATUS_DISABLED, even when the network is blocked.
So, why is the network blocked? Do my app need special permissions? Do my tablet need special configuration?
It's normal behaviour. When your screen is locked, it use doze mode. And Doze mode turn off internet communication and all background services. You need wakeup your device and after you can make all actions with internet. Documentations
In order to give a complete solution I will answer my question.
why is the network blocked?
As the documentation provided by Stanislav Kireev pointed, this BLOCKED network state happens because the device is in Doze. This device state does not allow internet access starting from Android 6.0 (API level 23).
But the documentation also says that "the system provides a configurable whitelist of apps that are partially exempt from Doze and App Standby optimizations". For more detailed explanation you can read Support for other use cases section. You can add your app to the whitelist from code or configuring the system.
Do my app need special permissions?
If you need to add your app to the whitelist from code, you need to add a permission in the manifest file:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
And add this code to your activity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
I got this solution from this answer.
Do my tablet need special configuration?
If you want, you can add your app from Settings > Battery > 3 dots > Battery optimisation. Choose All apps in the pick list, select your app and choose Don’t optimise option.
I got this solution from this answer (it has more detailed explanation).
Related
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.
I am using a foreground service to track the live location of the user. it is working fine in stock android devices, but in brands like oppo, vivo, Mi etc, the app is killed when the device comes into doze mode. I also tried to use FCM notifications still of no use. I am just wondering has Uber or Ola been able to crack this, bcuz i have seen most of the drivers have been using these brands. How are the able to keep their app alive in doze mode?
you need enable auto start permission for apps in oppo , vivo and mi
try below code worked for me
private void keepServicesInChineseDevices() {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
switch (manufacturer) {
case "xiaomi":
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
break;
case "oppo":
intent.setComponent(new ComponentName("com.coloros.safecenter",
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
break;
case "vivo":
intent.setComponent(new ComponentName("com.vivo.permissionmanager",
"com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
break;
}
List<ResolveInfo> arrayList = getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (arrayList.size() > 0) {
AppDataHolder.getSession(MyApplication.getAppContext()).setPermissionForChineseDevices(true);
startActivity(intent);
}
}
this article is also helpful
Thank you so much guys, for your responses. I would like to tell you that I wrote an email to google support and highlighted the issue to google support, in reply they mentioned below reply:
"Thanks for reaching out.
It seems that you can’t receive a push notification on some Android devices. Upon checking the affected device, it is affected by a device specific (known) issue, and it's caused by OEM features for battery optimization. When the app is swiped away, in some of OEMs which has implemented such a feature, the application is treated similar to "force-stopped" mechanism and services registered with the app that's swiped, is stopped.
For now, I strongly recommend contacting the support team of those affected OEMs to help get it resolved from their end.
You can read more about this issue and a possible way of solving it in this blog post(https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/).
I have asked the following quoted question but found that all working gone in vain as android is now not allowing to register the broadcast for network changes.
You can not do it in Manifest where as you can still get calls when you register it in your Activity and that context is still alive .
Now I have implemented in my activity and I am getting my broadcast receivers call and all is working as expected. But when I do start my activity , I received the call automatically. Can not I just skipp that thing on activity start ?
here is my old question that I have asked in this thread:
I have an application where I have implemented the BroadcastReceiver for the Network changes.
It alerts me when there is any change in the network connection, Like
the network gets disconnected, the network gets connected, the network
gets changed etc
But I have observe that it does not alert me when the Wifi is
connected but the Internet goes off from that network.
Is there something to check such case and can we make broadcast for it
??
I have searched alot but did not get any answer of this. I hope I made
myself quiet clear about my requirements.
Have you check the documentation here?
https://developer.android.com/training/monitoring-device-state/connectivity-monitoring?hl=es-419
It explains you how to use ConnectivityManager to check the changes on connectivity
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
You can even check the type:
boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
Or even allow your app (via the Manifest) to consider the changes, by supporting this action:
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
For bluetooth device found we receive Brodcast from Android with action :
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// New bluetooth device found
}
When we set device to discover able then this happens.
My question is what are the intents that are fired when device discoverable is turned off or bluetooth of other device turned off.
In my list view I am showing devices that are "FOUND" I am able to do this using above code. But I want to remove entry of the device which is no longer in range, no longer discoverable or has turned off the bluetooth are there any specific intent that Android platform fires ?
I have looked through BluetoothDevice, BluetoothAdapter reference APIs. But did n't found any useful broadcast action.
The intent you are searching for is BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED
Intent used to broadcast the change in connection state of the local Bluetooth adapter to a profile of the remote device.
This intent will have 3 extras:
EXTRA_CONNECTION_STATE - The current connection state.
EXTRA_PREVIOUS_CONNECTION_STATE - The previous connection state.
EXTRA_DEVICE - The remote device.
EXTRA_CONNECTION_STATE or EXTRA_PREVIOUS_CONNECTION_STATE can be:
STATE_DISCONNECTED
STATE_CONNECTING
STATE_CONNECTED
STATE_DISCONNECTING.
I'm reading a lot of conflicting information on this topic, so going to ask myself with some specific code examples. My Android app is getting "Network Unavailable" errors when trying to make an HTTP request from a background service, only when the phone is asleep. The phone is using the mobile network only when I get these errors (no wi-fi in the building).
I use this code to schedule my service:
static private void SchedulePoll(Context context,int minsFromNow)
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, minsFromNow);
Intent intent = new Intent(context, PSDroidBroadcastReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}
My service acquires a PARTIAL_WAKE_LOCK and then calls:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
At that point I'm getting a Network Not Available exception, only when phone in sleep mode.
Is it normal to have issues like this in sleep mode, or should I be able to make an Internet connection from my service? It seems like lots of apps check email and other things, so it should be normal and work most of the time?
I looked through the phones settings and made sure anything that was related to background connections was enabled. It is a Sprint HTC, Evo I think.
Turns out it was an application on the phone called "Juice Defender". I guess it is designed to save battery life, as soon as we disabled it, my app works. GMai also wasn't working with it enabled, so I feel pretty safe that there isn't much I could have done to design my app better... other than making the error message more intuitive.
Even with a Partial_Wake_Lock you need something like:
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_NEVER);
Taken from: How do I keep Wifi from disconnecting when phone is asleep?