1 /*
2  * Copyright (C) 2019 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.permissioncontroller.role.model;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.util.ArraySet;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import com.android.permissioncontroller.Constants;
27 
28 import java.util.Collections;
29 import java.util.Set;
30 
31 /**
32  * Manages user denied status for requesting roles.
33  */
34 public class UserDeniedManager {
35 
36     @Nullable
37     private static UserDeniedManager sInstance;
38 
39     private final SharedPreferences mPreferences;
40 
41     /**
42      * Get a singleton instance of this class
43      *
44      * @param context the context for retrieving shared preferences.
45      *
46      * @return the singleton instance of this class
47      */
48     @NonNull
getInstance(@onNull Context context)49     public static UserDeniedManager getInstance(@NonNull Context context) {
50         if (sInstance == null) {
51             sInstance = new UserDeniedManager(context);
52         }
53         return sInstance;
54     }
55 
UserDeniedManager(@onNull Context context)56     private UserDeniedManager(@NonNull Context context) {
57         context = context.getApplicationContext();
58         mPreferences = context.getSharedPreferences(Constants.REQUEST_ROLE_USER_DENIED_FILE,
59                 Context.MODE_PRIVATE);
60     }
61 
62     /**
63      * Check whether an application has been denied for a role once.
64      *
65      * @param roleName the name of the role
66      * @param packageName the package name of the application
67      *
68      * @return whether the application has been denied for the role once
69      */
isDeniedOnce(@onNull String roleName, @NonNull String packageName)70     public boolean isDeniedOnce(@NonNull String roleName, @NonNull String packageName) {
71         return isDenied(roleName, packageName, false);
72     }
73 
74     /**
75      * Remember that an application has been denied for a role once.
76      *
77      * @param roleName the name of the role
78      * @param packageName the package name of the application
79      */
setDeniedOnce(@onNull String roleName, @NonNull String packageName)80     public void setDeniedOnce(@NonNull String roleName, @NonNull String packageName) {
81         setDenied(roleName, packageName, false, true);
82     }
83 
84     /**
85      * Check whether an application is always denied for a role.
86      *
87      * @param roleName the name of the role
88      * @param packageName the package name of the application
89      *
90      * @return whether the application is always denied for the role
91      */
isDeniedAlways(@onNull String roleName, @NonNull String packageName)92     public boolean isDeniedAlways(@NonNull String roleName, @NonNull String packageName) {
93         return isDenied(roleName, packageName, true);
94     }
95 
96     /**
97      * Remember that an application is always denied for a role.
98      *
99      * @param roleName the name of the role
100      * @param packageName the package name of the application
101      */
setDeniedAlways(@onNull String roleName, @NonNull String packageName)102     public void setDeniedAlways(@NonNull String roleName, @NonNull String packageName) {
103         setDenied(roleName, packageName, true, true);
104     }
105 
106     /**
107      * Forget about whether an application is denied for a role, once or always.
108      *
109      * @param roleName the name of the role
110      * @param packageName the package name of the application
111      */
clearDenied(@onNull String roleName, @NonNull String packageName)112     public void clearDenied(@NonNull String roleName, @NonNull String packageName) {
113         setDenied(roleName, packageName, false, false);
114         setDenied(roleName, packageName, true, false);
115     }
116 
117     /**
118      * Forget about whether an application is denied for any of the roles, once or always.
119      *
120      * @param packageName the package name of the application
121      */
clearPackageDenied(@onNull String packageName)122     public void clearPackageDenied(@NonNull String packageName) {
123         mPreferences.edit()
124                 .remove(getKey(packageName, false))
125                 .remove(getKey(packageName, true))
126                 .apply();
127     }
128 
129     @NonNull
getKey(@onNull String packageName, boolean always)130     private static String getKey(@NonNull String packageName, boolean always) {
131         return (always ? Constants.REQUEST_ROLE_USER_DENIED_ALWAYS_KEY_PREFIX
132                 : Constants.REQUEST_ROLE_USER_DENIED_ONCE_KEY_PREFIX) + packageName;
133     }
134 
isDenied(@onNull String roleName, @NonNull String packageName, boolean always)135     private boolean isDenied(@NonNull String roleName, @NonNull String packageName,
136             boolean always) {
137         String key = getKey(packageName, always);
138         return mPreferences.getStringSet(key, Collections.emptySet()).contains(roleName);
139     }
140 
setDenied(@onNull String roleName, @NonNull String packageName, boolean always, boolean denied)141     private void setDenied(@NonNull String roleName, @NonNull String packageName, boolean always,
142             boolean denied) {
143         String key = getKey(packageName, always);
144         Set<String> roleNames = mPreferences.getStringSet(key, Collections.emptySet());
145         if (roleNames.contains(roleName) == denied) {
146             return;
147         }
148         roleNames = new ArraySet<>(roleNames);
149         if (denied) {
150             roleNames.add(roleName);
151         } else {
152             roleNames.remove(roleName);
153         }
154         if (roleName.isEmpty()) {
155             mPreferences.edit().remove(key).apply();
156         } else {
157             mPreferences.edit().putStringSet(key, roleNames).apply();
158         }
159     }
160 }
161