• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 foo.bar.print;
18 
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 
25 import android.app.Activity;
26 import android.content.Context;
27 import android.graphics.pdf.PdfDocument.Page;
28 import android.net.Uri;
29 import android.os.AsyncTask;
30 import android.os.Bundle;
31 import android.os.CancellationSignal;
32 import android.os.ParcelFileDescriptor;
33 import android.print.PageRange;
34 import android.print.PrintAttributes;
35 import android.print.PrintDocumentAdapter;
36 import android.print.PrintDocumentInfo;
37 import android.print.PrintManager;
38 import android.print.pdf.PrintedPdfDocument;
39 import android.support.v4.print.PrintHelper;
40 import android.util.SparseIntArray;
41 import android.view.Menu;
42 import android.view.MenuItem;
43 import android.view.View;
44 
45 /**
46  * Simple sample of how to use the print APIs.
47  */
48 public class Main extends Activity {
49 
50     public static final String LOG_TAG = "PrintActivity";
51 
52     private static final int PAGE_COUNT = 5;
53 
54     @Override
onCreate(Bundle savedInstanceState)55     protected void onCreate(Bundle savedInstanceState) {
56         super.onCreate(savedInstanceState);
57         setContentView(R.layout.activity_main);
58     }
59 
60     @Override
onCreateOptionsMenu(Menu menu)61     public boolean onCreateOptionsMenu(Menu menu) {
62         super.onCreateOptionsMenu(menu);
63         getMenuInflater().inflate(R.menu.activity_main, menu);
64         return true;
65     }
66 
67     @Override
onOptionsItemSelected(MenuItem item)68     public boolean onOptionsItemSelected(MenuItem item) {
69         switch (item.getItemId()) {
70             case R.id.menu_print:
71                 printView();
72                 return true;
73             case R.id.menu_print_uri_portrait_force:
74             case R.id.menu_print_uri_portrait:
75             case R.id.menu_print_uri_landscape:
76                 try {
77                     PrintHelper ph = new PrintHelper(this);
78                     Uri uri = null;
79                     switch (item.getItemId()) {
80                         case R.id.menu_print_uri_portrait_force:
81                             ph.setOrientation(PrintHelper.ORIENTATION_PORTRAIT);
82                             /* fall through */
83                         case R.id.menu_print_uri_portrait:
84                             uri = Uri.parse("android.resource://foo.bar.print/raw/portrait");
85                             break;
86                         case R.id.menu_print_uri_landscape:
87                             uri = Uri.parse("android.resource://foo.bar.print/raw/landscape");
88                             break;
89                     }
90 
91                     ph.printBitmap("Print Uri", uri);
92                 } catch (FileNotFoundException e) {
93                     e.printStackTrace();
94                 }
95                 return true;
96             default:
97                 return super.onOptionsItemSelected(item);
98         }
99     }
100 
printView()101     private void printView() {
102         PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
103         final View view = findViewById(R.id.content);
104 
105         printManager.print("Print_View",
106             new PrintDocumentAdapter() {
107                 private static final int RESULT_LAYOUT_FAILED = 1;
108                 private static final int RESULT_LAYOUT_FINISHED = 2;
109 
110                 private PrintAttributes mPrintAttributes;
111 
112                 @Override
113                 public void onLayout(final PrintAttributes oldAttributes,
114                         final PrintAttributes newAttributes,
115                         final CancellationSignal cancellationSignal,
116                         final LayoutResultCallback callback,
117                         final Bundle metadata) {
118 
119                     new AsyncTask<Void, Void, Integer>() {
120                         @Override
121                         protected void onPreExecute() {
122                             // First register for cancellation requests.
123                             cancellationSignal.setOnCancelListener(() -> cancel(true));
124                             mPrintAttributes = newAttributes;
125                         }
126 
127                         @Override
128                         protected Integer doInBackground(Void... params) {
129                             try {
130                                 // Pretend we do some layout work.
131                                 for (int i = 0; i < PAGE_COUNT; i++) {
132                                     // Be nice and respond to cancellation.
133                                     if (isCancelled()) {
134                                         return null;
135                                     }
136                                     pretendDoingLayoutWork();
137                                 }
138                                 return RESULT_LAYOUT_FINISHED;
139                             } catch (Exception e) {
140                                 return RESULT_LAYOUT_FAILED;
141                             }
142                         }
143 
144                         @Override
145                         protected void onPostExecute(Integer result) {
146                             // The task was not cancelled, so handle the layout result.
147                             switch (result) {
148                                 case RESULT_LAYOUT_FINISHED: {
149                                     PrintDocumentInfo info = new PrintDocumentInfo
150                                             .Builder("print_view.pdf")
151                                             .setContentType(PrintDocumentInfo
152                                                     .CONTENT_TYPE_DOCUMENT)
153                                             .setPageCount(PAGE_COUNT)
154                                             .build();
155                                     callback.onLayoutFinished(info, false);
156                                 } break;
157 
158                                 case RESULT_LAYOUT_FAILED: {
159                                     callback.onLayoutFailed(null);
160                                 } break;
161                             }
162                         }
163 
164                         @Override
165                         protected void onCancelled(Integer result) {
166                             // Task was cancelled, report that.
167                             callback.onLayoutCancelled();
168                         }
169 
170                         private void pretendDoingLayoutWork() throws Exception {
171 
172                         }
173                     }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
174                 }
175 
176                 @Override
177                 public void onWrite(final PageRange[] pages,
178                         final ParcelFileDescriptor destination,
179                         final CancellationSignal canclleationSignal,
180                         final WriteResultCallback callback) {
181 
182                     new AsyncTask<Void, Void, Integer>() {
183                         private static final int RESULT_WRITE_FAILED = 1;
184                         private static final int RESULT_WRITE_FINISHED = 2;
185 
186                         private final SparseIntArray mWrittenPages = new SparseIntArray();
187                         private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
188                                 Main.this, mPrintAttributes);
189 
190                         @Override
191                         protected void onPreExecute() {
192                             // First register for cancellation requests.
193                             canclleationSignal.setOnCancelListener(() -> cancel(true));
194 
195                             for (int i = 0; i < PAGE_COUNT; i++) {
196                                 // Be nice and respond to cancellation.
197                                 if (isCancelled()) {
198                                     return;
199                                 }
200 
201                                 // Write the page only if it was requested.
202                                 if (containsPage(pages, i)) {
203                                     mWrittenPages.append(mWrittenPages.size(), i);
204                                     Page page = mPdfDocument.startPage(i);
205                                     // The page of the PDF backed canvas size is in pixels (1/72") and
206                                     // smaller that the view. We scale down the drawn content and to
207                                     // fit. This does not lead to losing data as PDF is a vector format.
208                                     final float scale = (float) Math.min(mPdfDocument.getPageWidth(),
209                                             mPdfDocument.getPageHeight()) / Math.max(view.getWidth(), view.getHeight());
210                                     page.getCanvas().scale(scale, scale);
211                                     view.draw(page.getCanvas());
212                                     mPdfDocument.finishPage(page);
213                                 }
214                             }
215                         }
216 
217                         @Override
218                         protected Integer doInBackground(Void... params) {
219                             // Write the data and return success or failure.
220                             try {
221                                 mPdfDocument.writeTo(new FileOutputStream(
222                                         destination.getFileDescriptor()));
223                                 return RESULT_WRITE_FINISHED;
224                             } catch (IOException ioe) {
225                                 return RESULT_WRITE_FAILED;
226                             }
227                         }
228 
229                         @Override
230                         protected void onPostExecute(Integer result) {
231                             // The task was not cancelled, so handle the write result.
232                             switch (result) {
233                                 case RESULT_WRITE_FINISHED: {
234                                     PageRange[] pageRanges = computePageRanges(mWrittenPages);
235                                     callback.onWriteFinished(pageRanges);
236                                 } break;
237 
238                                 case RESULT_WRITE_FAILED: {
239                                     callback.onWriteFailed(null);
240                                 } break;
241                             }
242 
243                             mPdfDocument.close();
244                         }
245 
246                         @Override
247                         protected void onCancelled(Integer result) {
248                             // Task was cancelled, report that.
249                             callback.onWriteCancelled();
250                             mPdfDocument.close();
251                         }
252                     }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
253                 }
254 
255                 private PageRange[] computePageRanges(SparseIntArray writtenPages) {
256                     List<PageRange> pageRanges = new ArrayList<>();
257 
258                     int start;
259                     int end;
260                     final int writtenPageCount = writtenPages.size();
261                     for (int i = 0; i < writtenPageCount; i++) {
262                         start = writtenPages.valueAt(i);
263                         int oldEnd = end = start;
264                         while (i < writtenPageCount && (end - oldEnd) <= 1) {
265                             oldEnd = end;
266                             end = writtenPages.valueAt(i);
267                             i++;
268                         }
269                         PageRange pageRange = new PageRange(start, end);
270                         pageRanges.add(pageRange);
271                     }
272 
273                     PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
274                     pageRanges.toArray(pageRangesArray);
275                     return pageRangesArray;
276                 }
277 
278                 private boolean containsPage(PageRange[] pageRanges, int page) {
279                     final int pageRangeCount = pageRanges.length;
280                     for (int i = 0; i < pageRangeCount; i++) {
281                         if (pageRanges[i].getStart() <= page
282                                 && pageRanges[i].getEnd() >= page) {
283                             return true;
284                         }
285                     }
286                     return false;
287                 }
288         }, null);
289     }
290 }
291