Cool Android App: Andlytics

October 17th, 2011

After getting annoyed with the long load times on my mobile devices of the Android Developer site, which allows you to monitor downloads, comments, etc. for Android apps in the Market, I decided to see if there were any good apps on the Android Market that would allow me to monitor my app statistics easier.  After a quick search I discovered Andlytics.

Andlytics allows you to view your Android Market apps statistics including download counts, comments (with translations), ratings, and more.  It will also connect to your Admob account to provide ad revenue statistics for an app.  I haven’t been able to get the AdMob integration working, but even Admob’s mobile site doesn’t seem to work for me since I linked my gmail account.

One of the things that this app does differently is it’s use of animations.  While some of them seem a bit long and gratuitous, Andlytics shows how good looking an Android app can be.

If you have apps in the Android Market and like to keep tabs on them, give Andlytics a try.

The web is full of tutorials about setting up Java Web App authentication using j_security_check, but they mostly only cover authenticating users which are stored in an xml file on the server.  While this has it’s uses, it’s really not practical for enterprise applications.  Enterprise apps need more robust user management than can be accomplished with an xml file. Enter SQL and Hibernate.

The Hibernate Model

When it came time for me to set up database authentication, the most difficult part was figuring out how to create my Hibernate model objects such that I could use them with j_security_check. It was obvious that I need to create a User and Group class and give them a many-to-many association, but the problem is that Hibernate translates that association into SQL the same way many DBAs would, with a join table containing the primary keys for each object. This is fine if you make the username and group name the primary keys, but I prefer to have auto incremented ids. The solution is to force Hibernate to build this join table using the properties you want the user to log in with.

After creating the POJO User and Group classes, I added the annotations required by Hibernate. I chose annotations because of the convenience of having all of the markup in one file instead of having to modify two files every time I want to make a change.

Each class needs very similar annotations to ensure that the join table gets created in a useful fashion. We just need to specify the name of the join table, the names of the columns, and the names of the properties that those columns reference on each object. This ensures that the join table will not be built with the object’s id value, but rather the username and group name.

User.java

@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(name = "User_Group",
	joinColumns = { @JoinColumn(name = "user", referencedColumnName = "username") },
	inverseJoinColumns = { @JoinColumn(name = "groupname", referencedColumnName = "name") })

Group.java

@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(name = "User_Group",
	inverseJoinColumns = { @JoinColumn(name = "user", referencedColumnName = "username") },
	joinColumns = { @JoinColumn(name = "groupname", referencedColumnName = "name") })

Note

Make sure you add a @Table(name = “groupp”) annotation to the group table. That extra ‘p’ isn’t a typo, without it Hibernate won’t be able to create the table since “group” is a reserved word in SQL (at least in MySQL).

The Error Servlet

The j_security_check mechanism requires us to supply a login error page.  This, obviously, is where the user is directed if there is an error with their credentials.  This can be useful, but most apps and websites tend to redirect you back to the login page and simply display an error message, allowing the user to try again.  This is the functionality that we are going to emulate using a servlet and redirects.  All we need here is a servlet which redirects the user to the landing page with a URL parameter.

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
	response.sendRedirect(request.getContextPath() + "/manage/listGroupsUsers.jsp?loginerror=true");
}

A note about the redirect

You may be tempted to make the error page redirect the user directly to the login page. Don’t. j_security_check works by intercepting the user’s request of a secured resource and redirecting the user to that resource after authentication is complete. Accessing the login page directly will allow the user to authenticate, but the user will be redirected to the login page. This can be quite confusing and should be avoided unless you implement a login page which checks for an active session and does something different once the user is authenticated.

The Login Page

The two servlets we just created utilize the fact that when j_security_check forwards the request to the login screen, the parameters are also forwarded. So all we have to do is implement our login screen to handle that parameter in addition to containing the login form.

<%  // Print error message
    String error = request.getParameter("loginerror");
    if (error != null && error.equals("true")) {
%>
    <span class="error">Invalid username or password.</span>
<% } %>

<%-- Login Form --%>
<form action="j_security_check" method="post">
	<table>
		<thead>
			<tr>
				<td colspan="2">Login</td>
			</tr>
		</thead>
		<tr>
			<td align="right">Username:</td>
			<td><input type="text" name="j_username" /></td>
		</tr>
		<tr>
			<td align="right">Password:</td>
			<td><input type="password" name="j_password" /></td>
		</tr>
		<tr>
			<td> </td>
			<td><input type="submit" value="Login" /><td>
		</tr>
	</table>
</form>

The web.xml File

The last two changes we need to make are to the web.xml file. First we need to tell Tomcat we want to use forms authentication and tell it which forms (pages) to use. This is handled with the login-config element.

<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/loginError</form-error-page>
  </form-login-config>
</login-config>

The next step is to tell Tomcat which resources are protected and which role is required to access them. This is done with the security-constraint element. Be sure to replace the blue items with relevant values.

<security-constraint>
  <web-resource-collection>
    <web-resource-name>User Management</web-resource-name>
    <description>Accessible only to admins</description>
    <url-pattern>/manage/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <description>These are the roles with access</description>
    <role-name>manager</role-name>
    <role-name>root</role-name>
  </auth-constraint>
</security-constraint>

All Done

And that’s all there is to it. You now have a protected web app using the “not-quite-free-but-close” j_security_check and the all powerful Hibernate. Play around with this code and if you find some better solutions feel free to share them in the comments.

Custom List Views in Android

February 8th, 2011

The basic building block for most Android apps, and probably most mobile apps, is the ListView.  While Android makes it easy to make simple one-line-of-text lists, most people prefer the far nicer looking optional-icon-and-one-or-two-lines-of-text.  While it’s pretty easy to accomplish any one of those combinations, with a little bit of extra work up front you can create a reusable, highly customizable list row.

Before we start writing any code, we should take a look at how we want this list row to look. I said earlier this would be a highly customizable row, so lets start with what I consider the primary use case for the row: a row with an icon to the left and a title to the right, with an optional description underneath. Here’s the wireframe.

Icon, Title, and Detail row wireframe

The Magic is in the Layout

This layout could easily be achieved with two LinearLayouts, two TextViews and an ImageView, but we’re going for something a little more flexible.  Using a RelativeLayout, as described by Romain Guy at his great blog, will offer us that flexibility.  Lets first take a look at the layout  xml file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="70dip"
  android:padding="6dip">
    <ImageView
      android:id="@+id/image"
      android:layout_width="wrap_content"
      android:layout_height="fill_parent"
      android:layout_alignParentTop="true"
      android:layout_alignParentBottom="true"
      android:layout_marginRight="6dip" />
    <TextView
      android:id="@+id/detail"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_toRightOf="@id/image"
      android:layout_alignParentBottom="true"
      android:layout_alignParentRight="true"
      android:singleLine="true"
      android:ellipsize="marquee" />
    <TextView
      android:id="@+id/title"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_toRightOf="@id/image"
      android:layout_alignParentRight="true"
      android:layout_alignParentTop="true"
      android:layout_above="@id/detail"
      android:layout_alignWithParentIfMissing="true"
      android:gravity="center_vertical"/>
</RelativeLayout>

In addition to reducing the number of layout elements like Romain explains, this RelativeLayout scheme offers much more flexibility than LinearLayouts would. For instance, lets say we don’t have an icon, but just want a title and description. Since the title and detail TextViews have layout_width=”fill_parent” they will both fill the view like so.

Title and Detail row wireframe

Say, on the other hand, that we want an icon and title, but no detail text. The title view’s “layout_alignWithParentIfMissing” attribute tells it to fill the view vertically if the detail view is missing.  So we simply set the detail view’s visibility to “GONE” and we get the following.

Icon and Title row wireframe

And finally, if we don’t have an icon or a second line of text (and for some reason don’t want to use the built in simple list row), we can set the icon and detail view’s visibility to GONE and are left with a single line of text in a list row.

Title row wireframe

All of this flexibility is great, but we still need some java code to make it do something.

On to the Code

In order to make these rows work, Android has to know what data to put where.  That is where our custom ListAdapter comes into play.

The adapter is like a container for the numbers in a paint by number.  We use it to store our collection and implement it’s getView method to tell our list what information to put where.  Let’s get started by looking at the code.

public class StoryAdapter extends ArrayAdapter {

	private LayoutInflater mInflater;
	private ArrayList items;
	private Context context;

	public StoryAdapter(Context context, int textViewResourceId, ArrayList items) {
		super(context, textViewResourceId, items);
		mInflater = LayoutInflater.from(context);
		this.items = items;
		this.context = context;
	}

	@Override
	public int getCount() {
		return items.size();
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;

		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.storylist_row, parent, false);
			holder = new ViewHolder();
			holder.image = (ImageView) convertView.findViewById(R.id.image);
			holder.title = (TextView) convertView.findViewById(R.id.title);
			holder.detail = (TextView) convertView.findViewById(R.id.detail);

			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		// Fill in the actual story info
		Story s = items.get(position);

		if (s.getTitle().length() > 35)
			holder.title.setText(s.getTitle().substring(0, 32) + "...");
		else
			holder.title.setText(s.getTitle());

		if (s.getPubdate() != null)
			holder.detail.setText(s.getPubdate().getTime().toLocaleString());
		else
			holder.detail.setVisibility(Visibility.GONE);

		if (s.getThumb() != null)
 			holder.image.setImageBitmap(s.getThumb());
 		else {
 			holder.image.setVisibility(Visibility.GONE);
 		}
  		return convertView;
 	}

  	static class ViewHolder {
 		ImageView image;
 		TextView title;
 		TextView detail;
 	}
 }

This example, taken from my Genius app, uses a Story object to fill the list row with it’s information.  The beginning of the class should be pretty straight forward, so lets just move on to the getView method.

Android ListViews are all about reusing rows, so the first thing we do is see if the convert view already exists and create a new one if it doesn’t. We store the holder (which I’ll explain in a minute) in the row’s Tag property, allowing us to easily retrieve it later. Then we simple step through the properties from our list item, setting the view’s visibility to GONE if the property is null.

What’s the holder?

The static internal ViewHolder class is simply for our convenience. We assign a reference to all of the views in our row, and that way we don’t have to “findViewById” every time we want to fill in some information.

And that’s all there is

Now that we have our reusable row, all we have to do is instantiate our list adapter, fill it with data.

To make all of the items, including the adapter, truly reusable we can define an interface, including the getTitle() getDetail() and getIcon() methods, to use in our adapter. If you need to display something without all of those items, just create the method and make it return null.

Since I haven’t updated my blog/site in a while I decided to drop a quick post about the updates in my life.

After graduating from the University of Wisconsin – Stevens Point with a Bachelors in Computer Information Systems in May I went straight to work for Sentry Insurance here in Stevens Point. Insurance sure wasn’t where I though I’d be but I decided it was something I couldn’t do for a year or so.

A few weeks ago I changed my mind and submitted my resume for an iPhone developer position at a small company in a west Chicago suburb. After two weeks of interviews and tests I’ve accepted a position at Lextech Global Services and should be starting there next week.

I’m excited to be starting my new job in Illinois, and excited to be done with all of the moving. I’ll keep you filled in on how things go, but for now, let me just say you can expect a new version of Speaker Mute and an Android app in the coming months.

After experiencing the joys of no project management (i.e. rewrite after rewrite) I decided it was time to look into some open source, web based project management solutions. After searching the interweb, not only at what people were saying but also at what other projects were using, I decided to give the Ruby on Rails application Redmine a try. With an extensive feature list, decent support, and the all important ability to host multiple projects, this seemed like a good choice.

I ran into some difficulties, however, when I tried to actually install Redmine. See, I’m a poor college student and can’t afford fancy virtual private server hosting, I’ve got the standard, cheap, shared hosting, like many others. This means no root access, no compiling and update the ruby or rails binaries, and certainly no server wide changes.

Today I finally got Redmine installed, and it was actually quite simple, it was just a matter of putting together the different pieces of information I found on the web and making it work in my environment. Because I wasn’t able to find one coherent guide, I decided to write one up.

Prerequisites

To use this guide, you do need a Linux based host running cPanel. Any Linux host should work, but where I use cPanel to setup the Rails app you will need to figure it out for your environment.

You will also need support for Ruby on Rails applications. I think this comes pretty standard with most hosting packages, but if you have a limited plan you will have to double check.

The last thing you will need is shell (also called ssh) access to your host. I was able to just email support for my host and ask for ssh access and they gave it to me within an hour.

Let’s get started…

The first thing we need to do it set up our database.

1. Log into cPanel and go into the database management area (I’ll be using MySQL).

2. Add a new database named “redmine”. This will actually result in a database named “username_redmine”. That’s just fine.

3. Now create a new user to access this database. For simplicity I created a user named “redmine” (which resulted in a user named “username_redmine”) with a password of “redmine”.

4. Next you will need to give the redmine user access to the redmine database. This is done in the “Add User to Database” section. Just select the “username_redmine” database in the User drop down and then “username_redmine” in the Database dropdown. Then click Add.

5. On the next page, check the box that says “All Privileges” and click Make Changes.

Now that your database is set up, lets get the Ruby on Rails application working.

6. Go back to the cPanel Home and then into the Ruby on Rails section.

7. Create a new Rails application by entering “redmine” into the App Name box, select “Load on boot?”, and then click Create. Make a note of the path for the application, for me it was ~/rails_apps/redmine (with the ~ represented by a house icon). We’ll use this very soon.

8. If the status of the added application is “Running” just click the Stop button to stop it.

Now it’s time to dive into the shell.

9. First you will need to ssh into your host. If you are on a Linux or Mac you can just open up the Terminal application (if you’re on a Mac it’s found in /Applications/Utilities, if you’re on Linux you know where it is) and type ‘ssh <username>@<hostname>’ without the quotes, and replacing <username> with your username and <hostname> with your host name. Then enter your password. (For me this equates to ‘ssh rharter@ryanharter.com’)

10. Remember that path I told you to take note of earlier, now we’re going to change to that directory.

cd ~/rails_apps/redmine/

11. Now that we’re there, delete the contents of this directory. Note: This command can be very damaging if you’re in the wrong directory, it will delete everything in it’s way without asking and there is no taking it back. Just make sure you are in the right directory and you will be fine.

rm -rf *

12. Now before we download Redmine, we have to check which version of ruby and rails we have. Run the following commands.

ruby -v
rails -v

For me this showed a ruby version of 1.8.7 and rails version 2.3.3.

13. Now, head on over to http://www.redmine.org/wiki/redmine/RedmineInstall and use the table to figure out which version of Redmine you need. This is where I ran into trouble the first time. Since my Rails version is slightly outdated I was forced to go with trunk version r2886, which equates to stable version 0.8.7. Just download the latest version you need as a tar.gz archive.

14. Copy the downloaded Redmine up to your host using your favorite FTP client (or scp if you are a more advanced user) and place it in your home folder.

15. Back in your ssh console (which should still be in the ~/rails_apps/redmine directory), copy the redmine tar.gz (redmine-0.8.7.tar.gz for me) to your ~/rails_apps/redmine folder.

cp ~/redmine-0.8.7.tar.gz ./

16. Now extract the archive.

tar xvzf redmine-0.8.7.tar.gz

17. Since we don’t want a subdirectory, we move into the folder that is created (the name depends on the version you chose) and move the contents out, then we can remove the empty directory. While we’re here, we can also remove the tarball (tar.gz archive)

cd redmine-0.8.7
mv * ..
cd ..
rmdir redmine-0.8.7
rm redmine-0.8.7.tar.gz

Config, Config…

18. We have to modify the config files a bit for Redmine to work properly. First open up the config/environment.rb file in your favorite text editor and comment out the line that says “RAILS_GEM_VERSION = ’2.1.2′ unless defined? RAILS_GEM_VERSION” by putting a # in front of it.

nano config/environment.rb
<comment the line, then hit ctrl-o to save and crtl-x to exit>

19. Now copy the config/database.yml.example file to config/database.yml.

cp config/database.yml.example config/database.yml

20. Next we need to edit that file to user our database. If you didn’t use a MySQL database this may differ for you and you will need to consult to Redmine Installation manual for examples.

nano config/database.yml
=== Edit production section to look like below, supplying your settings from earlier ===
production:
  adapter: mysql
  database: username_redmine
  host: localhost
  username: username_redmine
  password: redmine
  encoding: utf8

You should only need to edit the database, username, and password lines.

21. Redmine stores information in cookies, so a session store needs to be set up. This also differs if you are using a different version of Redmine, so just check the manual. Note: There isn’t a config/initializers/session_store.rb file, but don’t worry about it, just type the command and it will do it’s thing. This confused me for a good hour.

RAILS_ENV=production rake config/initializers/session_store.rb

22. We’re almost there, now we just need to setup the tables in the database and populate it with default data.

RAILS_ENV=production rake db:migrate
RAILS_ENV=production rake redmine:load_default_data

Back to cPanel!

23. I would suggest creating a Rewrite for your Redmine install. This allows you to use a directory name (or even a subdomain) to access your Redmine install, as opposed to having to type a url like http://www.mydomain.com:12001/. To do this, go back to the Ruby on Rails section of your cPanel page. Second from the bottom, click Create Rewrite for your redmine application.

24. Either enter the directory name on the end of your url (if using a subdirectory) or select the proper subdomain and click Save.

25. Now just click Start for the redmine application and you should be up and running.

26. For the rewrite to work properly in all cases, we need to go back to the shell and make one more edit. Whichever directory you decided to have the rewrite use, whether it be for a subdomain or just a directory, there should be a .htaccess file. For me this was located at /home/rharter/public_html/baby/.htaccess. Open that file in your favorite text editor and copy the last line that says RewriteRule ^/?$ “http\:\/\/127\.0\.0\.1\:12012%{REQUEST_URI}” [P,QSA,L] byt change the ^/?$ to ^(.*)$.

nano /home/rharter/public_html/baby/.htaccess
<add the line>
ctrl-o (Save)
ctrl-x (Exit)

27. Your last step is to just point your browser to the url you are using and you should find a fully working Redmine install.

And that’s all there is to it. Seems like a lot of steps, but overall it’s pretty straight forward. Now if only the project that need managing were that straight forward.

My Wasted Week

February 17th, 2010

It’s not an episode of Scrubs, I’ve just been working on a project at work and found out today that I’ve wasted the last week on it.  See if I barrel through something without checking the details again.

Bacula logo

I’ve been building a new Bacula package for Snow Leopard, upgrading the old packages with the new source and, like always, spending my days interpreting compiler errors and swimming through C code, commenting sections, and adding #ifdefs galore, until the binary actually compiled on the Mac.

Today I found that there is an osx Makefile in the platforms directory of the Bacula source that will compile a Universal binary, and create an installer package for you.  All of that crap I spent the last week doing was unnecessary and all because I failed to read the release notes.

You win this round, inattentiveness!

A Theme to Remember

February 17th, 2010

You may have noticed the new theme for my blog. I’ve been told that I have to get rid of the default WordPress theme but have always had a hard time with themes.

I’ve always felt the taking themes off the Codex seems a little unoriginal since the good ones will always be in use by several other blogs as well.  I also find, especially given the fact that I work with, and blog about, Macs, most of the themes fitting for that topic are the same on all the Mac blogs, something imitating the Mac interface.

I wanted something simple and elegant, like the Mac, but that didn’t try to copy the OS X interface (or that stupid space scene, I can only take so much of it).  Seeing as I don’t really have much in the way of design abilities – I am a programmer after all – I found an excellent solution, copy something else instead.

Ever since I started learning Cocoa programming 6 years ago, I’ve been really impressed with the design of CocoaDevCentral, a tutorial site run by Scott Stevenson.  Lately I’ve especially liked the design of some of the new introductory tutorials.  I thought this would make a good blog template, and so I set out to design my own based off of that.

What you see now is the start of my new design.  There are still parts that I haven’t gotten to yet, like the comments, but they will come.  I’ve never felt that works like this should be hidden until complete, because there are always tweaks to be made and, frankly, if I waited to put it on the site then it would just never get there.

Choices released

January 10th, 2010

Choices ScreenshotSo back in June I got in line with many other Sprint customers for the release of the Palm Pre. Instead of taking home a phone that day I was on a mailing list, but a week later I had my Pre.  This truly was an amazing device.  Even beyond the specs and the fact that it’s a gorgeous touchscreen smartphone, my big interest was the OS.

WebOS was apparently in development at Palm for several years and is names such because it’s apps are written in a combination of HTML, CSS and JavaScript.  This is neat because it doesn’t just mean that when you open an app WebOS is opening a WebKit view and launching a local web page, but using Palm’s Mojo framework, they have built JavaScript bindings for many local things that many web languages lack.

Last week I decided to take some time and figure out Mojo and Palm’s web based developer tools, Ares, to create a simple app.  Probably 20 hours of development later, taking into account that I was learning WebOS development from scratch and that I’m not even much of a JavaScript programmer, I had a functioning app.

Choices is an admittedly simple app.  I mostly just wrote it to learn WebOS programming.  It simply displays three cards, allowing you to flip them to get randomized answers and help you make a choice.  It also offers a page for you to customize the choices you are presented with.  The idea is that, for instance, if you can’t decided between Sushi, Mexican, or Burgers for lunch, Choices can help you decide by just making a random decision.

With a $50 “review” fee to get apps in the app store, I’ve decided to go with a web release.  Just visit this page and enter your phone number, or go to it in the browser on your Pre or Pixi, and you will be directed to the app page.

What’s next for my WebOS development, who knows, but the OpenGL support is looking pretty cool ;)

I was recently asked to present at the November Association of IT Professionals (AITP) student chapter meeting on my Mac programming experience.  I talked about how I got started programming for the Mac and a few of my programs, what I learned from them, and also gave a quick demo creating a simple web browser to show how easy it is to program for the Mac.

You can watch the entire 35 minute presentation here.



If you prefer a larger version you can view it here: AITP Presentation Mac Development

Useful Bash Script functions

October 15th, 2009

Lately I’ve been working with a lot of Bash Script and have written a few useful functions.  I’ll add more shortly.

This first little guy just uses applescript to display a dialog to the user with the standard OK and Cancel buttons.  This is really good when I’m running scripts as policies (loginhooks, through SSH, using Casper) and there is either an error that I need to tell the user about, I want the user to do something before I continue, or I just want to annoy someone.

####################################
# Function: diaplay_dialog
#
# Usage: display_dialog <message> <icon>
#      <icon> can be "note", "caution", "stop"
#
function display_dialog {
    if [ $# -lt 2 ];then
        echo "Error: display_dialog requires two arguments"
        return 1
    fi

    dialog_message=$1
    dialog_type=$2

    /usr/bin/osascript -l AppleScript -e 'Tell Application "Finder"' \
        -e 'display dialog "'"$dialog_message"'" with icon '"$dialog_type"'' \
        -e 'end tell'
}

Example usage:

display_dialog "Stop looking at porn at work :( " "stop"
Example of using display_dialog function

Example of using display_dialog function