protected static void interactResult(int decisionId, int choice) {
   MTMDecision d;
   synchronized (openDecisions) {
     d = openDecisions.get(decisionId);
     openDecisions.remove(decisionId);
   }
   if (d == null) {
     LOGGER.log(Level.SEVERE, "interactResult: aborting due to stale decision reference!");
     return;
   }
   synchronized (d) {
     d.state = choice;
     d.notify();
   }
 }
  public static void interactResult(Intent i) {
    int decisionId = i.getIntExtra(DECISION_INTENT_ID, MTMDecision.DECISION_INVALID);
    int choice = i.getIntExtra(DECISION_INTENT_CHOICE, MTMDecision.DECISION_INVALID);
    Log.d(TAG, "interactResult: " + decisionId + " chose " + choice);
    Log.d(TAG, "openDecisions: " + openDecisions);

    MTMDecision d;
    synchronized (openDecisions) {
      d = openDecisions.get(decisionId);
      openDecisions.remove(decisionId);
    }
    if (d == null) {
      Log.e(TAG, "interactResult: aborting due to stale decision reference!");
      return;
    }
    synchronized (d) {
      d.state = choice;
      d.notify();
    }
  }
  void interact(final X509Certificate[] chain, String authType, CertificateException cause)
      throws CertificateException {
    /* prepare the MTMDecision blocker object */
    MTMDecision choice = new MTMDecision();
    final int myId = createDecisionId(choice);
    final String certMessage = certChainMessage(chain, cause);
    BroadcastReceiver decisionReceiver =
        new BroadcastReceiver() {
          public void onReceive(Context ctx, Intent i) {
            interactResult(i);
          }
        };
    master.registerReceiver(
        decisionReceiver, new IntentFilter(DECISION_INTENT + "/" + master.getPackageName()));
    LaunchRunnable lr = new LaunchRunnable(myId, certMessage);
    masterHandler.post(lr);

    Log.d(TAG, "openDecisions: " + openDecisions);
    Log.d(TAG, "waiting on " + myId);
    try {
      synchronized (choice) {
        choice.wait();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    master.unregisterReceiver(decisionReceiver);
    if (lr.launchNotifReceiver != null) master.unregisterReceiver(lr.launchNotifReceiver);
    Log.d(TAG, "finished wait on " + myId + ": " + choice.state);
    switch (choice.state) {
      case MTMDecision.DECISION_ALWAYS:
        storeCert(chain);
      case MTMDecision.DECISION_ONCE:
        break;
      default:
        throw (cause);
    }
  }
  int interact(final String message, final int titleId) {
    /* prepare the MTMDecision blocker object */
    MTMDecision choice = new MTMDecision();
    final int myId = createDecisionId(choice);

    masterHandler.post(
        new Runnable() {
          public void run() {
            Intent ni = new Intent(master, MemorizingActivity.class);
            ni.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
            ni.putExtra(DECISION_INTENT_ID, myId);
            ni.putExtra(DECISION_INTENT_CERT, message);
            ni.putExtra(DECISION_TITLE_ID, titleId);

            // we try to directly start the activity and fall back to
            // making a notification
            try {
              getUI().startActivity(ni);
            } catch (Exception e) {
              LOGGER.log(Level.FINE, "startActivity(MemorizingActivity)", e);
              startActivityNotification(ni, myId, message);
            }
          }
        });

    LOGGER.log(Level.FINE, "openDecisions: " + openDecisions + ", waiting on " + myId);
    try {
      synchronized (choice) {
        choice.wait();
      }
    } catch (InterruptedException e) {
      LOGGER.log(Level.FINER, "InterruptedException", e);
    }
    LOGGER.log(Level.FINE, "finished wait on " + myId + ": " + choice.state);
    return choice.state;
  }