I recently added Android's LVL copy protection to my app, and the results have been erratic to say the least.
Every test response that I manually set in the developer's console appears to work as intended. However, when I set "Respond Normally", that's where the trouble starts. On Wednesday, I first uploaded the app, and shortly after it was listed in the market, it reported LICENSED as expected.
However, yesterday afternoon without any warning, my app suddenly is telling me i'm NOT_LICENSED. I did not make any changes to either the developer's console or the code up to this point. After discovering this, I immediately unpublished until I could find a solution. I've already tried clearing both the app's cache and Google Play's cache.
So, I don't know what I did wrong here. I installed my own app on my phone via APK out of Eclipse, instead of buying my own app from the market. To do a live test of LVL, do I have to actually buy my own app, or is uploading to the developer's page sufficient? My LVL code is practically a carbon-copy of the example page, which I did in the version to try to get working before further optimizing it. I've posted it here with some identifiable information clipped out.
public class Main extends Activity {
private static final byte[] SALT = { <salt> };
private static final String B64 = "<base 64 key>";
private dbHelper db = new dbHelper(this);
private int requestCode;
LicenseCheckerCallback mLCC;
LicenseChecker mC;
Handler mH;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkL();
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 1) {
startActivity(new Intent(Main.this, MainProfiler.class)); //callback for profile setup
finish();
}
}
protected void checkL() {
String a = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
mH = new Handler();
mLCC = new settingsResolved();
mC = new LicenseChecker(
this,
new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), a)),
B64);
mC.checkAccess(mLCC);
}
protected class settingsResolved implements LicenseCheckerCallback {
@Override
public void allow(int reason) {
//the application is licensed properly
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
//authorize access
startFromCallback();
}
@Override
public void dontAllow(int reason) {
//the application is not licensed properly
Log.e("Main", "LVL Failed!");
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
failFromCallback(reason);
}
@Override
public void applicationError(int errorCode) {
//an error occurred
Log.e("Main", "LVL Error!");
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
errorFromCallback(errorCode);
}
}
private void startProcedure() {
if (db.getRunOnce()) { //this is the first run
Intent i = new Intent(Main.this, ProfileSetup.class);
i.putExtra("NewProfile", true);
startActivityForResult(i, requestCode);
} else { //this is not the first run
startActivity(new Intent(Main.this, MainProfiler.class));
finish();
}
}
private void failureState(int reason) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle("LVL Error");
adb.setCancelable(false);
adb.setMessage(<license refused message>));
adb.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
if (reason != Policy.NOT_LICENSED) {// not NOT_LICENSED, meaning the error is not due to a licensing issue
adb.setNegativeButton("Check Again", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
checkL();
}
});
} else {
adb.setNegativeButton("Google Play", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("market://details?id=<package name>"));
startActivity(i);
finish();
}
});
}
adb.create().show();
}
private void applicationError(int errorCode) {
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setTitle("LVL Error");
adb.setCancelable(false);
adb.setMessage(<application error message>);
adb.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
adb.create().show();
}
private void startFromCallback() {
mH.post(new Runnable() {
public void run() {
Log.i("LVL", "License Pass!");
startProcedure();
}
});
}
private void failFromCallback(final int reason) {
mH.post(new Runnable() {
public void run() {
failureState(reason);
}
});
}
private void errorFromCallback(final int errorCode) {
mH.post(new Runnable() {
public void run() {
applicationError(errorCode);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mC != null) {
mC.onDestroy();
}
}
}