1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bips; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.AsyncTask; 24 import android.os.Bundle; 25 import android.os.CancellationSignal; 26 import android.os.ParcelFileDescriptor; 27 import android.print.PageRange; 28 import android.print.PrintAttributes; 29 import android.print.PrintDocumentAdapter; 30 import android.print.PrintDocumentInfo; 31 import android.print.PrintManager; 32 import android.util.Log; 33 import android.webkit.URLUtil; 34 35 import java.io.FileOutputStream; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.OutputStream; 39 40 /** 41 * Activity to receive share-to-print intents for PDF documents. 42 */ 43 public class PdfPrintActivity extends Activity { 44 private static final String TAG = PdfPrintActivity.class.getSimpleName(); 45 private static final boolean DEBUG = false; 46 47 private CancellationSignal mCancellationSignal; 48 private String mJobName; 49 Uri mContentUri = null; 50 51 @Override onCreate(Bundle savedInstanceState)52 protected void onCreate(Bundle savedInstanceState) { 53 super.onCreate(savedInstanceState); 54 String action = getIntent().getAction(); 55 if (Intent.ACTION_SEND.equals(action)) { 56 mContentUri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM); 57 } else if (Intent.ACTION_VIEW.equals(action)) { 58 mContentUri = getIntent().getData(); 59 } 60 if (mContentUri == null) { 61 finish(); 62 } 63 mJobName = URLUtil.guessFileName(getIntent().getStringExtra(Intent.EXTRA_TEXT), null, 64 getIntent().resolveType(this)); 65 if (DEBUG) Log.d(TAG, "onCreate() uri=" + mContentUri + " jobName=" + mJobName); 66 67 PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); 68 if (printManager == null) { 69 finish(); 70 return; 71 } 72 73 PrintAttributes printAttributes = new PrintAttributes.Builder() 74 .setColorMode(PrintAttributes.COLOR_MODE_COLOR) 75 .build(); 76 printManager.print(mJobName, new PdfAdapter(), printAttributes); 77 } 78 79 @Override onDestroy()80 protected void onDestroy() { 81 if (DEBUG) Log.d(TAG, "onDestroy()"); 82 if (mCancellationSignal != null) { 83 mCancellationSignal.cancel(); 84 } 85 super.onDestroy(); 86 } 87 88 private class PdfAdapter extends PrintDocumentAdapter { 89 @Override onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle bundle)90 public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, 91 CancellationSignal cancellationSignal, LayoutResultCallback callback, 92 Bundle bundle) { 93 if (DEBUG) Log.d(TAG, "onLayout() attrs=" + newAttributes); 94 95 PrintDocumentInfo info = new PrintDocumentInfo.Builder(mJobName) 96 .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) 97 .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN) 98 .build(); 99 callback.onLayoutFinished(info, false); 100 } 101 102 @Override onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, CancellationSignal cancellationSignal, WriteResultCallback callback)103 public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor, 104 CancellationSignal cancellationSignal, WriteResultCallback callback) { 105 if (DEBUG) Log.d(TAG, "onWrite()"); 106 mCancellationSignal = cancellationSignal; 107 new PdfDeliverTask(fileDescriptor, callback).execute(); 108 } 109 110 @Override onFinish()111 public void onFinish() { 112 if (DEBUG) Log.d(TAG, "onFinish()"); 113 finish(); 114 } 115 } 116 117 private class PdfDeliverTask extends AsyncTask<Void, Void, Void> { 118 ParcelFileDescriptor mDescriptor; 119 PrintDocumentAdapter.WriteResultCallback mCallback; 120 PdfDeliverTask(ParcelFileDescriptor descriptor, PrintDocumentAdapter.WriteResultCallback callback)121 PdfDeliverTask(ParcelFileDescriptor descriptor, 122 PrintDocumentAdapter.WriteResultCallback callback) { 123 mDescriptor = descriptor; 124 mCallback = callback; 125 } 126 127 @Override doInBackground(Void... voids)128 protected Void doInBackground(Void... voids) { 129 try (InputStream in = getContentResolver().openInputStream(mContentUri)) { 130 if (in == null) { 131 throw new IOException("Failed to open input stream"); 132 } 133 try (OutputStream out = new FileOutputStream(mDescriptor.getFileDescriptor())) { 134 byte[] buffer = new byte[10 * 1024]; 135 int length; 136 while ((length = in.read(buffer)) >= 0 && !mCancellationSignal.isCanceled()) { 137 out.write(buffer, 0, length); 138 } 139 } 140 if (mCancellationSignal.isCanceled()) { 141 mCallback.onWriteCancelled(); 142 } else { 143 mCallback.onWriteFinished(new PageRange[] { PageRange.ALL_PAGES }); 144 } 145 } catch (IOException e) { 146 Log.w(TAG, "Failed to deliver content", e); 147 mCallback.onWriteFailed(e.getMessage()); 148 } 149 return null; 150 } 151 } 152 } 153