Sunday, July 31, 2011

Android library setup & licensing

Ok, we've got our main project set up as a library, and have set up a mini-project which just invokes virtually all the functionality of the library. There's one small issue to clear up before we tackle bring the licensing - somehow or other, one of the headings of the project has gotten messed up.

One way to get rid of it is get rid of the heading in the layout. Anyway, this will flag where it gets updated. I can put it back in later.

Ah, ok, I had changed the heading in strings.xml, to this:

Jlpt Vocabulary Quiz Level 4

And in the manifest, I had been referencing that same heading as the app label.

So what I can do is change the label to something easy and short.



Jlpt 4 Quiz


It will pull all the other strings from the library project.

Ok, let's see how this looks...yup. Great.

Hmm...the zero/zero on the start and end quiz numbers. Did they get stored as zero? This is a bit disturbing. Somehow I thought I had eliminated that.

I'm going to at least put a safegaurd in. Once I read it from memory, if it's zeros, I'm going to set the start to 1 and the end to the default quiz size.

Ok, that's taken care. Now, the licensing. Unfortunately, Google doesn't let you upload the licensing code if it's free. So, I think I need to pull that into a different library. Then, in the free app projects, I don't include that library, and in the paid apps, I do. I'm just struggling a bit with how to work that in.

Well, first off, it can't be accessed from the "main" library, as that's going to be used by both the free and paid versions. Also, it can't be accessed from the free version of the shell projects. So, it's only accessible from the paid versions of the shell projects. So, each shell project should look something like this:

public class BootStrapActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// validation code goes here

Intent i = new Intent(BootStrapActivity.this,
StartActivity.class);

startActivity(i);

}
}


So, let's just move it from the call to validation into this code.


if (false == appState.licensed){
validateLicense();
}



private void validateLicense() {
new ValidateLicense().valdidateLicense(this);
}


Oh, and I'm moving a lot of the primitive state out of AppState, which is just a duplicate of shared preferences.


public static boolean getLicensed(AppState appState){

SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(appState);


if (sharedPreferences.contains(InitUtils.LICENSED)) {
return sharedPreferences.getBoolean(InitUtils.LICENSED, false);
}

return false;
}


public static void setLicensed(AppState appState, boolean licensed) {

SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(appState);

SharedPreferences.Editor prefEditor = sharedPreferences.edit();

prefEditor.putBoolean(InitUtils.LICENSED, licensed);

prefEditor.commit();

}

Ok, now we have code like this:

if (false == licensed){
validateLicense();
}


Intent i = new Intent(BootStrapActivity.this,
StartActivity.class);

startActivity(i);

private void validateLicense() {

// this uses a callback to inform the app if the license is valid
new ValidateLicense().valdidateLicense(this);
}


Now, we have to jump back into the validate code and redo it to refer back to the BootStrapActivity instead of the StartActivity.


And change this in the success callback:

SharedPreferencesUtil.setLicensed(appState, true);


We still have to leave the awkward initiation of the download in the callback validation, so it doesn't get kicked off before an unlicensed callback kill the app.

Ok, let's take a look:

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

AppState appState = (AppState) this.getApplication();
boolean licensed = SharedPreferencesUtil.getLicensed(appState);

if (false == licensed){
validateLicense();
}

Intent i = new Intent(BootStrapActivity.this,
StartActivity.class);

startActivity(i);
}


Ok, clean up the interior references,

if (false == SharedPreferencesUtil.getLicensed(appState)) {
finish();
}


Ok, let's get a test in...

Hmm...it doesn't seem to have called the validation. I think what happened is, because I haven't gone through Panera's gateway, I'm connected to a network, but it's not getting a response from the server. This normally display a dialog box saying it's checking but in this case, it just called the start activity, probably killing the dialog.

Ok. Here's the solution. In the paid version, I can just call the start activity on a success in the validation. This will allow me to move the download of the media files back into start activity, where it belongs, and with only one call. Much cleaner. And in the free version, I just call StartActivity directly.


In the validateLicense:

Intent i = new Intent(ValidateLicense.this.mActivity, StartActivity.class);
ValidateLicense.this.mActivity.startActivity(i);

I can also check if it's already validated in the BootStrapActivity, and skip the validation:


AppState appState = (AppState) this.getApplication();
boolean licensed = SharedPreferencesUtil.getLicensed(appState);

if (false == licensed) {
validateLicense();
}

else {

Intent i = new Intent(BootStrapActivity.this, StartActivity.class);
startActivity(i);

}

Let's try it.

Ah, much better. I"m getting the "MarketNotManaged" message, which means I haven't added the app yet. Ok, let's upload of draft version of the apk.

This post is getting a bit long, so I'll address that in the next one.

No comments:

Post a Comment