Home | History | Annotate | Download | only in print
      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 com.android.server.print;
     18 
     19 import android.Manifest;
     20 import android.app.Notification;
     21 import android.app.NotificationManager;
     22 import android.app.PendingIntent;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.ResolveInfo;
     30 import android.content.pm.ServiceInfo;
     31 import android.database.ContentObserver;
     32 import android.net.Uri;
     33 import android.os.Binder;
     34 import android.os.Bundle;
     35 import android.os.Process;
     36 import android.os.RemoteException;
     37 import android.os.UserHandle;
     38 import android.print.IPrintDocumentAdapter;
     39 import android.print.IPrintJobStateChangeListener;
     40 import android.print.IPrintManager;
     41 import android.print.IPrinterDiscoveryObserver;
     42 import android.print.PrintAttributes;
     43 import android.print.PrintJobId;
     44 import android.print.PrintJobInfo;
     45 import android.print.PrinterId;
     46 import android.printservice.PrintServiceInfo;
     47 import android.provider.Settings;
     48 import android.text.TextUtils;
     49 import android.util.SparseArray;
     50 
     51 import com.android.internal.R;
     52 import com.android.internal.content.PackageMonitor;
     53 import com.android.internal.os.BackgroundThread;
     54 
     55 import java.io.FileDescriptor;
     56 import java.io.PrintWriter;
     57 import java.util.Iterator;
     58 import java.util.List;
     59 import java.util.Set;
     60 
     61 public final class PrintManagerService extends IPrintManager.Stub {
     62 
     63     private static final char COMPONENT_NAME_SEPARATOR = ':';
     64 
     65     private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
     66             "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
     67 
     68     private final Object mLock = new Object();
     69 
     70     private final Context mContext;
     71 
     72     private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
     73 
     74     private int mCurrentUserId = UserHandle.USER_OWNER;
     75 
     76     public PrintManagerService(Context context) {
     77         mContext = context;
     78         registerContentObservers();
     79         registerBoradcastReceivers();
     80     }
     81 
     82     public void systemRuning() {
     83         BackgroundThread.getHandler().post(new Runnable() {
     84             @Override
     85             public void run() {
     86                 final UserState userState;
     87                 synchronized (mLock) {
     88                     userState = getCurrentUserStateLocked();
     89                     userState.updateIfNeededLocked();
     90                 }
     91                 // This is the first time we switch to this user after boot, so
     92                 // now is the time to remove obsolete print jobs since they
     93                 // are from the last boot and no application would query them.
     94                 userState.removeObsoletePrintJobs();
     95             }
     96         });
     97     }
     98 
     99     @Override
    100     public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
    101             PrintAttributes attributes, String packageName, int appId, int userId) {
    102         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    103         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    104         String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
    105         final UserState userState;
    106         synchronized (mLock) {
    107             userState = getOrCreateUserStateLocked(resolvedUserId);
    108         }
    109         final long identity = Binder.clearCallingIdentity();
    110         try {
    111             return userState.print(printJobName, adapter, attributes,
    112                     resolvedPackageName, resolvedAppId);
    113         } finally {
    114             Binder.restoreCallingIdentity(identity);
    115         }
    116     }
    117 
    118     @Override
    119     public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
    120         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    121         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    122         final UserState userState;
    123         synchronized (mLock) {
    124             userState = getOrCreateUserStateLocked(resolvedUserId);
    125         }
    126         final long identity = Binder.clearCallingIdentity();
    127         try {
    128             return userState.getPrintJobInfos(resolvedAppId);
    129         } finally {
    130             Binder.restoreCallingIdentity(identity);
    131         }
    132     }
    133 
    134     @Override
    135     public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
    136         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    137         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    138         final UserState userState;
    139         synchronized (mLock) {
    140             userState = getOrCreateUserStateLocked(resolvedUserId);
    141         }
    142         final long identity = Binder.clearCallingIdentity();
    143         try {
    144             return userState.getPrintJobInfo(printJobId, resolvedAppId);
    145         } finally {
    146             Binder.restoreCallingIdentity(identity);
    147         }
    148     }
    149 
    150     @Override
    151     public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
    152         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    153         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    154         final UserState userState;
    155         synchronized (mLock) {
    156             userState = getOrCreateUserStateLocked(resolvedUserId);
    157         }
    158         final long identity = Binder.clearCallingIdentity();
    159         try {
    160             userState.cancelPrintJob(printJobId, resolvedAppId);
    161         } finally {
    162             Binder.restoreCallingIdentity(identity);
    163         }
    164     }
    165 
    166     @Override
    167     public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
    168         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    169         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    170         final UserState userState;
    171         synchronized (mLock) {
    172             userState = getOrCreateUserStateLocked(resolvedUserId);
    173         }
    174         final long identity = Binder.clearCallingIdentity();
    175         try {
    176             userState.restartPrintJob(printJobId, resolvedAppId);
    177         } finally {
    178             Binder.restoreCallingIdentity(identity);
    179         }
    180     }
    181 
    182     @Override
    183     public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
    184         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    185         final UserState userState;
    186         synchronized (mLock) {
    187             userState = getOrCreateUserStateLocked(resolvedUserId);
    188         }
    189         final long identity = Binder.clearCallingIdentity();
    190         try {
    191             return userState.getEnabledPrintServices();
    192         } finally {
    193             Binder.restoreCallingIdentity(identity);
    194         }
    195     }
    196 
    197     @Override
    198     public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
    199         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    200         final UserState userState;
    201         synchronized (mLock) {
    202             userState = getOrCreateUserStateLocked(resolvedUserId);
    203         }
    204         final long identity = Binder.clearCallingIdentity();
    205         try {
    206             return userState.getInstalledPrintServices();
    207         } finally {
    208             Binder.restoreCallingIdentity(identity);
    209         }
    210     }
    211 
    212     @Override
    213     public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    214             int userId) {
    215         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    216         final UserState userState;
    217         synchronized (mLock) {
    218             userState = getOrCreateUserStateLocked(resolvedUserId);
    219         }
    220         final long identity = Binder.clearCallingIdentity();
    221         try {
    222             userState.createPrinterDiscoverySession(observer);
    223         } finally {
    224             Binder.restoreCallingIdentity(identity);
    225         }
    226     }
    227 
    228     @Override
    229     public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    230             int userId) {
    231         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    232         final UserState userState;
    233         synchronized (mLock) {
    234             userState = getOrCreateUserStateLocked(resolvedUserId);
    235         }
    236         final long identity = Binder.clearCallingIdentity();
    237         try {
    238             userState.destroyPrinterDiscoverySession(observer);
    239         } finally {
    240             Binder.restoreCallingIdentity(identity);
    241         }
    242     }
    243 
    244     @Override
    245     public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
    246             List<PrinterId> priorityList, int userId) {
    247         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    248         final UserState userState;
    249         synchronized (mLock) {
    250             userState = getOrCreateUserStateLocked(resolvedUserId);
    251         }
    252         final long identity = Binder.clearCallingIdentity();
    253         try {
    254             userState.startPrinterDiscovery(observer, priorityList);
    255         } finally {
    256             Binder.restoreCallingIdentity(identity);
    257         }
    258     }
    259 
    260     @Override
    261     public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
    262         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    263         final UserState userState;
    264         synchronized (mLock) {
    265             userState = getOrCreateUserStateLocked(resolvedUserId);
    266         }
    267         final long identity = Binder.clearCallingIdentity();
    268         try {
    269             userState.stopPrinterDiscovery(observer);
    270         } finally {
    271             Binder.restoreCallingIdentity(identity);
    272         }
    273     }
    274 
    275     @Override
    276     public void validatePrinters(List<PrinterId> printerIds, int userId) {
    277         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    278         final UserState userState;
    279         synchronized (mLock) {
    280             userState = getOrCreateUserStateLocked(resolvedUserId);
    281         }
    282         final long identity = Binder.clearCallingIdentity();
    283         try {
    284             userState.validatePrinters(printerIds);
    285         } finally {
    286             Binder.restoreCallingIdentity(identity);
    287         }
    288     }
    289 
    290     @Override
    291     public void startPrinterStateTracking(PrinterId printerId, int userId) {
    292         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    293         final UserState userState;
    294         synchronized (mLock) {
    295             userState = getOrCreateUserStateLocked(resolvedUserId);
    296         }
    297         final long identity = Binder.clearCallingIdentity();
    298         try {
    299             userState.startPrinterStateTracking(printerId);
    300         } finally {
    301             Binder.restoreCallingIdentity(identity);
    302         }
    303     }
    304 
    305     @Override
    306     public void stopPrinterStateTracking(PrinterId printerId, int userId) {
    307         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    308         final UserState userState;
    309         synchronized (mLock) {
    310             userState = getOrCreateUserStateLocked(resolvedUserId);
    311         }
    312         final long identity = Binder.clearCallingIdentity();
    313         try {
    314             userState.stopPrinterStateTracking(printerId);
    315         } finally {
    316             Binder.restoreCallingIdentity(identity);
    317         }
    318     }
    319 
    320     @Override
    321     public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    322             int appId, int userId) throws RemoteException {
    323         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    324         final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    325         final UserState userState;
    326         synchronized (mLock) {
    327             userState = getOrCreateUserStateLocked(resolvedUserId);
    328         }
    329         final long identity = Binder.clearCallingIdentity();
    330         try {
    331             userState.addPrintJobStateChangeListener(listener, resolvedAppId);
    332         } finally {
    333             Binder.restoreCallingIdentity(identity);
    334         }
    335     }
    336 
    337     @Override
    338     public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    339             int userId) {
    340         final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    341         final UserState userState;
    342         synchronized (mLock) {
    343             userState = getOrCreateUserStateLocked(resolvedUserId);
    344         }
    345         final long identity = Binder.clearCallingIdentity();
    346         try {
    347             userState.removePrintJobStateChangeListener(listener);
    348         } finally {
    349             Binder.restoreCallingIdentity(identity);
    350         }
    351     }
    352 
    353     @Override
    354     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    355         if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
    356                 != PackageManager.PERMISSION_GRANTED) {
    357             pw.println("Permission Denial: can't dump PrintManager from from pid="
    358                     + Binder.getCallingPid()
    359                     + ", uid=" + Binder.getCallingUid());
    360             return;
    361         }
    362 
    363         synchronized (mLock) {
    364             final long identity = Binder.clearCallingIdentity();
    365             try {
    366                 pw.println("PRINT MANAGER STATE (dumpsys print)");
    367                 final int userStateCount = mUserStates.size();
    368                 for (int i = 0; i < userStateCount; i++) {
    369                     UserState userState = mUserStates.valueAt(i);
    370                     userState.dump(fd, pw, "");
    371                     pw.println();
    372                 }
    373             } finally {
    374                 Binder.restoreCallingIdentity(identity);
    375             }
    376         }
    377     }
    378 
    379     private void registerContentObservers() {
    380         final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
    381                 Settings.Secure.ENABLED_PRINT_SERVICES);
    382 
    383         ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
    384             @Override
    385             public void onChange(boolean selfChange, Uri uri) {
    386                 if (enabledPrintServicesUri.equals(uri)) {
    387                     synchronized (mLock) {
    388                         UserState userState = getCurrentUserStateLocked();
    389                         userState.updateIfNeededLocked();
    390                     }
    391                 }
    392             }
    393         };
    394 
    395         mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
    396                 false, observer, UserHandle.USER_ALL);
    397     }
    398 
    399     private void registerBoradcastReceivers() {
    400         PackageMonitor monitor = new PackageMonitor() {
    401             @Override
    402             public boolean onPackageChanged(String packageName, int uid, String[] components) {
    403                 synchronized (mLock) {
    404                     UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    405                     Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
    406                     while (iterator.hasNext()) {
    407                         ComponentName componentName = iterator.next();
    408                         if (packageName.equals(componentName.getPackageName())) {
    409                             userState.updateIfNeededLocked();
    410                             return true;
    411                         }
    412                     }
    413                 }
    414                 return false;
    415             }
    416 
    417             @Override
    418             public void onPackageRemoved(String packageName, int uid) {
    419                 synchronized (mLock) {
    420                     UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    421                     Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
    422                     while (iterator.hasNext()) {
    423                         ComponentName componentName = iterator.next();
    424                         if (packageName.equals(componentName.getPackageName())) {
    425                             iterator.remove();
    426                             persistComponentNamesToSettingLocked(
    427                                     Settings.Secure.ENABLED_PRINT_SERVICES,
    428                                     userState.getEnabledServices(), getChangingUserId());
    429                             userState.updateIfNeededLocked();
    430                             return;
    431                         }
    432                     }
    433                 }
    434             }
    435 
    436             @Override
    437             public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
    438                     int uid, boolean doit) {
    439                 synchronized (mLock) {
    440                     UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    441                     boolean stoppedSomePackages = false;
    442                     Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
    443                     while (iterator.hasNext()) {
    444                         ComponentName componentName = iterator.next();
    445                         String componentPackage = componentName.getPackageName();
    446                         for (String stoppedPackage : stoppedPackages) {
    447                             if (componentPackage.equals(stoppedPackage)) {
    448                                 if (!doit) {
    449                                     return true;
    450                                 }
    451                                 stoppedSomePackages = true;
    452                                 break;
    453                             }
    454                         }
    455                     }
    456                     if (stoppedSomePackages) {
    457                         userState.updateIfNeededLocked();
    458                     }
    459                     return false;
    460                 }
    461             }
    462 
    463             @Override
    464             public void onPackageAdded(String packageName, int uid) {
    465                 Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
    466                 intent.setPackage(packageName);
    467 
    468                 List<ResolveInfo> installedServices = mContext.getPackageManager()
    469                         .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
    470                                 getChangingUserId());
    471 
    472                 if (installedServices == null) {
    473                     return;
    474                 }
    475 
    476                 final int installedServiceCount = installedServices.size();
    477                 for (int i = 0; i < installedServiceCount; i++) {
    478                     ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
    479                     ComponentName component = new ComponentName(serviceInfo.packageName,
    480                             serviceInfo.name);
    481                     String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString();
    482                     showEnableInstalledPrintServiceNotification(component, label,
    483                             getChangingUserId());
    484                 }
    485             }
    486 
    487             private void persistComponentNamesToSettingLocked(String settingName,
    488                     Set<ComponentName> componentNames, int userId) {
    489                 StringBuilder builder = new StringBuilder();
    490                 for (ComponentName componentName : componentNames) {
    491                     if (builder.length() > 0) {
    492                         builder.append(COMPONENT_NAME_SEPARATOR);
    493                     }
    494                     builder.append(componentName.flattenToShortString());
    495                 }
    496                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
    497                         settingName, builder.toString(), userId);
    498             }
    499         };
    500 
    501         // package changes
    502         monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
    503                 UserHandle.ALL, true);
    504 
    505         // user changes
    506         IntentFilter intentFilter = new IntentFilter();
    507         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
    508         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
    509 
    510         mContext.registerReceiverAsUser(new BroadcastReceiver() {
    511             @Override
    512             public void onReceive(Context context, Intent intent) {
    513                 String action = intent.getAction();
    514                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
    515                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
    516                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
    517                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
    518                 }
    519             }
    520         }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
    521     }
    522 
    523     private UserState getCurrentUserStateLocked() {
    524         return getOrCreateUserStateLocked(mCurrentUserId);
    525     }
    526 
    527     private UserState getOrCreateUserStateLocked(int userId) {
    528         UserState userState = mUserStates.get(userId);
    529         if (userState == null) {
    530             userState = new UserState(mContext, userId, mLock);
    531             mUserStates.put(userId, userState);
    532         }
    533         return userState;
    534     }
    535 
    536     private void switchUser(int newUserId) {
    537         UserState userState;
    538         synchronized (mLock) {
    539             if (newUserId == mCurrentUserId) {
    540                 return;
    541             }
    542             mCurrentUserId = newUserId;
    543             userState = mUserStates.get(mCurrentUserId);
    544             if (userState == null) {
    545                 userState = getCurrentUserStateLocked();
    546                 userState.updateIfNeededLocked();
    547             } else {
    548                 userState.updateIfNeededLocked();
    549             }
    550         }
    551         // This is the first time we switch to this user after boot, so
    552         // now is the time to remove obsolete print jobs since they
    553         // are from the last boot and no application would query them.
    554         userState.removeObsoletePrintJobs();
    555     }
    556 
    557     private void removeUser(int removedUserId) {
    558         synchronized (mLock) {
    559             UserState userState = mUserStates.get(removedUserId);
    560             if (userState != null) {
    561                 userState.destroyLocked();
    562                 mUserStates.remove(removedUserId);
    563             }
    564         }
    565     }
    566 
    567     private int resolveCallingAppEnforcingPermissions(int appId) {
    568         final int callingUid = Binder.getCallingUid();
    569         if (callingUid == 0 || callingUid == Process.SYSTEM_UID
    570                 || callingUid == Process.SHELL_UID) {
    571             return appId;
    572         }
    573         final int callingAppId = UserHandle.getAppId(callingUid);
    574         if (appId == callingAppId) {
    575             return appId;
    576         }
    577         if (mContext.checkCallingPermission(
    578                 "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
    579                 != PackageManager.PERMISSION_GRANTED) {
    580             throw new SecurityException("Call from app " + callingAppId + " as app "
    581                     + appId + " without com.android.printspooler.permission"
    582                     + ".ACCESS_ALL_PRINT_JOBS");
    583         }
    584         return appId;
    585     }
    586 
    587     private int resolveCallingUserEnforcingPermissions(int userId) {
    588         final int callingUid = Binder.getCallingUid();
    589         if (callingUid == 0 || callingUid == Process.SYSTEM_UID
    590                 || callingUid == Process.SHELL_UID) {
    591             return userId;
    592         }
    593         final int callingUserId = UserHandle.getUserId(callingUid);
    594         if (callingUserId == userId) {
    595             return userId;
    596         }
    597         if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
    598                 != PackageManager.PERMISSION_GRANTED
    599             ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
    600                 != PackageManager.PERMISSION_GRANTED) {
    601             if (userId == UserHandle.USER_CURRENT_OR_SELF) {
    602                 return callingUserId;
    603             }
    604             throw new SecurityException("Call from user " + callingUserId + " as user "
    605                 + userId + " without permission INTERACT_ACROSS_USERS or "
    606                 + "INTERACT_ACROSS_USERS_FULL not allowed.");
    607         }
    608         if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
    609             return mCurrentUserId;
    610         }
    611         throw new IllegalArgumentException("Calling user can be changed to only "
    612                 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
    613     }
    614 
    615     private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
    616         if (TextUtils.isEmpty(packageName)) {
    617             return null;
    618         }
    619         String[] packages = mContext.getPackageManager().getPackagesForUid(
    620                 Binder.getCallingUid());
    621         final int packageCount = packages.length;
    622         for (int i = 0; i < packageCount; i++) {
    623             if (packageName.equals(packages[i])) {
    624                 return packageName;
    625             }
    626         }
    627         return null;
    628     }
    629 
    630     private void showEnableInstalledPrintServiceNotification(ComponentName component,
    631             String label, int userId) {
    632         UserHandle userHandle = new UserHandle(userId);
    633 
    634         Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
    635         intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
    636 
    637         PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
    638                 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle);
    639 
    640         Notification.Builder builder = new Notification.Builder(mContext)
    641                 .setSmallIcon(R.drawable.ic_print)
    642                 .setContentTitle(mContext.getString(R.string.print_service_installed_title, label))
    643                 .setContentText(mContext.getString(R.string.print_service_installed_message))
    644                 .setContentIntent(pendingIntent)
    645                 .setWhen(System.currentTimeMillis())
    646                 .setAutoCancel(true)
    647                 .setShowWhen(true);
    648 
    649         NotificationManager notificationManager = (NotificationManager) mContext
    650                 .getSystemService(Context.NOTIFICATION_SERVICE);
    651 
    652         String notificationTag = getClass().getName() + ":" + component.flattenToString();
    653         notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
    654                 userHandle);
    655     }
    656 }
    657