14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/*
24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2013 The Android Open Source Project
34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License.
64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at
74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and
144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License.
154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage com.android.server.print;
184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.Manifest;
20d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.app.Notification;
21d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.app.NotificationManager;
22d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.app.PendingIntent;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.BroadcastReceiver;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.ComponentName;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Context;
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.Intent;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.IntentFilter;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.content.pm.PackageManager;
29d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.content.pm.ResolveInfo;
30d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.content.pm.ServiceInfo;
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.database.ContentObserver;
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.net.Uri;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Binder;
347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.os.Bundle;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Process;
36704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganovimport android.os.RemoteException;
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.UserHandle;
38a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.print.IPrintDocumentAdapter;
39704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganovimport android.print.IPrintJobStateChangeListener;
404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.IPrintManager;
4144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.print.IPrinterDiscoveryObserver;
424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintAttributes;
432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslavimport android.print.PrintJobId;
444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.print.PrintJobInfo;
4544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport android.print.PrinterId;
46860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganovimport android.printservice.PrintServiceInfo;
474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.provider.Settings;
487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport android.text.TextUtils;
49a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport android.util.SparseArray;
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
51d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport com.android.internal.R;
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport com.android.internal.content.PackageMonitor;
53a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport com.android.internal.os.BackgroundThread;
544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
55b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.FileDescriptor;
56b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganovimport java.io.PrintWriter;
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Iterator;
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.List;
594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Set;
604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpublic final class PrintManagerService extends IPrintManager.Stub {
624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private static final char COMPONENT_NAME_SEPARATOR = ':';
644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
65d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav    private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
66d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav            "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
67d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final Object mLock = new Object();
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private final Context mContext;
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
72a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private int mCurrentUserId = UserHandle.USER_OWNER;
754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public PrintManagerService(Context context) {
774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mContext = context;
784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        registerContentObservers();
79a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        registerBoradcastReceivers();
80a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
81a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void systemRuning() {
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        BackgroundThread.getHandler().post(new Runnable() {
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            @Override
85a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public void run() {
862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                final UserState userState;
87a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                synchronized (mLock) {
882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                    userState = getCurrentUserStateLocked();
89a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    userState.updateIfNeededLocked();
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                // This is the first time we switch to this user after boot, so
922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                // now is the time to remove obsolete print jobs since they
932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                // are from the last boot and no application would query them.
942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                userState.removeObsoletePrintJobs();
95a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
96a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        });
974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
1017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            PrintAttributes attributes, String packageName, int appId, int userId) {
102a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
103a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
1047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
105a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final UserState userState;
106a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
107a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
108a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return userState.print(printJobName, adapter, attributes,
1127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                    resolvedPackageName, resolvedAppId);
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } finally {
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
119a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
120a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
121a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
122a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final UserState userState;
123a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
124a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
125a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1282fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return userState.getPrintJobInfos(resolvedAppId);
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } finally {
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1352fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
137a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
138a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final UserState userState;
139a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
140a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
141a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return userState.getPrintJobInfo(printJobId, resolvedAppId);
1454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } finally {
1464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
1474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    @Override
1512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
152a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
153a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
154a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final UserState userState;
155a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        synchronized (mLock) {
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
1584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
1594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        try {
1602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            userState.cancelPrintJob(printJobId, resolvedAppId);
1618c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        } finally {
1628c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
1638c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
1648c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
1658c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov
1668c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    @Override
1672fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
1688c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
1698c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
1702fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        final UserState userState;
1718c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        synchronized (mLock) {
1722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            userState = getOrCreateUserStateLocked(resolvedUserId);
1738c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        }
1748c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
1758c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        try {
1762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            userState.restartPrintJob(printJobId, resolvedAppId);
1774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        } finally {
1784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
1794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
182860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    @Override
183860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
184860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
185860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        final UserState userState;
186860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        synchronized (mLock) {
187860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
188860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        }
189860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        final long identity = Binder.clearCallingIdentity();
190860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        try {
191860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            return userState.getEnabledPrintServices();
192860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        } finally {
193860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            Binder.restoreCallingIdentity(identity);
194860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        }
195860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    }
196860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov
19744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
198d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
199d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
200d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        final UserState userState;
201d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        synchronized (mLock) {
202d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            userState = getOrCreateUserStateLocked(resolvedUserId);
203d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        }
204d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        final long identity = Binder.clearCallingIdentity();
205d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        try {
206d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            return userState.getInstalledPrintServices();
207d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        } finally {
208d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav            Binder.restoreCallingIdentity(identity);
209d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        }
210d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    }
211d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav
212d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    @Override
21344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
21444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            int userId) {
21544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
21644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final UserState userState;
21744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
21844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
21944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
22044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
22144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
22244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState.createPrinterDiscoverySession(observer);
22344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
22444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
22544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
22644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
22744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
22844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
22944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
23044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            int userId) {
23144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
23244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final UserState userState;
23344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
23444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
23544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
23644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
23744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
23844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState.destroyPrinterDiscoverySession(observer);
23944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
24044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
24144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
24244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
24344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
24444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
24544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
24644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            List<PrinterId> priorityList, int userId) {
24744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
24844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final UserState userState;
24944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
25044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
25144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
25344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
25444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState.startPrinterDiscovery(observer, priorityList);
25544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
25644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
25744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
25944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
26044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
26144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
26244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
26344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final UserState userState;
26444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
26544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
26644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
26744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
26844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
26944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState.stopPrinterDiscovery(observer);
27044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
27144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
27244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
27344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
27444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
27544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @Override
276d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void validatePrinters(List<PrinterId> printerIds, int userId) {
27744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
27844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final UserState userState;
27944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        synchronized (mLock) {
28044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
28144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
28244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
28344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
284d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            userState.validatePrinters(printerIds);
285d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } finally {
286d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
287d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
288d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
289d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
290d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    @Override
291d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void startPrinterStateTracking(PrinterId printerId, int userId) {
292d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
293d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final UserState userState;
294d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        synchronized (mLock) {
295d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
296d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
297d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
298d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
299d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            userState.startPrinterStateTracking(printerId);
300d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } finally {
301d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
302d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
303d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
304d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov
305d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    @Override
306d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    public void stopPrinterStateTracking(PrinterId printerId, int userId) {
307d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
308d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final UserState userState;
309d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        synchronized (mLock) {
310d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
311d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
312d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
313d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        try {
314d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            userState.stopPrinterStateTracking(printerId);
31544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } finally {
31644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
31744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
31844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
31944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
320b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    @Override
321704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
322704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            int appId, int userId) throws RemoteException {
323704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
324704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
325704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final UserState userState;
326704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        synchronized (mLock) {
327704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
328704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
329704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
330704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        try {
331704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            userState.addPrintJobStateChangeListener(listener, resolvedAppId);
332704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        } finally {
333704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
334704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
335704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
336704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
337704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    @Override
338704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
339704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            int userId) {
340704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
341704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final UserState userState;
342704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        synchronized (mLock) {
343704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            userState = getOrCreateUserStateLocked(resolvedUserId);
344704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
345704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        final long identity = Binder.clearCallingIdentity();
346704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        try {
347704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            userState.removePrintJobStateChangeListener(listener);
348704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        } finally {
349704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov            Binder.restoreCallingIdentity(identity);
350704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov        }
351704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    }
352704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
353704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov    @Override
354b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
355b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
356b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                != PackageManager.PERMISSION_GRANTED) {
357b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            pw.println("Permission Denial: can't dump PrintManager from from pid="
358b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    + Binder.getCallingPid()
359b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov                    + ", uid=" + Binder.getCallingUid());
360b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            return;
361b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
362b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
363b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        synchronized (mLock) {
3645fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav            final long identity = Binder.clearCallingIdentity();
3655fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav            try {
3665fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                pw.println("PRINT MANAGER STATE (dumpsys print)");
3675fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                final int userStateCount = mUserStates.size();
3685fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                for (int i = 0; i < userStateCount; i++) {
3693cb2be97a226ae605f7b983739e02f40c0403989Svetoslav Ganov                    UserState userState = mUserStates.valueAt(i);
3705fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                    userState.dump(fd, pw, "");
3715fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                    pw.println();
3725fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                }
3735fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav            } finally {
3745fe07aa7a81c840eaf52bf95d4d5bacd914a8106Svetoslav                Binder.restoreCallingIdentity(identity);
375b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov            }
376b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov        }
377b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    }
378b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
3794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private void registerContentObservers() {
3804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
3814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                Settings.Secure.ENABLED_PRINT_SERVICES);
3824b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
383a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
3844b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
3854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public void onChange(boolean selfChange, Uri uri) {
3864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                if (enabledPrintServicesUri.equals(uri)) {
3874b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    synchronized (mLock) {
388a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        UserState userState = getCurrentUserStateLocked();
389a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        userState.updateIfNeededLocked();
3904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
3914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
3924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
3934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        };
3944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
3954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
3964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                false, observer, UserHandle.USER_ALL);
3974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
3984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
399a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void registerBoradcastReceivers() {
4004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        PackageMonitor monitor = new PackageMonitor() {
4014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
402a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            public boolean onPackageChanged(String packageName, int uid, String[] components) {
4034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                synchronized (mLock) {
404a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
405a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
406a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    while (iterator.hasNext()) {
407a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        ComponentName componentName = iterator.next();
408a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        if (packageName.equals(componentName.getPackageName())) {
409a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            userState.updateIfNeededLocked();
410a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            return true;
411a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        }
4124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
4134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
414a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return false;
4154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
4184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public void onPackageRemoved(String packageName, int uid) {
4194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                synchronized (mLock) {
420a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
421a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
4224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    while (iterator.hasNext()) {
4234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        ComponentName componentName = iterator.next();
4244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        if (packageName.equals(componentName.getPackageName())) {
4254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            iterator.remove();
426a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            persistComponentNamesToSettingLocked(
427a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                    Settings.Secure.ENABLED_PRINT_SERVICES,
428a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                    userState.getEnabledServices(), getChangingUserId());
429a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                            userState.updateIfNeededLocked();
4304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            return;
4314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        }
4324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
4334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
4344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
4364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
4374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
4384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    int uid, boolean doit) {
4394b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                synchronized (mLock) {
440a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
441a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    boolean stoppedSomePackages = false;
442a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
4434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    while (iterator.hasNext()) {
4444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        ComponentName componentName = iterator.next();
4454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        String componentPackage = componentName.getPackageName();
4464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        for (String stoppedPackage : stoppedPackages) {
4474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            if (componentPackage.equals(stoppedPackage)) {
4484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                                if (!doit) {
4494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                                    return true;
4504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                                }
451a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                stoppedSomePackages = true;
452a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                                break;
4534b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                            }
4544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                        }
4554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    }
456a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    if (stoppedSomePackages) {
457a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        userState.updateIfNeededLocked();
458a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    }
4594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    return false;
4604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
4614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
463d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav            @Override
464d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav            public void onPackageAdded(String packageName, int uid) {
465d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
466d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                intent.setPackage(packageName);
467d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
468d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                List<ResolveInfo> installedServices = mContext.getPackageManager()
469d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                        .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
470d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                                getChangingUserId());
471d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
472cb247866acf10b039e02b600f8471b4a508f0ce8Svetoslav Ganov                if (installedServices == null) {
473cb247866acf10b039e02b600f8471b4a508f0ce8Svetoslav Ganov                    return;
474cb247866acf10b039e02b600f8471b4a508f0ce8Svetoslav Ganov                }
475cb247866acf10b039e02b600f8471b4a508f0ce8Svetoslav Ganov
476d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                final int installedServiceCount = installedServices.size();
477d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                for (int i = 0; i < installedServiceCount; i++) {
478d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                    ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
479d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                    ComponentName component = new ComponentName(serviceInfo.packageName,
480d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                            serviceInfo.name);
481d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                    String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString();
4824a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov                    showEnableInstalledPrintServiceNotification(component, label,
4834a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov                            getChangingUserId());
484d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                }
485d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav            }
486d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
487a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            private void persistComponentNamesToSettingLocked(String settingName,
488a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Set<ComponentName> componentNames, int userId) {
489a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                StringBuilder builder = new StringBuilder();
490a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                for (ComponentName componentName : componentNames) {
491a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    if (builder.length() > 0) {
492a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        builder.append(COMPONENT_NAME_SEPARATOR);
493a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    }
494a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    builder.append(componentName.flattenToShortString());
495a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                }
496a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                Settings.Secure.putStringForUser(mContext.getContentResolver(),
497a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        settingName, builder.toString(), userId);
4984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
4994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        };
5004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        // package changes
502a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
503a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                UserHandle.ALL, true);
5044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5054b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        // user changes
5064b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        IntentFilter intentFilter = new IntentFilter();
5074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
5082fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
5094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mContext.registerReceiverAsUser(new BroadcastReceiver() {
5114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            @Override
5124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            public void onReceive(Context context, Intent intent) {
5134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                String action = intent.getAction();
5144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
5154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
516a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
517a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
5184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                }
5194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
520a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
5214b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5224b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
523a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private UserState getCurrentUserStateLocked() {
524a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return getOrCreateUserStateLocked(mCurrentUserId);
5254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
527a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private UserState getOrCreateUserStateLocked(int userId) {
528a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        UserState userState = mUserStates.get(userId);
529a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (userState == null) {
530a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            userState = new UserState(mContext, userId, mLock);
531a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mUserStates.put(userId, userState);
5324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
533a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return userState;
5344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
5364b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private void switchUser(int newUserId) {
5372fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        UserState userState;
5384b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        synchronized (mLock) {
539a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (newUserId == mCurrentUserId) {
540a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return;
541a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
5424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mCurrentUserId = newUserId;
5432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            userState = mUserStates.get(mCurrentUserId);
5442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            if (userState == null) {
5452fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                userState = getCurrentUserStateLocked();
5462fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                userState.updateIfNeededLocked();
5472fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            } else {
5482fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav                userState.updateIfNeededLocked();
5492fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            }
5504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
5512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        // This is the first time we switch to this user after boot, so
5522fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        // now is the time to remove obsolete print jobs since they
5532fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        // are from the last boot and no application would query them.
5542fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        userState.removeObsoletePrintJobs();
5554b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
557a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private void removeUser(int removedUserId) {
5584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        synchronized (mLock) {
559a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            UserState userState = mUserStates.get(removedUserId);
560a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            if (userState != null) {
561a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                userState.destroyLocked();
562a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                mUserStates.remove(removedUserId);
5634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
5644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
565a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
566a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
567a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private int resolveCallingAppEnforcingPermissions(int appId) {
568a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int callingUid = Binder.getCallingUid();
569a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
570a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                || callingUid == Process.SHELL_UID) {
571a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return appId;
5724b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
573a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        final int callingAppId = UserHandle.getAppId(callingUid);
574a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        if (appId == callingAppId) {
575a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            return appId;
576a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
577d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        if (mContext.checkCallingPermission(
578d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
579a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                != PackageManager.PERMISSION_GRANTED) {
580a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            throw new SecurityException("Call from app " + callingAppId + " as app "
581d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    + appId + " without com.android.printspooler.permission"
582d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov                    + ".ACCESS_ALL_PRINT_JOBS");
5834b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
584a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        return appId;
5854b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
5864b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
587a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    private int resolveCallingUserEnforcingPermissions(int userId) {
5884b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final int callingUid = Binder.getCallingUid();
5894b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
5904b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                || callingUid == Process.SHELL_UID) {
5914b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return userId;
5924b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
5934b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        final int callingUserId = UserHandle.getUserId(callingUid);
5944b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (callingUserId == userId) {
5954b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return userId;
5964b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
5974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
5984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                != PackageManager.PERMISSION_GRANTED
5994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
6004b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                != PackageManager.PERMISSION_GRANTED) {
6014b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (userId == UserHandle.USER_CURRENT_OR_SELF) {
6024b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                return callingUserId;
6034b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
6044b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            throw new SecurityException("Call from user " + callingUserId + " as user "
605a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                + userId + " without permission INTERACT_ACROSS_USERS or "
606a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                + "INTERACT_ACROSS_USERS_FULL not allowed.");
6074b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
6084b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
6094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return mCurrentUserId;
6104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
6114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        throw new IllegalArgumentException("Calling user can be changed to only "
6124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
6134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
614d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
6157bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
6167bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        if (TextUtils.isEmpty(packageName)) {
6177bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            return null;
6187bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
6197bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        String[] packages = mContext.getPackageManager().getPackagesForUid(
6207bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                Binder.getCallingUid());
6217bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        final int packageCount = packages.length;
6227bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        for (int i = 0; i < packageCount; i++) {
6237bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            if (packageName.equals(packages[i])) {
6247bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav                return packageName;
6257bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav            }
6267bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        }
6277bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        return null;
6287bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    }
6297bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
630d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav    private void showEnableInstalledPrintServiceNotification(ComponentName component,
6314a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov            String label, int userId) {
6324a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov        UserHandle userHandle = new UserHandle(userId);
6334a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov
634d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
635d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
636d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
6374a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
6384a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle);
639d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
640d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        Notification.Builder builder = new Notification.Builder(mContext)
641d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setSmallIcon(R.drawable.ic_print)
642d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setContentTitle(mContext.getString(R.string.print_service_installed_title, label))
643d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setContentText(mContext.getString(R.string.print_service_installed_message))
644d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setContentIntent(pendingIntent)
645d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setWhen(System.currentTimeMillis())
646d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setAutoCancel(true)
647d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .setShowWhen(true);
648d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
649d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        NotificationManager notificationManager = (NotificationManager) mContext
650d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav                .getSystemService(Context.NOTIFICATION_SERVICE);
651d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
652d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        String notificationTag = getClass().getName() + ":" + component.flattenToString();
6534a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov        notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
6544a82b455f9832430207e3ecfddfad4b67b071407Svetoslav Ganov                userHandle);
655d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav    }
6564b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov}
657