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
17package com.android.printspooler.util;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
23import android.printservice.PrintService;
24import android.util.ArraySet;
25
26import java.util.List;
27import java.util.Set;
28
29/**
30 * Manage approved print services. These services are stored in the shared preferences.
31 */
32public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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