public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // This is called when a new Loader needs to be created. This
    // sample only has one Loader, so we don't care about the ID.
    // First, pick the base URI to use depending on whether we are
    // currently filtering.
    Uri baseUri = KeyRings.buildSecretKeyRingsUri();

    // Now create and return a CursorLoader that will take care of
    // creating a Cursor for the data being displayed.
    return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER);
  }
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
     case android.R.id.home:
       {
         Intent viewIntent = NavUtils.getParentActivityIntent(this);
         viewIntent.setData(KeyRings.buildGenericKeyRingUri(mDataUri));
         NavUtils.navigateUpTo(this, viewIntent);
         return true;
       }
   }
   return super.onOptionsItemSelected(item);
 }
  public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    setContentShown(false);
    switch (id) {
      case LOADER_ID_UNIFIED:
        {
          Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
          return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
        }

      default:
        return null;
    }
  }
  /**
   * If an Intent gives a signatureMasterKeyId and/or encryptionMasterKeyIds, preselect those!
   *
   * @param preselectedSignatureKeyId
   * @param preselectedEncryptionKeyIds
   */
  private void preselectKeys(
      long preselectedSignatureKeyId,
      long[] preselectedEncryptionKeyIds,
      ProviderHelper providerHelper) {
    if (preselectedSignatureKeyId != 0) {
      // TODO: don't use bouncy castle objects!
      try {
        PGPSecretKeyRing keyRing =
            providerHelper.getPGPSecretKeyRingWithKeyId(preselectedSignatureKeyId);

        PGPSecretKey masterKey = keyRing.getSecretKey();
        if (masterKey != null) {
          PGPSecretKey signKey = PgpKeyHelper.getFirstSigningSubkey(keyRing);
          if (signKey != null) {
            setSignatureKeyId(masterKey.getKeyID());
          }
        }
      } catch (ProviderHelper.NotFoundException e) {
        Log.e(Constants.TAG, "key not found!", e);
      }
    }

    if (preselectedEncryptionKeyIds != null) {
      Vector<Long> goodIds = new Vector<Long>();
      for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
        // TODO One query per selected key?! wtf
        try {
          long id =
              providerHelper.getMasterKeyId(
                  KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
                      Long.toString(preselectedEncryptionKeyIds[i])));
          goodIds.add(id);
        } catch (ProviderHelper.NotFoundException e) {
          Log.e(Constants.TAG, "key not found!", e);
        }
      }
      if (goodIds.size() > 0) {
        long[] keyIds = new long[goodIds.size()];
        for (int i = 0; i < goodIds.size(); ++i) {
          keyIds[i] = goodIds.get(i);
        }
        setEncryptionKeyIds(keyIds);
      }
    }
  }
  private void uploadKey() {
    // Send all information needed to service to upload key in other thread
    Intent intent = new Intent(this, KeychainIntentService.class);

    intent.setAction(KeychainIntentService.ACTION_UPLOAD_KEYRING);

    // set data uri as path to keyring
    Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
    intent.setData(blobUri);

    // fill values for this action
    Bundle data = new Bundle();

    String server = (String) mKeyServerSpinner.getSelectedItem();
    data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, server);

    intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

    // Message is received after uploading is done in KeychainIntentService
    KeychainIntentServiceHandler saveHandler =
        new KeychainIntentServiceHandler(
            this, getString(R.string.progress_uploading), ProgressDialog.STYLE_HORIZONTAL) {
          public void handleMessage(Message message) {
            // handle messages by standard KeychainIntentServiceHandler first
            super.handleMessage(message);

            if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {

              Toast.makeText(UploadKeyActivity.this, R.string.key_send_success, Toast.LENGTH_SHORT)
                  .show();
              finish();
            }
          }
        };

    // Create a new Messenger for the communication back
    Messenger messenger = new Messenger(saveHandler);
    intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);

    // show progress dialog
    saveHandler.showProgressDialog(this);

    // start service with intent
    startService(intent);
  }
  /** Signs and/or encrypts data based on parameters of class */
  public PgpSignEncryptResult execute(
      PgpSignEncryptInputParcel input,
      CryptoInputParcel cryptoInput,
      InputData inputData,
      OutputStream outputStream) {

    int indent = 0;
    OperationLog log = new OperationLog();

    log.add(LogType.MSG_PSE, indent);
    indent += 1;

    boolean enableSignature = input.getSignatureMasterKeyId() != Constants.key.none;
    boolean enableEncryption =
        ((input.getEncryptionMasterKeyIds() != null && input.getEncryptionMasterKeyIds().length > 0)
            || input.getSymmetricPassphrase() != null);
    boolean enableCompression = (input.getCompressionId() != CompressionAlgorithmTags.UNCOMPRESSED);

    Log.d(
        Constants.TAG,
        "enableSignature:"
            + enableSignature
            + "\nenableEncryption:"
            + enableEncryption
            + "\nenableCompression:"
            + enableCompression
            + "\nenableAsciiArmorOutput:"
            + input.isEnableAsciiArmorOutput()
            + "\nisHiddenRecipients:"
            + input.isHiddenRecipients());

    // add additional key id to encryption ids (mostly to do self-encryption)
    if (enableEncryption && input.getAdditionalEncryptId() != Constants.key.none) {
      input.setEncryptionMasterKeyIds(
          Arrays.copyOf(
              input.getEncryptionMasterKeyIds(), input.getEncryptionMasterKeyIds().length + 1));
      input.getEncryptionMasterKeyIds()[input.getEncryptionMasterKeyIds().length - 1] =
          input.getAdditionalEncryptId();
    }

    ArmoredOutputStream armorOut = null;
    OutputStream out;
    if (input.isEnableAsciiArmorOutput()) {
      armorOut = new ArmoredOutputStream(new BufferedOutputStream(outputStream, 1 << 16));
      if (input.getVersionHeader() != null) {
        armorOut.setHeader("Version", input.getVersionHeader());
      }
      // if we have a charset, put it in the header
      if (input.getCharset() != null) {
        armorOut.setHeader("Charset", input.getCharset());
      }
      out = armorOut;
    } else {
      out = outputStream;
    }

    /* Get keys for signature generation for later usage */
    CanonicalizedSecretKey signingKey = null;
    if (enableSignature) {

      updateProgress(R.string.progress_extracting_signature_key, 0, 100);

      try {
        // fetch the indicated master key id (the one whose name we sign in)
        CanonicalizedSecretKeyRing signingKeyRing =
            mProviderHelper.getCanonicalizedSecretKeyRing(input.getSignatureMasterKeyId());

        // fetch the specific subkey to sign with, or just use the master key if none specified
        signingKey = signingKeyRing.getSecretKey(input.getSignatureSubKeyId());

        // Make sure we are allowed to sign here!
        if (!signingKey.canSign()) {
          log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent);
          return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
        }

        switch (signingKey.getSecretKeyType()) {
          case DIVERT_TO_CARD:
          case PASSPHRASE_EMPTY:
            {
              if (!signingKey.unlock(new Passphrase())) {
                throw new AssertionError(
                    "PASSPHRASE_EMPTY/DIVERT_TO_CARD keyphrase not unlocked with empty passphrase."
                        + " This is a programming error!");
              }
              break;
            }

          case PIN:
          case PATTERN:
          case PASSPHRASE:
            {
              Passphrase localPassphrase = cryptoInput.getPassphrase();
              if (localPassphrase == null) {
                try {
                  localPassphrase =
                      getCachedPassphrase(signingKeyRing.getMasterKeyId(), signingKey.getKeyId());
                } catch (PassphraseCacheInterface.NoSecretKeyException ignored) {
                }
              }
              if (localPassphrase == null) {
                log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1);
                return new PgpSignEncryptResult(
                    log,
                    RequiredInputParcel.createRequiredSignPassphrase(
                        signingKeyRing.getMasterKeyId(),
                        signingKey.getKeyId(),
                        cryptoInput.getSignatureTime()),
                    cryptoInput);
              }
              if (!signingKey.unlock(localPassphrase)) {
                log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent);
                return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
              }
              break;
            }

          case GNU_DUMMY:
            {
              log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent);
              return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
            }
          default:
            {
              throw new AssertionError("Unhandled SecretKeyType! (should not happen)");
            }
        }

      } catch (ProviderHelper.NotFoundException e) {
        log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent);
        return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
      } catch (PgpGeneralException e) {
        log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent);
        return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
      }

      // Use preferred hash algo
      int requestedAlgorithm = input.getSignatureHashAlgorithm();
      ArrayList<Integer> supported = signingKey.getSupportedHashAlgorithms();
      if (requestedAlgorithm == PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED) {
        // get most preferred
        input.setSignatureHashAlgorithm(supported.get(0));
      } else if (!supported.contains(requestedAlgorithm)) {
        log.add(LogType.MSG_PSE_ERROR_HASH_ALGO, indent);
        return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
      }
    }
    updateProgress(R.string.progress_preparing_streams, 2, 100);

    /* Initialize PGPEncryptedDataGenerator for later usage */
    PGPEncryptedDataGenerator cPk = null;
    if (enableEncryption) {

      // Use preferred encryption algo
      int algo = input.getSymmetricEncryptionAlgorithm();
      if (algo == PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED) {
        // get most preferred
        // TODO: get from recipients
        algo = PgpConstants.sPreferredSymmetricAlgorithms.get(0);
      }
      // has Integrity packet enabled!
      JcePGPDataEncryptorBuilder encryptorBuilder =
          new JcePGPDataEncryptorBuilder(algo)
              .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
              .setWithIntegrityPacket(true);

      cPk = new PGPEncryptedDataGenerator(encryptorBuilder);

      if (input.getSymmetricPassphrase() != null) {
        // Symmetric encryption
        log.add(LogType.MSG_PSE_SYMMETRIC, indent);

        JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
            new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().getCharArray());
        cPk.addMethod(symmetricEncryptionGenerator);
      } else {
        log.add(LogType.MSG_PSE_ASYMMETRIC, indent);

        // Asymmetric encryption
        for (long id : input.getEncryptionMasterKeyIds()) {
          try {
            CanonicalizedPublicKeyRing keyRing =
                mProviderHelper.getCanonicalizedPublicKeyRing(KeyRings.buildUnifiedKeyRingUri(id));
            Set<Long> encryptSubKeyIds = keyRing.getEncryptIds();
            for (Long subKeyId : encryptSubKeyIds) {
              CanonicalizedPublicKey key = keyRing.getPublicKey(subKeyId);
              cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients()));
              log.add(
                  LogType.MSG_PSE_KEY_OK,
                  indent + 1,
                  KeyFormattingUtils.convertKeyIdToHex(subKeyId));
            }
            if (encryptSubKeyIds.isEmpty()) {
              log.add(
                  LogType.MSG_PSE_KEY_WARN, indent + 1, KeyFormattingUtils.convertKeyIdToHex(id));
              if (input.isFailOnMissingEncryptionKeyIds()) {
                return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
              }
            }
          } catch (ProviderHelper.NotFoundException e) {
            log.add(
                LogType.MSG_PSE_KEY_UNKNOWN, indent + 1, KeyFormattingUtils.convertKeyIdToHex(id));
            if (input.isFailOnMissingEncryptionKeyIds()) {
              return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
            }
          }
        }
      }
    }

    /* Initialize signature generator object for later usage */
    PGPSignatureGenerator signatureGenerator = null;
    if (enableSignature) {
      updateProgress(R.string.progress_preparing_signature, 4, 100);

      try {
        boolean cleartext =
            input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption;
        signatureGenerator =
            signingKey.getDataSignatureGenerator(
                input.getSignatureHashAlgorithm(),
                cleartext,
                cryptoInput.getCryptoData(),
                cryptoInput.getSignatureTime());
      } catch (PgpGeneralException e) {
        log.add(LogType.MSG_PSE_ERROR_NFC, indent);
        return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
      }
    }

    ProgressScaler progressScaler = new ProgressScaler(mProgressable, 8, 95, 100);
    PGPCompressedDataGenerator compressGen = null;
    OutputStream pOut;
    OutputStream encryptionOut = null;
    BCPGOutputStream bcpgOut;

    ByteArrayOutputStream detachedByteOut = null;
    ArmoredOutputStream detachedArmorOut = null;
    BCPGOutputStream detachedBcpgOut = null;

    try {

      if (enableEncryption) {
        /* actual encryption */
        updateProgress(R.string.progress_encrypting, 8, 100);
        log.add(enableSignature ? LogType.MSG_PSE_SIGCRYPTING : LogType.MSG_PSE_ENCRYPTING, indent);
        indent += 1;

        encryptionOut = cPk.open(out, new byte[1 << 16]);

        if (enableCompression) {
          log.add(LogType.MSG_PSE_COMPRESSING, indent);
          compressGen = new PGPCompressedDataGenerator(input.getCompressionId());
          bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
        } else {
          bcpgOut = new BCPGOutputStream(encryptionOut);
        }

        if (enableSignature) {
          signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
        }

        PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
        char literalDataFormatTag;
        if (input.isCleartextSignature()) {
          literalDataFormatTag = PGPLiteralData.UTF8;
        } else {
          literalDataFormatTag = PGPLiteralData.BINARY;
        }
        pOut =
            literalGen.open(
                bcpgOut,
                literalDataFormatTag,
                inputData.getOriginalFilename(),
                new Date(),
                new byte[1 << 16]);

        long alreadyWritten = 0;
        int length;
        byte[] buffer = new byte[1 << 16];
        InputStream in = inputData.getInputStream();
        while ((length = in.read(buffer)) > 0) {
          pOut.write(buffer, 0, length);

          // update signature buffer if signature is requested
          if (enableSignature) {
            signatureGenerator.update(buffer, 0, length);
          }

          alreadyWritten += length;
          if (inputData.getSize() > 0) {
            long progress = 100 * alreadyWritten / inputData.getSize();
            progressScaler.setProgress((int) progress, 100);
          }
        }

        literalGen.close();
        indent -= 1;

      } else if (enableSignature
          && input.isCleartextSignature()
          && input.isEnableAsciiArmorOutput()) {
        /* cleartext signature: sign-only of ascii text */

        updateProgress(R.string.progress_signing, 8, 100);
        log.add(LogType.MSG_PSE_SIGNING_CLEARTEXT, indent);

        // write -----BEGIN PGP SIGNED MESSAGE-----
        armorOut.beginClearText(input.getSignatureHashAlgorithm());

        InputStream in = inputData.getInputStream();
        final BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        // update signature buffer with first line
        processLine(reader.readLine(), armorOut, signatureGenerator);

        // TODO: progress: fake annealing?
        while (true) {
          String line = reader.readLine();

          // end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7
          if (line == null) {
            armorOut.write(NEW_LINE);
            break;
          }

          armorOut.write(NEW_LINE);

          // update signature buffer with input line
          signatureGenerator.update(NEW_LINE);
          processLine(line, armorOut, signatureGenerator);
        }

        armorOut.endClearText();

        pOut = new BCPGOutputStream(armorOut);
      } else if (enableSignature && input.isDetachedSignature()) {
        /* detached signature */

        updateProgress(R.string.progress_signing, 8, 100);
        log.add(LogType.MSG_PSE_SIGNING_DETACHED, indent);

        InputStream in = inputData.getInputStream();

        // handle output stream separately for detached signatures
        detachedByteOut = new ByteArrayOutputStream();
        OutputStream detachedOut = detachedByteOut;
        if (input.isEnableAsciiArmorOutput()) {
          detachedArmorOut =
              new ArmoredOutputStream(new BufferedOutputStream(detachedOut, 1 << 16));
          if (input.getVersionHeader() != null) {
            detachedArmorOut.setHeader("Version", input.getVersionHeader());
          }

          detachedOut = detachedArmorOut;
        }
        detachedBcpgOut = new BCPGOutputStream(detachedOut);

        long alreadyWritten = 0;
        int length;
        byte[] buffer = new byte[1 << 16];
        while ((length = in.read(buffer)) > 0) {
          // no output stream is written, no changed to original data!

          signatureGenerator.update(buffer, 0, length);

          alreadyWritten += length;
          if (inputData.getSize() > 0) {
            long progress = 100 * alreadyWritten / inputData.getSize();
            progressScaler.setProgress((int) progress, 100);
          }
        }

        pOut = null;
      } else if (enableSignature && !input.isCleartextSignature() && !input.isDetachedSignature()) {
        /* sign-only binary (files/data stream) */

        updateProgress(R.string.progress_signing, 8, 100);
        log.add(LogType.MSG_PSE_SIGNING, indent);

        InputStream in = inputData.getInputStream();

        if (enableCompression) {
          compressGen = new PGPCompressedDataGenerator(input.getCompressionId());
          bcpgOut = new BCPGOutputStream(compressGen.open(out));
        } else {
          bcpgOut = new BCPGOutputStream(out);
        }

        signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);

        PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
        pOut =
            literalGen.open(
                bcpgOut,
                PGPLiteralData.BINARY,
                inputData.getOriginalFilename(),
                new Date(),
                new byte[1 << 16]);

        long alreadyWritten = 0;
        int length;
        byte[] buffer = new byte[1 << 16];
        while ((length = in.read(buffer)) > 0) {
          pOut.write(buffer, 0, length);

          signatureGenerator.update(buffer, 0, length);

          alreadyWritten += length;
          if (inputData.getSize() > 0) {
            long progress = 100 * alreadyWritten / inputData.getSize();
            progressScaler.setProgress((int) progress, 100);
          }
        }

        literalGen.close();
      } else {
        pOut = null;
        // TODO: Is this log right?
        log.add(LogType.MSG_PSE_CLEARSIGN_ONLY, indent);
      }

      if (enableSignature) {
        updateProgress(R.string.progress_generating_signature, 95, 100);
        try {
          if (detachedBcpgOut != null) {
            signatureGenerator.generate().encode(detachedBcpgOut);
          } else {
            signatureGenerator.generate().encode(pOut);
          }
        } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
          // this secret key diverts to a OpenPGP card, throw exception with hash that will be
          // signed
          log.add(LogType.MSG_PSE_PENDING_NFC, indent);
          return new PgpSignEncryptResult(
              log,
              RequiredInputParcel.createNfcSignOperation(
                  signingKey.getRing().getMasterKeyId(),
                  signingKey.getKeyId(),
                  e.hashToSign,
                  e.hashAlgo,
                  cryptoInput.getSignatureTime()),
              cryptoInput);
        }
      }

      // closing outputs
      // NOTE: closing needs to be done in the correct order!
      if (encryptionOut != null) {
        if (compressGen != null) {
          compressGen.close();
        }

        encryptionOut.close();
      }
      // Note: Closing ArmoredOutputStream does not close the underlying stream
      if (armorOut != null) {
        armorOut.close();
      }
      // Note: Closing ArmoredOutputStream does not close the underlying stream
      if (detachedArmorOut != null) {
        detachedArmorOut.close();
      }
      // Also closes detachedBcpgOut
      if (detachedByteOut != null) {
        detachedByteOut.close();
      }
      if (out != null) {
        out.close();
      }
      if (outputStream != null) {
        outputStream.close();
      }

    } catch (SignatureException e) {
      log.add(LogType.MSG_PSE_ERROR_SIG, indent);
      return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
    } catch (PGPException e) {
      log.add(LogType.MSG_PSE_ERROR_PGP, indent);
      return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
    } catch (IOException e) {
      log.add(LogType.MSG_PSE_ERROR_IO, indent);
      return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log);
    }

    updateProgress(R.string.progress_done, 100, 100);

    log.add(LogType.MSG_PSE_OK, indent);
    PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_OK, log);
    if (detachedByteOut != null) {
      try {
        detachedByteOut.flush();
        detachedByteOut.close();
      } catch (IOException e) {
        // silently catch
      }
      result.setDetachedSignature(detachedByteOut.toByteArray());
    }
    return result;
  }