Android bring app to foreground on Firebase notification - android

I have the following code which brings my Android app to foreground once I receive a Firebase Push notification or FCM.
#ReactMethod
public void backToForeground() {
Context context = getAppContext();
String packageName = context.getApplicationContext().getPackageName();
Intent focusIntent = context.getPackageManager().getLaunchIntentForPackage(packageName).cloneFilter();
Activity activity = getCurrentActivity();
boolean isOpened = activity != null;
if (isOpened) {
focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
activity.startActivity(focusIntent);
} else {
// Custom flag to check whether app was started from this method
focusIntent.putExtra("FLAG_ON_CALL_BRING_TO_FRONT", "true");
focusIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK +
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED +
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD +
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
getReactApplicationContext().startActivity(focusIntent);
}
}
Now in MainActivity I have used the bundle as following:
#Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.show(this);
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras != null) {
// Custom flag defined in AppStateManagerModule
String extraString = extras.getString("FLAG_ON_CALL_BRING_TO_FRONT");
if (extraString != null) {
getWindow()
.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
);
}
}
}
My code is working correctly in the following cases:
When FCM is received on device:
If app is open, action is performed
If app is in background i.e minimized, app opens and action is performed
If app is killed, app opens and action is performed
If app is killed and phone is locked, app opens on top of lock screen and then action is performed
Now here's the case which doesn't work properly:
If I start my app and its in foreground or if its minimized and I lock my phone, my app is running fine and my code brings it to front, it performs the required operation BUT it doesn't show on top of lock screen.
Action is performed fine in point 5 but it doesnt show on top of lock screen.

If app is active or in background, after phone is locked it will still be considered active. So since an activity is active, it can't be thrown on top with intent since its already used to activate the activity.
We need to add window flags on an active activity to bring it to front like this:
if (isOpened) {
focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
activity.startActivity(focusIntent);
// Adding Window Flags to bring app forward on lock screen
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.getWindow()
.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
);
}
});
}

Related

Different behaviour when app is screen pinned

My app never goes to sleep while power is connected and if power is removed then the tablet goes into sleep. After powercable is reinserted the app is getting launched automatically when power is connected (Battery is charging).
To achive this I have implemented a BroadcastReceiver and within this Receiver I (re-) launch my app with:
if (action.equals(Intent.ACTION_POWER_CONNECTED)) {
// Start the MainActivity
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
context.startActivity(i);
}
In the MainActivity I use (in onCreate()):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
}
else{
}
if( something...) {
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Object o = this.getSystemService(Context.KEYGUARD_SERVICE);
if (o != null) {
KeyguardManager keyguardManager = (KeyguardManager) o;
keyguardManager.requestDismissKeyguard(this, null);
}
}
else {
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
This works fine as long as the app is not screen-pinned. If the app is screen-pinned then this works only once. I assume because the app gets launched from screen-pinned context ?? Any further plugging of the powercable launches the app but is getting overlayed by a battery charge % window which dissapears after ca. 5 seconds and then the tablet goes into sleep. Is there a difference in this context when the app is screen-pinned ?

Unlock Screen When Application is in Background

I have an activity that might by launched when screen is locked. I use this code to make it work:
if (powerManager != null) {
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "App:wakeuptag");
wakeLock.acquire(1000 * 60);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
} else {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
And so far, it works only if application was in foreground before user locked the screen. If application was in bacgkround state before screen was locked, then this code won't work.
Edit: I found out it's not because app is being in background, it's because the app was closed by pressing HOME button, if I close app with back button everything works fine. So, this is somehow relevant with HOME button.

Android turn on the screen

I making the application where an activity launch is scheduled by AlarmManager. I would like to appear even if the screen is turned off and device is locked.
To achive this a set the Window flags
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
And try to obtain lock for the screen
if(_lock == null)
{
PowerManager pm = (PowerManager)App.getAppContext()
.getSystemService(Context.POWER_SERVICE);
_lock = pm.newWakeLock(
PowerManager.FULL_WAKE_LOCK, "ScreenOn");
_lock.acquire();
}
The _lock is PowerManager.WakeLock which is released in onPause
protected void onPause()
{
if(_lock != null)
{
_lock.release();
}
}
This code is executed in onCreate and onRestart. Everything works OK if the activity is not launched yet.
But if it was launched earlier the screen is not turned off.
onRestart is called first
onResume is then called
onPause is called immediately
So the activity is not launched. My question is how to turn on the screen in such situation. (I am using API 15).
I came up with the solution. I created a new activity which will be trying to turn on the screen in the onCreate() and then wait until it is turned on. When the screen is ok it will launch the activity which should be displayed. To make the Android always create this activity
public class TurnOnScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isScreenOn()) openActivity();
else {
registerReceiver(mScreenOnReceiver, new IntentFilter(
Intent.ACTION_SCREEN_ON));
reciever_registered = true;
turnScreenOn();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (reciever_registered) {
unregisterReceiver(mScreenOnReceiver);
reciever_registered = false;
}
}
private boolean reciever_registered = false;
private final BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
openActivity();
}
};
private void openActivity() {
Intent intent = new Intent();
// ....
finish();
}
private void turnScreenOn() {
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
}
I am still looking for explanations why the screen is not turned on in onRestart.
Have you heard of "The Lighted Green Room"? Check out the code below, it may be what you're looking for.
http://code.google.com/p/ch-bfh-fbi-mobicomp-2011/source/browse/ch_simplix_android_repetitive_service/src/com/androidbook/longrun/LightedGreenRoom.java?spec=svn38&r=37
Just use your code :
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
in onCreate() only and remove all those other Activity-Cycle methods if they are not doing anything else then this.
I don't think you need any more code to use to perform it.

How to start new activity from lockscreen?

I am creating simple widget for contact management, which allows user to dial and send sms to desired contact.
It works fine as "normal widget", but when I add it as lockscreen widget on Android 4.2, sms app or dial app does not start.
Well in fact they star, but "behind" lockscreen, so user still must manually unlock screen to be able to dial/send sms.
I searched web for some solution, but nothing come in handy.
I' am aware of FLAG_DISABLE_KEYGUARD or FLAG_SHOW_WHEN_LOCKED, but since sms/dial apps are not "mine" so i dont know if they set up proper flag.
As a workaround i tried to create my activity which set those flag and then simply starts desired one (dial or sms), but this does not help.
There is a way to unlock screen, but this involves using KeyguardManager and KeyguardLock (which work fine), but in a result of using KeyguardLock.newKeyguardLock() I end up with phone not being able to turn lock automatically, surely because I do not release this lock (it causes lock to appear again, which is not what i want).
In fact, this widget should work simmilarly to default sms widget or mail widget on lock screen?
So, my question is, how to achieve that and start new activity from lockscreen?
Well, i found solution myself. it turned out i was close :)
To launch 3rd party app/activity, simplest solution is to create some kind of proxy activity, which will set proper flags on window and then launches desired activity and FINISHES.
sample code is shown below:
calling intent in widget (calling proxy):
#Override
public void onReceive(Context context, Intent intent) {
Utilities.printLog(TAG, "onReceive");
Utilities.printLog(TAG, "intent: " + intent);
if (intent.getAction().equals(ACTION)) {
final String number = intent.getStringExtra(EXTRAS);
Toast.makeText(context, "Selected number: " + number,
Toast.LENGTH_SHORT)
.show();
/** REMOVING KEYGUARD RECEIVER **/
// not really an option - lock is still holded by widget and screen
// cannot be locked again ;(
// KeyguardManager keyguardManager = (KeyguardManager) context
// .getSystemService(Context.KEYGUARD_SERVICE);
// KeyguardLock lock = keyguardManager
// .newKeyguardLock(Context.KEYGUARD_SERVICE);
// lock.disableKeyguard();
final Intent activity = new Intent(context, MainActivity.class);
activity.putExtras(intent.getExtras());
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
activity.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(activity);
}
super.onReceive(context, intent);
}
in proxy activity just call:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
final Intent callingIntent = getIntent();
final String actionToLaunch = callingIntent.getStringExtra(ContactsStackWidgetProvider.ACTION);
final String number = callingIntent.getStringExtra(ContactsStackWidgetProvider.EXTRAS);
final Intent activity = new Intent();
if (actionToLaunch.equals(Intent.ACTION_DIAL)) {
activity.setAction(Intent.ACTION_DIAL);
activity.setData(Uri.parse("tel:"+number));
} else if (actionToLaunch.equals(Intent.ACTION_SENDTO)) {
activity.setAction(Intent.ACTION_SENDTO);
activity.setData(Uri.parse("sms:"+number));
} else {
throw new IllegalArgumentException("Unrecognized action: "
+ actionToLaunch);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(activity);
finish();//it is important to finish, but after a small delay
}
}, 50L);
}

FLAG_TURN_SCREEN_ON does not always work

i start an activity from a BroadcastReceiver, which is triggered by an alaram (RTC_WAKEUP type). in onCreate of that activity i add these flags
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
);
problem is that sometimes (approximately 10% cases) the screen does not turn on. the alarm is correctly triggered (i here the sound of a notification, which is also fired in the receiver's onReceive(). then, if i hit the phone's power button, the screen turns on, showing my activity, and instantly turns off. after that, the power button works good. this happen on android 2.3.7 and here is the onReceive() method
#Override
public void onReceive(Context context, Intent intent) {
m_Context = context;
Bundle extras = intent.getExtras();
final int id = extras.getInt("timer_id");
Intent activityIntent = new Intent(m_Context, MyActivity.class);
activityIntent.putExtra("timer_id", id);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
m_Context.startActivity(activityIntent);
// and now load the alarm sound and play it for the desired time
showFinishedNotification();
}
i would like to avoid using PowerManager, as it needs a permission, and the flags are the prefered way.
what could be a problem? logcat does not show any problems...
From my experience and research on this topic:
The FLAG_TURN_SCREEN_ON can not be used to turn the screen ON and OFF multiple times in your application.
The FLAG_TURN_SCREEN_ON can only be used once to turn the screen ON when creating a new activity (preferably in the onCreate() method) or when re-creating a view.
Now, you can get around this limitation by:
Launching a new activity and setting the flag there, then finishing the activity (by the user or programmatically) to let the screen turn off.
Setting the params.screenBrightness parameters to as "dim" as possible, sometimes the screen "appears OFF". You can then increase the brightness to "turn ON" the screen. However, this often does not work as the screen is still dim but visible, also this doesn't work if the user locks the phone.
Using the Power Manager Wakelock (this still works but Android deprecated this functionality, so they are discouraging the use of this technique). However, as far as I can tell this is the only way I can get my application to turn the screen ON/OFF reliably.
None of these are ideal (in fact they feel like hacks) but just use the one that better suits your application needs.
You can read more here:
Android Alarm Clock Source Code
Android Desk Clock Source Code
Dimming the screen to appear OFF/ON
Using a wakelock to keep the screen ON/OFF
Waking up device and turning screen ON multiple options
I'm a bit late to the party here but I've been fighting this for a while now and finally found a way to get the screen to unlock every time. I add the flags in the onAttachToWindow() event. Typically I do this from a WakefulBroadcastReceiver so the screen transitions smoothly but that's use-case dependent.
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
//Screen On
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
private void clearFlags() {
//Don't forget to clear the flags at some point in time.
getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
problem is that sometimes (approximately 10% cases) the screen does not turn on
If I had to guess, the device is falling back asleep before the activity starts up. Once onReceive() returns, the device can and will fall back asleep, and it will be some time after onReceive() returns before your activity will start.
This same scenario, but replacing startActivity() with startService(), is why I had to write WakefulIntentService, which uses a WakeLock to ensure that the device stays awake long enough for it to do its work, then releases the WakeLock.
Late answer But it will help for anyone.
For higher and lower versions use following code (it working fine)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
keyguardManager.requestDismissKeyguard(this, null);
}
else{
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
setContentView(R.layout.activity_incoming_call);
}
Important Note: you should place before setContentView()
I use these three methods simultaneously which works at almost any device.
public static void turnScreenOnThroughKeyguard(#NonNull Activity activity) {
userPowerManagerWakeup(activity);
useWindowFlags(activity);
useActivityScreenMethods(activity);
}
private static void useActivityScreenMethods(#NonNull Activity activity) {
if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
try {
activity.setTurnScreenOn(true);
activity.setShowWhenLocked(true);
} catch (NoSuchMethodError e) {
Log.e(e, "Enable setTurnScreenOn and setShowWhenLocked is not present on device!");
}
}
}
private static void useWindowFlags(#NonNull Activity activity) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
private static void userPowerManagerWakeup(#NonNull Activity activity) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, tag);
wakeLock.acquire(TimeUnit.SECONDS.toMillis(5));
}
Targeting sdk 30
Following code enables to open Activity from PendingIntent, even if application
was cleared from recent apps
and screen is dimmed
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(view)
turnOnScreen()
}
private fun turnOnScreen() {
window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
)
setTurnScreenOn(true)
setShowWhenLocked(true)
val keyguardManager = getSystemService(KEYGUARD_SERVICE) as KeyguardManager
keyguardManager.requestDismissKeyguard(this, null)
}

Categories

Resources