I have to create an app, which detects user inactivity, and then start activity which displays some videos with WebView, and then when displaying with WebView is finished, it has to play videos from SDCard. I've already handled part with WebView and SDCard (with JavaScriptInterface etc.)
This application has to work with API 19 all the way to the newest one.
The question is - Is there a possibility to detect if user is inactive and start my application, or keep the app running in background, and then start activity in the foreground after the user becomes inactive for certain time?
I'm not trying to play ads, when user is not looking at his screen. Application is for my client, who have stores with all kind of electrical equipments, including smartphones. The goal is to play video presentations with hardware details specific for each smartphone (informations about processor, ram, camera, screen etc.).
In short: I have to make an app which is similar to "Demo Apps" created for example by Samsung (playing some kind of presentations on screen).
So far I've read and tested things like:
1) BroadcastReceiver with combination of ACTION_SCREEN_OFF / ACTION_SCREEN_ON events.
Receiver works properly, I can detect this event and then start activity, but... The screen is already off so i can't see the displayed activity - it's visible running in the foreground after unlocking the phone. Is there a way to unlock the phone when the event is received?
That's my code so far.
EventReceiver Class:
class EventReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
StringBuilder().apply {
append("Action: ${intent.action}\n")
append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
toString().also { log ->
Log.d(TAG, log)
Toast.makeText(context, log, Toast.LENGTH_LONG).show()
}
}
if (intent.action == Intent.ACTION_SCREEN_OFF) {
val i = Intent(context, MainActivity::class.java)
context.startActivity(i)
}
}
}
MainActivity Class:
val br : BroadcastReceiver = EventReceiver()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
addAction(Intent.ACTION_SCREEN_OFF)
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_BOOT_COMPLETED)
}
2) Foreground Services - I read that this is a great way to make some asyc stuff in the background and show notifications to user. Is there a way to start the activity with it?
3) Job Scheduler
4) Daydream / Dream Service - it actually works great with almost every API and manufacturer, but.. there's no way to set the app as Screen Saver on Huawei/Honor smartphones, at least from phone settings, I've read that this is possible with ADB etc. but this is not an option that I can use here.
It seems that none of these fullfill my expectations.
Related
I am working on android project, where NFC is used as a communication. I am facing a weird problem, when mobile device has a NFC, it is enabled, but it is not working on some devices (adapter is not enabled when debugging). I am writing logs and it prints, NFC on, adapter disabled.
For example: HTC One m9(os 7.0). Also happens with OnePlus One(os 9)! But again, it works on other devices.
Did you experience the same issue?
Here is some code:
object NfcUtil {
fun getNfcAdapter(c: Context): NfcAdapter? {
val manager = c.getSystemService(Context.NFC_SERVICE) as NfcManager
return manager.defaultAdapter
}
fun doesSupportHce(c: Context): Boolean {
return c.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
}
}
val adapter = NfcUtil.getNfcAdapter(this)
if (adapter != null && NfcUtil.doesSupportHce(this)) {
if (adapter.isEnabled) {
tvNfcOff.extHide()
} else {
tvNfcOff.extShow()
}
}
I think that if NFC is supported and enabled but the adapter is disabled (https://developer.android.com/reference/android/nfc/NfcAdapter#isEnabled()) I'll follow the guidelines and redirects the user to the settings screen with the intent mentioned in the documentation.
If the user come back few times you could monitor it and show a different message instead of redirecting to settings, something like: NFC is not working properly on your device. I'd check if you have lots of users using those devices, if yes, I will try to research more on the Operating System and Device having this issue.
And later on I will just try to debug it with that Device and that specific Operating System that is having this kind of issue. I'll try to see if other apps using NFC has same issues or they work fine, and by work fine I mean that the communication happens not that other apps dont show any warning/error popup message.
And if I found out its an issue in a specific OS Version, also with other apps, I'll just try to inform the users and get an update on which version the issue have been fixed. Otherwise if other apps can make a successful NFC communication in that device/OS that is not working for me, I'll just dig deeper.
For now I can say there is nothing wrong in your implementation and looks good.
It might be an issue with the current OS or if you have any Custom ROM that might not fully support or have a functional NFC driver.
Two additional bits of info that might be useful
1) Use a Broadcaster receiver to get notified when the NFC state changes, because using the quick settings pull down does not pause your app, therefore retesting nfc status in onResume does not work (a user changing via the full settings app will pause you App, though)
Example of how to do it in Java
#Override
protected void onCreate(Bundle savedInstanceState) {
// All normal onCreate Stuff
// Listen to NFC setting changes
this.registerReceiver(mReceiver, filter);
}
// Listen for NFC being turned on while in the App
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF);
switch (state) {
case NfcAdapter.STATE_OFF:
// Tell the user to turn NFC on if App requires it
break;
case NfcAdapter.STATE_TURNING_OFF:
break;
case NfcAdapter.STATE_ON:
// Do something with this to enable NFC listening
break;
case NfcAdapter.STATE_TURNING_ON:
break;
}
}
}
};
2) Don't assume that the device has a NFC settings page, if your app works with and without NFC, if the adapter is null don't assume you can start an Intent to the NFC settings page as suggested by #denis_lor as this will cause a crash if the OS does not have a NFC adapter to turn on.
I need to be able to send my GPS-location to a server every time I receive a silent-push notification from Firebase. The timer for sending a notification is currently set to every 10 minutes. When the phone is charging this is not a problem, but when it's idle and the application is in the background, the onMessageReceived from FirebaseMessagingService is only called every few hours. This leads me to believe it has something to do with the new power management rules for Android 9.0. But for my application to work I need to be able to send my location every 10 minutes. Not just sometimes.
I have tried to set the battery optimisation to 'not optimised' using Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
This does not seem to have any effect.
I also tried setting the priority of the Firebase notification to High. This works, but only for 10 messages per day, which means it's not a solution for my application. (Source: Power Management restrictions)
I am now trying to always have the application in the 'Active' bucket by opening a foregroundService. This should make sure the app is never in any other bucket, where the notifications can be deferred for a few hours.
An app is in the active bucket if the user is currently using the app, for example:
The app has launched an activity
The app is running a foreground service
The app has a sync adapter associated with a content provider used by a foreground app
The user clicks on a notification from the app
If an app is in the active bucket, the system does not place any restrictions on the app's jobs, alarms, or FCM messages.
(Source: Power Buckets Android9).
This does not seem like a solution I should want, though, since it might not be best practice. And it doesn't seem to work either anyways.
This is my onMessageReceived function:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
PushNotificationManager.getInstance().handlePushNotification(object, getApplicationContext());
}
}
Right now I am clueless as to why the Firebase messages do not enter the onMessageReceived function.
Tim,
I think that the main problem is with how you send the push notification and what is its content.
If you check here - https://firebase.google.com/docs/cloud-messaging/android/receive
you will see that if the message contains notification data and the app is at background then the push notification goes to the Notification area.
You need to send a push notification that contains only data:
(Here you can find more information about the different types - https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages)
Here is what is the explanation how to trigger it-
In a trusted environment such as Cloud Functions or your app server, use the Admin SDK or the FCM Server Protocols: Set the data key only.
Please note that if you need to do a long running operation, then you will need to start a separate service (the service should present a notification in the notification area that it is running, otherwise you will get a crash on the newer Android versions)
Fixed by using AlarmManager. Schedule an alarm in 10 minutes, and when completing the code within the alarm, schedule a new alarm in 10 minutes.
AlarmManager can wake the phone if it is in doze mode, which means all code inside the trigger will be executed properly.
I have a simple Flutter app that start a native background service using MethodChannel. This native background service notify my Flutter app using BasicMessageChannel<String> to display text when a particular native information is catched. All of this work perfectly when my app is in foreground. When an other app is in foreground, I can't see the text without having to switch to my app.
I want that my native service can display a particular Flutter screen even if an other application is running in foreground.
It can be perceived as not user friendly, but this is an message of utmost importance.
Any suggestion or solution will be welcome !
Note : Native service is for the moment only available in Java for Android, I'm working on C# for IOS side.
On Android you need to display a high priority notification. This displays the slide-down notification panel which will appear over the lock screen or another app. Since you are using native code already, you can create this notification there, or send a message to the Dart side (as you are doing, using MethodChannel) where it can use the flutter_local_notifications plugin to display it. When the user click the notification, your flutter app is brought to the foreground. In Java you might use code similar to this:
// Create an intent which triggers the fullscreen notification
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.setAction("SELECT_NOTIFICATION");
Class mainActivityClass = getMainActivityClass(context);
intent.setClass(context, mainActivityClass);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Build the notification as an ongoing high priority item to ensures it will show as
// a heads up notification which slides down over top of the current content.
final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID);
builder.setOngoing(true);
// Set notification content intent to take user to fullscreen UI if user taps on the
// notification body.
builder.setContentIntent(pendingIntent);
// Set full screen intent to trigger display of the fullscreen UI when the notification
// manager deems it appropriate.
builder.setFullScreenIntent(pendingIntent, true);
// Setup notification content.
int resourceId = context.getResources().getIdentifier("app_icon", "drawable", context.getPackageName());
builder.setSmallIcon(resourceId);
builder.setContentTitle("Your notification title");
builder.setContentText("Your notification content.");
MyPlugin.notificationManager().notify(someId, builder.build());
Then, for Android 8.1 or higher, add the following to your MainActivity class, found under the android/app/src/main/java/packageName/ folder
GeneratedPluginRegistrant.registerWith(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
}
(This shows the Flutter app even when the screen is locked.)
Flutter only has one activity, so the above code will bring that Flutter activity to the foreground (note that you don't always see the notification, but sometimes you do - if you set it to autoCancel then touching it clears it). It's up to you to build the correct screen in Flutter, which you can do as you send the notification. Use Navigator.push or equivalent to change the page that Flutter is showing.
I've been using onTaskRemoved() method in a Service to detect when an app was removed from the device's RECENT list by swiping it away. I preform some logging and some other operations that need to take place when this happens. It works perfectly. For android below 6... But background service is being killed after swiping off in android 6.
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.e("ClearFromRecentSsss", "sttttts");
Intent intent = new Intent("in.com.example");
sendBroadcast(intent);
}
Some manufactures like xiaomi, Oppo have their own background strategy which is autostart. You need to redirect user to auto start activity and tell user to switch on:
Go like this and allow your app to autostart:
Settings > permissions > Autostart
Autostart setting varies by manufactures like in Xiaomi you can find it in their SecurityCenter app.
Autostart is blocking your service to restart, So turn it on manually and the check again . I'm afraid there is no inbuilt API to do so . So you need to redirect users to specified screen as per manufactures to turn auto start On. Have a look at Links below:
link1
link2
In HTML5WebView.java (pastebin link)(source) I have:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
System.out.println("TAG - BACK PRESSED IN WEB VIEW");
return super.onKeyDown(keyCode, event);
}
And in the activity that starts the web view I have:
#Override
public void onBackPressed() {
System.out.println("TAG - BACK PRESSED IN WEB PLAYER ACTIVITY");
super.onBackPressed();
}
Now when I'm playing an embedded youtube video normally (not fullscreen), both methods are called when I press the back button. When I put the video into fullscreen mode (using the youtube player fullscreen button), none of the methods are called. My only guess is, the back button is being consumed by the web view to undo the fullscreen action (but even that doesn't work).
I am trying to get the back button to immediatly kill the web view, even if there is a video in fullscreen mode.
See the problem in action here, had to post it externally because the gif > 2MB
If I was you I would delete the embed play of youtube video's or ask google that won't be seen as abuse. Because the embed play of youtube video's can be seen as a abuse of this:
Your app violates our Device and Network Abuse policy by downloading,
monetizing, or otherwise accessing YouTube videos in violation of the
YouTube Terms of Service or YouTube API Terms of Service.
More Info: https://play.google.com/about/privacy-security/device-network-abuse/ https://www.youtube.com/static?template=terms
For example, your app contains: YouTube background play functionality
This is a violation of the YouTube Terms of Service.
That is what I got in my experience because I also made a app where people could watch some YT embed video's but after some updates the app wouldn't be update becuase I got this error that it is abuse so I am warning you that's all.