I'm building a prototype application of a larger system. This prototype will be offline but still look like it's getting information from a server. Even when the app is not open (using DeamonThread).
So I created the Android application and now trying to add an AI (within the app) that create and delete tasks. It works, but when I try to add Notifications from the DeamonThread it won't since Thread is not an Activity.
I tried to change it to
extends Activity implements Runnable
But then it's not possible to make it Deamon.
Feels like I'm missing something easy..
public void run() {
while (counter < 100) {
try {
sleep(random.nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
Task task = new Task("AI", "this was the " + counter
+ " AI message", flow);
sendNotation();
}
counter++;
}
}
private void sendNotation() {
NotificationManager nm=(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(this, Flippin.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
String body = "This is a message from Adam";
String title = "One new Task";
NotificationCompat.Builder n = new NotificationCompat.Builder(this);
n.setContentIntent(pi);
n.setSmallIcon(R.drawable.notif);
n.setContentTitle(title);
n.setContentText(body);
n.setDefaults(Notification.DEFAULT_ALL);
n.setAutoCancel(true);
nm.notify(uniqueID, n.build());
finish();
}
If you want to start a daemon, then you should look at Service
There are many tutorials out there for sending notification from Service.
And yes, it is possible to send notification from non-UI thread, using Handler.
This is the solution I was looking for, only thing I needed was to get access to the context (my application). NOTE I do believe this is a bad design, but since this is used only for a prototype I'll see it as perfect.
In Android Manifest file declare following
<application android:name="com.example.MyApplication">
</application>
then write the class
public class MyApplication extends Application{
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
Now every where call MyApplication.getAppContext() to get your application context statically.
private void sentNotation() {
NotificationManager nm = (NotificationManager) MyApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(MyApplication.getAppContext(), Flippin.class);
PendingIntent pi = PendingIntent.getActivity(MyApplication.getAppContext(), 0, intent, 0);
String body = "This is a message from Adam";
String title = "One new Task";
NotificationCompat.Builder n = new NotificationCompat.Builder(MyApplication.getAppContext());
n.setContentIntent(pi);
n.setSmallIcon(R.drawable.notif);
n.setContentTitle(title);
n.setContentText(body);
n.setDefaults(Notification.DEFAULT_ALL);
n.setAutoCancel(true);
nm.notify(uniqueId, n.build());
finish();
}
Related
I'm using an IntentService to saveData to a SQLDatabase & upload data to Parse. The IntentService works fine if I keep the app running. It also executes propery if I minimise it(by pressing the home button).
But if I press the navigation button and destory the app(the thing where the app screen scales down and you swipe it off); then the IntentService stops running(it doesnt even call onDestory).
What I want is to have the service execute all the tasks; and destory itself. Hence, START_STICKY (Intent) is not required as I dont want it to run continuously in the background.
Starting IntentService
Intent intent_publishService = new Intent(getApplicationContext(), PublishService.class);
Bundle basket_storyData = new Bundle();
basket_storyData.putAll( packStoryData() );
intent_publishService.putExtra(KEY_BASKET_STORY_DATA, basket_storyData);
intent_publishService.putParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA, (ArrayList<? extends Parcelable>) final_image_data);
startService(intent_publishService);
PublishService.class (Snippet)
#Override
protected void onHandleIntent(Intent intent)
{
Log.i(TAG, "ONHANDLEINTENT" );
context = getApplicationContext();
final String KEY_BASKET_IMAGE_DATA = "key_basket_image_data";
final String KEY_BASKET_STORY_DATA = "key_basket_story_data";
final String KEY_BASKET_EXTRA = "key_basket_extra";
ArrayList<ImagesData> _iDataSave = new ArrayList<ImagesData>();
_iDataSave.addAll( (Collection<? extends ImagesData>) intent.getParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA) );
Log.i(TAG, "_iDataSize:" + Integer.toString(_iDataSave.size()) );
//Get Bundle Values
Bundle storyBundle = intent.getBundleExtra(KEY_BASKET_STORY_DATA);
publishStory(storyBundle, _iDataSave);
}
Edit1: Manifest Declaration
<service android:name="com.example.create.main.PublishService" />
SOLVED
You will need START_STICKY in this case to indicate to android that you wish to try to continue to do work after the app is killed.
When the user swipes away from the app chooser, that will kill the app process unconditionally. You can't prevent that from happening - it is intended to give the user control over what is running at that very moment.
Here's what needs to be done:
1) Change IntentService >> Service
2) Move all the code to onStartCommand
3) Using a separate thread so that everything is done off the UI-Thread
4) Declaring it as a separate process in the Manifest
PublishService.class (Snippet)
#Override
public int onStartCommand(final Intent intent, int flags, int startId)
{
Log.i(TAG, "ONSTARTCOMMAND" );
Intent notificationIntent = new Intent(this, MyFriendList_Activity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification.Builder builder = new Notification.Builder(getApplicationContext());
builder.setAutoCancel(false);
builder.setTicker("this is ticker text");
builder.setContentTitle("WhatsApp Notification");
builder.setContentText("You have a new message");
builder.setSmallIcon(R.drawable.ic_launcher);
//builder.setContentIntent(pendingIntent);
builder.setOngoing(true);
builder.setNumber(100);
// Sets the progress indicator to a max value, the current completion
// percentage, and "determinate" state
builder.setProgress(0, 0, true);
Notification notificationFinal = builder.getNotification();
startForeground(ONGOING_NOTIFICATION_ID, notificationFinal );
Runnable r = new Runnable()
{
public void run()
{
context = getApplicationContext();
final String KEY_BASKET_IMAGE_DATA = "key_basket_image_data";
final String KEY_BASKET_STORY_DATA = "key_basket_story_data";
final String KEY_BASKET_EXTRA = "key_basket_extra";
ArrayList<ImagesData> _iDataSave = new ArrayList<ImagesData>();
_iDataSave.addAll( (Collection<? extends ImagesData>) intent.getParcelableArrayListExtra(KEY_BASKET_IMAGE_DATA) );
Log.i(TAG, "_iDataSize:" + Integer.toString(_iDataSave.size()) );
//Get Bundle Values
Bundle storyBundle = intent.getBundleExtra(KEY_BASKET_STORY_DATA);
publishStory(storyBundle, _iDataSave);
}
};
Thread t = new Thread(r);
t.start();
//return START_STICKY;
//return START_REDELIVER_INTENT;
//return START_CONTINUATION_MASK;
return START_NOT_STICKY;
}
Manifest Declaration
<service
android:name="com.example.create.main.PublishService"
android:process=".publishservice" />
Concern
startForeground() + separate Process + running on a separate Thread
--- maybe all 3-are not required?
Edit 1: Also; you could skip all the foreground stuff; and return START_CONTINUATION_MASK ; but thats not recommended as every device has a different way of handling that return type
Hello guys i am building an app in which i would like to add subscription. That means that every user has to pay monthly.
So i want to check if the user has paid he will be able to proceed with the orders if he didn't then i want a dialog to redirect him to pay. What would you suggest me to use Service, BroadcastReceiver or AlarmaManager?
I was thinking of creating a Service and within it create an AsyncTask that will check to the database if the user has paid and then if not inform the user with a dialog. Also i was thinking of creating Notiofications to the user that the subscription ending.
What is your opinion???
I developed a similar function to check many bills. I combined the three methods to ensure stability. But I think you should use Google Play In-app Billing to achieve subscriptions instead of using a local database. If you must use a database to subscribe:
1.After users subscribe, saved info to the database and start a service. the service start a thread,the thread get Data and Analyzing user payments. then use AlarmManager to set Notification and stopSelf.
public class NotificationService extends Service {
...
private AlarmManager am;
private PendingIntent pi;
private NotificationManager mNM;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Thread thread = new Thread(null, mTask, "AlarmService_Service");
thr.start();
return START_REDELIVER_INTENT;
}
Runnable mTask = new Runnable() {
public void run() {
List<Subscription> mDataList = getData;
if (mDataList.size() > 0) {
for (Subscription mSubscription : mDataList) {
if (mSubscription.isSub == true) {
Intent intent = new Intent(NotificationService.this,
AlamrReceiver.class);
intent.putExtra("data", (Serializable)mSubscription);
intent.setData(Uri.parse("custom://" + uniqueCode));
intent.setAction(String.valueOf(uniqueCode));
am = (AlarmManager) getSystemService(ALARM_SERVICE);
pi = PendingIntent.getBroadcast(
NotificationService.this, uniqueCode, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
am.set(AlarmManager.RTC_WAKEUP, reminderTime, pi);
uniqueCode = uniqueCode + 1;
}
}
}
NotificationService.this.stopSelf();
}
};
}
2.Receive broadcast information and show Notification.
public class AlamrReceiver extends BroadcastReceiver {
private NotificationManager mNM;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
mNM = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
Subscription mSubscription = intent.getSerializableExtra("data");
if (mSubscription != null) {
showNotification(context, mSubscription);
}
}
private void showNotification(Context context, Subscription mSubscription) {
...
NotificationCompat.Builder builder = new NotificationCompat.Builder(
context);
builder.setContentTitle(text);
builder.setContentText(subTitleString + currencyString);
builder.setSmallIcon(Common.CATEGORY_ICON[cIcon]);
builder.setDefaults(Notification.DEFAULT_VIBRATE);
builder.setAutoCancel(true);
Intent intent = new Intent(context, BillDetailsActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(BillDetailsActivity.class);
intent.putExtra("dataMap", (Serializable) tMap);
stackBuilder.addNextIntent(intent);
PendingIntent contentIntent = stackBuilder.getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
int uniqueRequestCode = (int) System.currentTimeMillis();
mNM.notify(uniqueRequestCode, builder.build());
}
}
Do not forget BOOT_COMPLETED , when the phone restarted , start the service and check the database
I am not sure of concept of your app, but if you want to check whether user has subscribed for current month or not, you don't need to run a Service for that.
You should check this in Splash Screen or Main Activity of your app. But anyways,
if you still need to do this, i suggest to go with Service or AlarmManager.
BroadcastReceiver won't work alone, you need to trigger them on particular events according to your need.
Also if you use service, please keep in mind that Android MIGHT kill your service in low memory kind of situation.
So i'll suggest that you should go with AlarmManager, which will check for subscription status after specific time or something.
PS : i know this should be addded as comment, but i don't have enough reputations to comment so posted as answer
I'd like to make an notification which start to count time when user exited android application. If user do not executed application after 1hours, It notified me to execute and If user ignoring it, It executes saved SMS messages. I found some examples on timer, but I do not know how to find application exit time. Please give me some advice with full code. I am desperately need it...
TimerTask task = new TimerTask(){
public void run() {
try {
mainTime++;
int min = mainTime / 60;
int sec = mainTime % 60;
String strTime = String.format("%s : %s", min, sec);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Timer mTimer = new Timer();
mTimer.schedule(task, 0, 60000);
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.putExtra("Chack your app", smsBody);
sendIntent.putExtra("12345678", phonenumber);
sendIntent.setType("vnd.android-dir/mms-sms");
startActivity(sendIntent);
Okay so what you need to do is to store the system time locally (may be using SharedPreferences) when the application exits. You can register a BroadcastReceiver which will help you trigger some action when 1hr or a certain time has passed from the locally stored time when app exited.
If you want to know how to handle programmatically when and how to exit the app , please refer this answer.
You could also try to use the Android alarm system. Once the user exit your application, you could set up an Alarm. Something like:
YourActivityOrFragment.java
#Override
protected void onStop() {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis());
c.add(Calendar.HOUR,1);
scheduleAlarm(c.getTimeInMillis());
}
private void scheduleAlarm(long time) {
Intent yourIntent = new Intent("Some_ID");
PendingIntent pi = PendingIntent.getBroadcast(YourClass.this, ALARM_ID, yourIntent, PendingIntent.FLAG_CANCEL_CURRENT);
// Put some extras here, if you need so. Like:
// yourIntent.putExtra("field","value");
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,time,pi);
}
Now, create a BroadcastReceiver to handle those alarms.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String LOG_TAG = AlarmReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "Alarm fired!");
Intent it = new Intent(context, YourNotificationHandler.class);
// Get your Extras here. And do whatever you want, if you need.
// For what you said, there's no need to start an Activity, so let's handle that alarm as a service.
context.startService(it);
// But if for some reason you want to start an Activity, just do it like:
// context.startActivity(it);
}
}
On your AndroidManifest.xml declare your BroadcastReceiver.
<receiver android:name=".AlarmReceiver" >
<intent-filter>
<action android:name="Some_ID" />
<category android:name="android.intent.category.default" />
</intent-filter>
</receiver>
And last of all, create your service to handle your notifications, you could try something like an IntentService. On that file, you'll have a onHandleIntent(Intent intent) method. Get your Intent there, and it's Extras, and do whatever you want to do. Later, just call your Notifications. I've used a utility class on my projects to handle those, but feel free to choose how you'll do that.
Example:
public static void createService(Context context, CharSequence tickerMessage, CharSequence title,
CharSequence message, int icon, int id, Intent intent, long[] pattern, Boolean autoCancel) {
PendingIntent p = PendingIntent.getService(context, 0, intent, 0);
Notification n;
int apiLevel = Build.VERSION.SDK_INT;
if (apiLevel >= 11) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setTicker(tickerMessage)
.setContentText(message)
.setSmallIcon(icon)
.setContentIntent(p)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
if (pattern.length > 0) {
builder.setVibrate(pattern);
}
if (autoCancel != null) {
builder.setAutoCancel(autoCancel);
}
if (apiLevel >= 17) {
// Android 4.2+
n = builder.build();
}
else {
// Android 3.x
n = builder.getNotification();
}
}
else {
// Android 2.2+
n = new Notification(icon, tickerMessage, System.currentTimeMillis());
// Data
n.setLatestEventInfo(context, title, message, p);
}
NotificationManager nm = (NotificationManager)
context.getSystemService(Activity.NOTIFICATION_SERVICE);
nm.notify(id, n);
}
You can read more about alarms here.
More on Service here.
BroadcastReceiver here.
Notifications, here and here.
And this might be an interesting read about Notification as well.
Currently I am working on GCM (Google Cloud message), it allow user to push the message to user device. And I would like achieve the following requirement :
if the user has already enter app , ignore it
if the user has not enter the app , click on notification to enter the app
And the work flow of my app is:
WelcomePage (download json and create data set from it) => MainPage (Display base on the data set)
The code to handle notification
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
String notifyMsg = "";
JSONTokener tokener = new JSONTokener(msg);
if (tokener != null) {
try {
notifyMsg = new JSONObject(tokener).getString("msg");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Intent myintent = new Intent(this, WelcomePageActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
The problem is if I use WelcomePageActivity class , it will create a new activity if I am at the main page, how can I adjust the code to fit my requirement ?
Thanks
For
1. if the user has already enter app , ignore it:
in the onReceive() , check if your app is running, do not notify.
It can be checked with something like:
ActivityManager activityManager =(ActivityManager)gpsService.this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList= activityManager.getRunningServices(Integer.MAX_VALUE);
if((serviceList.size() > 0)) {
boolean found = false;
for(int i = 0; i < serviceList.size(); i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName serviceName = serviceInfo.service;
if(serviceName.getClassName().equals("Packagename.ActivityOrServiceName")) {
//Your service or activity is running
break;
}
}
if the user has not enter the app , click on notification to enter the app
from the code above, you'l know if you would like to resume the app or launch - call Splash Screen or in your case WelcomeActivity.
About the workflow of your app, i'd suggest check whether you need to download the data every time or not. Can save it maybe or update/download only when required, and rest of flow works as it is.
In your AndroidManifest.xml, define your WelcomePageActivity with the flag android:launchMode="singleTop". From the definition of this flag:
A new instance of a "singleTop" activity may also be created to handle
a new intent. However, if the target task already has an existing
instance of the activity at the top of its stack, that instance will
receive the new intent (in an onNewIntent() call); a new instance is
not created.
So with this flag, your activity will not be created again, rather it will receive a call in the onNewIntent() function with the Intent you used to create the PendingIntent for the notification. You could override this function, and use the intent to pass the activity new information.
You will not able to receive any notification click event so,
try this code :
Intent myintent = new Intent(this, TestActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
public class TestActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// check for your app state is running or not
if(appRunning == false) {
// start your WelcomePage activity.
}
}
}
1.Create an object in GcmIntentService
public static final Object CURRENTACTIVIYLOCK = new Object();
//for storing current activity
public static Activity currentActivity;
2.Update this object value in onPause and onResume of MainActivity to recognize Activity is running or not.
#Override
public void onResume() {
super.onResume();
System.out.println("onResume Home page");
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = this;
}
}
#Override
public void onPause() {
super.onPause();
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = null;
}
}
3.In GcmIntentService class, check for the current activity in onHandleIntent method.
synchronized (CURRENTACTIVIYLOCK) {
if (currentActivity != null) {
if (currentActivity.getClass() == HomePageActivity.class) {
} else {
sendNotification(extras.getString("message"));
}
} else {
sendNotification(extras.getString("message"));
}
I'm sure this will help you.
I am trying to display a notification in the Android notifications bar even if my application is closed.
I've tried searching, but I have had no luck finding help.
An example of this is a news application. Even if the phone screen is off or the news application is closed, it can still send a notification for recent news and have it appear in the notification bar.
How might I go about doing this in my own application?
You have to build a Service that handles your news and shows notifications when it knows that are new news (Service Doc).
The service will run in background even if your application is closed.
You need a BroadcastReciever to run the service in background after the boot phase is completed. (Start service after boot).
The service will build your notifications and send them through the NotificationManager.
EDIT: This article may suit your needs
The selected answer is still correct, but only for devices running Android 7 versions and below.
As of Android 8+, you can no longer have a service running in the background while your app is idle/closed.
So, it now depends on how you set up your notifications from your GCM/FCM server. Ensure to set it to the highest priority. If your app is in the background or just not active and you only send notification data, the system process your notification and send it to the Notification tray.
I used this answer to write a service, and as an exmaple you need to call ShowNotificationIntentService.startActionShow(getApplicationContext()) inside one of your activities:
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
public class ShowNotificationIntentService extends IntentService {
private static final String ACTION_SHOW_NOTIFICATION = "my.app.service.action.show";
private static final String ACTION_HIDE_NOTIFICATION = "my.app.service.action.hide";
public ShowNotificationIntentService() {
super("ShowNotificationIntentService");
}
public static void startActionShow(Context context) {
Intent intent = new Intent(context, ShowNotificationIntentService.class);
intent.setAction(ACTION_SHOW_NOTIFICATION);
context.startService(intent);
}
public static void startActionHide(Context context) {
Intent intent = new Intent(context, ShowNotificationIntentService.class);
intent.setAction(ACTION_HIDE_NOTIFICATION);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_SHOW_NOTIFICATION.equals(action)) {
handleActionShow();
} else if (ACTION_HIDE_NOTIFICATION.equals(action)) {
handleActionHide();
}
}
}
private void handleActionShow() {
showStatusBarIcon(ShowNotificationIntentService.this);
}
private void handleActionHide() {
hideStatusBarIcon(ShowNotificationIntentService.this);
}
public static void showStatusBarIcon(Context ctx) {
Context context = ctx;
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx)
.setContentTitle(ctx.getString(R.string.notification_message))
.setSmallIcon(R.drawable.ic_notification_icon)
.setOngoing(true);
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, STATUS_ICON_REQUEST_CODE, intent, 0);
builder.setContentIntent(pIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = builder.build();
notif.flags |= Notification.FLAG_ONGOING_EVENT;
mNotificationManager.notify(STATUS_ICON_REQUEST_CODE, notif);
}
}