1/*
2 * Copyright (C) 2017 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
18package android.provider;
19
20import android.content.ComponentName;
21import android.content.ContentResolver;
22import android.text.TextUtils;
23
24import com.android.internal.util.ArrayUtils;
25
26import java.util.Collection;
27import java.util.HashSet;
28import java.util.Iterator;
29import java.util.function.Function;
30
31/**
32 * Utilities for dealing with {@link String} values in {@link Settings}
33 *
34 * @hide
35 */
36public class SettingsStringUtil {
37    private SettingsStringUtil() {}
38
39    public static final String DELIMITER = ":";
40
41    /**
42     * A {@link HashSet} of items, that uses a common convention of setting string
43     * serialization/deserialization of separating multiple items with {@link #DELIMITER}
44     */
45    public static abstract class ColonDelimitedSet<T> extends HashSet<T> {
46
47        public ColonDelimitedSet(String colonSeparatedItems) {
48            for (String cn :
49                    TextUtils.split(TextUtils.emptyIfNull(colonSeparatedItems), DELIMITER)) {
50                add(itemFromString(cn));
51            }
52        }
53
54        protected abstract T itemFromString(String s);
55        protected String itemToString(T item) {
56            return String.valueOf(item);
57        }
58
59        @Override
60        public String toString() {
61            StringBuilder sb = new StringBuilder();
62            Iterator<T> it = iterator();
63            if (it.hasNext()) {
64                sb.append(itemToString(it.next()));
65                while (it.hasNext()) {
66                    sb.append(DELIMITER);
67                    sb.append(itemToString(it.next()));
68                }
69            }
70            return sb.toString();
71        }
72
73
74        public static class OfStrings extends ColonDelimitedSet<String> {
75            public OfStrings(String colonSeparatedItems) {
76                super(colonSeparatedItems);
77            }
78
79            @Override
80            protected String itemFromString(String s) {
81                return s;
82            }
83
84            public static String addAll(String delimitedElements, Collection<String> elements) {
85                final ColonDelimitedSet<String> set
86                        = new ColonDelimitedSet.OfStrings(delimitedElements);
87                return set.addAll(elements) ? set.toString() : delimitedElements;
88            }
89
90            public static String add(String delimitedElements, String element) {
91                final ColonDelimitedSet<String> set
92                        = new ColonDelimitedSet.OfStrings(delimitedElements);
93                if (set.contains(element)) {
94                    return delimitedElements;
95                }
96                set.add(element);
97                return set.toString();
98            }
99
100            public static String remove(String delimitedElements, String element) {
101                final ColonDelimitedSet<String> set
102                        = new ColonDelimitedSet.OfStrings(delimitedElements);
103                if (!set.contains(element)) {
104                    return delimitedElements;
105                }
106                set.remove(element);
107                return set.toString();
108            }
109
110            public static boolean contains(String delimitedElements, String element) {
111                final String[] elements = TextUtils.split(delimitedElements, DELIMITER);
112                return ArrayUtils.indexOf(elements, element) != -1;
113            }
114        }
115    }
116
117    public static class ComponentNameSet extends ColonDelimitedSet<ComponentName> {
118        public ComponentNameSet(String colonSeparatedPackageNames) {
119            super(colonSeparatedPackageNames);
120        }
121
122        @Override
123        protected ComponentName itemFromString(String s) {
124            return ComponentName.unflattenFromString(s);
125        }
126
127        @Override
128        protected String itemToString(ComponentName item) {
129            return item.flattenToString();
130        }
131
132        public static String add(String delimitedElements, ComponentName element) {
133            final ComponentNameSet set = new ComponentNameSet(delimitedElements);
134            if (set.contains(element)) {
135                return delimitedElements;
136            }
137            set.add(element);
138            return set.toString();
139        }
140
141        public static String remove(String delimitedElements, ComponentName element) {
142            final ComponentNameSet set = new ComponentNameSet(delimitedElements);
143            if (!set.contains(element)) {
144                return delimitedElements;
145            }
146            set.remove(element);
147            return set.toString();
148        }
149
150        public static boolean contains(String delimitedElements, ComponentName element) {
151            return ColonDelimitedSet.OfStrings.contains(
152                    delimitedElements, element.flattenToString());
153        }
154    }
155
156    public static class SettingStringHelper {
157        private final ContentResolver mContentResolver;
158        private final String mSettingName;
159        private final int mUserId;
160
161        public SettingStringHelper(ContentResolver contentResolver, String name, int userId) {
162            mContentResolver = contentResolver;
163            mUserId = userId;
164            mSettingName = name;
165        }
166
167        public String read() {
168            return Settings.Secure.getStringForUser(
169                    mContentResolver, mSettingName, mUserId);
170        }
171
172        public boolean write(String value) {
173            return Settings.Secure.putStringForUser(
174                    mContentResolver, mSettingName, value, mUserId);
175        }
176
177        public boolean modify(Function<String, String> change) {
178            return write(change.apply(read()));
179        }
180    }
181}
182