1 /*
2  * Copyright (C) 2015 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.printspooler.util;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.SharedPreferences;
22 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
23 import android.printservice.PrintService;
24 import android.util.ArraySet;
25 
26 import java.util.List;
27 import java.util.Set;
28 
29 /**
30  * Manage approved print services. These services are stored in the shared preferences.
31  */
32 public class ApprovedPrintServices {
33     /**
34      * Used for locking accesses to the approved services.
35      */
36     static final public Object sLock = new Object();
37 
38     private static final String APPROVED_SERVICES_PREFERENCE = "PRINT_SPOOLER_APPROVED_SERVICES";
39     private final SharedPreferences mPreferences;
40 
41     /**
42      * Create a new {@link ApprovedPrintServices}
43      *
44      * @param owner The {@link Context} using this object.
45      */
ApprovedPrintServices(Context owner)46     public ApprovedPrintServices(Context owner) {
47         mPreferences = owner.getSharedPreferences(APPROVED_SERVICES_PREFERENCE,
48                 Context.MODE_PRIVATE);
49     }
50 
51     /**
52      * Get {@link Set} of approved services.
53      *
54      * @return A {@link Set} containing all currently approved services.
55      */
getApprovedServices()56     public Set<String> getApprovedServices() {
57         return mPreferences.getStringSet(APPROVED_SERVICES_PREFERENCE, null);
58     }
59 
60     /**
61      * Check if a {@link PrintService} is approved.
62      *
63      * This function does not acquire the {@link #sLock}.
64      *
65      * @param service The {@link ComponentName} of the {@link PrintService} that might be approved
66      * @return true iff the service is currently approved
67      */
isApprovedService(ComponentName service)68     public boolean isApprovedService(ComponentName service) {
69         final Set<String> approvedServices = getApprovedServices();
70 
71         if (approvedServices != null) {
72             final String flattenedString = service.flattenToShortString();
73 
74             for (String approvedService : approvedServices) {
75                 if (approvedService.equals(flattenedString)) {
76                     return true;
77                 }
78             }
79         }
80 
81         return false;
82     }
83 
84     /**
85      * Add a {@link PrintService} to the list of approved print services.
86      *
87      * @param serviceToAdd The {@link ComponentName} of the {@link PrintService} to be approved.
88      */
addApprovedService(ComponentName serviceToAdd)89     public void addApprovedService(ComponentName serviceToAdd) {
90         synchronized (sLock) {
91             Set<String> oldApprovedServices =
92                     mPreferences.getStringSet(APPROVED_SERVICES_PREFERENCE, null);
93 
94             Set<String> newApprovedServices;
95             if (oldApprovedServices == null) {
96                 newApprovedServices = new ArraySet<String>(1);
97             } else {
98                 // Copy approved services.
99                 newApprovedServices = new ArraySet<String>(oldApprovedServices);
100             }
101             newApprovedServices.add(serviceToAdd.flattenToShortString());
102 
103             SharedPreferences.Editor editor = mPreferences.edit();
104             editor.putStringSet(APPROVED_SERVICES_PREFERENCE, newApprovedServices);
105             editor.apply();
106         }
107     }
108 
109     /**
110      * Add a {@link OnSharedPreferenceChangeListener} that listens for changes to the approved
111      * services. Should only be called while holding {@link #sLock} to synchronize against
112      * {@link #addApprovedService}.
113      *
114      * @param listener {@link OnSharedPreferenceChangeListener} to register
115      */
registerChangeListenerLocked(OnSharedPreferenceChangeListener listener)116     public void registerChangeListenerLocked(OnSharedPreferenceChangeListener listener) {
117         mPreferences.registerOnSharedPreferenceChangeListener(listener);
118     }
119 
120     /**
121      * Unregister a listener registered in {@link #registerChangeListenerLocked}.
122      *
123      * @param listener {@link OnSharedPreferenceChangeListener} to unregister
124      */
unregisterChangeListener(OnSharedPreferenceChangeListener listener)125     public void unregisterChangeListener(OnSharedPreferenceChangeListener listener) {
126         mPreferences.unregisterOnSharedPreferenceChangeListener(listener);
127     }
128 
129     /**
130      * Remove all approved {@link PrintService print services} that are not in the given set.
131      *
132      * @param serviceNamesToKeep The {@link ComponentName names } of the services to keep
133      */
pruneApprovedServices(List<ComponentName> serviceNamesToKeep)134     public void pruneApprovedServices(List<ComponentName> serviceNamesToKeep) {
135         synchronized (sLock) {
136             Set<String> approvedServices = getApprovedServices();
137 
138             if (approvedServices == null) {
139                 return;
140             }
141 
142             Set<String> newApprovedServices = new ArraySet<>(approvedServices.size());
143 
144             final int numServiceNamesToKeep = serviceNamesToKeep.size();
145             for(int i = 0; i < numServiceNamesToKeep; i++) {
146                 String serviceToKeep = serviceNamesToKeep.get(i).flattenToShortString();
147                 if (approvedServices.contains(serviceToKeep)) {
148                     newApprovedServices.add(serviceToKeep);
149                 }
150             }
151 
152             if (approvedServices.size() != newApprovedServices.size()) {
153                 SharedPreferences.Editor editor = mPreferences.edit();
154 
155                 editor.putStringSet(APPROVED_SERVICES_PREFERENCE, newApprovedServices);
156                 editor.apply();
157             }
158         }
159     }
160 }
161