1 /*
2  * Copyright (C) 2018 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 android.perftests.utils;
18 
19 import android.content.Context;
20 import android.provider.Settings;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 
25 import java.util.Objects;
26 
27 /**
28  * Provides utilities to interact with the device's {@link Settings}.
29  */
30 public final class SettingsHelper {
31 
32     public static final String NAMESPACE_SECURE = "secure";
33     public static final String NAMESPACE_GLOBAL = "global";
34 
35     private static int DEFAULT_TIMEOUT_MS = 5000;
36 
37     /**
38      * Uses a Shell command to "asynchronously" set the given preference, returning right away.
39      */
set(@onNull String namespace, @NonNull String key, @Nullable String value)40     public static void set(@NonNull String namespace, @NonNull String key, @Nullable String value) {
41         if (value == null) {
42             delete(namespace, key);
43             return;
44         }
45         ShellHelper.runShellCommand("settings put %s %s %s default", namespace, key, value);
46     }
47 
48     /**
49      * Uses a Shell command to "synchronously" set the given preference by registering a listener
50      * and wait until it's set.
51      */
syncSet(@onNull Context context, @NonNull String namespace, @NonNull String key, @Nullable String value)52     public static void syncSet(@NonNull Context context, @NonNull String namespace,
53             @NonNull String key, @Nullable String value) {
54         if (value == null) {
55             syncDelete(context, namespace, key);
56             return;
57         }
58 
59         String currentValue = get(namespace, key);
60         if (value.equals(currentValue)) {
61             // Already set, ignore
62             return;
63         }
64 
65         OneTimeSettingsListener observer = new OneTimeSettingsListener(context, namespace, key,
66                 DEFAULT_TIMEOUT_MS);
67         set(namespace, key, value);
68         observer.assertCalled();
69         assertNewValue(namespace, key, value);
70     }
71 
72     /**
73      * Uses a Shell command to "asynchronously" delete the given preference, returning right away.
74      */
delete(@onNull String namespace, @NonNull String key)75     public static void delete(@NonNull String namespace, @NonNull String key) {
76         ShellHelper.runShellCommand("settings delete %s %s", namespace, key);
77     }
78 
79     /**
80      * Uses a Shell command to "synchronously" delete the given preference by registering a listener
81      * and wait until it's called.
82      */
syncDelete(@onNull Context context, @NonNull String namespace, @NonNull String key)83     public static void syncDelete(@NonNull Context context, @NonNull String namespace,
84             @NonNull String key) {
85         String currentValue = get(namespace, key);
86         if (currentValue == null || currentValue.equals("null")) {
87             // Already set, ignore
88             return;
89         }
90 
91         OneTimeSettingsListener observer = new OneTimeSettingsListener(context, namespace, key,
92                 DEFAULT_TIMEOUT_MS);
93         delete(namespace, key);
94         observer.assertCalled();
95         assertNewValue(namespace, key, "null");
96     }
97 
98     /**
99      * Gets the value of a given preference using Shell command.
100      */
101     @NonNull
get(@onNull String namespace, @NonNull String key)102     public static String get(@NonNull String namespace, @NonNull String key) {
103         return ShellHelper.runShellCommand("settings get %s %s", namespace, key);
104     }
105 
assertNewValue(@onNull String namespace, @NonNull String key, @Nullable String expectedValue)106     private static void assertNewValue(@NonNull String namespace, @NonNull String key,
107             @Nullable String expectedValue) {
108         String actualValue = get(namespace, key);
109         if (!Objects.equals(actualValue, expectedValue)) {
110             throw new AssertionError("invalid value for " + namespace + ":" + key + ": expected '"
111                     + actualValue + "' , got '" + expectedValue + "'");
112         }
113     }
114 
SettingsHelper()115     private SettingsHelper() {
116         throw new UnsupportedOperationException("contain static methods only");
117     }
118 }
119