18c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov/*
28c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
38c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov *
48c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
58c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * you may not use this file except in compliance with the License.
68c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * You may obtain a copy of the License at
78c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov *
88c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
98c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov *
108c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
118c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
128c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * See the License for the specific language governing permissions and
148c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * limitations under the License.
158c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov */
168c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
178c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovpackage com.android.printspooler;
188c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
198c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.app.Notification;
20a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganovimport android.app.Notification.InboxStyle;
218c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.app.NotificationManager;
228c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.app.PendingIntent;
238c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.content.BroadcastReceiver;
248c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.content.Context;
258c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.content.Intent;
26a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganovimport android.graphics.drawable.BitmapDrawable;
27a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganovimport android.net.Uri;
28835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.os.AsyncTask;
29835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.os.PowerManager;
30835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganovimport android.os.PowerManager.WakeLock;
318c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.os.RemoteException;
328c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.os.ServiceManager;
338c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.os.UserHandle;
348c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.print.IPrintManager;
352fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
368c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.print.PrintJobInfo;
378c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.print.PrintManager;
38704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganovimport android.provider.Settings;
398c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovimport android.util.Log;
408c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
41a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganovimport java.util.ArrayList;
42a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganovimport java.util.List;
43a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
448c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov/**
458c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * This class is responsible for updating the print notifications
468c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov * based on print job state transitions.
478c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov */
488c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganovpublic class NotificationController {
492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public static final boolean DEBUG = false;
508c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
518c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    public static final String LOG_TAG = "NotificationController";
528c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
538c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
548c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
552fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
56704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
57704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private static final String EXTRA_PRINTJOB_LABEL = "EXTRA_PRINTJOB_LABEL";
58704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private static final String EXTRA_PRINTER_NAME = "EXTRA_PRINTER_NAME";
598c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
608c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    private final Context mContext;
618c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    private final NotificationManager mNotificationManager;
628c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
638c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    public NotificationController(Context context) {
648c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        mContext = context;
658c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        mNotificationManager = (NotificationManager)
668c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
678c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
688c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
69a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
70a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        List<PrintJobInfo> notifyPrintJobs = new ArrayList<PrintJobInfo>();
71a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
72a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        final int printJobCount = printJobs.size();
73a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        for (int i = 0; i < printJobCount; i++) {
74a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            PrintJobInfo printJob = printJobs.get(i);
75a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (shouldNotifyForState(printJob.getState())) {
76a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                notifyPrintJobs.add(printJob);
77a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
788c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
798c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
80a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        updateNotification(notifyPrintJobs);
81a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
82a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
83a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private void updateNotification(List<PrintJobInfo> printJobs) {
84a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        if (printJobs.size() <= 0) {
85a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            removeNotification();
86a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } else if (printJobs.size() == 1) {
87a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            createSimpleNotification(printJobs.get(0));
88a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        } else {
89a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            createStackedNotification(printJobs);
90a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
91a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
92a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
93a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private void createSimpleNotification(PrintJobInfo printJob) {
94a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        switch (printJob.getState()) {
958c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            case PrintJobInfo.STATE_FAILED: {
96d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                createFailedNotification(printJob);
978c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            } break;
988c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
99a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_BLOCKED: {
100a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (!printJob.isCancelling()) {
101a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    createBlockedNotification(printJob);
102a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                } else {
103a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    createCancellingNotification(printJob);
104a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
1058c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            } break;
106d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
107a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            default: {
108a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (!printJob.isCancelling()) {
109a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    createPrintingNotification(printJob);
110a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                } else {
111a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    createCancellingNotification(printJob);
112a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
113d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            } break;
1148c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
1158c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
1168c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
117d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private void createPrintingNotification(PrintJobInfo printJob) {
1188c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        Notification.Builder builder = new Notification.Builder(mContext)
119704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                .setContentIntent(createContentIntent(printJob.getId()))
120a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setSmallIcon(computeNotificationIcon(printJob))
121a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentTitle(computeNotificationTitle(printJob))
12232c5eb3bf89938ba2221e67362571628e1efd520Svetoslav Ganov                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
123835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        createCancelIntent(printJob))
124798bed6cc7d273e72b0253288605db9cd2b57740Svetoslav Ganov                .setContentText(printJob.getPrinterName())
1258c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                .setWhen(System.currentTimeMillis())
126835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                .setOngoing(true)
1278c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                .setShowWhen(true);
128a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mNotificationManager.notify(0, builder.build());
1298c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
1308c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
131d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private void createFailedNotification(PrintJobInfo printJob) {
1328c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        Notification.Builder builder = new Notification.Builder(mContext)
133704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                .setContentIntent(createContentIntent(printJob.getId()))
134a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setSmallIcon(computeNotificationIcon(printJob))
135a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentTitle(computeNotificationTitle(printJob))
13632c5eb3bf89938ba2221e67362571628e1efd520Svetoslav Ganov                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
137835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        createCancelIntent(printJob))
1385ab717f21a2dbcd78fb37d40e31393d129743599Svetoslav                .addAction(R.drawable.ic_restart, mContext.getString(R.string.restart),
1398c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                        createRestartIntent(printJob.getId()))
140704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                .setContentText(printJob.getPrinterName())
141d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                .setWhen(System.currentTimeMillis())
142d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                .setOngoing(true)
143d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                .setShowWhen(true);
144a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mNotificationManager.notify(0, builder.build());
145d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
146d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
147d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    private void createBlockedNotification(PrintJobInfo printJob) {
148d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        Notification.Builder builder = new Notification.Builder(mContext)
149704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                .setContentIntent(createContentIntent(printJob.getId()))
150a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setSmallIcon(computeNotificationIcon(printJob))
151a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentTitle(computeNotificationTitle(printJob))
152d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel),
153d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                        createCancelIntent(printJob))
154704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                .setContentText(printJob.getPrinterName())
1558c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                .setWhen(System.currentTimeMillis())
156835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                .setOngoing(true)
1578c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                .setShowWhen(true);
158a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov           mNotificationManager.notify(0, builder.build());
159a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
160a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
161a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private void createCancellingNotification(PrintJobInfo printJob) {
162a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        Notification.Builder builder = new Notification.Builder(mContext)
163a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentIntent(createContentIntent(printJob.getId()))
164a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setSmallIcon(computeNotificationIcon(printJob))
165a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentTitle(computeNotificationTitle(printJob))
166a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentText(printJob.getPrinterName())
167a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setWhen(System.currentTimeMillis())
168a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setOngoing(true)
169a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setShowWhen(true);
170a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mNotificationManager.notify(0, builder.build());
1718c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
1728c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
173a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private void createStackedNotification(List<PrintJobInfo> printJobs) {
174a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        Notification.Builder builder = new Notification.Builder(mContext)
175a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setContentIntent(createContentIntent(null))
176a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setWhen(System.currentTimeMillis())
177a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setOngoing(true)
178a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                .setShowWhen(true);
179a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
180a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        final int printJobCount = printJobs.size();
181a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
182a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        InboxStyle inboxStyle = new InboxStyle();
183a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        inboxStyle.setBigContentTitle(String.format(mContext.getResources().getQuantityText(
184a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                R.plurals.composite_notification_title_template,
185a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                printJobCount).toString(), printJobCount));
186a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
187a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        for (int i = printJobCount - 1; i>= 0; i--) {
188a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            PrintJobInfo printJob = printJobs.get(i);
189a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            if (i == printJobCount - 1) {
190a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                builder.setLargeIcon(((BitmapDrawable) mContext.getResources().getDrawable(
191a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        computeNotificationIcon(printJob))).getBitmap());
192d91cb3ea61ea5096637c5d2b5e3e6147d0d2cce3Svetoslav Ganov                builder.setSmallIcon(computeNotificationIcon(printJob));
193a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                builder.setContentTitle(computeNotificationTitle(printJob));
194a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                builder.setContentText(printJob.getPrinterName());
195a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
196a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            inboxStyle.addLine(computeNotificationTitle(printJob));
197a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
198a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
199a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        builder.setNumber(printJobCount);
200a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        builder.setStyle(inboxStyle);
201a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
202a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mNotificationManager.notify(0, builder.build());
203a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
204a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
205a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private String computeNotificationTitle(PrintJobInfo printJob) {
206a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        switch (printJob.getState()) {
207a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_FAILED: {
208a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                return mContext.getString(R.string.failed_notification_title_template,
209a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        printJob.getLabel());
210a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
211a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
212a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_BLOCKED: {
213a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (!printJob.isCancelling()) {
214a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return mContext.getString(R.string.blocked_notification_title_template,
215a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.getLabel());
216a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                } else {
217a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return mContext.getString(
218a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            R.string.cancelling_notification_title_template,
219a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.getLabel());
220a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
221a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
222a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
223a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            default: {
224a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (!printJob.isCancelling()) {
225a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return mContext.getString(R.string.printing_notification_title_template,
226a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.getLabel());
227a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                } else {
228a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return mContext.getString(
229a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            R.string.cancelling_notification_title_template,
230a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                            printJob.getLabel());
231a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
232a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
233a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
234a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
235a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
236a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private void removeNotification() {
237a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        mNotificationManager.cancel(0);
2388c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
2398c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
240704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    private PendingIntent createContentIntent(PrintJobId printJobId) {
241704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
242a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        if (printJobId != null) {
243a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId.flattenToString());
244a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            intent.setData(Uri.fromParts("printjob", printJobId.flattenToString(), null));
245a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
246a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        return PendingIntent.getActivity(mContext, 0, intent, 0);
247704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
248704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
249835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov    private PendingIntent createCancelIntent(PrintJobInfo printJob) {
2508c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
2512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
252704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        intent.putExtra(EXTRA_PRINT_JOB_ID, printJob.getId());
253704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        intent.putExtra(EXTRA_PRINTJOB_LABEL, printJob.getLabel());
254704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        intent.putExtra(EXTRA_PRINTER_NAME, printJob.getPrinterName());
2558c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
2568c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
2578c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
2582fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    private PendingIntent createRestartIntent(PrintJobId printJobId) {
2598c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
2602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
261704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        intent.putExtra(EXTRA_PRINT_JOB_ID, printJobId);
2628c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
2638c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
2648c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
265a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private static boolean shouldNotifyForState(int state) {
266a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        switch (state) {
267a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_QUEUED:
268a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_STARTED:
269a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_FAILED:
270a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_COMPLETED:
271a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_CANCELED:
272a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_BLOCKED: {
273a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                return true;
274a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
275a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
276a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        return false;
277a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
278a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
279a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    private static int computeNotificationIcon(PrintJobInfo printJob) {
280a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        switch (printJob.getState()) {
281a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_FAILED:
282a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            case PrintJobInfo.STATE_BLOCKED: {
283a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                return com.android.internal.R.drawable.ic_print_error;
284a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
285a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            default: {
286a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                if (!printJob.isCancelling()) {
287a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return com.android.internal.R.drawable.ic_print;
288a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                } else {
289a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                    return R.drawable.stat_notify_cancelling;
290a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                }
291a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov            }
292a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov        }
293a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov    }
294a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov
2958c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    public static final class NotificationBroadcastReceiver extends BroadcastReceiver {
2968c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        private static final String LOG_TAG = "NotificationBroadcastReceiver";
2978c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
2988c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        @Override
2998c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        public void onReceive(Context context, Intent intent) {
3008c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            String action = intent.getAction();
3018c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
302704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
303704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                String printJobLabel = intent.getExtras().getString(EXTRA_PRINTJOB_LABEL);
304704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                String printerName = intent.getExtras().getString(EXTRA_PRINTER_NAME);
305835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
3068c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            } else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
307704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov                PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
3088c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                handleRestartPrintJob(context, printJobId);
3098c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            }
3108c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
3118c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
3122fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
313835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                final String printJobLabel, final String printerName) {
3148c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            if (DEBUG) {
3158c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
3168c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            }
3178c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
318835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // Call into the print manager service off the main thread since
319835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // the print manager service may end up binding to the print spooler
320835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // service which binding is handled on the main thread.
321835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            PowerManager powerManager = (PowerManager)
322835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    context.getSystemService(Context.POWER_SERVICE);
323835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
324835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    LOG_TAG);
325835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            wakeLock.acquire();
326835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
327835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            new AsyncTask<Void, Void, Void>() {
328835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                @Override
329835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                protected Void doInBackground(Void... params) {
330835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // We need to request the cancellation to be done by the print
331835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // manager service since it has to communicate with the managing
332835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // print service to request the cancellation. Also we need the
333835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // system service to be bound to the spooler since canceling a
334835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // print job will trigger persistence of current jobs which is
335835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // done on another thread and until it finishes the spooler has
336835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // to be kept around.
337835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    try {
338a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                        IPrintManager printManager = IPrintManager.Stub.asInterface(
339a18661d5922e5ae24ccce8e815aeba437a2fba82Svetoslav Ganov                                ServiceManager.getService(Context.PRINT_SERVICE));
340835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        printManager.cancelPrintJob(printJobId, PrintManager.APP_ID_ANY,
341835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                UserHandle.myUserId());
342835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    } catch (RemoteException re) {
343835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        Log.i(LOG_TAG, "Error requestion print job cancellation", re);
344835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    } finally {
345835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        wakeLock.release();
346835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
347835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    return null;
348835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                }
349835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
3508c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
3518c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
3522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        private void handleRestartPrintJob(final Context context, final PrintJobId printJobId) {
3538c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            if (DEBUG) {
3548c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov                Log.i(LOG_TAG, "handleRestartPrintJob() printJobId:" + printJobId);
3558c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            }
3568c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
357835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // Call into the print manager service off the main thread since
358835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // the print manager service may end up binding to the print spooler
359835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            // service which binding is handled on the main thread.
360835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            PowerManager powerManager = (PowerManager)
361835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    context.getSystemService(Context.POWER_SERVICE);
362835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
363835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    LOG_TAG);
364835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            wakeLock.acquire();
365835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov
366835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            new AsyncTask<Void, Void, Void>() {
367835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                @Override
368835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                protected Void doInBackground(Void... params) {
369835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // We need to request the restart to be done by the print manager
370835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // service since the latter must be bound to the spooler because
371835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // restarting a print job will trigger persistence of current jobs
372835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // which is done on another thread and until it finishes the spooler has
373835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    // to be kept around.
374835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    try {
375835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        IPrintManager printManager = IPrintManager.Stub.asInterface(
376835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                ServiceManager.getService(Context.PRINT_SERVICE));
377835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        printManager.restartPrintJob(printJobId, PrintManager.APP_ID_ANY,
378835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                                UserHandle.myUserId());
379835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    } catch (RemoteException re) {
380835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        Log.i(LOG_TAG, "Error requestion print job restart", re);
381835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    } finally {
382835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                        wakeLock.release();
383835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    }
384835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                    return null;
385835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov                }
386835835ee6f913408ac91678d6056896a2c5b25e3Svetoslav Ganov            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
3878c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
3888c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
3898c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov}
390