package org.ea.sqrl.services; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.pdf.PdfDocument; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; import android.print.PrintDocumentInfo; import android.print.pdf.PrintedPdfDocument; import android.support.annotation.RequiresApi; import android.text.Layout; import android.text.TextPaint; import android.util.Log; import org.ea.sqrl.R; import org.ea.sqrl.processors.SQRLStorage; import org.ea.sqrl.utils.DocumentPrintUtils; import org.ea.sqrl.utils.Utils; import java.io.FileOutputStream; import java.io.IOException; import io.nayuki.qrcodegen.QrCode; /** * * @author Daniel Persson */ @RequiresApi(Build.VERSION_CODES.KITKAT) public class IdentityPrintDocumentAdapter extends PrintDocumentAdapter { private static final String TAG = "IdentityPrint"; private final Activity activity; private final String identityName; private final boolean withoutPassword; private PrintedPdfDocument mPdfDocument; public IdentityPrintDocumentAdapter(Activity activity, String identityName, boolean withoutPassword) { this.activity = activity; this.identityName = identityName; this.withoutPassword = withoutPassword; } @Override public void onLayout( PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle metadata ) { mPdfDocument = new PrintedPdfDocument(activity, newAttributes); if (cancellationSignal.isCanceled() ) { callback.onLayoutCancelled(); return; } PrintDocumentInfo info = new PrintDocumentInfo .Builder("Identity.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(1) .build(); callback.onLayoutFinished(info, true); } @Override public void onWrite( final PageRange[] pageRanges, final ParcelFileDescriptor destination, final CancellationSignal cancellationSignal, final WriteResultCallback callback ) { PdfDocument.Page page = mPdfDocument.startPage(0); if (cancellationSignal.isCanceled()) { callback.onWriteCancelled(); mPdfDocument.close(); mPdfDocument = null; return; } drawPage(page); mPdfDocument.finishPage(page); try { mPdfDocument.writeTo(new FileOutputStream( destination.getFileDescriptor())); } catch (IOException e) { callback.onWriteFailed(e.toString()); return; } finally { mPdfDocument.close(); mPdfDocument = null; } callback.onWriteFinished(pageRanges); } private void drawPage(PdfDocument.Page page) { SQRLStorage storage = SQRLStorage.getInstance(activity); Canvas canvas = page.getCanvas(); int marginLeftRight = 35; int marginTop = 65; int lastBlockY = marginTop; TextPaint headlineTextPaint = new TextPaint(); headlineTextPaint.setTextSize(16); headlineTextPaint.setFakeBoldText(true); TextPaint bodyTextPaint = new TextPaint(); bodyTextPaint.setTextSize(12); TextPaint identityTextTextPaint = new TextPaint(bodyTextPaint); identityTextTextPaint.setTypeface(Typeface.MONOSPACE); identityTextTextPaint.setFakeBoldText(true); String identityTitle = "\"" + identityName + "\" SQRL Identity"; lastBlockY += DocumentPrintUtils.drawTextBlock( canvas, identityTitle, Layout.Alignment.ALIGN_CENTER, headlineTextPaint, marginTop, marginLeftRight); lastBlockY += DocumentPrintUtils.drawTextBlock( canvas, activity.getString(R.string.print_identity_desc1), Layout.Alignment.ALIGN_NORMAL, bodyTextPaint, lastBlockY + 20, marginLeftRight) + 20; byte[] saveData; if(this.withoutPassword) { saveData = storage.createSaveDataWithoutPassword(); } else { saveData = storage.createSaveData(); } int canvasMiddle = canvas.getWidth() / 2; QrCode qrCode = QrCode.encodeBinary(saveData, QrCode.Ecc.MEDIUM); Bitmap bitmap = qrCode.toImage(3, 0); int bitmapWidth = bitmap.getScaledWidth(canvas); canvas.drawBitmap(bitmap, canvasMiddle - (bitmapWidth / 2), lastBlockY + 20, new Paint()); lastBlockY += bitmap.getScaledHeight(canvas) + 20; lastBlockY += DocumentPrintUtils.drawTextBlock( canvas, activity.getString(R.string.print_identity_desc2), Layout.Alignment.ALIGN_NORMAL, bodyTextPaint, lastBlockY + 20, marginLeftRight) + 30; int i = 0; try { Utils.refreshStorageFromDb(activity); for (String identityTextBlock : storage.getVerifyingRecoveryBlock().split("\n")) { lastBlockY += DocumentPrintUtils.drawTextBlock( canvas, identityTextBlock, Layout.Alignment.ALIGN_CENTER, identityTextTextPaint, lastBlockY + 3, marginLeftRight) + 3; i++; } } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } DocumentPrintUtils.drawTextBlock( canvas, activity.getString(R.string.print_identity_desc3), Layout.Alignment.ALIGN_NORMAL, bodyTextPaint, lastBlockY + 20, marginLeftRight); DocumentPrintUtils.drawPrintPageFooter(activity, canvas); } }