MyPrintService.java revision e8c204dc3956cdcffd88cdcf96b5a644a9b7d2ad
1package foo.bar.printservice;
2
3import android.content.Context;
4import android.content.Intent;
5import android.net.Uri;
6import android.os.AsyncTask;
7import android.os.Handler;
8import android.os.Looper;
9import android.os.Message;
10import android.print.PrintAttributes;
11import android.print.PrintAttributes.Margins;
12import android.print.PrintAttributes.MediaSize;
13import android.print.PrintAttributes.Resolution;
14import android.print.PrintAttributes.Tray;
15import android.print.PrintJobInfo;
16import android.print.PrinterCapabilitiesInfo;
17import android.print.PrinterId;
18import android.print.PrinterInfo;
19import android.printservice.PrintJob;
20import android.printservice.PrintService;
21import android.printservice.PrinterDiscoverySession;
22import android.util.Log;
23import android.widget.Toast;
24
25import libcore.io.IoUtils;
26
27import java.io.BufferedInputStream;
28import java.io.BufferedOutputStream;
29import java.io.File;
30import java.io.FileInputStream;
31import java.io.FileOutputStream;
32import java.io.IOException;
33import java.io.InputStream;
34import java.io.OutputStream;
35import java.util.ArrayList;
36import java.util.List;
37
38public class MyPrintService extends PrintService {
39
40    private static final String LOG_TAG = "MyPrintService";
41
42    private Handler mHandler;
43
44    private PrinterInfo mFirstFakePrinter;
45
46    private PrinterInfo mSecondFakePrinter;
47
48    private AsyncTask<Void, Void, Void> mFakePrintTask;
49
50    private FakePrinterDiscoverySession mSession;
51
52    @Override
53    public void onCreate() {
54        mFirstFakePrinter = new PrinterInfo.Builder(generatePrinterId("Printer 1"),
55                "SHGH-21344", PrinterInfo.STATUS_READY).create();
56        mSecondFakePrinter = new PrinterInfo.Builder(generatePrinterId("Printer 2"),
57                "OPPPP-09434", PrinterInfo.STATUS_READY).create();
58    }
59
60    @Override
61    protected void onConnected() {
62        Log.i(LOG_TAG, "#onConnected()");
63        mHandler = new MyHandler(getMainLooper());
64    }
65
66    @Override
67    protected void onDisconnected() {
68        Log.i(LOG_TAG, "#onDisconnected()");
69        if (mSession != null) {
70            mSession.cancellAddingFakePrinters();
71        }
72    }
73
74    @Override
75    protected PrinterDiscoverySession onCreatePrinterDiscoverySession() {
76        return new FakePrinterDiscoverySession(this);
77    }
78
79    @Override
80    protected void onRequestCancelPrintJob(PrintJob printJob) {
81        Log.i(LOG_TAG, "#onRequestCancelPrintJob() printJobId: " + printJob.getId());
82        if (mHandler.hasMessages(MyHandler.MSG_HANDLE_PRINT_JOB)) {
83            mHandler.removeMessages(MyHandler.MSG_HANDLE_PRINT_JOB);
84            if (printJob.isQueued() || printJob.isStarted()) {
85                printJob.cancel();
86            }
87        } else if (mFakePrintTask != null) {
88            mFakePrintTask.cancel(true);
89        } else {
90            if (printJob.isQueued() || printJob.isStarted()) {
91                printJob.cancel();
92            }
93        }
94    }
95
96    @Override
97    public void onPrintJobQueued(final PrintJob printJob) {
98        Log.i(LOG_TAG, "#onPrintJobQueued()");
99//        printJob.fail("I am lazy today!");
100        Message message = mHandler.obtainMessage(MyHandler.MSG_HANDLE_PRINT_JOB, printJob);
101//        mHandler.sendMessageDelayed(message, 20000);
102        mHandler.sendMessageDelayed(message, 0);
103    }
104
105    private void handleHandleQueuedPrintJob(final PrintJob printJob) {
106        if (printJob.isQueued()) {
107            printJob.start();
108        }
109
110        final PrintJobInfo info = printJob.getInfo();
111        final File file = new File(getFilesDir(), info.getLabel() + ".pdf");
112
113        Toast.makeText(MyPrintService.this,
114                "[STARTED] Printer: " + info.getPrinterId().getLocalId(),
115                Toast.LENGTH_SHORT).show();
116
117        mFakePrintTask = new AsyncTask<Void, Void, Void>() {
118            @Override
119            protected Void doInBackground(Void... params) {
120                // Simulate slow print service
121//                SystemClock.sleep(20000);
122
123                InputStream in = new BufferedInputStream(
124                        new FileInputStream(printJob.getDocument().getData()));
125                OutputStream out = null;
126                try {
127                    out = new BufferedOutputStream(new FileOutputStream(file));
128                    final byte[] buffer = new byte[8192];
129                    while (true) {
130                        if (isCancelled()) {
131                            if (printJob.isStarted()) {
132                                printJob.cancel();
133                            }
134                            break;
135                        }
136                        final int readByteCount = in.read(buffer);
137                        if (readByteCount < 0) {
138                            break;
139                        }
140                        out.write(buffer, 0, readByteCount);
141                    }
142                } catch (IOException ioe) {
143                    /* ignore */
144                } finally {
145                    IoUtils.closeQuietly(in);
146                    IoUtils.closeQuietly(out);
147                    if (isCancelled()) {
148                        file.delete();
149                    }
150                }
151                return null;
152            }
153
154            @Override
155            protected void onPostExecute(Void result) {
156                if (printJob.isStarted()) {
157                    printJob.complete();
158                }
159
160                Toast.makeText(MyPrintService.this,
161                        "[COMPLETED] Printer: " + info.getPrinterId().getLocalId(),
162                        Toast.LENGTH_SHORT).show();
163
164                file.setReadable(true, false);
165
166                Intent intent = new Intent(Intent.ACTION_VIEW);
167                intent.setDataAndType(Uri.fromFile(file), "application/pdf");
168                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
169                startActivity(intent, null);
170
171                mFakePrintTask = null;
172            }
173        };
174        mFakePrintTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
175    }
176
177    private final class MyHandler extends Handler {
178        public static final int MSG_HANDLE_PRINT_JOB = 3;
179
180        public MyHandler(Looper looper) {
181            super(looper, null, true);
182        }
183
184        @Override
185        public void handleMessage(Message message) {
186            switch (message.what) {
187                case MSG_HANDLE_PRINT_JOB: {
188                    PrintJob printJob = (PrintJob) message.obj;
189                    handleHandleQueuedPrintJob(printJob);
190                } break;
191            }
192        }
193    }
194
195    private final class FakePrinterDiscoverySession extends  PrinterDiscoverySession {
196        private final Handler mSesionHandler = new SessionHandler(getMainLooper());
197
198        public FakePrinterDiscoverySession(Context context) {
199            super(context);
200        }
201
202        @Override
203        public void onOpen(List<PrinterId> priorityList) {
204            Log.i(LOG_TAG, "#onStartDiscoverPrinters()");
205            Message message1 = mSesionHandler.obtainMessage(
206                    SessionHandler.MSG_ADD_FIRST_FAKE_PRINTER, this);
207            mSesionHandler.sendMessageDelayed(message1, 0);
208
209            Message message2 = mSesionHandler.obtainMessage(
210                    SessionHandler.MSG_ADD_SECOND_FAKE_PRINTER, this);
211            mSesionHandler.sendMessageDelayed(message2, 10000);
212        }
213
214        @Override
215        public void onClose() {
216            cancellAddingFakePrinters();
217            Log.i(LOG_TAG, "#onStopDiscoverPrinters()");
218        }
219
220        @Override
221        public void onRequestPrinterUpdate(PrinterId printerId) {
222            if (printerId.equals(mFirstFakePrinter.getId())) {
223                PrinterCapabilitiesInfo capabilities =
224                        new PrinterCapabilitiesInfo.Builder(printerId)
225                    .setMinMargins(new Margins(0, 0, 0, 0), new Margins(0, 0, 0, 0))
226                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
227                            MediaSize.ISO_A2), true)
228                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
229                            MediaSize.ISO_A3), false)
230                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
231                            MediaSize.ISO_A4), false)
232                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
233                            MediaSize.NA_LETTER), false)
234                    .addResolution(new Resolution("R1", getString(
235                            R.string.resolution_600x600), 600, 600), true)
236                    .addInputTray(new Tray("FirstInputTray", getString(
237                            R.string.input_tray_first)), false)
238                    .addOutputTray(new Tray("FirstOutputTray", getString(
239                            R.string.output_tray_first)), false)
240                    .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE
241                            | PrintAttributes.DUPLEX_MODE_LONG_EDGE
242                            | PrintAttributes.DUPLEX_MODE_SHORT_EDGE,
243                            PrintAttributes.DUPLEX_MODE_NONE)
244                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR
245                            | PrintAttributes.COLOR_MODE_MONOCHROME,
246                            PrintAttributes.COLOR_MODE_COLOR)
247                    .setFittingModes(PrintAttributes.FITTING_MODE_NONE
248                            | PrintAttributes.FITTING_MODE_FIT_TO_PAGE,
249                            PrintAttributes.FITTING_MODE_NONE)
250                    .setOrientations(PrintAttributes.ORIENTATION_PORTRAIT
251                            | PrintAttributes.ORIENTATION_LANDSCAPE,
252                            PrintAttributes.ORIENTATION_PORTRAIT)
253                    .create();
254
255                PrinterInfo printer = new PrinterInfo.Builder(mFirstFakePrinter)
256                        .setCapabilities(capabilities)
257                        .create();
258
259                List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
260                printers.add(printer);
261                updatePrinters(printers);
262
263            } else if (printerId.equals(mSecondFakePrinter.getId())) {
264                PrinterCapabilitiesInfo capabilities =
265                        new PrinterCapabilitiesInfo.Builder(printerId)
266                    .setMinMargins(new Margins(0, 0, 0, 0), new Margins(0, 0, 0, 0))
267                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
268                            MediaSize.ISO_A4), true)
269                    .addMediaSize(MediaSize.createMediaSize(getPackageManager(),
270                            MediaSize.ISO_A5), false)
271                    .addResolution(new Resolution("R1", getString(
272                            R.string.resolution_200x200), 200, 200), true)
273                    .addResolution(new Resolution("R2", getString(
274                            R.string.resolution_300x300), 300, 300), false)
275                    .addInputTray(new Tray("FirstInputTray", getString(
276                            R.string.input_tray_first)), false)
277                    .addInputTray(new Tray("SecondInputTray", getString(
278                            R.string.input_tray_second)), true)
279                    .addOutputTray(new Tray("FirstOutputTray", getString(
280                            R.string.output_tray_first)), false)
281                    .addOutputTray(new Tray("SecondOutputTray",  getString(
282                            R.string.output_tray_second)), true)
283                    .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE
284                            | PrintAttributes.DUPLEX_MODE_LONG_EDGE
285                            | PrintAttributes.DUPLEX_MODE_SHORT_EDGE,
286                            PrintAttributes.DUPLEX_MODE_SHORT_EDGE)
287                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR
288                            | PrintAttributes.COLOR_MODE_MONOCHROME,
289                            PrintAttributes.COLOR_MODE_MONOCHROME)
290                    .setFittingModes(PrintAttributes.FITTING_MODE_FIT_TO_PAGE
291                            | PrintAttributes.FITTING_MODE_NONE,
292                            PrintAttributes.FITTING_MODE_FIT_TO_PAGE)
293                    .setOrientations(PrintAttributes.ORIENTATION_PORTRAIT
294                            | PrintAttributes.ORIENTATION_LANDSCAPE,
295                            PrintAttributes.ORIENTATION_LANDSCAPE)
296                    .create();
297
298                PrinterInfo printer = new PrinterInfo.Builder(mSecondFakePrinter)
299                    .setCapabilities(capabilities)
300                    .create();
301
302                List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
303                printers.add(printer);
304                updatePrinters(printers);
305            }
306        }
307
308        private void addFirstFakePrinter(PrinterDiscoverySession session) {
309            List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
310            printers.add(mFirstFakePrinter);
311            session.addPrinters(printers);
312        }
313
314        private void addSecondFakePrinter(PrinterDiscoverySession session) {
315            List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
316            printers.add(mSecondFakePrinter);
317            session.addPrinters(printers);
318        }
319
320        private void cancellAddingFakePrinters() {
321            mSesionHandler.removeMessages(SessionHandler.MSG_ADD_FIRST_FAKE_PRINTER);
322            mSesionHandler.removeMessages(SessionHandler.MSG_ADD_SECOND_FAKE_PRINTER);
323        }
324
325        final class SessionHandler extends Handler {
326            public static final int MSG_ADD_FIRST_FAKE_PRINTER = 1;
327            public static final int MSG_ADD_SECOND_FAKE_PRINTER = 2;
328
329            public SessionHandler(Looper looper) {
330                super(looper, null, true);
331            }
332
333            @Override
334            public void handleMessage(Message message) {
335                switch (message.what) {
336                    case MSG_ADD_FIRST_FAKE_PRINTER: {
337                        PrinterDiscoverySession session =
338                                (PrinterDiscoverySession) message.obj;
339                        addFirstFakePrinter(session);
340                    } break;
341
342                    case MSG_ADD_SECOND_FAKE_PRINTER: {
343                        PrinterDiscoverySession session =
344                                (PrinterDiscoverySession) message.obj;
345                        addSecondFakePrinter(session);
346                    } break;
347                }
348            }
349        }
350    }
351}
352