1 /*
2  * Copyright (C) 2020 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.car.hardware.power;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.util.SparseBooleanArray;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.util.ArrayList;
27 import java.util.Iterator;
28 import java.util.List;
29 
30 /**
31  * Utility class used when dealing with PowerComponent.
32  *
33  * @hide
34  */
35 public final class PowerComponentUtil {
36     /**
37      * The component is marked as enabled in the power policy.
38      */
39     public static final int COMPONENT_STATE_ENABLED = 1;
40 
41     /**
42      * The component is marked as disabled in the power policy.
43      */
44     public static final int COMPONENT_STATE_DISABLED = 2;
45 
46     /**
47      * The component is not specified in the power policy.
48      */
49     public static final int COMPONENT_STATE_UNTOUCHED = 3;
50 
51     @IntDef(prefix = { "COMPONENT_STATE_" }, value = {
52             COMPONENT_STATE_ENABLED,
53             COMPONENT_STATE_DISABLED,
54             COMPONENT_STATE_UNTOUCHED
55     })
56     @Retention(RetentionPolicy.SOURCE)
57     public @interface ComponentState { }
58 
59     /**
60      * Represetns an invalid power component.
61      */
62     public static final int INVALID_POWER_COMPONENT = -1;
63 
64     /**
65      * The first component in {@link PowerComponent}.
66      */
67     public static final int FIRST_POWER_COMPONENT = PowerComponent.AUDIO;
68 
69     /**
70      * The last component in {@link PowerComponent}.
71      *
72      * <p> This should be updated when a new component is added to {@link PowerComponent}.
73      */
74     public static final int LAST_POWER_COMPONENT = PowerComponent.CPU;
75 
76     private static final String POWER_COMPONENT_PREFIX = "POWER_COMPONENT_";
77 
78     private static final String POWER_COMPONENT_AUDIO = "AUDIO";
79     private static final String POWER_COMPONENT_MEDIA = "MEDIA";
80     private static final String POWER_COMPONENT_DISPLAY = "DISPLAY";
81     private static final String POWER_COMPONENT_BLUETOOTH = "BLUETOOTH";
82     private static final String POWER_COMPONENT_WIFI = "WIFI";
83     private static final String POWER_COMPONENT_CELLULAR = "CELLULAR";
84     private static final String POWER_COMPONENT_ETHERNET = "ETHERNET";
85     private static final String POWER_COMPONENT_PROJECTION = "PROJECTION";
86     private static final String POWER_COMPONENT_NFC = "NFC";
87     private static final String POWER_COMPONENT_INPUT = "INPUT";
88     private static final String POWER_COMPONENT_VOICE_INTERACTION = "VOICE_INTERACTION";
89     private static final String POWER_COMPONENT_VISUAL_INTERACTION = "VISUAL_INTERACTION";
90     private static final String POWER_COMPONENT_TRUSTED_DEVICE_DETECTION =
91             "TRUSTED_DEVICE_DETECTION";
92     private static final String POWER_COMPONENT_LOCATION = "LOCATION";
93     private static final String POWER_COMPONENT_MICROPHONE = "MICROPHONE";
94     private static final String POWER_COMPONENT_CPU = "CPU";
95 
96     private interface ComponentFilter {
filter(int[] components)97         boolean filter(int[] components);
98     }
99 
100     // PowerComponentUtil is intended to provide static variables and methods.
PowerComponentUtil()101     private PowerComponentUtil() {}
102 
103     /**
104      * Checks whether the given component is valid.
105      */
isValidPowerComponent(int component)106     public static boolean isValidPowerComponent(int component) {
107         return component >= FIRST_POWER_COMPONENT && component <= LAST_POWER_COMPONENT;
108     }
109 
110     /**
111      * Checks whether the given policy has one ore more components specified in the given filter.
112      */
hasComponents(@onNull CarPowerPolicy policy, @NonNull CarPowerPolicyFilter filter)113     public static boolean hasComponents(@NonNull CarPowerPolicy policy,
114             @NonNull CarPowerPolicyFilter filter) {
115         SparseBooleanArray filterSet = new SparseBooleanArray();
116         int[] components = filter.getComponents();
117         for (int i = 0; i < components.length; i++) {
118             filterSet.put(components[i], true);
119         }
120 
121         ComponentFilter componentFilter = (c) -> {
122             for (int i = 0; i < c.length; i++) {
123                 if (filterSet.get(c[i])) {
124                     return true;
125                 }
126             }
127             return false;
128         };
129 
130         if (componentFilter.filter(policy.getEnabledComponents())) {
131             return true;
132         }
133         return componentFilter.filter(policy.getDisabledComponents());
134     }
135 
136     /**
137      * Matches the given string to {@link PowerComponent}.
138      */
toPowerComponent(@ullable String componentArg, boolean prefix)139     public static int toPowerComponent(@Nullable String componentArg, boolean prefix) {
140         String component = componentArg;
141         if (component == null) {
142             return INVALID_POWER_COMPONENT;
143         }
144         if (prefix) {
145             if (!component.startsWith(POWER_COMPONENT_PREFIX)) {
146                 return INVALID_POWER_COMPONENT;
147             }
148             component = component.substring(POWER_COMPONENT_PREFIX.length());
149         }
150         switch (component) {
151             case POWER_COMPONENT_AUDIO:
152                 return PowerComponent.AUDIO;
153             case POWER_COMPONENT_MEDIA:
154                 return PowerComponent.MEDIA;
155             case POWER_COMPONENT_DISPLAY:
156                 return PowerComponent.DISPLAY;
157             case POWER_COMPONENT_BLUETOOTH:
158                 return PowerComponent.BLUETOOTH;
159             case POWER_COMPONENT_WIFI:
160                 return PowerComponent.WIFI;
161             case POWER_COMPONENT_CELLULAR:
162                 return PowerComponent.CELLULAR;
163             case POWER_COMPONENT_ETHERNET:
164                 return PowerComponent.ETHERNET;
165             case POWER_COMPONENT_PROJECTION:
166                 return PowerComponent.PROJECTION;
167             case POWER_COMPONENT_NFC:
168                 return PowerComponent.NFC;
169             case POWER_COMPONENT_INPUT:
170                 return PowerComponent.INPUT;
171             case POWER_COMPONENT_VOICE_INTERACTION:
172                 return PowerComponent.VOICE_INTERACTION;
173             case POWER_COMPONENT_VISUAL_INTERACTION:
174                 return PowerComponent.VISUAL_INTERACTION;
175             case POWER_COMPONENT_TRUSTED_DEVICE_DETECTION:
176                 return PowerComponent.TRUSTED_DEVICE_DETECTION;
177             case POWER_COMPONENT_LOCATION:
178                 return PowerComponent.LOCATION;
179             case POWER_COMPONENT_MICROPHONE:
180                 return PowerComponent.MICROPHONE;
181             case POWER_COMPONENT_CPU:
182                 return PowerComponent.CPU;
183             default:
184                 if (component.matches("\\d+")) {
185                     int componentNumber = Integer.parseInt(component);
186                     if (componentNumber >= PowerComponent.MINIMUM_CUSTOM_COMPONENT_VALUE) {
187                         return componentNumber;
188                     }
189                 }
190                 return INVALID_POWER_COMPONENT;
191         }
192     }
193 
194     /**
195      * Convert {@link PowerComponent} to string.
196      */
197     @NonNull
powerComponentToString(int component)198     public static String powerComponentToString(int component) {
199         switch (component) {
200             case PowerComponent.AUDIO:
201                 return POWER_COMPONENT_AUDIO;
202             case PowerComponent.MEDIA:
203                 return POWER_COMPONENT_MEDIA;
204             case PowerComponent.DISPLAY:
205                 return POWER_COMPONENT_DISPLAY;
206             case PowerComponent.BLUETOOTH:
207                 return POWER_COMPONENT_BLUETOOTH;
208             case PowerComponent.WIFI:
209                 return POWER_COMPONENT_WIFI;
210             case PowerComponent.CELLULAR:
211                 return POWER_COMPONENT_CELLULAR;
212             case PowerComponent.ETHERNET:
213                 return POWER_COMPONENT_ETHERNET;
214             case PowerComponent.PROJECTION:
215                 return POWER_COMPONENT_PROJECTION;
216             case PowerComponent.NFC:
217                 return POWER_COMPONENT_NFC;
218             case PowerComponent.INPUT:
219                 return POWER_COMPONENT_INPUT;
220             case PowerComponent.VOICE_INTERACTION:
221                 return POWER_COMPONENT_VOICE_INTERACTION;
222             case PowerComponent.VISUAL_INTERACTION:
223                 return POWER_COMPONENT_VISUAL_INTERACTION;
224             case PowerComponent.TRUSTED_DEVICE_DETECTION:
225                 return POWER_COMPONENT_TRUSTED_DEVICE_DETECTION;
226             case PowerComponent.LOCATION:
227                 return POWER_COMPONENT_LOCATION;
228             case PowerComponent.MICROPHONE:
229                 return POWER_COMPONENT_MICROPHONE;
230             case PowerComponent.CPU:
231                 return POWER_COMPONENT_CPU;
232             default:
233                 if (component >= PowerComponent.MINIMUM_CUSTOM_COMPONENT_VALUE) {
234                     return Integer.toString(component);
235                 }
236                 return "unknown component";
237         }
238     }
239 
240     /**
241      * Convert list of {@link PowerComponent} to list of strings.
242      */
243     @NonNull
powerComponentsToStrings(Iterable<Integer> components)244     public static List<String> powerComponentsToStrings(Iterable<Integer> components) {
245         List<String> powerComponents = new ArrayList<>();
246         Iterator<Integer> componentsIterator = components.iterator();
247         while (componentsIterator.hasNext()) {
248             Integer component = componentsIterator.next();
249             powerComponents.add(powerComponentToString(component));
250         }
251         return powerComponents;
252     }
253 
254     /**
255      * Convert list of {@link PowerComponent} to string containing a list of the components,
256      * each separated by a comma and a space. (Example: "AUDIO, WIFI")
257      */
258     @NonNull
powerComponentsToString(Iterable<Integer> components)259     public static String powerComponentsToString(Iterable<Integer> components) {
260         StringBuilder builder = new StringBuilder();
261         Iterator<Integer> componentsIterator = components.iterator();
262         // Do first element separately to not start the list with a comma
263         if (componentsIterator.hasNext()) {
264             builder.append(powerComponentToString(componentsIterator.next()));
265         }
266         while (componentsIterator.hasNext()) {
267             builder.append(
268                     String.format(", %s", powerComponentToString(componentsIterator.next())));
269         }
270         return builder.toString();
271     }
272 
273     /**
274      * Convert list of strings to list of {@link PowerComponent}.
275      */
276     @NonNull
toPowerComponents(Iterable<String> components, boolean prefix)277     public static Iterable<Integer> toPowerComponents(Iterable<String> components, boolean prefix) {
278         List<Integer> powerComponents = new ArrayList<>();
279         Iterator<String> componentsIterator = components.iterator();
280         while (componentsIterator.hasNext()) {
281             String component = componentsIterator.next();
282             powerComponents.add(toPowerComponent(component, prefix));
283         }
284         return powerComponents;
285     }
286 }
287