I start an activity from a background service which unlocks the phone and starts an activity. What I want to achieve is to go to home screen just after the activity is loaded. I created a button on the activity that I go to just after unlocking and on its OnClick method I used:
moveTaskToBack(true);
Now, I need to call buttonName.performClick() somewhere but where? I tried onResume and onPause so far, but no luck. How or where can I make sure the activity is fully loaded?
//What I do on my Service to start Activity that unlocks the phone
Intent dialogIntent = new Intent(this, StartStopActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
This is the activity class:
public class StartStopActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_stop);
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);
Button returnButton = (Button) findViewById(R.id.button3);
returnButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
moveTaskToBack(true);
}
});
//returnButton.performClick();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
public void turnOnScreen(){
// turn on screen
Log.v("ProximityActivity", "ON!");
mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "tag");
mWakeLock.acquire();
}
#TargetApi(21) //Suppress lint error for PROXIMITY_SCREEN_OFF_WAKE_LOCK
public void turnOffScreen(){
// turn off screen
Log.v("ProximityActivity", "OFF!");
mWakeLock = mPowerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "tag");
mWakeLock.acquire();
}
Use startActivityForResult and onActivityResult just turn the screen on and set you parameters to keep the screen on if you want
OnClick method will only be called when you click on a view. You just can't invoke it without clicking on anything.
Just copy the code that you have inside your onclick method and put in inside your oncreate(). or anywhere where you want that piece of code to be executed.
It will not be automatically called if you don't actually click on that view to which you have set the click listener.
Change your code like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_stop);
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);
moveTaskToBack(true);
}
Related
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
);
}
});
}
In my application, i need to launch an activity and turn screen on, when high-priority FCM message is received. It's an alarm activity, which is very, very important for users.
On most Android devices, the code is working fine. However, on some Huawei or LG devices, the activity is not launched when the device is in Doze mode, or in the pocket (proximity sensor). The behaviour should be similar like Alarm clocks, calls etc.
Here is my code:
FirebaseMessagingService:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent dialogIntent = new Intent(getBaseContext(), AlarmActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
dialogIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
getApplication().startActivity(dialogIntent);
}
Alarm Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set flags so an activity fire on the screen
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
);
setContentView(R.layout.activity_alarm);
.
.
}
I wanted to use SCREEN_BRIGHT_WAKE_LOCK before I launch an activity, but it's deprecated.
I am using in my activity this code:
#Override
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setShowWhenLocked(true);
setTurnScreenOn(true);
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
keyguardManager.requestDismissKeyguard(this, null);
}
} else {
//noinspection deprecation
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
);
}
}
.....
}
To prevent different behavior on different devices I use in my activity layout this:
<android.support.design.widget.CoordinatorLayout
....
android:keepScreenOn="true"
>
I want to create an android application to trigger the alarm. I have a button called btnStart. When the user click the button, in 3 second, it should go to AlarmReceiverActivity.java and start play the sound.
the btnStart onclick method look like
btnStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int i = 3;
Intent intent = new Intent (MapPage.this, AlarmReceiverActivity.class);
PendingIntent pending =
PendingIntent.getActivity(MapPage.this, 2, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+(i * 1000), pending);
if (toast != null){
toast.cancel();
}
toast = Toast.makeText(getApplicationContext(), "Alarm for activity is set in : "+ i +" second", toast.LENGTH_SHORT);
toast.show();
}
});
and the AlarmReceiverActivity.java look like this
public class AlarmReceiverActivity extends Activity{
private MediaPlayer mMediaPlayer;
private PowerManager.WakeLock mWakeLock;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Wake Log");
mWakeLock.acquire();
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
Button stopAlarm = (Button) findViewById(R.id.stopAlarm);
stopAlarm.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMediaPlayer.stop();
finish();
}
});
playSound (this, getAlarmUri());
}
to make this short question short, there are some method that I not state above. When I click the button, I got and error. It say that
java.lang.RunTimeException: Unable to start activity ComponentInfo{com.example.splashscreen/com.example.splashscreen.AlarmReceiverActivity}: android.util.AndroidRuntimeException: requestFeature() must be called before adding content
Any idea on how to solve this problem ? Thank you in advance
Chnage the order like this..
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
Put this:
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
before this:
setContentView(R.layout.alarm);
From the docs on requestWindowFeature (emphasis added):
Enable extended screen features. This must be called before setContentView(). May be called as many times as desired as long as it is before setContentView(). If not called, no extended features will be available. You can not turn off a feature once it is requested. You canot use other title features with FEATURE_CUSTOM_TITLE.
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.
I am creating application that shows notification icon in statusbar. When user opens statusbar and taps on the icon the application should be launched.
I am searching a way to avoid re-creation of application during this launch. I have created test application and add log messages to handlers onCreate, onRestart, onResume, onStop and onDestroy. Log messages demonstrates the problem:
User starts application - onCreate, onResume
User presses HOME button - onStop
User opens list of applications and starts application again - onRestart, onResume
User presses HOME button - onStop
User opens list of recent applications and selects the application - onRestart, onResume
User presses HOME button - onStop
User opens statusbar and taps on the application icon - onDestroy, onCreate, onResume.
Step 7 has a different behavior then 3) and 5) - there is onDestroy here. In other words, instance of the application is recreated. Is it possible to avoid this recreation?
This is a code of my test activity:
public class MainActivity extends Activity {
private final String LOG_TAG = "com.example.notificationtest";
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showNotification(this);
Log.d(LOG_TAG, "NotificationTest: OnCreate");
}
#Override protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "NotificationTest: OnRestart");
}
#Override protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "NotificationTest: OnResume");
}
#Override protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "NotificationTest: OnDestroy");
}
#Override protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "NotificationTest: OnStop");
}
private static final int NOTIF_ID = 91371;
public static void showNotification(Context context) {
final Intent result_intent = new Intent(context, MainActivity.class);
result_intent.setAction(Intent.ACTION_MAIN);
result_intent.addCategory(Intent.CATEGORY_LAUNCHER);
//result_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//result_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//result_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
TaskStackBuilder stack_builder = TaskStackBuilder.create(context);
stack_builder.addParentStack(MainActivity.class);
stack_builder.addNextIntent(result_intent);
PendingIntent pending_intent = stack_builder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
android.support.v4.app.NotificationCompat.Builder builder = new android.support.v4.app.NotificationCompat.Builder(context);
Resources res = context.getResources();
builder.setContentIntent(pending_intent)
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
.setTicker("test")
.setWhen(System.currentTimeMillis())
.setAutoCancel(false)
.setContentTitle("title")
.setContentInfo("cinfo")
.setContentText("ctext");
Notification n = builder.build();
n.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NOTIF_ID, n);
}
}
There are some flags, that can be set to result_intent, like FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_CLEAR_TASK and FLAG_ACTIVITY_NEW_TASK. They allow to specify that activity should be restarted on launch (with activity launch mode "singleTop", "singleTask" etc). But what flag should be set to avoid restarting? Probably I should configure pending_intent in some way?
Any help will be very appreciated.
Solved
Thanks a lot for the answers, the problem is solved.
Same problem is described here. I have checked test project from that topic and found difference with my code. To solve the problem my code should be changed in follow way:
final Intent result_intent = new Intent(context, MainActivity.class);
//result_intent.setAction(Intent.ACTION_MAIN); // (1)
//result_intent.addCategory(Intent.CATEGORY_LAUNCHER); // (2)
result_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
another set of flags works too:
result_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
main point was to comment lines (1) and (2)
add this:
result_intent..setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
It works like
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
also maintains activity stack