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