I have developed a widget which will fetch the data from a server and do some modifications and display in widget.
I have a ALARM manager which starts a service in every 10 sec and service fetches data with async task and display.
It consumes a lot of CPU usage.
Kindly help if I can change the code design and make the widget more effective.
I use Jsoup to connect and fetch data.
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Log.d("Widget : " , "Inside onUpdate widget");
// To prevent any ANR timeouts, we perform the update in a service
final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final Calendar TIME = Calendar.getInstance();
TIME.set(Calendar.MINUTE, 0);
TIME.set(Calendar.SECOND, 0);
TIME.set(Calendar.MILLISECOND, 0);
final Intent i = new Intent(context, UpdateService.class);
if (service == null)
{
service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
}
m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), 100 * 60, service);
}
public static class UpdateService extends Service {
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// System.out.println("Inside config change ");
enableControls(this);
}
#Override
public void onStart(Intent intent, int startId) {
// Build the widget update for today
mContext = this;
Log.d("Widget : " , "Service started");
enableControls(this);
}
public static void enableControls(Context context){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_status);
Intent active = new Intent(context, MyWidgetProvider.class);
active.setAction(ACTION_WIDGET_REFRESH);
active.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
pushWidgetUpdate(context, remoteViews);
fetchStatus();
}
public static void fetchStatus(){
new AsyncTask<String, Void, String>() {
#Override
protected String doInBackground(String... urls) {
try {
if(getWiFiStatus(mContext) == true ){
boolean getRedirectedURL = false;
String url,finalURL;
finalURL = "http://mobile.server.status";
Document doc = Jsoup.connect(finalURL).get();
while(getRedirectedURL == false){
Log.d(LOG_TAG,"inside while loop ---- : " + getRedirectedURL);
doc = Jsoup.connect(finalURL).get();
Log.d(LOG_TAG,"Complete doc: " + doc);
// System.out.println("Found the doc : " +doc.toString().contains("status"));
// Log.d(LOG_TAG,"Whole data third :"+doc);
// System.out.println("Printing redirected URL " + (docHead.select("meta")));
if(doc.toString().contains("status")){
getRedirectedURL = true;
break;
}
else
getRedirectedURL = false;
Elements docHead = doc.select("meta");
for(Element emt :docHead) {
url =null;
//Log.d(LOG_TAG,"Value boolean :"+emt.getElementsByAttribute("http-equiv").toString().toLowerCase().contains("url"));
if(emt.getElementsByAttribute("http-equiv").toString().toLowerCase().contains("url") ){
//getRedirectedURL = true;
url = emt.getElementsByAttribute("http-equiv").toString().toLowerCase().split("url=")[1].toString();
if (emt.getElementsByAttribute("http-equiv").toString().toLowerCase().contains("http://")){
finalURL = null;
finalURL = url.split("\"")[0].toString();
}
else
finalURL = finalURL + url.split("\"")[0].toString();
//Log.d(LOG_TAG,"Final URL :"+finalURL);
}
// else
// getRedirectedURL = false;
}
}
Log.d(LOG_TAG,"Final URL :"+finalURL);
doc = Jsoup.connect(finalURL).get();
Document noFramesDoc = Jsoup.parseBodyFragment(doc.toString());
}
else{
refreshStatus(mContext);
}
} catch (UnknownHostException exception){
System.out.println("Inside unknown host : ");
}
catch (Exception e) {
Log.d(LOG_TAG,"other Exception found :"+e.toString());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
if(mContext != null)
}
#Override
protected void onCancelled() {
}
}.execute();
}
Related
I am downloading multiple files one after the other in service. I want to update download progress in notification. But my notification doesn't update when I kill my app. Download works on different thread. Download works fine in when app is running. When I kill app from recent section, I am unable to update notification.
Here is my DownloadService class
public class DownloadService extends Service {
public static DownloadMap<String, Downloadables> map = new DownloadMap<String, Downloadables>();
private static Thread thread;
private DownloadCancelReceiver receiver;
public DownloadService() {
}
public class BackgroundThread extends Thread {
int serviceId;
private DownloadMap<String, Downloadables> map;
private SpeedRevisionDatabase helper;
private final int notificationId = 1;
private RemoteViews remoteViewsSmall, remoteViewsBig;
private NotificationManagerCompat notificationManager;
private NotificationCompat.Builder mBuilder, mBuilderComplete, downloadFailBuilder;
public BackgroundThread(int serviceId, DownloadMap<String, Downloadables> map) {
this.serviceId = serviceId;
this.map = new DownloadMap<>();
this.map.putAll(map);
}
#Override
public void run() {
remoteViewsSmall = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification_small);
remoteViewsBig = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification);
Intent cancelDownload = new Intent("CANCEL_DOWNLOAD");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, cancelDownload, 0);
remoteViewsBig.setOnClickPendingIntent(R.id.tvCancel, pendingIntent);
notificationManager = NotificationManagerCompat.from(DownloadService.this);
mBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
mBuilder.setContentTitle("Download is in progress")
.setContentText("Please wait...")
.setSmallIcon(R.mipmap.download)
.setOngoing(true)
.setCustomContentView(remoteViewsSmall)
.setCustomBigContentView(remoteViewsBig)
.setPriority(NotificationCompat.PRIORITY_HIGH);
notificationManager.notify(notificationId, mBuilder.build());
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
try {
String path = getApplicationContext().getApplicationInfo().dataDir + "/" + "UEP";
File uepFolder = new File(path);
if (!uepFolder.exists()) {
uepFolder.mkdir();
}
int i = 0;
while (map.entrySet().iterator().hasNext()) {
Log.e("WhileCheck", "Now i is " + i);
Map.Entry data = (Map.Entry) map.entrySet().iterator().next();
try {
Downloadables download = (Downloadables) data.getValue();
if (NetworkUtil.getConnectivityStatus(getApplicationContext()) == 0) {
throw new InternetDisconnectedException("Internet Disconnected");
}
HttpURLConnection urlConnection;
InputStream inputStream;
//finding file on internet
try {
URL url = new URL(download.URL);
if (url.toString().endsWith(".xps")) {
url = new URL(url.toString().replace(".xps", ".pdf"));
}
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
inputStream = urlConnection.getInputStream();
} catch (IOException e) {
Log.e("IOException", "" + e.getMessage());
i++;
map.remove(data.getKey());
notificationManager.notify(notificationId, mBuilder.build());
continue;
}
//Downloading file over internet
File file = new File(uepFolder + "/" + download.FileName + "" + download.Format + ".download");
try {
int fileSize = urlConnection.getContentLength();
FileOutputStream fileOutput = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int bufferLength = 0;
int count = 0;
int previousProgress = 0;
while ((bufferLength = inputStream.read(buffer)) > 0) {
if (this.isInterrupted()) {
throw new InterruptedException("Thread has been kill (Destroyed)");
}
fileOutput.write(buffer, 0, bufferLength);
count += bufferLength;
int progress = (int) (count * 100L / (float) fileSize);
if (previousProgress > 999) {
updateProgress(map.insertedCount, i, progress, download.Name);
notificationManager.notify(notificationId, mBuilder.build());
previousProgress = 0;
}
previousProgress++;
}
fileOutput.close();
} catch (IOException e) {
Log.e("IOException", "" + e.getMessage());
i++;
map.remove(data.getKey());
continue;
}
File actualFile = new File(uepFolder + "/" + download.FileName + "" + download.Format);
file.renameTo(actualFile);
Log.e("Downloaded",""+actualFile.getAbsoluteFile());
} catch (InterruptedException | InternetDisconnectedException e) {
throw e;
}
i++;
map.remove(data.getKey());
Log.e("Downloaded", "Remaining files are "+map.size());
}
Log.e("WhileCheck", "While End");
// Due to thread, sometime the sequence of code flow is not in correct flow, and "Download complete" Notifaction is getting shown
// Hence this check is required.
if (this.isInterrupted()) {
throw new InterruptedException("Thread has been kill (Destroyed)");
}
notificationManager.cancel(notificationId);
mBuilderComplete = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
mBuilderComplete.setOngoing(false)
.setContentTitle("Download Complete")
.setColor(Color.WHITE)
.setSmallIcon(R.drawable.download);
notificationManager.notify(2, mBuilderComplete.build());
Log.e("DownloadingService", "File downloaded successfully");
stopSelf();
map.insertedCount = 0;
} catch (InterruptedException e) {
closeNotification();
Log.e("InterruptedException", "" + e.getMessage());
} catch (InternetDisconnectedException e) {
stopSelf();
closeNotification();
showNotification("Internet disconnected", "Download failed. Try again later.");
Log.e("InternetDisconnect", "" + e.getMessage());
}
}
private void updateProgress(int totalFiles, int currentFileCount, int currentProgress, String fileName) {
remoteViewsSmall.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
remoteViewsSmall.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);
remoteViewsBig.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
remoteViewsBig.setTextViewText(R.id.tvFileName, "Downloading " + fileName);
remoteViewsBig.setTextViewText(R.id.tvCurrentProgress, currentProgress + "%");
remoteViewsBig.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);
remoteViewsBig.setProgressBar(R.id.currentProgress, 100, currentProgress, false);
}
public void closeNotification() {
if (notificationManager != null)
notificationManager.cancel(notificationId);
}
public void showNotification(String title, String message) {
downloadFailBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
downloadFailBuilder.setOngoing(false)
.setContentTitle(title)
.setContentText(message)
.setColor(Color.WHITE)
.setSmallIcon(android.R.drawable.stat_sys_warning);
notificationManager.notify(3, downloadFailBuilder.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
ArrayList<Downloadables> list = (ArrayList<Downloadables>) intent.getSerializableExtra("downloadList");
for (Downloadables d : list) {
String key = d.Name + "" + d.FileName;
map.put(key, d);
}
if (thread == null || !thread.isAlive()) {
thread = new BackgroundThread(startId, map);
receiver = new DownloadCancelReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter.addAction("CANCEL_DOWNLOAD");
registerReceiver(receiver, intentFilter);
thread.start();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.e("Service", " Stop");
try {
thread.interrupt();
} catch (Exception e) {
Log.e("Exception", "" + e.getMessage());
}
map.clear();
unregisterReceiver(receiver);
//closeNotification();
}
public static class DownloadCancelReceiver extends BroadcastReceiver {
public DownloadCancelReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equalsIgnoreCase("CANCEL_DOWNLOAD")) {
Intent intent1 = new Intent(context, DownloadService.class);
context.stopService(intent1);
}
}
}
public void initChannels(Context context) {
if (Build.VERSION.SDK_INT < 26) {
return;
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("default", "Channel name", NotificationManager.IMPORTANCE_LOW);
channel.setDescription("Channel description");
channel.setImportance(NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
notificationManager.createNotificationChannel(channel);
}
private class InternetDisconnectedException extends Exception {
public InternetDisconnectedException(String message) {
super(message);
}
}
public static class DownloadMap<String, Downloadables> extends HashMap<String, Downloadables> {
public int insertedCount;
#Override
public Downloadables put(String key, Downloadables value) {
insertedCount++;
return super.put(key, value);
}
}
}
And From activity I start service like this.
ArrayList<Downloadables> list = helper.GetVideoFileList();
Intent intent1 = new Intent(SRDownloadActivity.this, DownloadService.class);
intent1.putExtra("downloadList", list);
startService(intent1);
I can even Add files to HashMap while downloading is in progress. It also worked fine.
I am unable to figure it out why it is not running in background since it is on different thread.
Here is my notification look like
Threads are killed by the Android OS even if the main app is still working and they dont have access to the UI thats why u should use AsyncTask class its a like a thread that works in background but it has access to the UI of the main. And the jobdispatcher class can help u assign jobs in the background
Here is a good tutorial https://youtu.be/das7FmQIGik
Application is working with in Kitkat version. After lollipop version application is not working properly. I am thinking problem with getRunningTasks() . Could you please give me guidance ,How to overcome this problem.
public class StartupServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Log.d("Detector", "Auto Start" + AppLockerPreference.getInstance(context).isAutoStart());
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
if (AppLockerPreference.getInstance(context).isAutoStart()){
if (AppLockerPreference.getInstance(context).isServiceEnabled()){
context.startService(new Intent(context, DetectorService.class));
}else{
AppLockerPreference.getInstance(context).saveServiceEnabled(false);
}
}
return;
}else if (AppLockerPreference.getInstance(context).isServiceEnabled()){
Toast.makeText(context, "App------>6", Toast.LENGTH_SHORT).show();
context.startService(new Intent(context, DetectorService.class));
}
}
}
DetectorService
public class DetectorService extends Service {
//public static final String ACTION_DETECTOR_SERVICE = "com.gueei.detector.service";
#Override
public IBinder onBind(Intent intent) {
return null;
}
private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
}
return;
}
// Fall back on the old API.
stopForeground(true);
mNM.notify(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
}
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
stopForeground(false);
}
#Override
public void onCreate() {
//debug: log.i("Detector","Service.Oncreate");
initConstant();
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
}
#Override
public void onDestroy() {
//debug: log.i("Detector","Service.Ondestroy");
mThread.interrupt();
// Make sure our notification is gone.
stopForegroundCompat(R.string.service_running);
}
// This is the old onStart method that will be called on the pre-2.0
// platform. On 2.0 or later we override onStartCommand() so this
// method will not be called.
#Override
public void onStart(Intent intent, int startId) {
//debug: log.i("Detector","Service.Onstart");
handleCommand(intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//debug: log.i("Detector","Service.OnStartCommand");
handleCommand(intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return Service.START_STICKY;
}
private void handleCommand(Intent intent){
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_running);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.statusbar_icon, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, AppLockerActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, text,
text, contentIntent);
startForegroundCompat(R.string.service_running, notification);
startMonitorThread((ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE));
}
private void startMonitorThread(final ActivityManager am){
if (mThread!=null)
mThread.interrupt();
mThread = new MonitorlogThread(new ActivityStartingHandler(this));
mThread.start();
}
private static Thread mThread;
private static boolean constantInited = false;
private static Pattern ActivityNamePattern;
private static String logCatCommand;
private static String ClearlogCatCommand;
private void initConstant() {
//debug: log.i("Detector","Service.OninitConstant");
if (constantInited) return;
String pattern = getResources().getString(R.string.activity_name_pattern);
//debug: log.d("Detector", "pattern: " + pattern);
ActivityNamePattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
logCatCommand = getResources().getString(R.string.logcat_command);
ClearlogCatCommand = getResources().getString(R.string.logcat_clear_command);
}
MonitorlogThread
private class MonitorlogThread extends Thread{
ActivityStartingListener mListener;
public MonitorlogThread(ActivityStartingListener listener){
//debug: log.i("Detector","Monitor//debug: logThread");
mListener = listener;
}
BufferedReader br;
private Context context;
#Override
public void run() {
//debug: log.i("Detector","RUN!");
while(!this.isInterrupted() ){
try {
Thread.sleep(100);
////debug: log.i("Detector","try!");
//This is the code I use in my service to identify the current foreground application, its really easy:
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
//Toast.makeText(context, "App------>7", Toast.LENGTH_SHORT).show();
Log.d("Android", "App------>7----"+am);
//RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
Log.d("Android", "App------>8----"+foregroundTaskInfo);
//Toast.makeText(context, "App------>7"+foregroundTaskInfo, Toast.LENGTH_SHORT).show();
//Thats it, then you can easily access details of the foreground app/activity:
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mListener!=null){
//mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskAppName);
mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskActivityName);
}
} catch (InterruptedException e) {
// good practice
Thread.currentThread().interrupt();
return;
}
}
}
}
Use this code for above 5.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
UsageStatsManager usageStatsManager = (UsageStatsManager) ctx.getSystemService("usagestats");
long milliSecs = 60 * 1000;
Date date = new Date();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, date.getTime() - milliSecs, date.getTime());
if (queryUsageStats.size() > 0) {
Log.i(TAG, "UsageStats size: " + queryUsageStats.size());
}
long recentTime = 0;
String recentPkg = "";
for (int i = 0; i < queryUsageStats.size(); i++) {
UsageStats stats = queryUsageStats.get(i);
if (i == 0 && !getPackageName().equals(stats.getPackageName())) {
Log.i(TAG, "PackageName: " + stats.getPackageName() + " " + stats.getLastTimeStamp());
}
if (stats.getLastTimeStamp() > recentTime) {
String recentTime = stats.getLastTimeStamp();
String recentPkg = stats.getPackageName();
}
};
} catch (Exception e) {
e.printStackTrace();
}
}
Can you try this.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
ActivityManager.RunningAppProcessInfo runningAppProcessInfo = (ActivityManager.RunningAppProcessInfo) am.getRunningAppProcesses();
String foregroundTaskPackageName = runningAppProcessInfo.pkgList.getClass().getPackage().getName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = runningAppProcessInfo.pkgList.getClass().getName();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
} else {
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
Use RunningAppProcessInfo instead of getRunningTasks for SDK versions greater than KitKat.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
...
} else {
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
...
}
I'm developing an app which gets GPS Location every ten minutes and sends it to a server, in order to do that I use a Timer, requestLocationUpdates and Android Asynchronous Http Client library. The positions need to be saved for up to 12 hours every ten minutes.
To keep an app alive, I use wakelock in onCreate inside Service
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
and onDestroy()
wl.release();
The service is started and stopped by buttons in MainActivity. My main problem is that I only get the position twice (on start and after 10mins, no position update after 20mins) if user presses Home Button and moves the app to back. It seems to be okay as long as I lock the screen on the app, but the process seems to be killed after few minutes when I lock on Home Screen.
Here is the whole code of my GPS Service:
public class UpdatePositionService extends Service {
private PowerManager.WakeLock wl;
private Handler mHandler = new Handler(Looper.getMainLooper());
private AsyncHttpClient client = new AsyncHttpClient();
private SharedPreferences preferences;
public static final String USER_PREFERENCES = "userPreferences";
private Timer updatingTimer;
private TimerTask task = new TimerTask() {
#Override
public void run() {
mHandler.post(new Runnable() {
public void run() {
preferences = getSharedPreferences(USER_PREFERENCES, MODE_PRIVATE);
final String uid = preferences.getString("userid", "");
final String pause = readFromFile("pause.txt");
final String userState = readFromFile("user.txt");
final String workid = readFromFile("work.txt");
final String consid = readFromFile("cons.txt");
if (!pause.equals("1") && !userState.equals("0")) {
Log.e("mmd:test:123", "dochodzi " + userState);
final LocationManager[] lm = {(LocationManager)
getSystemService(Context.LOCATION_SERVICE)};
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
_if();
lm[0].requestLocationUpdates(LocationManager
.GPS_PROVIDER, 6000, 10, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
String updatedPause = readFromFile("pause.txt");
_if();
lm[0].removeUpdates(this);
lm[0] = null;
if (!updatedPause.equals("1")) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("lat", location.getLatitude());
params.put("long", location.getLongitude());
params.put("workid", workid);
params.put("type", userState);
params.put("cons", consid);
String url = "http://example.com/api/event/add";
client.post(url, params,
new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode,
Header[] headers, byte[] responseBody) {
String response = new String(
responseBody);
if (!response.equals("ERROR")) {
} else {
}
}
#Override
public void onFailure(
int statusCode, Header[] headers,
byte[] responseBody,
Throwable error) {}
});
}
}
#Override
public void onStatusChanged(String provider, int
status, Bundle extras) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onProviderDisabled(String provider) {}
});
}
}
});
}
};
private void _if() {
if (ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(UpdatePositionService.this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {}
}
#Override
public void onCreate() {
super.onCreate();
updatingTimer = new Timer();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager
.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
}
#Override
public void onDestroy() {
updatingTimer.cancel();
mHandler.removeCallbacksAndMessages(null);
wl.release();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int time = 1000 * 60 * 10; // 10 mins
updatingTimer.scheduleAtFixedRate(task, 3000, time);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
private String readFromFile(String filename) {
String ret = "";
try {
InputStream inputStream = openFileInput(filename);
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader
(inputStream);
BufferedReader bufferedReader = new BufferedReader
(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
stringBuilder.append(receiveString);
}
inputStream.close();
ret = stringBuilder.toString();
}
} catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return ret;
}
}
To expand #CommonsWare comment. Setting up a service for this is a bad idea - and also does not work as you have seen. Android kills it and the party is over. To do any periodic task you have to setup an alarm using the alarm manager. To do this register an alarm - better in some receiver that is setup to receive on boot - cause when rebooting all your alarms go bye bye:
private void setupAlarm(Context context, boolean setup) {
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
pi = PendingIntent.getBroadcast(context, NOT_USED, yourIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (setup) { // setup the alarms
try {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + SOME_DELAY, THE_INTERVAL_BETWEEN_ALARMS, pi);
} catch (InstantiationException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
} catch (IllegalAccessException e) {
// should not happen
throw new RuntimeException(UNABLE_TO_SET_ALARMS, e);
}
} else { // teardown the alarms
// send message to the monitors that the party is over
Intent i = new Intent(YOUR_ABORTING_ACTION, Uri.EMPTY, context, YOUR_SERVICE_CLASS);
WakefulIntentService.sendWakefulWork(context, i);
// cancel the alarms
am.cancel(pi);
}
d("alarms " + (setup ? "enabled" : "disabled"));
}
Then in the onReceive of the receivers registered to receive the broadcast from the AlarmManager (they hold wakelocks for you that never fail) delegate to a WakefulIntentService
#Override
final public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
final boolean enable = ac_setup_alarm.equals(action);
setupAlarm(context, enable);
} else if (ac_monitor.equals(action)) {
// monitoring - got broadcast from ALARM
WakefulIntentService.sendWakefulWork(context, YOUR_SERVICE_CLASS);
} else if (ac_reschedule_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setAction(ac_monitor.toString());
rescheduleAlarm(context);
} else {
w("Received bogus intent : " + intent);
}
}
Alternatively to use a wakeful intent service you can use a WakefulBroadcastReceiver - but you have to write the service. The (my) code is here - works!
I am trying to run below code it gives exception saying:
java.lang.RuntimeException: Unable to start service com.example.testfeeds.UpdateWidgetService#410a33c8 with Intent { cmp=com.example.testfeeds/.UpdateWidgetService (has extras) }: android.os.NetworkOnMainThreadException
which i understand that new version of Android won't allow network operations in main thread. People suggested me to use Async Task
but I don't know how to use that. Can someone show me in below code?
Thanks in advance
public class WidgetService extends Service {
/*
* So pretty simple just defining the Adapter of the listview
* here Adapter is ListProvider
* */
/*#Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
return (new ListProvider(this.getApplicationContext(), intent));
}*/
public static int numberOfItems=0;
//numberOfItems=0;
private static String LOG = "testwidgets";
ArrayList<String> feedsPubDate;
#SuppressWarnings("deprecation")
#Override
public void onStart(Intent intent, int startId) {
Log.i(LOG, "Called");
// Create some random data
feedsPubDate=new ArrayList<String>();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this .getApplicationContext());
int[] allWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
ComponentName thisWidget = new ComponentName(getApplicationContext(), WidgetProvider.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
for (int widgetId : allWidgetIds) {
// Create some random data
///////////////////////////////////////////////////////////////////////////
RemoteViews remoteViews = new RemoteViews(this.getApplicationContext().getPackageName(),
R.layout.widget_layout);
Log.d("numberOfItems intially", String.valueOf(numberOfItems));
try {
numberOfItems=doTestFeed();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Set the text
remoteViews.setTextColor(R.id.empty_view,Color.WHITE);
remoteViews.setTextViewText(R.id.empty_view," "+ String.valueOf(numberOfItems));
Log.w(LOG, String.valueOf(numberOfItems));
////////////////////////////////////////////////////////////////////////////
// Register an onClickListener
Intent clickIntent = new Intent(this.getApplicationContext(),
WidgetProvider.class);
clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
allWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.empty_view, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
int doTestFeed() throws MalformedURLException, ParseException
{
Log.d("msg"," in do test feed");
InputStream is = null;
int x = 0;
URL myURL = new URL("http://yunn.yu.edu.jo/index.php?option=com_content&view=category&id=55&layout=blog&Itemid=104&format=feed&type=rss");
try {
URLConnection conn = myURL.openConnection();
is = conn.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
XmlPullParserFactory pullParserFactory;
try {
pullParserFactory = XmlPullParserFactory.newInstance();
XmlPullParser parser = pullParserFactory.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
Log.d("msg","before making parsing");
x=parseXML(parser);
Log.d("msg","after making parsing");
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.d("msg"," done testing");
return x;
}
//////////////////////////////////////////////////////////////////////////////////
#SuppressLint("SimpleDateFormat")
private int parseXML(XmlPullParser parser) throws XmlPullParserException,IOException, ParseException
{
Log.d("msg"," in parser");
int eventType = parser.getEventType();
int getElement=0;
String pubDate=null;
while (eventType != XmlPullParser.END_DOCUMENT){
String tagName = null;
switch (eventType){
//----------------------------------//
case XmlPullParser.START_DOCUMENT:
{
// do nothing
}
break;
//----------------------------------//
case XmlPullParser.START_TAG:
{ tagName = parser.getName();
if ("item".equals(tagName)){
getElement=1;
} else if (getElement!=0){
if ("pubDate".equals(tagName)){
pubDate= parser.nextText();
feedsPubDate.add(pubDate);
Log.d("value",pubDate);
}
}
}
break;
//----------------------------------//
case XmlPullParser.END_TAG:
{ tagName = parser.getName();
if (tagName.equalsIgnoreCase("item") && getElement != 0){
}
}
break;
//----------------------------------//
}// end-switch.
eventType= parser.next();
}// end-while.
int i=0;
SharedPreferences sp = getSharedPreferences("tempData", 0);
String dateStringA=sp.getString("recentPubDate", null);
Log.d("oldest date",dateStringA);
for(String s : feedsPubDate )
{
String dateStringB = feedsPubDate.get(i);
SimpleDateFormat parserSDF = new SimpleDateFormat("EEE, DD MMM yyyy HH:mm:ss");
Date dateA = null;
try {
dateA = parserSDF.parse(dateStringA);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Date dateB = null;
try {
dateB = parserSDF.parse(dateStringB);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (dateA.compareTo(dateB) < 0) {
Log.d("imp msg","one new item");
numberOfItems++;
}
i++;
}
Log.d("update result", String.valueOf(numberOfItems));
// Toast.makeText(GeneralNews.this,"The size of the list"+feedsTitles.size() , Toast.LENGTH_LONG).show();
return numberOfItems;
} //end xmlParser method.
//////////////////////////////////////////////////////////////////////////////////
}
I think this question might be helpful for you: How to use AsyncTask
You can make your AsyncTask an inner class of your Service, and do your network-operations in the doInBackground() method of AsyncTask. From doInBackground() you can return any kind of data to the onPostExecute() method of AsyncTask, where you can do further stuff with the received data.
And here, an AsyncTask example: AsyncTask Android example
it is about ui thread. I guess Services have some issues with ui thread. onPostExecutes have to be run on ui thread. so, because of Services have not ui thread, it breaks on executing onPostExecute on non-ui thread.
I suggest
new Thread(){
public void run() {
Object result=null;
Looper l = Looper.getMainLooper();
Handler h = new Handler(l);
h.post(new Runnable() {
#Override
public void run() {
if (result != null){
response.OnResponse(true, "", result);
} else {
response.OnResponse(false, errMessage, null);
}
}
});
};
}.start();
of course, this has not Thread pool in AsyncTask, but you can convert this code to use a Thread pool.
A simple example:
public class YourAsyncTask extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... params) {
// your load work
return myString;
}
#Override
protected void onPostExecute(String result) {
}
}
Use new YourAsyncTask ().execute() to call it.
As example:
You have log in Activity and when you press "Login" application need to validate against Service and switch to main Activity:
private class HeavyTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String... args) {
//do something here
// like tell to Service to do some async task
return null;
}
protected void onPostExecute(Void results) {
// here actually we wait any event from Service about task done
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent().setClass(FirstLoginActivity.this, MainActivity.class).setData(getIntent().getData()));
finish();
}
}, 1000);
}
}, 500);
}
}
And this is how I call it:
HeavyTask task = new HeavyTask();
task.execute(user, passwordText, login_outbound_proxy); // as example
Pretty simple example that will help you to sort things out in addition to theory
If API version is 11 or above android:targetSDk does not allow netwrok on main thread But it works in below in HoneyComb.n
Try to remove android:targetSdkVersion line from your manifest.
I did this in 3rd party code and work for me most of time.
It worked for me.
I am writing an app in which i am using two tabs, one to get list of facebook friends and second tab to get list of phonebook friends
And In Phonebook friends tab i am also getting friends birthdays and also showing reminder for that, and i am able to get reminder as well if i will try it alone, without combined to another Tab (i.e.: with Facebook Tab)
It means once i combined it in Tabs, then i am not getting any birthday Notifications.
I am using below class to get Notifications for Phonebook friends birthdays:
public class BirthdayReminder extends ListActivity {
// TODO: call/write message on birthday
// TODO: hideNotificationPref
private final DateFormatSymbols dateSymbols = new DateFormatSymbols();
private Database db;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setFastScrollEnabled(true);
this.db = new Database(getContentResolver());
// debug code
// Debug.logDatabase(this);
// start BirthdayBroadcastReceiver if it is activated
Preferences prefs = Preferences.getInstance(getApplicationContext());
if (prefs.getActivateService()) {
BirthdayBroadcastReceiver.restart(getApplicationContext());
}
}
#Override
protected void onResume() {
super.onResume();
updateView();
}
private void updateView() {
// create new list adapter
MultiListAdapter listAdapter = new MultiListAdapter();
List<ListAdapter> adapterList = listAdapter.getListAdapters();
// load birthday and contact information
List<Contact> contacts = this.db.getAllContacts();
List<BirthContact> birthContacts = BirthContactHelper.createBirthContactList(contacts);
// group all contacts by known and unknown birthday
SortedSet<BirthContact> knownBirthdays = new TreeSet<BirthContact>(new BirthContactBirthdayComparator());
SortedSet<BirthContact> unknownBirthdays = new TreeSet<BirthContact>(new BirthContactNameComparator());
for (BirthContact birthContact : birthContacts) {
DateOfBirth dateOfBirth = birthContact.getDateOfBirth();
if (dateOfBirth != null) {
knownBirthdays.add(birthContact);
} else {
unknownBirthdays.add(birthContact);
}
}
Integer currentMonth = null;
BirthContactAdapter currentBirthContactAdapter = null;
String[] monthStrs = this.dateSymbols.getMonths();
for (BirthContact birthContact : knownBirthdays) {
int month = birthContact.getDateOfBirth().getDate().get(Calendar.MONTH);
if (currentMonth == null || currentMonth != month) {
currentMonth = month;
currentBirthContactAdapter = new BirthContactAdapter(this);
adapterList.add(new CategoryAdapter(this, monthStrs[currentMonth]));
adapterList.add(currentBirthContactAdapter);
}
currentBirthContactAdapter.add(birthContact);
}
adapterList.add(new CategoryAdapter(this, getResources().getString(R.string.unknownBirthdays)));
adapterList.add(new BirthContactAdapter(this, unknownBirthdays));
setListAdapter(listAdapter);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
BirthContact birthContact = (BirthContact) l.getAdapter().getItem(position);
Intent editorIntent = new Intent(this, BirthdayEditor.class);
editorIntent.putExtra(BirthdayEditor.CONTACT_ID, birthContact.getContact().getId());
startActivity(editorIntent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.preferences:
startActivity(new Intent(this, PreferenceWindow.class));
return true;
case R.id.quit:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I am using below code to call two different classes while click on a particular tab.
but whenever i change it to tab, i am not getting any notification, TabSample.java:
public class TabSample extends TabActivity {
String response;
#SuppressWarnings("unused")
private static JSONArray jsonArray;
public static TabHost mTabHost;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bundle extras = getIntent().getExtras();
if (extras == null) {
return;
}
response = getIntent().getStringExtra("FRIENDS");
try {
jsonArray = new JSONArray(response);
} catch (JSONException e) {
FacebookUtility.displayMessageBox(this,
this.getString(R.string.json_failed));
}
setTabs();
}
private void setTabs() {
addTab("", R.drawable.tab_menu, com.chr.tatu.sample.friendslist.facebook.FriendsList.class);
addTab("", R.drawable.tab_contact, com.chr.tatu.sample.friendslist.contacts.BirthdayReminder.class);
}
Notification:
public class BirthdayBroadcastReceiver extends BroadcastReceiver {
private static final String TIMED = "timed";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getBooleanExtra(TIMED, false)) {
notifyBirthdays(context);
}
start(context);
}
private static PendingIntent createPendingIntent(Context context) {
Intent intent = new Intent(context, BirthdayBroadcastReceiver.class);
intent.putExtra(TIMED, true);
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void start(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = createPendingIntent(context);
Preferences prefs = Preferences.getInstance(context);
Time nextUpdateTime = prefs.getUpdateTime();
Calendar wakeUpCal = Calendar.getInstance();
wakeUpCal.set(Calendar.HOUR_OF_DAY, nextUpdateTime.getHours());
wakeUpCal.set(Calendar.MINUTE, nextUpdateTime.getMinutes());
wakeUpCal.set(Calendar.SECOND, wakeUpCal.getActualMinimum(Calendar.SECOND));
wakeUpCal.set(Calendar.MILLISECOND, wakeUpCal.getActualMinimum(Calendar.MILLISECOND));
if (wakeUpCal.before(Calendar.getInstance())) {
wakeUpCal.add(Calendar.DAY_OF_MONTH, 1);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, wakeUpCal.getTimeInMillis(), pendingIntent);
}
public static void stop(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = createPendingIntent(context);
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
public static void restart(Context context) {
stop(context);
start(context);
}
private void notifyBirthdays(Context context) {
Calendar today = CalendarUtils.todaysCalendar();
Database db = new Database(context.getContentResolver());
Preferences prefs = Preferences.getInstance(context);
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources res = context.getResources();
List<Contact> contacts = db.getAllContacts();
// calculate next birthdays
SortedMap<Integer, List<String>> nextBirthdays = new TreeMap<Integer, List<String>>();
for (Contact contact : contacts) {
Integer timeSpanToNextBirthday = null;
for (RawContact rawContact : contact.getRawContacts()) {
for (DateOfBirth dateOfBirth : rawContact.getDatesOfBirth()) {
int timeSpan = CalendarUtils.timeSpanToNextBirthday(today, dateOfBirth.getDate());
if (timeSpanToNextBirthday == null || timeSpanToNextBirthday > timeSpan) {
timeSpanToNextBirthday = timeSpan;
}
}
}
if (timeSpanToNextBirthday != null && timeSpanToNextBirthday <= prefs.getDaysBeforeReminder()) {
List<String> infoNames = nextBirthdays.get(timeSpanToNextBirthday);
if (infoNames == null) {
infoNames = new ArrayList<String>();
nextBirthdays.put(timeSpanToNextBirthday, infoNames);
}
infoNames.add(contact.getName());
}
}
// collect all sentences for the notification
List<String> notificationTexts = new ArrayList<String>();
int countBirthdays = 0;
for (Integer days : nextBirthdays.keySet()) {
List<String> birthdayList = nextBirthdays.get(days);
String names = StringUtils.join(birthdayList, ", ").toString();
notificationTexts.add(getBirthdayText(res, days, names));
countBirthdays += birthdayList.size();
}
// cancel all notifications (clear old once)
notificationManager.cancelAll();
// create new notification
if (notificationTexts.size() > 0) {
String titleText = String.format(res.getQuantityString(R.plurals.notificationTitle, countBirthdays),
countBirthdays);
Intent intent = new Intent(context, BirthdayReminder.class);
Notification notification = new Notification(R.drawable.balloons2, titleText, System.currentTimeMillis());
if (countBirthdays > 1) {
notification.number = countBirthdays;
}
PendingIntent pi = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
notification.setLatestEventInfo(context, titleText, StringUtils.join(notificationTexts, ", "), pi);
notificationManager.notify(0, notification);
}
}
private String getBirthdayText(Resources res, int days, String names) {
String text;
switch (days) {
case 0:
text = String.format(res.getString(R.string.notificationText_today), names);
break;
case 1:
text = String.format(res.getString(R.string.notificationText_tomorrow), names);
break;
default:
text = String.format(res.getString(R.string.notificationText_other), days, names);
}
return text;
}
}
Are you using correct package name with Notifications Service class, like i have made same type of project few months ago and i was struggling at same movement and when i got my mistake that was just silly:
It is the correct way:
<receiver android:name="packagename.BirthdayBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>