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