title: Why is Android's LVL locking me out of my own app?
body: <p>I recently added Android's LVL copy protection to my app, and the results have been erratic to say the least.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <pre><code>public class Main extends Activity {
  private static final byte[] SALT = { &lt;salt&gt; };
  private static final String B64 = "&lt;base 64 key&gt;";
  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(&lt;license refused message&gt;));
      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=&lt;package name&gt;"));
                  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(&lt;application error message&gt;);
      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();
      }
  }
  </code></pre>
  
  <p>}</p>