Pay It Square Update
posted on 03/22/11 at 06:54:37 pm by Joel Ross
A few months ago, I was gung ho about getting an Android app out for use with Pay It Square. And I was pretty close. But priorities change and opportunities come up that just can't be passed up.
tl;dr version: Pay It Square has merged with Open Systems Technologies.
The slightly longer version: Back in October, PayPal hosted their Innovate Developer Conference, and we decided it was the right time to make the trip to start building some relationships with PayPal. That did happen, but there were two things that took place at the conference that (in my opinion) changed the trajectory of Pay It Square:
- We won an X award in the Request/Send Money category.
- PayPal announced the launch of their own App Store.
After Innovate, we focused on the opportunity that the app store presented. As part of that, we made major architectural changes to the site, including what essentially turned out to be a rewrite of the site. We moved from web forms and the Kinetic Framework to ASP.NET MVC 3 and NHibernate. We launched the revamped site back in January, and started working on what our app would look like through PayPal. As part of that, we used the same infrastructure and built an app that can be used fully through Facebook. We launched that last week.
We also built a rest-based API for Pay It Square that gives you access to just about everything an organizer can do through the website. We launched that back in January, although we haven't actively promoted it yet. Having it has allowed us to do a couple of things. First, we farmed out the development of an Android and iPhone application (which is why my Android series sputtered - I stopped doing the main development on it). With the API, they can use a well-known interface to interact with Pay It Square, providing a way for organizers to completely manage their Collect Pages on the go. Secondly, the first official use of the API occurred last week, when we had a pool use Tourneytopia to run a charity tournament. Tourneytopia offers integration with Pay It Square, and it uses the API to do it's work. The charity so far has raised over $2,500.
While all of this technical work was going on, we were also talking to Open Systems Technologies (OST) about a partnership between our two companies, which culminated in Pay It Square merging with OST a couple of weeks ago. We're even briefly mentioned in the OST Company video (look for the site around the 55 second mark).
Brian and I founded Pay It Square a few years ago, and our intent was to build a useful utility and see where it went from there. We were convinced there was a market for this type of service, and the entrance of WePay into the market, and it's subsequent fund raising reinforced our beliefs. But there were skills that we just don't possess that we needed to make Pay It Square successful, and the partnership with OST provides us with access to those, as well as giving us access to more development time to build out a few features we feel are key to rounding out our offering.
We're excited to see what the future holds for us, and looking forward to being able to realize the vision we've had for Pay It Square. It's definitely been an adventure, and it's not over yet!
Categories: Pay It Square
Android Development, Part 5a: Starting Activities
posted on 10/12/10 at 08:03:00 pm by Joel Ross
This is Part 5a of an ongoing series. The rest of the series is always viewable and up to date at http://www.rosscode.com/android. If you're just checking in, the archives are worth a look.
I took a week off, but I'm back with more details on user interfaces. Again, I'm not a designer, nor will I ever claim to be, but I have had a bit of experience with getting a few screens running in the application I'm writing for Pay It Square.
I'm going to cover a technique I use to start new actions. So far, I haven't touched on starting actions, but that's a key piece to building a useful application. Most of the examples I've seen show activities starting right in the code from another activity. I don't particularly care for that, as that's giving too much knowledge about the flow of an application to the views. I'd prefer to handle starting new activities through either something under my presenters (like a workflow, for example), or from my presenters.
But that's difficult to do because starting activities requires a reference to the context. And under normal circumstances, your context is attached to your activity. I sought to split those two things. What I came up with works in some cases, but not all. It's great for fire and forget activities, but doesn't work when you need to get a result back from an activity. For me, that solved most of my screen switching needs. If I run across a situation that it doesn't solve, then I'll deal with that then.
So, what does this look like? Well, here's my interface:
1: public interface IActivityStarter {
2: void setClassName(String packageName, String className);
3: void putExtra(String name, Serializable value);
4: void startActivity();
5: }
I'm not doing anything too complicated when it comes to starting another activity - a user takes an action on a screen, and that takes them to another screen. I am not calling out to any of Android's system activities either, so my interface is pretty simple. I allow for extra information to be attached to the intent, the class for the intent to target, and a way to actually start the activity.
Let's back up a step. Android uses an Intent to start new activities. Depending on how you specify your intent, the request can either be handled by the OS, or it can be handled by a specific activity in your application. Your application's activities are defined in the AndroidManifest.xml file for your application. Whether you realize it or not, an activity is set up for you when you create a new application. It looks like similar to this:
1: <activity android:name=".Activities.main" android:label="@string/app_name">
2: <intent-filter>
3: <action android:name="android.intent.action.MAIN" />
4: <category android:name="android.intent.category.LAUNCHER" />
5: </intent-filter>
6: </activity>
When the application launches, Android filters the available activities, looking for one with an action of MAIN and a category of LAUNCHER, and when it finds it, it uses that to start the application.
For this post, we'll be looking at how a user can go from the main screen to the settings screen. Our settings activity is defined in our manifest as follows:
1: <activity android:name=".Activities.settings" android:label="@string/app_name">
2: <intent-filter>
3: <action android:name="com.Develomatic.PayItSquare.Activities.SETTINGS" />
4: </intent-filter>
5: </activity>
I've defined my action to be the same as my namespace, since I plan to call this action explicitly from my main activity. If I had a button on my main screen that took you to the settings, without using my ActivityStarter, it would look like this (this code would be inside a click listener for the button in my activity, for example):
1: Intent intent = new Intent();
2: intent.setClassName("com.Develomatic.PayItSquare", "com.Develomatic.PayItSquare.Activities.settings");
3: startActivity(intent);
Pretty straightforward and works, but it presents a major problem: It can't be tested - for two reasons. First, I'm only doing testing on my business layer right now, and this is in my UI layer. Second, it actually starts an activity - something that will be difficult to verify in an automated fashion.
By introducing an abstraction, I can then verify that the presenter intends to start an activity using a mock, but not actually start the activity. Now, instead of having my activity start a new activity directly, it now signals to the presenter that a button was clicked, and the presenter handles starting a new activity, like so:
1: private final IActivityStarter activityStarter;
2:
3: @Inject
4: public MainPresenter(IActivityStarter activityStarter) {
5: this.activityStarter = activityStarter;
6: }
7:
8: public void SettingsClicked() {
9: activityStarter.setClassName("com.Develomatic.PayItSquare",
10: "com.Develomatic.PayItSquare.Activities.settings");
11: activityStarter.startActivity();
12: }
I've included the constructor so you can see that the IActivityStarter is injected in through it. I haven't shown it yet, but one other piece of functionality I've allowed is attaching custom data to the intent through the putExtra() method. This allows me to attach any Serializable class to the intent, and allow the activity handling the intent to have access to the data. From the web world, this is roughly the equivalent of clicking a row in a grid and including parameters on the querystring to an edit screen. Implementing Serializable on your objects is pretty simple, and Eclipse handles it nicely for you if you ask nicely (Ctrl-1 is your friend!).
Now that we're working against an interface, verifying that the intended action was taken can now be done easily:
1: @Mock private IActivityStarter activityStarter;
2:
3: @BeforeSpecification
4: public void before() {
5: SUT = new MainPresenter(activityStarter);
6: }
7:
8: @Specification
9: public void shouldStartANewActivityForSettings() {
10: expect.that(new Expectations() {
11: {
12: one(activityStarter).startActivity();
13: allowing(activityStarter);
14: }
15: });
16:
17: SUT.SettingsClicked();
18: }
Now for the hard part: the actual implementation of our activity starter:
1: public class ActivityStarter implements IActivityStarter {
2: @Inject protected static Provider<Context> contextProvider;
3: private Intent intent;
4:
5: private Intent getIntent() {
6: if(intent == null) {
7: intent = new Intent();
8: }
9: return intent;
10: }
11:
12: @Override
13: public void putExtra(String name, Serializable value) {
14: getIntent().putExtra(name, value);
15: }
16:
17: @Override
18: public void setClassName(String packageName, String className) {
19: getIntent().setClassName(packageName, className);
20: }
21:
22: @Override
23: public void startActivity() {
24: contextProvider.get().startActivity(getIntent());
25: }
26: }
This class resides in our UI project, as it deals directly with Android classes, but it isn't tied to a particular activity, so it's relatively isolated from the rest of our code. The key piece here is the static context provider injected into this. We covered this in part 3 when we talked about requestStaticInjection() with Roboguice. With a reference to the context provider, we're able to get at the current context on demand, which means we can start new activities in a clean way.
I'd planned to cover a couple of other techniques I'm using, but this went longer than expected, so I think I'll stick with just this one for now, and cover the other techniques in part 5b.
Categories: Android
Android Development, Part 1a: From Nothing To Running
posted on 09/28/10 at 06:43:11 pm by Joel Ross
This is part 1a in an ongoing series about my experiences developing an Android app to use with Pay It Square. If you're just joining us, first, thanks! And second, here's where we've been so far:
- Part 0: Introduction
- Part 1: Project Structure and Tools
- Part 2: Presenters and Activities
- Part 3: Roboguice
- Part 4: UI Basics
I've also added an easy to remember index page at http://www.rosscode.com/android that I'll keep current as I post more parts.
Wait, what? Part 1a? Yes, I'm going backwards, but I got a few questions on how my projects are actually set up - from a tactical standpoint. So I'm going to go back and revisit project setup in more detail. More specifically, we'll go from nothing to our first test with Instinct, and then move on to getting our activity all wired up and running the application.
I'll be using Eclipse, and I'll assume we've already run through one of the many tutorials out there for getting it installed and working with the Android SDK. To start with, we'll create a new Android Project:
I've targeted Android 1.5 and a minimum SDK version of 3, just because I don't have any need for anything offered by the newer SDKs, and I don't really want to limit the devices the software can work on. Also note that I am not asking the project creation wizard to create a test project. I'll do that myself later.
Next, we'll add two new projects: one for our core library, and one for our tests. I accept the standard settings for the projects, and named one <ProjectName>.Core and the other <ProjectName>.Tests. When all is said and done, I end up with a project that looks like this:
Next, we need to add our references to our libraries. To just get unit tests working, all we have to add is a reference to Instinct. I like to add a folder at the same level as my projects called lib, and put the libraries under that. Then I can add references by right clicking on the project, selecting properties, and going to Java Build Path.
When you add a reference to Instinct, you're not just adding Instinct. Remember, Instinct sits on top of jMock, so you'll need to add references to much more than just Instinct. Here's my reference list:
Now, we need to add a test. Let's assume we have an application with a database that stores a user. On our main screen, we want to show a message: "Welcome Back, <Name>". We'll test a presenter, and ensure that it sets the text on the view to the user name retrieved from the user repository.
Let's create our test class. I prefer to call my test classes specs, so I'll create a class called MainPresenterSpecs, since my activity is called "main". Here's the full code, minus import statements:
1: @RunWith(InstinctRunner.class)
2: public class MainPresenterSpecs {
3: @Subject private MainPresenter SUT;
4: @Mock private IMainActivity activity;
5: @Mock private IUserRepository userRepository;
6:
7: @BeforeSpecification
8: public void before() {
9: SUT = new MainPresenter(userRepository);
10: }
11:
12: @Specification
13: public void it_should_load_user_name_on_load_of_activity() {
14: final User user = new User();
15: user.setName("Joel Ross");
16:
17: expect.that(new Expectations() {
18: {
19: one(userRepository).get(); will(returnValue(user));
20: one(activity).setUserNameTo("Joel Ross");
21: }
22: });
23:
24: SUT.InitializeWith(activity);
25: }
26: }
If you take this code and put it in your solution, you'll notice a few things. Mainly, it won't compile. I wrote the spec for what I want to have happen when the first screen loads. But now I need to go at least create the classes and interfaces referenced here. These will all be in our Core project.
First up: User. Pretty straightforward data class:
1: public class User {
2: private String name;
3: public void setName(String value) {
4: name = value;
5: }
6: public String getName() {
7: return name;
8: }
9: }
Next, the two interfaces, IMainActivity and IUserRepository. If you're not familiar with Eclipse, now would be a good time to note that if you place your cursor over either of the interface names and press Ctrl-1, you'll get options to fix the issue with the code. In this case, one of the options will be to create an interface. You can then specify which project you want the code in. In this case, I created them in the Core project:
1: public interface IUserRepository {
2: User get();
3: }
4:
5: public interface IMainActivity {
6: void setUserNameTo(String name);
7: }
Now, we just have the presenter to implement. It's a simple implementation, so let's just implement it now:
1: public class MainPresenter {
2: private IUserRepository userRepository;
3:
4: public MainPresenter(IUserRepository userRepository) {
5: this.userRepository = userRepository;
6: }
7:
8: public void InitializeWith(IMainActivity activity) {
9: User user = userRepository.get();
10: activity.setUserNameTo(user.getName());
11: }
12: }
We're all set to run our test now, right? Well not quite. We didn't add a reference to our Core project from our tests, so let's do that now. Back under the "Java Build Path" settings, we can go to the Projects tab, and add our Core library. After doing that, our code is now error free.
To run our tests, we can right click on the test project, select "Run As" -> JUnit Test. The first time you do this, you'll be presented with a dialog asking you how you want to run the test. Check "Use configuration specific settings" and then select "Eclipse JUnit Launcher". After doing so, click OK, and you'll be presented with the best sight a TDD developer can see:
OK, so we have a passing test. Now we need to get the activity working and have it show in our application. This involves getting Roboguice wired up, so we'll add a reference to that from our Android project. Then, as I detailed in Part 3, we need to add an Application class, a module, and a setting in our manifest file. We also need to add a reference to our Core project from our Android project. Once we do that, we can implement our activity. I added a TextView to my main layout xml file, set up the activity to be roboguice-ready, and here's what I came up with:
1: public class main extends GuiceActivity implements IMainActivity {
2: @Inject private MainPresenter presenter;
3: @InjectView(R.id.welcomeMessage) TextView welcomeMessage;
4: @Override
5: public void onCreate(Bundle savedInstanceState) {
6: super.onCreate(savedInstanceState);
7: setContentView(R.layout.main);
8: presenter.InitializeWith(this);
9: }
10:
11: public void setUserNameTo(String name){
12: welcomeMessage.setText("Welcome Back, " + name);
13: }
14: }
Now that everything is coded, all that's left is to implement IUserRepository. I just created a fake one that returns a dummy user for my purposes, and bound it in my module. Now, I'm ready to run the project. I can right click on the Android project and select "Run As" -> "Android Application". This will fire up the emulator, and after a few minutes, our application will start up, and display our message. Right?
Well, not quite. First, we need to add a reference to Roboguice to the core library, and add an @Inject annotation to the constructor in our MainPresenter. Then, when we fire up the app again, we'll see this:
Just as we set out to do! We've gone from nothing to a running and tested application in a very short time.
For those who want to get their hands on the resulting code, I've created a git repository to hold it:
This is my first time posting and sharing code via git and GitHub, so if it doesn't work correctly, let me know. I didn't commit the .metadata folder, so you will need to import the projects into Eclipse after cloning from git. Also, Eclipse probably won't know where your Android SDK is located. Just set the location of the SDK in the Project?s Properties and you should be all set.
Next time, we'll get back on track and dive deeper into activities.
Categories: Android
Reading More
posted on 09/23/10 at 06:48:23 pm by Joel Ross
When our oldest daughter started first grade, one of her biggest adjustments was actually going to sleep at a reasonable time. She's apparently a lot like me in her night owliness (that's a word, right?), and would be up until 10 or 11 at night, while needing to be up at 7:00 AM the next morning.
That just wasn't sustainable, and someone gave us some advice: An hour before she should be going to sleep, have her play in her room for the first 30 minutes. After that, turn off all the lights except for a small lamp at her bedside and have her read for the last 30 minutes. It's been about two years since we started doing that, and it's been amazing to see how well it continues to works for her. She used to pop back out of her room 30 minutes after "going to sleep" just about every night. Within a week of using the new process, that stopped completely.
I'm sure you're thinking, "Um, Joel, this isn't a parenting blog now, is it, because that's not what I signed up for!" No, I'm not turning this into a parenting blog (but that tip above is golden!). No, I bring this up because I've started to use this technique for me.
Well, not the playing in my bedroom part.
No, I'm talking about the reading part. I started to notice that I'd go to bed a bit too wound up, and end up laying in bed with ideas running through my head for a good 20 minutes before I'd finally drift off. Now, I didn't come out of my room complaining I couldn't sleep, but the symptoms definitely sounded familiar. So, I decided to give it a try. I changed my routine to shut down what I'm doing around 12:30 and read for 30 minutes. I forced myself to do it for the first few times, but once it became a habit, I started looking forward to it. I've been doing this since Memorial Day, and I've read more this summer than I have in the previous two years combined.
I've got a routine down: I grab a spot on the couch, and four or five nights a week, I'll read a book, usually on my Kindle. I rotate back and forth between technical books and fiction books. So far this summer, I've read 5 technical books and 6 fiction books, which is pretty good for me, since I'm a slow reader, although now that I'm reading regularly, my speed has increased quite a bit. I've also stopped reading articles when I find them. I used to read it right then, but now, I'll send the page to Instapaper, and the nights I don't read a book, I'll read through that queue on my phone (using InstaFetch). I'm reading more articles than I have in the past now as well.
The best part? At the end of the half hour, I'm completely relaxed and my mind is cleared. I head up to bed and am asleep within 5 minutes.
The worst part? A few times I've woken up at 3:00 AM lying on the couch with the Kindle on my chest.
Categories: Personal
Android Development, Part 4: UI Basics
posted on 09/21/10 at 07:32:37 pm by Joel Ross
Let's preface this by stating up front that I've never been very good with UI design. Switching platforms hasn't really changed that, so while I'll touch on how I'm creating my user interfaces in Android, certainly don't copy my screens. A blind monkey could probably do better!
I'm getting ahead of myself though. This is part 4 in an ongoing series about my experiences developing an Android app to use with Pay It Square. If you're just joining us, first, thanks! and second, here's where we've been so far:
- Part 0: Introduction
- Part 1: Project Structure and Tools
- Part 2: Presenters and Activities
- Part 3: Roboguice
Let's start with the basics. You have two choices when laying out an activity. You can either dynamically add controls to the activity through code, or you can design your layout in an XML file. So far, I've stuck with the XML file approach, except in one case - a tab-based page. But even in that case, I have a base layout in XML, and each individual tab has its own XML layout as well.
In my limited experiences, there's three main ViewGroups to start your activities with. Each will have child Views or ViewGroups, but the type of ViewGroup you choose will determine how it actually looks.
- LinearLayout: This organizes child elements into either a horizontal or vertical row.
- RelativeLayout: This is the ViewGroup I've found to be the most flexible, but also the hardest to work with. More on that later.
- TableLayout: From a web developer's perspective, this is very similar to HTML tables.
Remember that each of the above ViewGroups can have child ViewGroups, so your layout options are pretty flexible. There are other types of ViewGroups you can use as well, such as a ListView and TabHost. There's more, but I'll stick to the ones I've had experience with so far.
Inside each ViewGroup, you'll have Views. These are things such as text boxes, labels, drop downs, etc. Basic UI elements. How they're displayed is determined by both the ViewGroup they are in and the properties on the View.
Let's look at an example of the layout of the activity I went over in part 2 (setting the user name and password to log into Pay It Square). First, I created an XML file under res/layout called settings.xml. I'm using a RelativeLayout, as I think that provides the most flexibility, although in this case, it's probably not necessary. Here's the layout in its entirety.
1: <?xml version="1.0" encoding="utf-8"?>
2: <RelativeLayout
3: xmlns:android="http://schemas.android.com/apk/res/android"
4: android:layout_width="fill_parent"
5: android:layout_height="fill_parent">
6: <TextView
7: android:id="@+id/signIn"
8: android:text="@string/signInHeader"
9: android:layout_width="fill_parent"
10: android:layout_height="wrap_content"
11: android:gravity="center"
12: android:textSize="20px"
13: android:padding="10px"
14: android:textStyle="bold"
15: android:textColor="#669900" />
16: <EditText
17: android:id="@+id/userName"
18: android:layout_width="fill_parent"
19: android:layout_height="wrap_content"
20: android:hint="@string/userNameHint"
21: android:layout_below="@+id/signIn"
22: android:layout_marginLeft="10px"
23: android:layout_marginRight="10px"
24: android:imeOptions="actionNext" />
25: <EditText
26: android:id="@+id/password"
27: android:layout_width="fill_parent"
28: android:password="true"
29: android:layout_height="wrap_content"
30: android:layout_below="@+id/userName"
31: android:hint="@string/passwordHint"
32: android:layout_marginLeft="10px"
33: android:layout_marginRight="10px"
34: android:imeOptions="actionDone" />
35: <Button
36: android:text="@string/signIn"
37: android:id="@+id/save"
38: android:layout_width="fill_parent"
39: android:layout_height="wrap_content"
40: android:layout_below="@+id/password"
41: android:textSize="16px"
42: android:layout_marginLeft="10px"
43: android:layout_marginRight="10px"
44: android:textStyle="bold" />
45: </RelativeLayout>
I have a RelativeLayout that is set to fill everything it can. In this case, it fills the screen, but it could also be included as an activity inside a tab. In that case, it'd fill up the whole tab. Inside the ViewGroup, I have four Views - a label describing what the screen is for, two textboxes for entering a user name and password, and finally, a button, which checks your credentials.
Tying the XML to an activity is pretty simple. In the override for the onCreate() method of the activity, you reference the generated R class and load it that way:
1: @Override
2: public void onCreate(Bundle savedInstanceState) {
3: super.onCreate(savedInstanceState);
4: setContentView(R.layout.settings);
5: presenter.InitializeWith(this);
6: }
Here's what it looks like when rendered:
The XML itself is pretty straightforward. You can set the color of text (android:textColor), size (android:textSize), alignment (android:gravity), padding (android:padding) and margin (android:layout_margin), etc.
Since I'm using a RelativeLayout, I need to specify where my elements are relative to other items. In this case, I've only used android:layout_below, but there are also options for putting elements next to other elements, as well as how they should be aligned in relation to other elements.
One attribute you can provide on Views is android:imeOptions. These aren't explicitly needed, but they provide for a better user experience. In the layout above, I have android:imeOptions="actionNext" on my user name EditView. This means that when the virtual keyboard is shown while your cursor is in the user name field, the keyboard will show a "Next" button instead of the default return. Touching that button moves the cursor to the Password field, where the IME option is set to Done. The keyboard will now show Done, and touching that will hide the keyboard. There are other IME actions available, but the two I've used served my needs just fine.
There are a lot more thorough tutorials on UI layout than what I could provide, including a great series on Tekpub by Donn Felker, but there are a few tips I'd like to highlight. For me, while they were small things, they really helped make layouts less painful and more user friendly.
- Use margins and padding. It sounds so simple, but it really enhances the look when text or text boxes aren't butting right up against the edge of the screen or another control.
- Order matters. I'm talking specifically about the RelativeLayout here. I used DroidDraw to lay out a relative screen, specifying exactly where all my elements should be in relation to each other, and then generated the XML file. When I pulled it into my application, controls were rendering on top of each other, and what was really odd was that switching from one tab to another and then back again caused the layout to slowly fix itself. By the third or fourth switch, the layout looked great. What I eventually came to realize was that DroidDraw seemingly dropped controls into the XML in a random order. I had controls at the top of the XML file that specified its layout relative to a control lower in the file. As a result, when it came time to render (at least the first time), the control it was supposed to be positioned next to hadn't been rendered. Just changing the order of elements fixed the view.
- Lose the labels. I'm a web developer through and through. I'm trained to layout my screens in table format with a label on the left, and a textbox on the right. But this isn't the web, and space is limited. Make use of android:hint to add watermarks on your text input, and stretch those textboxes out as wide as you can. This also helps with the ordering and relative layouts, because for most screens, the layout is much simpler once you drop all the unnecessary labels.
- Use the imeOptions and inputType. I touched on this already, but it's worth repeating. It's annoying to be required to enter an email address in an application and not have the "@" on the primary keyboard screen. It's equally annoying to have the keyboard have a return key instead of a "Next" key when there's more textboxes to fill out. It's such a simple thing to implement, yet makes the application so much easier to use.
I do plan to go a little more in-depth on some of the more complicated activities I'm using, like lists and tabs. But first, I've been getting a few questions about how I configured Eclipse and my projects to get it all working, so next time, we'll take a step back and look at that.
Categories: Android
Android Development, Part 3: Wiring Up Roboguice
posted on 09/14/10 at 08:46:15 pm by Joel Ross
This is part 3 in an ongoing series documenting my adventures building my first Android application. If you're here for the first time, you might want to check out the previous posts for background.
I'm a huge believer in the benefits of inversion of control, both in aiding in testing the code and in how it lets you separate concerns. The hard part of IoC is wiring it all up. I've been using Ninject to handle that for me in the .NET world, and when I moved to Android, I looked for something similar. Luckily, the solution was a pretty easy decision. Since Guice is what Ninject was based on, Roboguice was a natural choice. Getting it set up is actually pretty simple, but worth taking a step back and look at how to set it up.
After you've downloaded it, you need to add a reference to both roboguice-1.0.jar and guice-2.0-no_aop.jar. Roboguice works on top of Guice, so we need them both. After doing that, you create a new class that inherits from GuiceApplication. This is where the inject process takes place. If you're familiar with Ninject, the fact that Roboguice uses modules will be familiar. You can add multiple modules, and this allows you to segregate your bindings or only load certain bindings under certain conditions. For now, we'll be simple and just load one module.
1: public class Application extends GuiceApplication {
2: @Override
3: protected void addApplicationModules(List<Module> modules) {
4: modules.add(new IoCModule());
5: }
6: }
And the module looks like this:
1: public class IoCModule extends AbstractAndroidModule {
2: @Override
3: protected void configure() {
4: requestStaticInjection(DataHelper.class);
5: bind(IDataHelper.class).to(DataHelper.class);
6: bind(IPreferenceRepository.class).to(PreferenceRepository.class);
7: }
8: }
I haven't talked about the actual classes bound in the module, but the classes don't really matter. They just show how you bind an interface to a implementation. Pretty straightforward, and very similar to how Ninject does it. The method requestStaticInjection() will inject static properties on a class. In the case for the DataHelper class, I'm injecting a context provider. I'll cover that in a bit, as that's a pretty nice Roboguice feature.
The last piece to getting this all working is a small addition to the AndroidManifest.xml file. There's an application element, and it needs to have an attribute added called android:name, and should be set equal to the Application class we created above (fully qualified). Thus, you end up with this:
1: <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2: package="com.Develomatic.PayItSquare"
3: android:versionCode="1"
4: android:versionName="1.0">
5: <application
6: android:icon="@drawable/icon"
7: android:label="@string/app_name"
8: android:name="com.Develomatic.PayItSquare.Application" >
9: ...
10: </application>
11: </manifest>
One thing you may have noticed is that my presenters aren't in the module. That's because I'm not using any interfaces for my presenters, and am using the @Inject annotation in my Activities. That signals to Roboguice that it needs to inject that presenter, and it looks for a constructor on my presenters with the @Inject annotation. It's essentially self-binding.
For the injection to work, your activities have to inherit from a Roboguice-specific activity. It provides a base class for most of the *Activity classes provided by Android, so if you need a list activity, you inherit from GuiceListActivity, for a tab activity, you inherit from GuiceTabActivity, etc.
Note that I'm specifically referring to Roboguice 1.0. While putting this together, I checked Roboguice's source, and noticed that trunk uses Robo*Activity naming instead of Guice*Activity naming. I'm assuming the functionality is roughly the same, but you'd have to try it for yourself to be sure.
There are some nice features build specifically for Android in Roboguice. One I showed in part 2, and that is View injection - being able to declare a field like @InjectView(R.id.user_name) TextView userName; and avoid the whole call to findViewById and casting it is nice. But once you get to using Android for a while, you'll realize an old phrase suddenly has new meaning: "Context is king." In this case, I'm referring to Android's context. There's methods on activities to get at the current context, but passing that around is painful. Trust me on this one; I tried before I realized how Roboguice helped me here. I ended up with an unmaintainable mess. But with Roboguice, it's pretty simple. I haven't yet talked about how I'm doing database access, but again, it's not entirely important to the discussion. Just know that to open a database, I'm using the SQLiteOpenHelper, and it's constructor takes in the current context. Well, I wanted this class to be injected into my repository classes, and I want it to all happen "automagically" through Roboguice. If I was doing this by hand, I'd need to pass the activity's context from the activity to the presenter, from the presenter to the repository, and finally from the repository down to the data helper. Like I said, that's messy. My presenter and repository have no need to know about the context, other than to pass it on, so why go through the hassle? Luckily, Roboguice provides an alternative. I have a static field on my DataHelper class that provides me with a context provider. Then I have the DataHelper constructor use that provider to call it's parent constructor:
1: public class DataHelper extends SQLiteOpenHelper implements IDataHelper {
2: @Inject protected static Provider<Context> contextProvider;
3:
4: public DataHelper() {
5: super(contextProvider.get(), "PayItSquare", null, 1);
6: }
7: }
Now I can remove any knowledge of the context from my presenter and repository, and most likely, from my activity. It's figured out on the fly when a DataHelper is needed, all by a context provider built into Roboguice. And remember, the call to requestStaticInjection(DataHelper.class); is what sets that contextProvider field.
I definitely still feel like I'm new to Roboguice, and I'm sure there's functionality that I'm missing out. For example, I'd like to find a way to have my presenter and activity tied together automatically, but haven't figured out how to specify constructor parameters when requesting an instance. But even the little bit I've figured out has been a huge help when building my application. I don't think I'd build an app without it (or at least something similar).
Next up: I think it's time to talk about layouts.
Categories: Android
Android Development: Part 2: Presenters and Activities
posted on 09/08/10 at 04:18:22 am by Joel Ross
This is part 2 of an on-going series on Android development (or at least my warped interpretation of it). If you missed the introduction of the application or a discussion of the tools, you might want to check those out first.
I mentioned earlier that I'm using an MVP pattern, but didn't go into much more detail than that. Well, that's about to change, as that's exactly what this post is all about.
In the Android world, Activities are the equivalent of views in MVP. The way Android works is that Intents are responsible for activating activities. If you're not familiar with Android development, that probably didn't make a lot of sense, but the bottom line is that Android is view-first rather than presenter-first. This has some implications in how the presenter and activity interact, so it's important to note that.
I've picked a pretty simple screen in my application to demonstrate how my activities and presenters work together. It's a screen where you set your user name and password to be used to connect to Pay It Square. Note that, for now, I?ll ignore how the data is actually stored and retrieved, and just leave that logic hidden behind an interface.
While Android starts with the activity, I like to start with my tests. I am not testing my Activities right now, since I plan to keep them relatively thin. The presenter will essentially be responsible for two things: populating the activity with the existing settings, and saving those settings back to the data store when the activity says it's time. So let's write a couple of specs to indicate that.
As I said in part 1, I'm using Instinct as my testing framework, so that?s what I'm going to show. The basic test spec looks like this:
1: @RunWith(InstinctRunner.class)
2: public class SettingsPresenterSpecs {
3: @Subject private SettingsPresenter SUT;
4:
5: @BeforeSpecification
6: public void before() {
7: SUT = new SettingsPresenter(preferenceRepository);
8: }
9:
10: @Specification
11: void shouldSetUserAndPasswordOnView() {
12:
13: }
14: }
This doesn't do anything except ?new up? the presenter. I've defined a spec, but there's no expectations set up yet. I've also defined my presenter as the subject of the test, and marked it to run with the Instinct test runner. But essentially, this spec doesn't do anything. So let's fix that. I know I'll have a data store to hold the user's current username and password, as well as the activity. Both will be interfaces, and we'll talk about wiring that up in a bit. For now, we'll assume the presenter will be constructor injected. This changes things a bit, and I now need two mocks: one for IPreferenceRepository and one for ISettingsActivity.
Side note: I'm trying to get into the ?Java way? of naming things, but I'm still using "I" to prefix my interfaces. I'm showing my C# bias, but it is what it is.
Now, before we update the spec to reflect our changes, there's one thing that isn't quite right. I intend to use an IoC container to create my presenters, so the container will be responsible for instantiating any dependencies the presenter needs. But we said earlier that the Activity is where the process starts in an Android app, so our container won't be activating the activity for us. As a result, it can't be constructor injected. It will have to be passed in later. I've settled on a base presenter that handles that for me through a call to a method called InitializeWith(activity);. Updating our spec, we end up with this:
1: @RunWith(InstinctRunner.class)
2: public class SettingsPresenterSpecs {
3: @Subject private SettingsPresenter SUT;
4: @Mock private ISettingsActivity activity;
5: @Mock private IPreferenceRepository preferenceRepository;
6:
7: @BeforeSpecification
8: public void before() {
9: SUT = new SettingsPresenter(preferenceRepository);
10: }
11:
12: @Specification
13: void shouldSetUserNameAndPasswordOnView() {
14: SUT.InitializeWith(activity);
15: }
16: }
You can see how the repository is injected in the constructor, and since the presenter begins its interaction with the activity once InitializeWith is called, I've added that to the spec. Notice that Instinct provides simple ways to create mocks by adding @Mock onto the declaration.
The only thing missing is what we expect to happen. Instinct provides a way to set up expectations on my mocks, so that's what we'll use. First, the presenter should get the current user preferences and then it should set those on the activity. To do that, we update our spec to include those expectations:
1: @Specification
2: void shouldSetUserNameAndPasswordOnView() {
3: expect.that(new Expectations() {
4: {
5: one(preferenceRepository).get(); will(returnValue(new Preference("jross", "test1234");));
6: one(activity).setUserName("jross");
7: one(activity).setPassword("test1234");
8: }
9: });
10:
11: SUT.InitializeWith(activity);
12: }
We're stubbing the call to preferenceRepository.get() to return a preference, and then we're expecting it to be set on the view. Next, we need a spec to save the updated username and password. That's very similar:
1: @Specification
2: void shouldSaveUserNameAndPassword() {
3: expect.that(new Expectations() {
4: {
5: one(preferenceRepository).save("jross2", "test4321");
6: }
7: });
8:
9: SUT.Save("jross2", "test4321");
10: }
Now, let's move onto the presenter, and get these tests to pass. Like I said, I have a base class for my presenter. It doesn't do much, but it helps with the interaction with the activity:
1: public class BasePresenter<T extends IActivity> {
2: private T activity;
3:
4: protected T getActivity(){
5: return activity;
6: }
7:
8: protected BasePresenter() { }
9:
10: public void InitializeWith(T activity) {
11: this.activity = activity;
12: }
13: }
Nothing too fancy here, but it cleans up some repetitive code in my presenters. Here's my SettingsPresenter that satisfies those specs we created:
1: public class SettingsPresenter extends BasePresenter<ISettingsActivity> {
2: private IPreferenceRepository preferenceRepository;
3:
4: @Inject
5: public SettingsPresenter(IPreferenceRepository preferenceRepository) {
6: this.preferenceRepository = preferenceRepository;
7: }
8:
9: @Override
10: public void InitializeWith(ISettingsActivity activity) {
11: super.InitializeWith(activity);
12:
13: Preference preference = preferenceRepository.get();
14: getActivity().setUserName(preference.getUserName());
15: getActivity().setPassword(preference.getPassword());
16: }
17:
18: public void Save(String userName, String password) {
19: preferenceRepository.save(userName, password);
20: }
21: }
The implementation is pretty simple. About the only thing to note is the @Inject on the constructor. This is what signals Roboguice to use that constructor when an instance of the SettingsPresenter is requested.
This brings us to the activity. Remember, this is activated by Android when an Intent is fired that this activity matches. I'll talk about firing intents in a future part, but for now, it's enough to know that the activity will be created for us.
Whether you realized it or not, we defined an interface for our activity:
1: public interface ISettingsActivity extends IActivity {
2: void setUserName(String userName);
3: void setPassword(String password);
4: }
We also know that the activity will have a couple of text boxes and a button, and when the button is clicked, it should call Save() on our presenter. With that knowledge, we can implement our activity. To get injection working for Roboguice, our activities will extend GuiceActivity. And of course, we'll need to implement our ISettingsActivity interface.
Before we dive into the code, another nice thing that Roboguice provides for you is injection of screen elements. Normally, you would have a field to represent the screen element like this:
1: private TextView getUserName() {
2: (TextView) findViewById(R.id.user_name);
3: }
With Roboguice, this becomes:
1: @InjectView(R.id.user_name) protected TextView userName;
It's not a huge savings, but it looks much cleaner when viewing an activity with a lot of UI elements. Anyway, onto the activity.
1: public class settings extends GuiceActivity implements ISettingsActivity {
2: @Inject protected SettingsPresenter presenter;
3: @InjectView(R.id.save) protected Button saveButton;
4: @InjectView(R.id.user_name) protected TextView userName;
5: @InjectView(R.id.password) protected TextView password;
6:
7: @Override
8: public void onCreate(Bundle savedInstanceState) {
9: super.onCreate(savedInstanceState);
10: setContentView(R.layout.settings);
11: saveButton.setOnClickListener(saveClick);
12: presenter.InitializeWith(this);
13: }
14:
15: public void setUserName(String userName) {
16: this.userName.setText(userName);
17: }
18:
19: public void setPassword(String password) {
20: this.password.setText(password);
21: }
22:
23: private OnClickListener saveClick = new OnClickListener() {
24: @Override
25: public void onClick(View v) {
26: presenter.Save(userName.getText().toString();, password.getText().toString());
27: finish();
28: }
29: };
30: }
I have fields for the three elements: userName, password and the saveButton. I marked my presenter with @Inject so that it gets instantiated for me, and then I'm calling presenter.InitializeWith(this) in the onCreate method. I'm also wiring up the save button to call presenter.Save() when clicked.
At this point, we now have an activity that injects itself into the presenter, a presenter that handles setting up the activity, and then processes actions taken on the activity.
I've purposely left out a couple of things from this: how Roboguice is actually wired up and the different XML files that Android needs to layout the UI. I do plan to cover those in future parts, starting next time with more information about Roboguice.
Categories: Android
Android Development, Part 1: Project Structure and Tools
posted on 09/01/10 at 08:13:55 am by Joel Ross
This is the first part of an ongoing series about my adventures in building my first (non-trivial) Android application. For more information about the application, you should peruse my series introduction.
I still don't plan to show any code yet, so I guess you can still consider this an introduction to the application. I feel it's important to talk about the tools and frameworks I'm using, and then talk about how I'm structuring my application.
First, the tools and libraries I'm using:
- Eclipse and the Android SDK: Just about every tutorial lists Eclipse as the editor, and for good reason. There's some nice features there, including a lot of nice refactorings. It's not quite as good as Resharper and Visual Studio, and I still fumble my way around a bit, but it gets the job done.
- Instinct: This is a BDD framework based on jMock that John Sonmez showed me. It doesn't use the AAA syntax that I'm used to, but it works and allows me to test code in roughly the same way that I'm used to. This uses jUnit to run the tests, which works well, since Eclipse has nice integration to run jUnit tests directly in the UI.
- Roboguice: Back when I spent more time in IRC, I remember Nate Kohari talking about how he based Ninject on Guice, a IoC container in the Java world. Well, Roboguice is essentially Guice, but with a few additions that make it easier to work with Android-specific objects. Since I work with Ninject on a daily basis, going with this just made sense.
- kSoap2: I'm communicating with existing SOAP web services from the Pay It Square site, so I'm using a fork of kSoap2 specifically compiled for Android.
We're considering moving to a more REST-based interface for our web services, and if that happens, we'll swap out kSoap2 for something else. I've also thought about moving to using json for data transportation instead of XML, but that's down the road as well. V1 is top priority right now, and XML and SOAP work fine for now, as long as I properly insulate their usage.
I've been asked if I'm going to be using MonoDroid to build this application. The short answer is no. The slightly longer answer is that when I started building the application, I wasn't yet in the MonoDroid beta program (I am now), and I wanted to get a feel for what it's like to build for the Android platform using the toolset Google recommends. It's the same reason I would probably go with Objective C if/when we build an app for iPhone. I will definitely be exercising MonoDroid, but not for this, at least not right now.
On to project structure. Right now, I have three projects. First, I have my UI project, which contains all of my Activities, layout files, resources, and my application manifest. It's the only project that actually has a reference to the Android library.
Next, I have my core library. I'm using the MVP pattern, and this project contains all of my presenters. It contains any of my services, repositories and domain objects as well. It also has a series of interfaces I've created that wrap functionality in the Android libraries. I've done the work to create interfaces for all of the Android-specific functionality so that I can easily test the core library with my third project - my tests. Wrapping the interfaces gives me two things: 1.) It's testable, because I can't run Instinct's tests against any Android objects, and 2.) More importantly, it allows me define how my presenters will interact with the Android OS, rather than the other way around. That's not entirely true, but it sounds good, right?
Now that we've laid out the tools I'm using and the structure of my project, it's finally time to get into some code. In part 2, I'll get into the details of how I'm actually wiring up my presenters and activities.
Categories: Android
Android Development, Part 0 of N: Introduction
posted on 08/25/10 at 09:00:00 am by Joel Ross
I've spent the last few weeks building my first Android application. I wanted to get my feet wet, but watching videos and reading about it just doesn't quite cut it for me, so I decided it was time to dive into a real application - the best way for me to learn. It took me a while, but I finally found an app worth building, so that's what I'm doing.
This is my first dip into the Java pool, so it's been a bit slow going - learning a new language (yes, it's very similar to C#, but different enough to trip me up every now and then), a new IDE, and a new environment. I've been doing mobile development at TrackAbout, but not for Android, so it's a bit different, although there are some similarities.
Anyway, I'm going to do a little series about Android development. No promise on how many articles it'll be or a schedule - just that since I'm going to be doing the development, I should write about my progress.
We'll start off with an overview of the application, so we're all on the same page and have an understanding of what will be built. I created a few mockup using Balsamiq Mockups, and while I'm sure the look will change, the functionality will be roughly the same. The application will be a mobile application for Pay It Square. For those not familiar with Pay It Square, it's a site that allows you to create collect pages so you can collect money from friends, do event registrations, or collect donations. We think allowing people to see and manage their collect pages on the go will be a great addition.
I didn't mock up all of the screens, but I have a few I'll share. The main screen will show you a list of your collect pages, along with a bit of information about each one, such as information about how many people have and haven't paid, how much each member owes, and how much you've collected so far. Once you select one of the collect pages, you're taken to a tabbed interface, where you can see a list of who's paid, who hasn't paid, and be able to add new payees. The screens are below.
For V1, we're mainly focusing on displaying information, rather than collecting it (with the exception of adding a payee). V2 will add more of that functionality, but we want to get something out the door soon, so we've limited scope to be able to accomplish that. The functionality required to implement these few screens (and a couple of others not shown) will be what I plan to cover in this series.
Categories: Android
What’s On My Phone
posted on 04/06/10 at 12:10:36 am by Joel Ross
I've been relatively quiet lately, and part of it's because I've been so busy with work and the NCAA tournament that I haven't had time. And in recent months, I've switched to be more a consumer of technology than a producer - in the form of a new phone. Well, not new, but relatively so. Back in November, I got a Motorola Droid - I actually got it the day it was released. I turned in my Touch Pro 2 (which I really liked) and moved to Android. It's not a move I've ever regretted.
Anyway, today, Dan Hounshell tweeted that he'd like to see a list of the apps I'm using on my phone, along with a promise to follow up with is own. I responded saying that sounded like a great idea - with the hope being that someone will point out an application that I'm missing.
I'll preface this by pointing out that I haven't purchased an app yet - every app listed is either free or the "light" version of a paid application. I'm not against paying for an app - it's just that I'm cheap, and I haven't found a key feature or app that's justified it.
So let's get started. The three apps I use the most are built-in: Mail, calendar and browser. I have 5 email accounts that I've added to my phone - my personal one (which is actually a consolidation of quite a few), my work one and three for Develomatic. They're all Google Apps accounts, so the integration is seamless. I've granted access to my work calendar from my personal Google account, and have various calendars for my personal account anyway, and they're all synced to my phone as well. I even have The Wife's calendar on my phone, so I no longer have to check the fridge to find out what's going on this weekend. The browser is also very sold, and I have a couple of bookmarks that I use all the time: Google Reader and Instapaper.
But that's not the real reason we're here, right? We're talking about what I've grabbed from the Marketplace. So let's get to it. I'll start with the apps on my home screen:
- Twidroid: From every review I've seen of twitter clients on Android, Twidroid is always number one. I tried a couple others early on, and none even came close.
- Google Maps: It's technically built in as well, but it's worth highlighting. It comes with free voice navigation which works very well. I love that it zooms in and out based on how fast I'm going.
- Foursquare: I don't use Foursquare like most people do, I don't think. I have no friends on it, and when I check in somewhere, it doesn't tweet that or post it to Facebook. But I still try to check in where ever I go. I used it extensively on our recent trip to Hawaii and have used it to remember a few places that we went to while we were there. I do find it a bit ironic that I'm the "mayor" of more places in Hawaii than in Michigan though!
- Bible from YouVersion.com: I like that they have quite a few reading plans and it syncs those plans between the web and my phone so I can remember where I am.
- CalWidget: While not technically an application, it does take up 1/2 of my main screen. The default calendar widget doesn't do it for me. This gives me a lot of customizations for what I want to show up from my calendar, what size I want it to be, and how I want it to look. Both The Wife and I use it and love it.
The Droid only has 3 screens. What's listed above covers the main screen. One of the other screens contains links to direct dial contacts - The Wife (both home and mobile), parents, friends, etc. I also have the "Power Control" widget so I can quickly turn on and off wireless and Bluetooth.
The last screen contains programs I use often, but not all the time.
- Games Folder
- ThrottleCopter: Such a simple game, but it's addicting. Basically, you press the screen, the copter goes up. Release and it goes down, and your goal is not to hit the top or bottom of the cave.
- Robo Defense: I haven't played this in a while because it's too addicting. I played quite a few games over the course of a couple of weeks, and realized I was wasting 30-45 minutes at a time. Still, I love the tower defense type games.
- Flight Director: This is probably my favorite game I have. Planes come on the screen and you use your finger to draw a path to the runway. Your goal? Land as many planes as you can without any crashing.
- Toss It: Another simple game. Take a balled up piece of paper and "toss" it into a trash can while a fan is blowing at different speeds. I think it would be a lot cooler if it used the accelerometer, but it's still something that you can play for to kill a few minutes.
- ShopSavvy: Two weeks after I got my Droid, my garbage disposal decided that leaking water into the area where the power connected would be a good idea. After numerous blown circuits, I headed to Home Depot to get a replacement. I found a 1/2 HP replacement. On a whim, I scanned it with ShopSavvy and found it online for 1/2 the price, and realized it's reviews were awful. As a result, I bought a 1 HP garbage disposal that was highly rated for the same price. Yeah, ShopSavvy is a keeper.
- KeePassDroid: I've use KeePass to save all of my passwords on my laptop/desktop for years. Being able to access that same info on my phone is nice, although I do wish that it supported the 2.x file format, but alas, I'm stuck on 1.x for now.
- Pandora: I work from home, so I use my desktop machine to play music most of the time, but the combo of my Droid and the AUX input on my car stereo is killer.
- Facebook: The Android Facebook app is pretty weak. I don't use this a lot other than for its ability to sync Facebook contacts with my phone contacts. If I want to go to Facebook, I'll just go to their mobile interface (not m.facebook.com though - touch.facebook.com is a far better experience).
- Key Ring: This stores all of the store shopping cards in my phone so I don't have to carry them. Sounds great, except a lot of scanners don't work well with the shiny screen on the Droid. But for the ones that work, it's great!
- Aldiko: I haven't found a book reader that I love (Amazon, where are you?) but Aldiko is best I've found. It's slow, but it allows me to read an ebook on the go.
- TripIt: I use this rarely, since I don't travel like I used to, but when I do travel, it's nice to have all of my travel plans handy.
- Fring: IM and Skype on my phone. Not sure I really want to have IM capabilities on my phone, but at times it does come in handy.
- Google Voice: I don't use this to it's full extent mainly because I don't want to go through the hassle of telling everyone I know I have a new number. But I do give out my Voice number any time I have to fill out a phone number online or call someone that I really don't want to have my number.
- Evernote: I use this mainly for reading notes I've taken on my desktop, but it's nice to have the option to take notes if I have to.
Those are the main applications that I use. I have others installed, and while they're decent applications, they're just not ones I use all the time:
- AppBrain: I like the idea here. Install this, and then go to their website. You can search the market place and select apps to install and they get installed on your phone. And it keeps track of the apps you have installed for you online. This seems like the perfect thing to have if I ever needed to swap out my phone for another one.
- Gesture Search: Google released this and it's pretty cool. I just don't think to open it. It seems to me that this belongs as part of the OS rather than an app living in isolation.
- PapiRiver: I'm a sucker for games that use the accelerometer. This is one that does.
- Read Later: This isn't really an application. It provides an option for the browser's "Share" menu to save the current URL to Instapaper, which I use all the time.
- Skype mobile: The official Skype app on Android. It only works over 3G, which seems a little odd to me, but whatever. It works good in test. I'll have to try doing our daily stand up meeting one day.
- TasKiller: I use this rarely, but every now and then, I use it to kill an app. Simple, but effective.
- The Weather Channel: This one ends up living in the Notification area and I can always see the current temp where I'm at. It also shows me any warnings in the area by turning red. It's one I end up using all the time, but never really think about the fact that I'm using it.
I linked a few of the apps, but for the rest, they either don't have a dedicated web page, or it's just easier to search in the Android Marketplace.
There are a few things that I'm missing though and would really, really like to see:
- DropBox: I already use Dropbox to sync my Keepass password file between different machines. I'd like to have it automatically do that on my phone too. It's coming, but I want it now!
- Kindle App: I recently turned 3G on my Kindle on long enough to sync where I was in a book between it and my desktop (because The Wife keeps stealing the Kindle!). If there was a version of the Kindle software for Android, I'd leave it on permanantly.
- Instapaper: Yeah, the mobile web page is nice, but I'd really like to see a native application. The author of Instapaper states he has no plans for this, because he doesn't have time. That's unfortunate. What's more unfortunate is that the API doesn't allow you to build your own. Maybe someday.
That's what's on my phone. What's on yours? What am I missing?
Categories: Software









