I have an application where I'm using GCM and I want to receive notifications only when app is closed, but when it's foreground don't receive them.
So is there some functionality to disable GcmListenerService for a while?
You do this wrong way. It is irrelevant really when your app will receive GCM message. In your case it's more important when it react to it. So instead of disabling your application component, I'd simply put some logic that would either ignore messages under certain conditions (like it's in foreground) or handle them differently in that case. That, for me, looks like better way than turning your app completely deaf.
You will have to track if your app is in foreground / background using Activity Life cycle callback.
public class SampleApplication extends Application
{
private static int sRunningActivityCount = 0;
#Override
public void onCreate()
{
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(){
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState)
{
}
#Override
public void onActivityStarted(Activity activity)
{
sRunningActivityCount++;
}
#Override
public void onActivityResumed(Activity activity)
{
}
#Override
public void onActivityPaused(Activity activity)
{
}
#Override
public void onActivityStopped(Activity activity)
{
sRunningActivityCount--;
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
#Override
public void onActivityDestroyed(Activity activity)
{
}
});
}
public static boolean isAppBackground()
{
return sRunningActivityCount == 0;
}
public static boolean isAppForeground()
{
return sRunningActivityCount != 0;
}
}
You can use the following to enable/disable receiving GCM notifications:
public void setNotifications(boolean enabled)
{
mPackageManager.setComponentEnabledSetting(new ComponentName(mContext, YourGcmListenerService.class), enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Intent intent = new Intent(mContext, YourGcmListenerService.class);
if (enabled)
{
mContext.startService(intent);
}
else
{
mContext.stopService(intent);
}
}
Related
I am creating one app In which I want to check status of activity like activity is in foreground or in background.this is working perfect from code but I want to bring activity to foreground when it is in background for that I am using service so when activity is going to background state I am calling that service and from that service I am launching activity but service is working ok upto version 10 after that same code of intent is not working.
This is my code.
MainActivity.Java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(android.os.Build.VERSION.SDK_INT>=29 &&
!Settings.canDrawOverlays(getApplicationContext())) {
MainActivity.this.startActivity(new
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
}
}
This is DigitalApp class which extend application and from this I am calling service.
public class DigitalApp extends Application implements Application.ActivityLifecycleCallbacks
{
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
Toast.makeText(this,"App is in foreground with
activity::"+activity.getLocalClassName(),Toast.LENGTH_LONG).show();
Log.d("Tracking Activity Started", activity.getLocalClassName());
Log.d("TAG","App is in foreground");
}
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
Toast.makeText(this,"App enters background with
activity::"+activity.getLocalClassName(),Toast.LENGTH_LONG).show();
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
Log.d("Tracking Activity Stopped", activity.getLocalClassName());
Log.d("TAG","App enters background");
Intent i= null;
getApplicationContext().startService(new
Intent(getApplicationContext(),service.class));
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
This is Service class.
#Override
public void onCreate() {
super.onCreate();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "IN HANDLER OF SERVICE",
Toast.LENGTH_LONG).show();
Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(i);
}, 3000);
}
I am passing intent in handler to launch activity when it is going to background state.handler is in oncreate method of service.I want launch activity from there again after it is going to background state.
I am using flag new task but with this flag activity is not launching will I add other flags?
from the onStop() of your activity start the service like this-
fun launchService(){
val serviceIntent = Intent(this, LaunchAppService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
}else{
startService(serviceIntent)
}
}
and show notification for foreground service like this
I have a situation, that when my app goes in background (not killed completely!) and last alive activity was BActivity. In this state. I receive a push notification.
When notification is clicked it should open the last activity which was opened earlier i.e., (BActivity).
Question How to open that last specific paused activity?
Is any answer like set flag or manifest configs?
If I understood correctly, you want to bring your app back to foreground after you receive a push notification? In that case, use the following code:
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
where MainActivity is the launcher Activity that you have specified in AndroidManifest.xml.
This should bring your app to foreground in its previous state, if there ever was one, and otherwise launch MainActivity.
For an explanation see here.
You can try by adding the activity life cycle callback to your application. And judge the activity type of current paused or resumed activity, etc. The sample code:
public static void init(Application app) {
app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
private int activityCount = 0;
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
AppUtils.attachActivity(activity);
}
#Override
public void onActivityStarted(Activity activity) {
activityCount++;
AppUtils.attachForeActivity(activity);
}
#Override
public void onActivityResumed(Activity activity) {
if (!isForeGround) {
isForeGround = true;
notifyForegroundChange(true);
}
}
#Override
public void onActivityPaused(Activity activity) {
// no-op
}
#Override
public void onActivityStopped(Activity activity) {
AppUtils.detachForeActivity(activity);
activityCount--;
if (activityCount == 0) {
isForeGround = false;
notifyForegroundChange(false);
Log.i(TAG, "Activity foreground: " + System.currentTimeMillis());
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
// no-op
}
#Override
public void onActivityDestroyed(Activity activity) {
AppUtils.detachActivity(activity);
}
});
}
Here we use the activityCount filed to calculate current actived activities count. When it's 0, the app is background, otherwise foreground. You can judge the activity type by the callback method provided.
Hope it helps!
From an Android Service, I would like to call an Activity method, but only if the Activity is in the foreground.
I would like nothing to happen in case the Activity is not in the foreground.
Which is the simplest way to achieve that?
From a Service always better to broadcast events if the activity is listening to that broadcast will respond. If the activity is not listening then nothing will happen it will ignore.
This is the better solution than the one which you have asked.
I found a very simple solution, adapted from this previous answer:
On the Service:
Intent intent = new Intent(MainActivity.RECEIVER_INTENT);
intent.putExtra(MainActivity.RECEIVER_MESSAGE, myMessage);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
On the Activity:
public static final String RECEIVER_INTENT = "RECEIVER_INTENT";
public static final String RECEIVER_MESSAGE = "RECEIVER_MESSAGE";
Create a listener on onCreate():
public void onCreate(Bundle savedInstanceState) {
...
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra(RECEIVER_MESSAGE);
// call any method you want here
}
};
}
register it in onStart():
#Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((mBroadcastReceiver),
new IntentFilter(RECEIVER_INTENT)
);
}
unregister it in onStop():
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
super.onStop();
}
You can do this using a Interface just to check if the activity is in background or in foreground.
I am sharing some code to have some idea.
public interface CheckAppInForeground {
boolean isAppInForGround();
}
In your Activity
public class MainActivity extends AppCompatActivity implements CheckAppInForeground {
Boolean isAppInForeGround;
#Override
protected void onResume() {
super.onResume();
isAppInForeGround = true;
}
#Override
protected void onStop() {
super.onStop();
isAppInForeGround = false;
}
#Override
public boolean isAppInForGround() {
return isAppInForeGround;
}
}
And your service class
public class MyService extends Service {
Activity activity;
public MyService(Activity activity) {
this.activity = activity;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MainActivity mainActivity = (MainActivity) activity;
if (activity != null) {
boolean isActivityInForGround = mainActivity.isAppInForGround();
if (isActivityInForGround) {
// Do what you want to do when activity is in foreground
} else {
// Activity is in background
}
} else {
// Activity is destroyed
}
return super.onStartCommand(intent, flags, startId);
}
}
I think i am clear with the code. If you find something missing or unclear please let me know
Hey I have an application where I want to now when the APP goes to onPause or onDestroy because I want to call a certain function when this happens.
I tried to override the onPause in an activity and extended that activity in all project but the onPause was being called on every migration between activities (which is logical) but this is not what I want.
I want to know when the user exits the app or pauses it (pressing the home button)
Regards,
Pull this dependency in your build.gradle file:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Then in your Application class, use this:
public class MyApplication extends Application implements LifecycleObserver {
#Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
Update your AndroidManifest.xml file:
<application
android:name=".MyApplication"
....>
</application>
in all of your activities :
#Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
Log.e("TAG", "Activity Minimized");
}
in your main activity :
#Override
public void onBackPressed() {
Log.e("TAG", "App Exit");
super.onBackPressed();
}
note : there is no way to detect when app killed by system ( for example quit with task manager )
I use this method to detect if the app goes to background or is killed
step 1:
Make a service like this
public class OnClearFromRecentService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("ClearFromRecentService", "Service Started");
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("ClearFromRecentService", "Service Destroyed");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.e("ClearFromRecentService", "END");
//Code here
stopSelf();
}
}
step 2)register this service in manifest.xml
<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />
step 3) Then start this service on your splash activity
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
So now when your app is manually killed, the onDestroy method will be called
Try this on your code and let me know if its working.
Happy Coding :)
If the user exits the application the onDestroy() callback will be called, if the user presses the home button the onStop() callback will be called.
So you want to know when the whole Application goes into Bacground, the method from Activity.onPause tells you when a single abtivity goes into background.
For your needs you could add
to your android manifest. this will call a class like this with name "YourApplication"
public class YourApplication extends Application {
#Override
public void onCreate() {}
public public void onTerminate() {
super.onTerminate();
}
}
e.g. for "onCreate" or "onTerminate" of the whole App (not for every single Activity).
But java documentation say you should not trust that onTerminate is called on every app destroy (see: android.app.Application subclass, onTerminate is not being called).
I Think the best way is, if you
add a own Methode "onPause" and "onResume" to your Application class
in ALL your Activities you store into Application class when onPause or onResume is called
and you call you own Application.onPause when ALL of you activities are in "onPause"
and you call you Application.onResume when first Activity is back in
"onResume"
Implement
Application.ActivityLifecycleCallbacks
in your Application Class. It will implement the following ActivityLifeCycle Methods :
isActivityVisible()
onActivityCreated()
onActivityStarted()
onActivityResumed()
onActivityPaused()
onActivityStopped()
onActivitySaveInstanceState()
onActivityDestroyed()
And Register the callback listener in OnCreate() of application class like :
registerActivityLifecycleCallbacks(this);
Define a Global variable in application class.
private static boolean isActive;
Now change the activity life cycle's overridden method like this:
public static boolean isActivityVisible() {
return isActive;
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
isActive = true;
}
#Override
public void onActivityPaused(Activity activity) {
isActive = false;
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
isActive = false;
}
and you can perform the required operations on the value of isActive variable.
I have a BroadCastReceiver that is listen for incoming short messages. In SmsReceiver I want to start an Activity to process the sms. In many situation the Activity is running while getting message and I don't want to start it again.
In fact I want to see that if that Activity is already running (visible or not killed yet) just take it to front and otherwise start it with new task.
Any idea?
I mixed some ideas from here and other places and finally solved the problem. I write the solution here for other people that may have similar situations:
In amy Activity:
static boolean isRunning = false;
#Override
public void onStart() {
super.onStart();
isRunning = true;
}
public void onStop() {
isRunning = false;
super.onStop();
}
public static boolean isRuuning() {
return isRunning;
}
#Override
public void onCreate(Bundle savedInstanceState) {
smsReceiver = new SmsReceiver();
smsReceiver.setActivity(this);
// ...
}
Inside my SmsReceiver:
static MyActivity myActivity;
public void setActivity(MyActivity MyActivity) {
SmsReceiver.myActivity = myActivity;
}
if( MyActivity.isRuuning() ) {
SmsReceiver.myActivity.receiveNewMessage(smsBody);
} else {
// Create an intent and start it
}
This works fine for me.