From: Nathaniel Wesley Filardo Date: Thu, 8 Jul 2010 05:22:55 +0000 (-0400) Subject: Fix application resumption while computing in the background X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=88bca660468c1642c96661d06d8c5e526b726e7d;p=android-vcpass Fix application resumption while computing in the background --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c982d87..4232e58 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -11,7 +11,7 @@ - + diff --git a/src/org/ietfng/ns/android/vcpass/VCPass.java b/src/org/ietfng/ns/android/vcpass/VCPass.java index 6de8978..b65f319 100644 --- a/src/org/ietfng/ns/android/vcpass/VCPass.java +++ b/src/org/ietfng/ns/android/vcpass/VCPass.java @@ -54,7 +54,7 @@ public class VCPass extends Activity Log.i("VCPass", "CREATE"); - if(0) { + if(false) { PackageManager pm = getPackageManager(); Intent intent = new Intent("org.ietfng.ns.android.vcpass.CHAL_PRESENT"); ResolveInfo ri = pm.resolveActivity(intent, 0); diff --git a/src/org/ietfng/ns/android/vcpass/VCPassActivity.java b/src/org/ietfng/ns/android/vcpass/VCPassActivity.java index 8d46be4..154087d 100644 --- a/src/org/ietfng/ns/android/vcpass/VCPassActivity.java +++ b/src/org/ietfng/ns/android/vcpass/VCPassActivity.java @@ -25,6 +25,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Bundle; +import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.util.Log; @@ -145,9 +146,19 @@ extends Activity /* * * * * * Private state * * * * * */ - private Resources res; // Android - private int[] response; // For state saving - private Thread calcThread; + private Resources res; // Android + private int[] response; // For state saving + private CalcState calcstate; // For onRetainNonConfigurationInstance + + private class CalcState { + Handler uih; // UI thread waiting for results + VCPassActivity self; // The object of the UI + + Thread calcThread; // The worker + Intent spawner; // The intent which spawned it, + // also used as the callback intent. + String e; // Error + }; /* * * * * * Private utility functions * * * * * */ @@ -158,15 +169,6 @@ extends Activity finish(); } - private final void - postYieldError(final Intent s, final String e) { - runOnUiThread(new Runnable(){ - public final void run() { - yieldError(s,e); - } - }); - } - /** Prepare an int array for use as a response store */ private static final void resetResponse(int[] chal) { @@ -241,6 +243,32 @@ extends Activity } } + private static final void update_canvas_touch( + Canvas c, + Paint p, + int ix) + { + int x = ix % VCParameters.GRID_X; + int y = ix / VCParameters.GRID_X; + + float w = c.getWidth(); + float h = c.getHeight(); + + Rect sq = new Rect((int)(x*w + /VCParameters.GRID_X + ), + (int)(y*h + /VCParameters.GRID_Y + ), + (int)((x+1)*w + /VCParameters.GRID_X + ), + (int)((y+1)*h + /VCParameters.GRID_Y + )); + c.drawRect(sq, p); + } + private final class VCPassTouchHandler implements View.OnTouchListener { @@ -248,11 +276,10 @@ extends Activity private Canvas c; private Paint p; - public VCPassTouchHandler(Canvas c, int[] r) { + public VCPassTouchHandler(Canvas c, Paint p, int[] r) { this.r = r; this.c = c; - p = new Paint(); - p.setARGB(127,0,255,0); + this.p = p; } private int expected_motion = MotionEvent.ACTION_DOWN; @@ -304,25 +331,13 @@ extends Activity label = VCParameters.VCVOC_DISTING_UP; } } - r[VCParameters.GRID_X*last_down_y - + last_down_x] = label; + int ix = VCParameters.GRID_X*last_down_y + last_down_x; + r[ix] = label; expected_motion = MotionEvent.ACTION_DOWN; - Rect sq = new Rect((int)(last_down_x*w - /VCParameters.GRID_X - ), - (int)(last_down_y*h - /VCParameters.GRID_Y - ), - (int)((last_down_x+1)*w - /VCParameters.GRID_X - ), - (int)((last_down_y+1)*h - /VCParameters.GRID_Y - )); - Log.d("VCPTH", encodeResponse(r).toString()); - c.drawRect(sq, p); + // Log.d("VCPTH", encodeResponse(r).toString()); + update_canvas_touch(c,p,ix); v.invalidate(); } else { throw new RuntimeException("Unexpected action:" + action + "\n"); @@ -398,25 +413,27 @@ extends Activity return; } - /* - * XXX Do we have to draw blanks here? Does our graphic state - * get saved for us? - */ - - Bitmap chal = origchal.copy(origchal.getConfig(), true); - Canvas c = new Canvas(chal); - // Switch off the titlebar // requestWindowFeature(Window.FEATURE_NO_TITLE); - // Lock orientation - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // Load layout setContentView(R.layout.vcpact); + // Lock orientation + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + + Bitmap chal = origchal.copy(origchal.getConfig(), true); + Canvas c = new Canvas(chal); + + Paint imgupdp = new Paint(); + imgupdp.setARGB(127,0,255,0); + + for(int ix = 0; ix < response.length; ix++) { + if(response[ix] != -1) { update_canvas_touch(c,imgupdp,ix); } + } ImageView imgview = (ImageView) findViewById(R.id.image); imgview.setScaleType(ImageView.ScaleType.FIT_CENTER); imgview.setImageBitmap(chal); - imgview.setOnTouchListener(new VCPassTouchHandler(c, response)); + imgview.setOnTouchListener(new VCPassTouchHandler(c, imgupdp, response)); imgview.getViewTreeObserver() .addOnPreDrawListener( new VCPassPreDrawListener(spawner, imgview, origchal)); @@ -551,50 +568,55 @@ extends Activity } - private final void - _intent_createChallenge(final Intent spawner, + private static final void + _intent_createChallenge(final CalcState cs, boolean quiet) { - char[] useed = spawner.getCharArrayExtra(EXTRA_USER_SLIDE_SEED ); - char[] vseed = spawner.getCharArrayExtra(EXTRA_VOCABULARY_SEED ); - int minevt = spawner.getIntExtra (EXTRA_MINIMUM_EVENTS, -1); + char[] useed = cs.spawner.getCharArrayExtra(EXTRA_USER_SLIDE_SEED ); + char[] vseed = cs.spawner.getCharArrayExtra(EXTRA_VOCABULARY_SEED ); + int minevt = cs.spawner.getIntExtra (EXTRA_MINIMUM_EVENTS, -1); if(useed == null || vseed == null) { - postYieldError(spawner, "Null seed"); + cs.e = "Null seed"; + cs.calcThread = null; + synchronized(cs) { + cs.calcThread = null; + finishIfAnswered(cs); + } return; } final VCGenerator.ProgCallback pcb = quiet ? null : new VCGenerator.ProgCallback() { public void progress(final int x) { - runOnUiThread(new Runnable() { - public final void run() { - getWindow().setFeatureInt( - Window.FEATURE_PROGRESS, - x*9000 - /VCParameters.GRID_X - /VCParameters.GRID_Y); - } - }); + if(cs.uih != null) { + cs.uih.post(new Runnable() { + public final void run() { + cs.self.getWindow().setFeatureInt( + Window.FEATURE_PROGRESS, + x*9000 + /VCParameters.GRID_X + /VCParameters.GRID_Y); + } + }); + } } }; CreatedChallenge cc = do_createChallenge(useed, vseed, minevt, pcb); if(cc.error != null) { - postYieldError(spawner, cc.error); - return; + cs.e = cc.error; + } else { + cs.spawner.putExtra(EXTRA_CHALLENGE, (Parcelable)cc.bm); + cs.spawner.putExtra(EXTRA_SECRET, cc.plain); + Log.d("VCPassAct_i_cC", cc.plain); + cs.calcThread = null; } - spawner.putExtra(EXTRA_CHALLENGE, (Parcelable)cc.bm); - spawner.putExtra(EXTRA_SECRET, cc.plain); - - calcThread = null; - - runOnUiThread(new Runnable() { - final public void run() { - setResult(RESULT_OK, spawner); - finish(); - } - }); + synchronized(cs) { + // This will either work or, if we're UIless, will get + // picked up on resume when the UI starts back up again + finishIfAnswered(cs); + } } private final void @@ -610,24 +632,58 @@ extends Activity setContentView(tv); } - calcThread = new Thread(new Runnable() { - public final void run() { - _intent_createChallenge(spawner, quiet); - } - }); - - calcThread.start(); + Object glnci = getLastNonConfigurationInstance(); + if(glnci != null) { + Log.d(DBGN, "glnci is nonnull, checking..."); + calcstate = (CalcState) glnci; + synchronized(calcstate) { + calcstate.uih = new Handler(); + calcstate.self = this; + finishIfAnswered(calcstate); + } + } else { + calcstate = new CalcState(); + calcstate.spawner = spawner; + calcstate.uih = new Handler(); + calcstate.self = this; + calcstate.calcThread = new Thread(new Runnable() { + public final void run() { + _intent_createChallenge(calcstate, quiet); + } + }); + + calcstate.calcThread.start(); + } } /* * * * * * Android interface core * * * * * */ + private static void finishIfAnswered(final CalcState cs) { + Runnable r = null; + if(cs.uih == null) { + Log.d(DBGN, "Null cs.uih; can't finish now!"); + return; + } + if(cs.e != null) { + r = new Runnable(){ public void run() { + cs.self.yieldError(cs.spawner,cs.e); + }}; + } else if(cs.calcThread == null) { + r = new Runnable(){ public void run() { + cs.self.setResult(RESULT_OK, cs.spawner); + cs.self.finish(); + }}; + } + if(r != null) { + cs.uih.post(r); + } + } + @Override public void onCreate(Bundle sis) { super.onCreate(sis); - Log.i(DBGN, "CREATE"); - res = getResources(); Intent spawner = getIntent(); @@ -648,9 +704,20 @@ extends Activity public void onPause() { super.onPause(); - if(isFinishing()) { - if(calcThread != null) { calcThread.interrupt(); } - } + Log.d(DBGN, "onPause"); + + if(calcstate != null) { + synchronized(calcstate) { + if(isFinishing()) { + if(calcstate.calcThread != null) { + calcstate.calcThread.interrupt(); + } + } + + finishIfAnswered(calcstate); + calcstate.uih = null; + } + } } @Override @@ -662,4 +729,10 @@ extends Activity outState.putIntArray(SAVED_STATE_KEY_RESPONSE, response); } } + + @Override + public Object onRetainNonConfigurationInstance() { + Log.d(DBGN, "ornci!"); + return calcstate; + } } diff --git a/src/org/ietfng/ns/android/vcpass/VCPassImport.java b/src/org/ietfng/ns/android/vcpass/VCPassImport.java index 7aebd63..41d82d8 100644 --- a/src/org/ietfng/ns/android/vcpass/VCPassImport.java +++ b/src/org/ietfng/ns/android/vcpass/VCPassImport.java @@ -14,7 +14,7 @@ public final class VCPassImport extends Activity { - private static final boolean TRY_QRCODE = false; + private static final boolean TRY_QRCODE = true; /* * * * * * Protocol parameters * * * * * */ @@ -68,7 +68,7 @@ extends Activity intent.putExtra(VCPassActivity.EXTRA_CHALLENGE,cfpc); intent.putExtra(VCPassActivity.EXTRA_PROMPT_TEXT, getString(R.string.import_test)); - Log.d("VCPass", intent.toString()); + Log.d(DBGN, intent.toString()); startActivityForResult(intent, REQ_PRESENT); } @@ -161,12 +161,19 @@ extends Activity finish(); } + @Override public void onActivityResult(int req, int res, Intent data) { + super.onActivityResult(req, res, data); + if(res == RESULT_CANCELED && req != REQ_PRESENT) { - setResult(RESULT_CANCELED, getIntent()); + Log.d(DBGN, "CANCEL?"); + setResult(RESULT_CANCELED, getIntent()); + finish(); + return; } if(data == null) { // being canceled; report failure upstream + Log.d(DBGN, "Null data?"); setResult(RESULT_CANCELED, null); finish(); return; @@ -185,6 +192,7 @@ extends Activity cfpc = (Bitmap) data.getParcelableExtra( VCPassActivity.EXTRA_CHALLENGE); cfps = data.getStringExtra(VCPassActivity.EXTRA_SECRET); + launchChallenger(); break; case REQ_PRESENT: @@ -224,32 +232,34 @@ extends Activity Log.i(DBGN, "CREATE"); + String act = getIntent().getAction(); + Log.d(DBGN, act); + if(sis != null) { useed = sis.getCharArray (SAVED_STATE_USEED); vseed = sis.getCharArray (SAVED_STATE_VSEED); cfpc = (Bitmap) sis.getParcelable(SAVED_STATE_CFPC ); cfps = sis.getString (SAVED_STATE_CFPS ); - } - - String act = getIntent().getAction(); - Log.d(DBGN, act); - - if (act.equals(ACTION_IMPORT_SEED) - || act.equals(ACTION_IMPORT_AND_CREATE)) { - importSeed(); - } else { - setResult(RESULT_CANCELED, null); - finish(); - } + } else { + if (act.equals(ACTION_IMPORT_SEED) + || act.equals(ACTION_IMPORT_AND_CREATE)) { + importSeed(); + } else { + setResult(RESULT_CANCELED, null); + finish(); + } + } } @Override public void onSaveInstanceState(Bundle outState) { + + Log.i(DBGN, "onSaveInstanceState"); + outState.putCharArray (SAVED_STATE_USEED, useed); outState.putCharArray (SAVED_STATE_VSEED, vseed); outState.putParcelable(SAVED_STATE_CFPC , cfpc ); outState.putString (SAVED_STATE_CFPS , cfps ); } - }