From 98963260dc30f1dc3e89dbd0efdfcdc6398d753c Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 16 Dec 2015 16:57:05 -0800 Subject: [PATCH] Prefer printers that have been used physically close to the current location of the user. Commonly the users prints on a printer that this near the user current location. Hence if possible we want to show the user printers that he used before and that are close to him. Hence store the location of the previous uses of a printer and prefer printer that are close to the user. Unfortunately getLastLocation might not report a usable location and it will take at least 5 seconds until the first usable location arrives. At this time the user might have already opened the destionation spinner. It would be unexpected for the printers to suddenly change under the users finger. Hence it might be that we did first show the printer without any location information and then once the location is known we cannot update thedestination spinner anymore. The select printer activity does not have this issue, hence in the worst case the user has to enter this activity to select a printer and by then the location is usually determined. This is not ideal but better than before. Bug: 24133609 Change-Id: Ie7d20cf3d9dd163e57903f8f6ecc0b3fd4f4374e --- packages/PrintSpooler/AndroidManifest.xml | 2 + .../ui/FusedPrintersProvider.java | 403 ++++++++++++++---- .../pm/DefaultPermissionGrantPolicy.java | 8 + 3 files changed, 335 insertions(+), 78 deletions(-) diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 937eb157268c7..af9d25196bec5 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -38,6 +38,8 @@ + + > { +public final class FusedPrintersProvider extends Loader> + implements LocationListener { private static final String LOG_TAG = "FusedPrintersProvider"; private static final boolean DEBUG = false; @@ -70,10 +81,22 @@ public final class FusedPrintersProvider extends Loader> { private static final int MAX_FAVORITE_PRINTER_COUNT = 4; + /** Interval of location updated in ms */ + private static final int LOCATION_UPDATE_MS = 30 * 1000; + + /** Maximum acceptable age of the location in ms */ + private static final int MAX_LOCATION_AGE_MS = 10 * 60 * 1000; + + /** The worst accuracy that is considered usable in m */ + private static final int MIN_LOCATION_ACCURACY = 50; + + /** Maximum distance where a printer is still considered "near" */ + private static final int MAX_PRINTER_DISTANCE = MIN_LOCATION_ACCURACY * 2; + private final List mPrinters = new ArrayList<>(); - private final List mFavoritePrinters = + private final List> mFavoritePrinters = new ArrayList<>(); private final PersistenceManager mPersistenceManager; @@ -84,33 +107,111 @@ public final class FusedPrintersProvider extends Loader> { private boolean mPrintersUpdatedBefore; + /** Last known location, can be null or out of date */ + private final Object mLocationLock; + private Location mLocation; + + /** Location used when the printers were updated the last time */ + private Location mLocationOfLastPrinterUpdate; + + /** Reference to the system's location manager */ + private final LocationManager mLocationManager; + + /** + * Get a reference to the current location. + */ + private Location getCurrentLocation() { + synchronized (mLocationLock) { + return mLocation; + } + } + public FusedPrintersProvider(Context context) { super(context); + mLocationLock = new Object(); mPersistenceManager = new PersistenceManager(context); + mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); } public void addHistoricalPrinter(PrinterInfo printer) { mPersistenceManager.addPrinterAndWritePrinterHistory(printer); } + /** + * Add printer to dest, or if updatedPrinters add the updated printer. If the updated printer + * was added, remove it from updatedPrinters. + * + * @param dest The list the printers should be added to + * @param printer The printer to add + * @param updatedPrinters The printer to add + */ + private void updateAndAddPrinter(List dest, PrinterInfo printer, + Map updatedPrinters) { + PrinterInfo updatedPrinter = updatedPrinters.remove(printer.getId()); + if (updatedPrinter != null) { + dest.add(updatedPrinter); + } else { + dest.add(printer); + } + } + + /** + * Compute the printers, order them appropriately and deliver the printers to the clients. We + * prefer printers that have been previously used (favorites) and printers that have been used + * previously close to the current location (near printers). + * + * @param discoveredPrinters All printers currently discovered by the print discovery session. + * @param favoritePrinters The ordered list of printers. The earlier in the list, the more + * preferred. + */ private void computeAndDeliverResult(Map discoveredPrinters, - List favoritePrinters) { + List> favoritePrinters) { List printers = new ArrayList<>(); - // Add the updated favorite printers. + // Store the printerIds that have already been added. We cannot compare the printerInfos in + // "printers" as they might have been taken from discoveredPrinters and the printerInfo does + // not equals() anymore + HashSet alreadyAddedPrinter = new HashSet<>(MAX_FAVORITE_PRINTER_COUNT); + + Location location = getCurrentLocation(); + + // Add the favorite printers that have last been used close to the current location final int favoritePrinterCount = favoritePrinters.size(); - for (int i = 0; i < favoritePrinterCount; i++) { - PrinterInfo favoritePrinter = favoritePrinters.get(i); - PrinterInfo updatedPrinter = discoveredPrinters.remove( - favoritePrinter.getId()); - if (updatedPrinter != null) { - printers.add(updatedPrinter); - } else { - printers.add(favoritePrinter); + if (location != null) { + for (int i = 0; i < favoritePrinterCount; i++) { + // Only add a certain amount of favorite printers + if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) { + break; + } + + PrinterInfo favoritePrinter = favoritePrinters.get(i).first; + Location printerLocation = favoritePrinters.get(i).second; + + if (printerLocation != null + && !alreadyAddedPrinter.contains(favoritePrinter.getId())) { + if (printerLocation.distanceTo(location) <= MAX_PRINTER_DISTANCE) { + updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters); + alreadyAddedPrinter.add(favoritePrinter.getId()); + } + } } } - // Add other updated printers. + // Add the other favorite printers + for (int i = 0; i < favoritePrinterCount; i++) { + // Only add a certain amount of favorite printers + if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) { + break; + } + + PrinterInfo favoritePrinter = favoritePrinters.get(i).first; + if (!alreadyAddedPrinter.contains(favoritePrinter.getId())) { + updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters); + } + } + + // Add other updated printers. Printers that have already been added have been removed from + // discoveredPrinters in the calls to updateAndAddPrinter final int printerCount = mPrinters.size(); for (int i = 0; i < printerCount; i++) { PrinterInfo printer = mPrinters.get(i); @@ -142,6 +243,21 @@ public final class FusedPrintersProvider extends Loader> { if (DEBUG) { Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode()); } + + mLocationManager.requestLocationUpdates(LocationRequest.create() + .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this, + Looper.getMainLooper()); + + Location lastLocation = mLocationManager.getLastLocation(); + if (lastLocation != null) { + onLocationChanged(lastLocation); + } + + // Jumpstart location with a single forced update + Criteria oneTimeCriteria = new Criteria(); + oneTimeCriteria.setAccuracy(Criteria.ACCURACY_FINE); + mLocationManager.requestSingleUpdate(oneTimeCriteria, this, Looper.getMainLooper()); + // The contract is that if we already have a valid, // result the we have to deliver it immediately. if (!mPrinters.isEmpty()) { @@ -158,6 +274,8 @@ public final class FusedPrintersProvider extends Loader> { Log.i(LOG_TAG, "onStopLoading() " + FusedPrintersProvider.this.hashCode()); } onCancelLoad(); + + mLocationManager.removeUpdates(this); } @Override @@ -188,28 +306,32 @@ public final class FusedPrintersProvider extends Loader> { + " " + FusedPrintersProvider.this.hashCode()); } - updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters); + updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, + getCurrentLocation()); } }); final int favoriteCount = mFavoritePrinters.size(); List printerIds = new ArrayList<>(favoriteCount); for (int i = 0; i < favoriteCount; i++) { - printerIds.add(mFavoritePrinters.get(i).getId()); + printerIds.add(mFavoritePrinters.get(i).first.getId()); } mDiscoverySession.startPrinterDiscovery(printerIds); List printers = mDiscoverySession.getPrinters(); - if (!printers.isEmpty()) { - updatePrinters(printers, mFavoritePrinters); - } + + updatePrinters(printers, mFavoritePrinters, getCurrentLocation()); } } - private void updatePrinters(List printers, List favoritePrinters) { + private void updatePrinters(List printers, + List> favoritePrinters, + Location location) { if (mPrintersUpdatedBefore && mPrinters.equals(printers) - && mFavoritePrinters.equals(favoritePrinters)) { + && mFavoritePrinters.equals(favoritePrinters) + && Objects.equals(mLocationOfLastPrinterUpdate, location)) { return; } + mLocationOfLastPrinterUpdate = location; mPrintersUpdatedBefore = true; // Some of the found printers may have be a printer that is in the @@ -271,6 +393,60 @@ public final class FusedPrintersProvider extends Loader> { onStopLoading(); } + /** + * Check if the location is acceptable. This is to filter out excessively old or inaccurate + * location updates. + * + * @param location the location to check + * @return true iff the location is usable. + */ + private boolean isLocationAcceptable(Location location) { + return location != null + && location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos() + - MAX_LOCATION_AGE_MS * 1000_000L + && location.hasAccuracy() + && location.getAccuracy() < MIN_LOCATION_ACCURACY; + } + + @Override + public void onLocationChanged(Location location) { + synchronized(mLocationLock) { + // We expect the user to not move too fast while printing. Hence prefer more accurate + // updates over more recent ones for LOCATION_UPDATE_MS. We add a 10% fudge factor here + // as the location provider might send an update slightly too early. + if (isLocationAcceptable(location) + && !location.equals(mLocation) + && (mLocation == null + || location + .getElapsedRealtimeNanos() > mLocation.getElapsedRealtimeNanos() + + LOCATION_UPDATE_MS * 0.9 * 1000_000L + || (!mLocation.hasAccuracy() + || location.getAccuracy() < mLocation.getAccuracy()))) { + // Other callers of updatePrinters might want to know the location, hence cache it + mLocation = location; + + if (areHistoricalPrintersLoaded()) { + updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, mLocation); + } + } + } + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + // nothing to do + } + + @Override + public void onProviderEnabled(String provider) { + // nothing to do + } + + @Override + public void onProviderDisabled(String provider) { + // nothing to do + } + public boolean areHistoricalPrintersLoaded() { return mPersistenceManager.mReadHistoryCompleted; } @@ -294,7 +470,7 @@ public final class FusedPrintersProvider extends Loader> { public boolean isFavoritePrinter(PrinterId printerId) { final int printerCount = mFavoritePrinters.size(); for (int i = 0; i < printerCount; i++) { - PrinterInfo favoritePritner = mFavoritePrinters.get(i); + PrinterInfo favoritePritner = mFavoritePrinters.get(i).first; if (favoritePritner.getId().equals(printerId)) { return true; } @@ -303,28 +479,22 @@ public final class FusedPrintersProvider extends Loader> { } public void forgetFavoritePrinter(PrinterId printerId) { - List newFavoritePrinters = null; + final int favoritePrinterCount = mFavoritePrinters.size(); + List> newFavoritePrinters = new ArrayList<>( + favoritePrinterCount - 1); // Remove the printer from the favorites. - final int favoritePrinterCount = mFavoritePrinters.size(); for (int i = 0; i < favoritePrinterCount; i++) { - PrinterInfo favoritePrinter = mFavoritePrinters.get(i); - if (favoritePrinter.getId().equals(printerId)) { - newFavoritePrinters = new ArrayList<>(); - newFavoritePrinters.addAll(mPrinters); - newFavoritePrinters.remove(i); - break; + if (!mFavoritePrinters.get(i).first.getId().equals(printerId)) { + newFavoritePrinters.add(mFavoritePrinters.get(i)); } } - // If we removed a favorite printer, we have work to do. - if (newFavoritePrinters != null) { - // Remove the printer from history and persist the latter. - mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId); + // Remove the printer from history and persist the latter. + mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId); - // Recompute and deliver the printers. - updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters); - } + // Recompute and deliver the printers. + updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation()); } private final class PersistenceManager { @@ -333,17 +503,22 @@ public final class FusedPrintersProvider extends Loader> { private static final String TAG_PRINTERS = "printers"; private static final String TAG_PRINTER = "printer"; + private static final String TAG_LOCATION = "location"; private static final String TAG_PRINTER_ID = "printerId"; private static final String ATTR_LOCAL_ID = "localId"; private static final String ATTR_SERVICE_NAME = "serviceName"; + private static final String ATTR_LONGITUDE = "longitude"; + private static final String ATTR_LATITUDE = "latitude"; + private static final String ATTR_ACCURACY = "accuracy"; + private static final String ATTR_NAME = "name"; private static final String ATTR_DESCRIPTION = "description"; private final AtomicFile mStatePersistFile; - private List mHistoricalPrinters = new ArrayList<>(); + private List> mHistoricalPrinters = new ArrayList<>(); private boolean mReadHistoryCompleted; @@ -402,7 +577,7 @@ public final class FusedPrintersProvider extends Loader> { boolean writeHistory = false; final int printerCount = mHistoricalPrinters.size(); for (int i = 0; i < printerCount; i++) { - PrinterInfo historicalPrinter = mHistoricalPrinters.get(i); + PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first; if (!historicalPrinter.getId().equals(printer.getId())) { continue; @@ -414,7 +589,8 @@ public final class FusedPrintersProvider extends Loader> { continue; } - mHistoricalPrinters.set(i, printer); + mHistoricalPrinters.set(i, new Pair(printer, + mHistoricalPrinters.get(i).second)); // We only persist limited information in the printer history, hence check if // we need to persist the update. @@ -433,7 +609,14 @@ public final class FusedPrintersProvider extends Loader> { if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) { mHistoricalPrinters.remove(0); } - mHistoricalPrinters.add(printer); + + Location location = getCurrentLocation(); + if (!isLocationAcceptable(location)) { + location = null; + } + + mHistoricalPrinters.add(new Pair(printer, location)); + writePrinterHistory(); } @@ -441,7 +624,7 @@ public final class FusedPrintersProvider extends Loader> { boolean writeHistory = false; final int printerCount = mHistoricalPrinters.size(); for (int i = printerCount - 1; i >= 0; i--) { - PrinterInfo historicalPrinter = mHistoricalPrinters.get(i); + PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first; if (historicalPrinter.getId().equals(printerId)) { mHistoricalPrinters.remove(i); writeHistory = true; @@ -462,63 +645,91 @@ public final class FusedPrintersProvider extends Loader> { return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified(); } - private List computeFavoritePrinters(List printers) { + /** + * Sort the favorite printers by weight. If a printer is in the list multiple times for + * different locations, all instances are considered to have the accumulative weight. The + * actual favorite printers to display are computed in {@link #computeAndDeliverResult} as + * only at this time we know the location to use to determine if a printer is close enough + * to be preferred. + * + * @param printers The printers to sort. + * @return The sorted printers. + */ + private List> sortFavoritePrinters( + List> printers) { Map recordMap = new ArrayMap<>(); - // Recompute the weights. + // Compute the weights. float currentWeight = 1.0f; final int printerCount = printers.size(); for (int i = printerCount - 1; i >= 0; i--) { - PrinterInfo printer = printers.get(i); - // Aggregate weight for the same printer - PrinterRecord record = recordMap.get(printer.getId()); + PrinterId printerId = printers.get(i).first.getId(); + PrinterRecord record = recordMap.get(printerId); if (record == null) { - record = new PrinterRecord(printer); - recordMap.put(printer.getId(), record); + record = new PrinterRecord(); + recordMap.put(printerId, record); } + + record.printers.add(printers.get(i)); + + // Aggregate weight for the same printer record.weight += currentWeight; currentWeight *= WEIGHT_DECAY_COEFFICIENT; } - // Soft the favorite printers. + // Sort the favorite printers. List favoriteRecords = new ArrayList<>( recordMap.values()); Collections.sort(favoriteRecords); // Write the favorites to the output. - final int favoriteCount = Math.min(favoriteRecords.size(), - MAX_FAVORITE_PRINTER_COUNT); - List favoritePrinters = new ArrayList<>(favoriteCount); - for (int i = 0; i < favoriteCount; i++) { - PrinterInfo printer = favoriteRecords.get(i).printer; - favoritePrinters.add(printer); + final int recordCount = favoriteRecords.size(); + List> favoritePrinters = new ArrayList<>(printerCount); + for (int i = 0; i < recordCount; i++) { + favoritePrinters.addAll(favoriteRecords.get(i).printers); } return favoritePrinters; } + /** + * A set of printers with the same ID and the weight associated with them during + * {@link #sortFavoritePrinters}. + */ private final class PrinterRecord implements Comparable { - public final PrinterInfo printer; + /** + * The printers, all with the same ID, but potentially different properties or locations + */ + public final List> printers; + + /** The weight associated with the printers */ public float weight; - public PrinterRecord(PrinterInfo printer) { - this.printer = printer; + /** + * Create a new record. + */ + public PrinterRecord() { + printers = new ArrayList<>(); } + /** + * Compare two records by weight. + */ @Override public int compareTo(PrinterRecord another) { return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight); } } - private final class ReadTask extends AsyncTask> { + private final class ReadTask + extends AsyncTask>> { @Override - protected List doInBackground(Void... args) { + protected List> doInBackground(Void... args) { return doReadPrinterHistory(); } @Override - protected void onPostExecute(List printers) { + protected void onPostExecute(List> printers) { if (DEBUG) { Log.i(LOG_TAG, "read history completed " + FusedPrintersProvider.this.hashCode()); @@ -541,7 +752,8 @@ public final class FusedPrintersProvider extends Loader> { final int printerCount = printers.size(); for (int i = printerCount - 1; i >= 0; i--) { - ComponentName printerServiceName = printers.get(i).getId().getServiceName(); + ComponentName printerServiceName = printers.get(i).first.getId() + .getServiceName(); if (!enabledComponents.contains(printerServiceName)) { printers.remove(i); } @@ -552,12 +764,13 @@ public final class FusedPrintersProvider extends Loader> { // Compute the favorite printers. mFavoritePrinters.clear(); - mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters)); + mFavoritePrinters.addAll(sortFavoritePrinters(mHistoricalPrinters)); mReadHistoryCompleted = true; // Deliver the printers. - updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters); + updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, + getCurrentLocation()); // We are done. mReadTask = null; @@ -567,12 +780,12 @@ public final class FusedPrintersProvider extends Loader> { } @Override - protected void onCancelled(List printerInfos) { + protected void onCancelled(List> printerInfos) { // We are done. mReadTask = null; } - private List doReadPrinterHistory() { + private List> doReadPrinterHistory() { final FileInputStream in; try { in = mStatePersistFile.openRead(); @@ -584,7 +797,7 @@ public final class FusedPrintersProvider extends Loader> { return new ArrayList<>(); } try { - List printers = new ArrayList<>(); + List> printers = new ArrayList<>(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, StandardCharsets.UTF_8.name()); parseState(parser, printers); @@ -605,8 +818,9 @@ public final class FusedPrintersProvider extends Loader> { return Collections.emptyList(); } - private void parseState(XmlPullParser parser, List outPrinters) - throws IOException, XmlPullParserException { + private void parseState(XmlPullParser parser, + List> outPrinters) + throws IOException, XmlPullParserException { parser.next(); skipEmptyTextTags(parser); expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS); @@ -624,8 +838,9 @@ public final class FusedPrintersProvider extends Loader> { expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS); } - private boolean parsePrinter(XmlPullParser parser, List outPrinters) - throws IOException, XmlPullParserException { + private boolean parsePrinter(XmlPullParser parser, + List> outPrinters) + throws IOException, XmlPullParserException { skipEmptyTextTags(parser); if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) { return false; @@ -647,6 +862,25 @@ public final class FusedPrintersProvider extends Loader> { expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); parser.next(); + skipEmptyTextTags(parser); + Location location; + if (accept(parser, XmlPullParser.START_TAG, TAG_LOCATION)) { + location = new Location(""); + location.setLongitude( + Double.parseDouble(parser.getAttributeValue(null, ATTR_LONGITUDE))); + location.setLatitude( + Double.parseDouble(parser.getAttributeValue(null, ATTR_LATITUDE))); + location.setAccuracy( + Float.parseFloat(parser.getAttributeValue(null, ATTR_ACCURACY))); + parser.next(); + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_LOCATION); + parser.next(); + } else { + location = null; + } + // If the printer is available the printer will be replaced by the one read from the // discovery session, hence the only time when this object is used is when the // printer is unavailable. @@ -655,7 +889,7 @@ public final class FusedPrintersProvider extends Loader> { builder.setDescription(description); PrinterInfo printer = builder.build(); - outPrinters.add(printer); + outPrinters.add(new Pair(printer, location)); if (DEBUG) { Log.i(LOG_TAG, "[RESTORED] " + printer); @@ -700,15 +934,16 @@ public final class FusedPrintersProvider extends Loader> { } } - private final class WriteTask extends AsyncTask, Void, Void> { + private final class WriteTask + extends AsyncTask>, Void, Void> { @Override protected Void doInBackground( - @SuppressWarnings("unchecked") List... printers) { + @SuppressWarnings("unchecked") List>... printers) { doWritePrinterHistory(printers[0]); return null; } - private void doWritePrinterHistory(List printers) { + private void doWritePrinterHistory(List> printers) { FileOutputStream out = null; try { out = mStatePersistFile.startWrite(); @@ -720,7 +955,7 @@ public final class FusedPrintersProvider extends Loader> { final int printerCount = printers.size(); for (int i = 0; i < printerCount; i++) { - PrinterInfo printer = printers.get(i); + PrinterInfo printer = printers.get(i).first; serializer.startTag(null, TAG_PRINTER); @@ -737,6 +972,18 @@ public final class FusedPrintersProvider extends Loader> { .flattenToString()); serializer.endTag(null, TAG_PRINTER_ID); + Location location = printers.get(i).second; + if (location != null) { + serializer.startTag(null, TAG_LOCATION); + serializer.attribute(null, ATTR_LONGITUDE, + String.valueOf(location.getLongitude())); + serializer.attribute(null, ATTR_LATITUDE, + String.valueOf(location.getLatitude())); + serializer.attribute(null, ATTR_ACCURACY, + String.valueOf(location.getAccuracy())); + serializer.endTag(null, TAG_LOCATION); + } + serializer.endTag(null, TAG_PRINTER); if (DEBUG) { diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index f604bb781452b..b254f29e0d5a3 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -594,6 +594,14 @@ final class DefaultPermissionGrantPolicy { } } + // Print Spooler + PackageParser.Package printSpoolerPackage = getSystemPackageLPr( + "com.android.printspooler"); + if (printSpoolerPackage != null + && doesPackageSupportRuntimePermissions(printSpoolerPackage)) { + grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId); + } + mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId); } }