Category Archives: Android

End Of the Semester

For Jon and I this is the end of the road for undergrad.  This Android project was a great way to end it.  All three of us want to continue to work on the app after school ends, we still have plans for it.

 

I’ve learned quite a bit over the course of the semester, not just coding with Android but how to work with a team.   We all became pretty good at using git, although sometimes the project still hates me and doesn’t want to work but that’s ok.  We have hundreds and hundreds of emails over the past few months talking about the app.  We also took advantage of the library TVs and did a bit of code review at our (bi)-weekly meetings.  Of course, we all learned Java for Android quite a bit, too and attempting to use the GUI for XML.

 

This was a great experience and a great way to end my undergraduate degree.

 

 

Thanks to everyone who helped along the way,

 

James Celona

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.

Using 3rd Party Libraries

Task Butler uses two open source third party libraries: ActionBar Sherlock and AmbilWarna

ActionBarSherlock is an excellent library that emulates the Ice Cream Sandwich action bar in older versions of Android. This was crucial for our app because we were developing for 2.2+, and having to design an entirely different UI would have been inelegant and a massive amount of extra work. Jake Wharton’s ABS uses the same API calls as Android’s official library, so one can follow Google’s API specification to use his library. Google has its own support library with limited features available, but ABS is a much more complete solution. It was critical to the design of our UI and I thank him for developing it and releasing it for free.

The AmbilWarna color picker dialog is a neat piece of code that provides a color selector for users. We needed a way for users to pick colors for their categories and this seemed like a much nicer solution than giving users limited choices like other apps do. Picture attached.

ColorPicker_1

From the blog Code Your Enthusiasm » WSU CS by Jon and used with permission of the author. All other rights reserved by the author.

Task Butler available on Google Play!

As of this writing, our summer/fall project Task Butler is available to be downloaded on the Google Play store! I am very proud of what we accomplished and I invite anyone with an Android device to check it out. Feedback is always appreciated, of course.

 

Grab it here.

From the blog Code Your Enthusiasm » WSU CS by Jon and used with permission of the author. All other rights reserved by the author.

Using IntentService With AlarmManager to Schedule Alarms

Many Linux developers look for a cron like service when starting to develop on Android, well luckily it exists in the form of AlarmManager. AlarmManager allows you to schedule your application to run at a time in the future, however it is cleared on boot–should/can be re registered with the system through OnBoot BroadcastReceiver.

AndroidManifest.xml; you need to register the two BroadcastReceivers, and the service. Also get permission to use the WakeLock, and to get Boot_Completed signal.

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
     <receiver android:name=".service.OnBootReceiver" >
         <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
         </intent-filter>
     </receiver>

     <receiver android:name=".service.OnAlarmReceiver" >
     </receiver>

     <service android:name=".service.TaskButlerService" >
     </service>
</application>

This is a BroadcastReceiver for the OnBoot complete, used to reschedule alarms with the AlarmManager since after boot the alarms are flashed out. There is only 2 lines of code in the onReceive() method, that is due to your own onReceive() needing to be short. The first line acquires a partial WakeLock to keep the CPU running, while our IntentService is executing.

package edu.worcester.cs499summer2012.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * BroadCastReceiver for android.intent.action.BOOT_COMPLETED
 * passes all responsibility to TaskButlerService.
 * @author Dhimitraq Jorgji
 *
 */
public class OnBootReceiver extends BroadcastReceiver{
	@Override
	public void onReceive(Context context, Intent intent) {

		WakefulIntentService.acquireStaticLock(context); //acquire a partial WakeLock
		context.startService(new Intent(context, TaskButlerService.class)); //start TaskButlerService
	}
}

IntentService is my favorite way of getting things done in the background, separate from the main thread of my application. Usually I don’t inherit IntentService directly, and I suggest you do the same; define a synchronized method to acquire a WakeLock before you continue on with whatever you need to accomplish.

package edu.worcester.cs499summer2012.service;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;

/**
 * Acquires a partial WakeLock, allows TaskButtlerService to keep the CPU alive
 * until the work is done.
 * @author Dhimitraq Jorgji
 *
 */
public class WakefulIntentService extends IntentService {
	public static final String
	LOCK_NAME_STATIC="edu.worcester.cs499summer2012.TaskButlerService.Static";;
	public static final String
	LOCK_NAME_LOCAL="edu.worcester.cs499summer2012.TaskButlerService.Local";
	private static PowerManager.WakeLock lockStatic=null;
	private PowerManager.WakeLock lockLocal=null;

	public WakefulIntentService(String name) {
		super(name);
	}
	/**
	 * Acquire a partial static WakeLock, you need too call this within the class
	 * that calls startService()
	 * @param context
	 */
	public static void acquireStaticLock(Context context) {
		getLock(context).acquire();
	}

	synchronized private static PowerManager.WakeLock getLock(Context context) {
		if (lockStatic==null) {
			PowerManager
			mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
			lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
					LOCK_NAME_STATIC);
			lockStatic.setReferenceCounted(true);
		}
		return(lockStatic);
	}

	@Override
	public void onCreate() {
		super.onCreate();
		PowerManager mgr=(PowerManager)getSystemService(Context.POWER_SERVICE);
		lockLocal=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
				LOCK_NAME_LOCAL);
		lockLocal.setReferenceCounted(true);
	}

	@Override
	public void onStart(Intent intent, final int startId) {
		lockLocal.acquire();
		super.onStart(intent, startId);
		getLock(this).release();
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		lockLocal.release();
	}
}

Now we can simply inheriting the WakeFulIntentService, and do all our work with in one simple method onHandleIntent(Intent). The method can be called from within anywhere in your program and it will handle everything on a background thread like any Service, also safely since it holds a WakeLock until the method completes at which point it returns the lock and exits nicely.

package edu.worcester.cs499summer2012.service;

import java.util.List;

import android.content.Intent;

import edu.worcester.cs499summer2012.database.TasksDataSource;
import edu.worcester.cs499summer2012.task.Task;

/**
 * An IntentService that takes care of setting up alarms for Task Butler
 * to remind the user of upcoming events
 * @author Dhimitraq Jorgji
 *
 */
public class TaskButlerService extends WakefulIntentService{

	public TaskButlerService() {
		super("TaskButlerService");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		TasksDataSource db = TasksDataSource.getInstance(this); //get access to the instance of TasksDataSource
		TaskAlarm alarm = new TaskAlarm();

		List<Task> tasks = db.getAllTasks(); //Get a list of all the tasks there
		for (Task task : tasks) {
			// Cancel existing alarm
			alarm.cancelAlarm(this, task.getID());

			//Procrastinator and Reminder alarm
			if(task.isPastDue()){
				alarm.setReminder(this, task.getID());
			}

			//handle repeat alarms
			if(task.isRepeating() && task.isCompleted()){
				task = alarm.setRepeatingAlarm(this, task.getID());
			}

			//regular alarms
			if(!task.isCompleted() && (task.getDateDue() >= System.currentTimeMillis())){
				alarm.setAlarm(this, task);
			}
		}
		super.onHandleIntent(intent);
	}
}

At this point you just need a BroadcastReceiver to receive your alarms.

package edu.worcester.cs499summer2012.service;

import edu.worcester.cs499summer2012.database.TasksDataSource;
import edu.worcester.cs499summer2012.task.Task;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

/**
 * BroadCastReceiver for Alarms, displays notifications as it receives alarm
 * and then starts TaskButlerService to update alarm schedule with AlarmManager
 * @author Dhimitraq Jorgji
 *
 */
public class OnAlarmReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		WakefulIntentService.acquireStaticLock(context); //acquire a partial WakeLock

		//send notification, bundle intent with taskID
		NotificationHelper notification = new NotificationHelper();
		Bundle bundle = intent.getExtras();
		int id = bundle.getInt(Task.EXTRA_TASK_ID);
		TasksDataSource db = TasksDataSource.getInstance(context);
		Task task = db.getTask(id);

		if(task.hasFinalDateDue() || task.getPriority() == Task.URGENT){
			notification.sendPersistentNotification(context, task); // send basic notification
		} else {
			notification.sendBasicNotification(context, task); // send basic notification
		}

		context.startService(new Intent(context, TaskButlerService.class)); //start TaskButlerService
	}
}

The setAlarm method:
NOTE:I use a method to create PendingIntent so my pending intents mach if the id passed in is the same, and because of of the FLAG_UPDATE_CURRENT the pending intent updates a possibly existing PendingIntent rather than duplicating.

	/**
	 * Set a One Time Alarm using the taskID
	 * @param context
	 * @param id id of task to retrieve task from SQLite database
	 */
	public void setAlarm(Context context, int id){
		TasksDataSource db = TasksDataSource.getInstance(context);
		Task task = db.getTask(id);
		AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
		am.set(AlarmManager.RTC_WAKEUP, task.getDateDue(), getPendingIntent(context, id));
	}

	//get a PendingIntent
	PendingIntent getPendingIntent(Context context, int id) {
		Intent intent =  new Intent(context, OnAlarmReceiver.class)
		.putExtra(Task.EXTRA_TASK_ID, id);
		return PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
	}

All of the source code for Task Butler can be found on GitHub, including the above code.

Any questions shoot away in the comments bellow.

From the blog Live and Code » WSU CS by dhimitraq and used with permission of the author. All other rights reserved by the author.

QA Testing

The release candidate is ready to go and so starts the crazy amount of bug testing we will need to do.  We need to assure we check all the edge cases and all the scenarios in which the user could break our app.  It reminds me of the last time working before a Mahadev assignment is due and checking if anything could go wrong.  We need to make sure things like:

repeating alarms actually set to the proper date.

what happens if you delete a task right before it’s due, does the alarm still go off? What about deleting it before looking at the notification? (we corrected this one earlier)

What happens if you set something to go off in the past, how will our app handle it?

Do the notifications stack correctly if it repeats frequently?

Does the app do anything about SQL injection?

Does anything happen if a task has all the same information?

what about categories, does the name matter?

If you create a category in a different activity can you use it in addTaskActivity?

———

The list seems to be endless and ones where we need to create like 20 tasks to make sure everything works at that high of a load is up to Jon/Dhimitri since my VM doesn’t really play nice.

Questions like these are a great way to test to make sure the app is functional.  I’ll doing another write up about what google would like our app to.

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.

JellyBean Notification with Backwards Compatibility

Using NotificationCompa from android.support.v4.app allows for backwards compatibility when creating notifications for your Android app. Bellow is a class that defines two basic methods for the notifications, however at this point it should be easy to go trough the documentation, and call the extra methods to set more things–even using the new android Jelly Bean notification goodies– for example the second method creates a persistent notification by setting onGoing flag true.

Speaking of flags:

//you can NOT set flags directly like
notification.flags |= Notification.FLAG_AUTO_CANCEL;
//you have to use the methods in NotificationCompat.Builder
builder.setAutoCancel(true); 

Things of note in the code is that in Notification notification = builder.getNotification(); notification is still a Notification object and not a NotificationCompat object, however the builder was defined as a NotificationCompat.Builder, this is helpful because the NotificationManager.notify() only accepts Notification objects.

package edu.worcester.cs499summer2012.service;

import edu.worcester.cs499summer2012.R;
import edu.worcester.cs499summer2012.activity.ViewTaskActivity;
import edu.worcester.cs499summer2012.task.Task;

import android.app.Notification;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

/**
 * Creates Notifications using NotificationCompat to allow for
 * comparability though different API levels
 * 
 * @author Dhimitraq Jorgji
 *
 */
public class NotificationHelper{
	/**
	 * Basic Text Notification for Task Butler, using NotificationCompat
	 * @param context 
	 * @param id id of task, call task.getID() and pass it to this parameter
	 */
	public void sendBasicNotification(Context context, Task task) {
		NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
			.setContentText(task.getName())
			.setContentTitle(context.getText(R.string.app_name))
			.setSmallIcon(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? 
					R.drawable.ic_notification : R.drawable.ic_notification_deprecated)
			.setAutoCancel(true)
			.setContentIntent(getPendingIntent(context, task.getID()))
			.setWhen(System.currentTimeMillis())
			.setDefaults(Notification.DEFAULT_ALL);
		Notification notification = builder.getNotification();
		NotificationManager notificationManager = getNotificationManager(context);
		notificationManager.notify(task.getID(), notification);
	}
	/**
	 * Basic Text Notification with Ongoing flag enabled for Task Butler, using NotificationCompat
	 * @param context 
	 * @param id id of task, call task.getID() and pass it to this parameter
	 */
	public void sendPersistentNotification(Context context, Task task) {
		NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
			.setContentText(task.getName())
			.setContentTitle(context.getText(R.string.app_name))
			.setSmallIcon(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? 
					R.drawable.ic_notification : R.drawable.ic_notification_deprecated)
			.setAutoCancel(true)
			.setContentIntent(getPendingIntent(context,task.getID()))
			.setWhen(System.currentTimeMillis())
			.setOngoing(true)
			.setDefaults(Notification.DEFAULT_ALL);
		Notification notification = builder.getNotification();
		NotificationManager notificationManager = getNotificationManager(context);
		notificationManager.notify(task.getID(), notification);
	}
	//get a PendingIntent
	PendingIntent getPendingIntent(Context context, int id) {
		Intent intent =  new Intent(context, ViewTaskActivity.class)
			.putExtra(Task.EXTRA_TASK_ID, id);
		return PendingIntent.getActivity(context, id, intent, 0);
	}
	//get a NotificationManager
	NotificationManager getNotificationManager(Context context) {
		return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
	}
}

All of the source code for Task Butler can be found on GitHub, including the above code.

Any questions shoot away in the comments bellow.

From the blog Live and Code » WSU CS by dhimitraq and used with permission of the author. All other rights reserved by the author.

Great Meeting the Other day

Synergy! haha, Jon Dhimitri and I met up on Thursday to discuss the final process in the app.  I figured since Dhimitri has that little netbook that he can’t do much with that I would bring a VGA cable to the library and set my laptop up on the big screen.  I’ll remember not to listen to Dhimitri though because the VGA cable wouldn’t fit so I had to run back and grab an HDMI, the result:

Look at him pointing, Synergy!

It actually worked out really well, and I wish we had started doing it earlier.  We used My/Jon’s laptop and were able to solve a problem in Dhimitri’s ViewCalendarActivity which turned out to be some weird problem with using .get__() (it was a call to a different class outside the package) which it didn’t like and wouldn’t allow the calendar to move more than a month away.

The meeting lasted a pretty long time where we discussed where the app was going and who was testing it.  I suggested we use r/androidDev from Reddit considering we would definitely get some feedback from knowledgeable app devs who are happy to help.  I think it might be a good idea to get some freshmen CS students into the testing too, I’ll email whomever is doing 101/140 this year and ask.

The app is looking awesome, excited for these next few weeks.

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.

First Meet With Dhimitri

Jon, Dhimitri and I had a meeting today to catch Dhimitri up on what we have been doing and the plan for the next few months.  We met in the library and discussed how to set up Action Bar Sherlock and demo’d the app again.  We plan on following the style guide very thoroughly so the app will flow how normal Android apps work.  We also talked about trying the app done to a point where we could start field testing the app with students around campus and get a feel for what works and what will need improvement.

 

Everything seemed to go pretty well, I’ll be working on editing a task that has been previously made using ‘add task’ and I think I may just have the edit copy the old task and replace the new data instead of just updating, not too sure yet.

 

We talked about doing SQLite a little bit but the point still stands about leaving it out until later (if we want/need it).

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.

Working on a facelift

Howdy all,

Jon and I aren’t graphic designers, actually I just ran into this problem at work,  and it’s pretty obvious this app isn’t going to be the prettiest bell at the ball.  Whatever, form follows function.  Right now I’m working on making the ‘create activity’ section contain everything we’re going to need Calendar style date picker, notes, title, priority radio buttons and that should be it for now.

I’ve ran into a bit of a problem with saving the tasks and I can’t figure out why they aren’t being recreated on restart for now I’m just leaving it alone (which is why nothing has been committed yet).  Since Jon built most of the onRestart() I’m sure he’ll know what’s wrong once we meet THIS SUNDAY FOR SURE so I’m not too concerned.  I found out today that the GUI for android dev is terrific, it really is.  I was fussing around with all the ugly xml and switched over only to see the GUI version was so smooth and easy to use.

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.

Catching Up on GIT

Howdy all,

Luckily Jon and I have been working internships all summer using some sort of variation of a Version Control System.  I guess I didn’t learn as much as I thought in 401 for GIT as I really needed.  My git-foo has improved significantly (Jon’s is still way above mine, though. )  Right now I’m working on my james-dev branch (at least the one I push to) and usually branch when I’m trying something new.  I’m really digging the issue tracker but, I think one day this week I am going to take some time out, probably with Jon, and really get our Wiki in gear.

In other news, old news that I never mentioned, Joe was MIA for a while and I finally got in contact with him and he said he was too busy and couldn’t commit I emailed Karl about it but I never got a response, I’m sure he’s just enjoying summer.

From the blog jamescelona » WSU CS by jamescelona and used with permission of the author. All other rights reserved by the author.