• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.car.rotary;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
20 
21 import android.content.ComponentName;
22 import android.graphics.Rect;
23 import android.view.KeyEvent;
24 import android.view.View;
25 import android.view.accessibility.AccessibilityNodeInfo;
26 import android.view.accessibility.AccessibilityWindowInfo;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 
31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
32 import com.android.internal.util.dump.DualDumpOutputStream;
33 
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Map;
37 
38 /** Utility methods for dumpsys. */
39 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
40 final class DumpUtils {
DumpUtils()41     private DumpUtils() {}
42 
43     /** Writes {@code focusDirection} to a dump in text or proto format. */
writeFocusDirection(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @View.FocusRealDirection int focusDirection)44     static void writeFocusDirection(@NonNull DualDumpOutputStream dumpOutputStream,
45             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
46             @View.FocusRealDirection int focusDirection) {
47         if (!dumpAsProto) {
48             dumpOutputStream.write(fieldName, fieldId, Navigator.directionToString(focusDirection));
49             return;
50         }
51         int val;
52         switch (focusDirection) {
53             case View.FOCUS_LEFT:
54                 val = RotaryProtos.FOCUS_LEFT;
55                 break;
56             case View.FOCUS_UP:
57                 val = RotaryProtos.FOCUS_UP;
58                 break;
59             case View.FOCUS_RIGHT:
60                 val = RotaryProtos.FOCUS_RIGHT;
61                 break;
62             case View.FOCUS_DOWN:
63                 val = RotaryProtos.FOCUS_DOWN;
64                 break;
65             default:
66                 throw new IllegalArgumentException("Invalid direction: " + focusDirection);
67         }
68         dumpOutputStream.write(fieldName, fieldId, val);
69     }
70 
71     /** Writes {@code rect} to a dump in text or proto format. */
writeRect(@onNull DualDumpOutputStream dumpOutputStream, @NonNull Rect rect, @NonNull String fieldName, long fieldId)72     static void writeRect(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull Rect rect,
73             @NonNull String fieldName, long fieldId) {
74         long fieldToken = dumpOutputStream.start(fieldName, fieldId);
75         dumpOutputStream.write("left", RotaryProtos.Rect.LEFT, rect.left);
76         dumpOutputStream.write("top", RotaryProtos.Rect.TOP, rect.top);
77         dumpOutputStream.write("right", RotaryProtos.Rect.RIGHT, rect.right);
78         dumpOutputStream.write("bottom", RotaryProtos.Rect.BOTTOM, rect.bottom);
79         dumpOutputStream.end(fieldToken);
80     }
81 
82     /** Writes {@code afterScrollAction} to a dump in text or proto format. */
writeAfterScrollAction(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, RotaryService.AfterScrollAction afterScrollAction)83     static void writeAfterScrollAction(@NonNull DualDumpOutputStream dumpOutputStream,
84             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
85             RotaryService.AfterScrollAction afterScrollAction) {
86         if (!dumpAsProto) {
87             dumpOutputStream.write(fieldName, fieldId, afterScrollAction.name());
88             return;
89         }
90         int val;
91         switch (afterScrollAction) {
92             case NONE:
93                 val = RotaryProtos.AFTER_SCROLL_DO_NOTHING;
94                 break;
95             case FOCUS_PREVIOUS:
96                 val = RotaryProtos.AFTER_SCROLL_FOCUS_PREVIOUS;
97                 break;
98             case FOCUS_NEXT:
99                 val = RotaryProtos.AFTER_SCROLL_FOCUS_NEXT;
100                 break;
101             case FOCUS_FIRST:
102                 val = RotaryProtos.AFTER_SCROLL_FOCUS_FIRST;
103                 break;
104             case FOCUS_LAST:
105                 val = RotaryProtos.AFTER_SCROLL_FOCUS_LAST;
106                 break;
107             default:
108                 throw new IllegalArgumentException(
109                         "Invalid after scroll action: " + afterScrollAction);
110         }
111         dumpOutputStream.write(fieldName, fieldId, val);
112     }
113 
114     /** Writes {@code componentName} to a dump in text or proto format. */
writeComponentNameToString(@onNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId, @Nullable ComponentName componentName)115     static void writeComponentNameToString(@NonNull DualDumpOutputStream dumpOutputStream,
116             @NonNull String fieldName, long fieldId, @Nullable ComponentName componentName) {
117         dumpOutputStream.write(fieldName, fieldId,
118                 componentName == null ? null : componentName.flattenToShortString());
119     }
120 
121     /** Writes {@code object.toString()} to a dump in text or proto format. */
writeObject(@onNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName, long fieldId, @Nullable Object object)122     static void writeObject(@NonNull DualDumpOutputStream dumpOutputStream,
123             @NonNull String fieldName, long fieldId, @Nullable Object object) {
124         dumpOutputStream.write(fieldName, fieldId, object == null ? null : object.toString());
125     }
126 
127     /**
128      * Writes the result of {@link Object#toString} on each of {@code objects}' elements to a dump
129      * in text or proto format. In the latter case, the field must be {@code repeated}.
130      */
writeObjects(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull Object[] objects)131     static void writeObjects(@NonNull DualDumpOutputStream dumpOutputStream,
132             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
133             @NonNull Object[] objects) {
134         if (!dumpAsProto) {
135             dumpOutputStream.write(fieldName, fieldId, Arrays.toString(objects));
136             return;
137         }
138         for (Object object : objects) {
139             writeObject(dumpOutputStream, fieldName, fieldId, object);
140         }
141     }
142 
143     /**
144      * Writes the given integers to a dump in text or proto format. In the latter case, the field
145      * must be {@code repeated}.
146      */
writeInts(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals)147     static void writeInts(@NonNull DualDumpOutputStream dumpOutputStream,
148             boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals) {
149         if (!dumpAsProto) {
150             dumpOutputStream.write(fieldName, fieldId, Arrays.toString(vals));
151             return;
152         }
153         for (int val : vals) {
154             dumpOutputStream.write(fieldName, fieldId, val);
155         }
156     }
157 
158     /**
159      * Writes the given keycodes to a dump in text or proto format. In the former case, the keycodes
160      * are written as {@link KeyCode} constants. In the latter case, the field must be {@code
161      * repeated}.
162      */
writeKeyCodes(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals)163     static void writeKeyCodes(@NonNull DualDumpOutputStream dumpOutputStream,
164             boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals) {
165         if (!dumpAsProto) {
166             StringBuilder sb = new StringBuilder();
167             sb.append('[');
168             for (int i = 0; i < vals.length; i++) {
169                 if (i > 0) {
170                     sb.append(", ");
171                 }
172                 sb.append(KeyEvent.keyCodeToString(vals[i]));
173             }
174             sb.append(']');
175             dumpOutputStream.write(fieldName, fieldId, sb.toString());
176             return;
177         }
178         for (int val : vals) {
179             dumpOutputStream.write(fieldName, fieldId, val);
180         }
181     }
182 
183     /**
184      * Writes the given CharSequences to a dump in text or proto format, converting them to strings.
185      * In the latter case, the field must be {@code repeated}.
186      */
writeCharSequences(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull Collection<CharSequence> vals)187     static void writeCharSequences(@NonNull DualDumpOutputStream dumpOutputStream,
188             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
189             @NonNull Collection<CharSequence> vals) {
190         if (!dumpAsProto) {
191             dumpOutputStream.write(fieldName, fieldId, vals.toString());
192             return;
193         }
194         for (CharSequence val : vals) {
195             dumpOutputStream.write(fieldName, fieldId, val.toString());
196         }
197     }
198 
199     /**
200      * Writes the given integers to a dump in text or proto format. In the latter case, the field
201      * must be {@code repeated}.
202      */
writeIntegers(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull Collection<Integer> vals)203     static void writeIntegers(@NonNull DualDumpOutputStream dumpOutputStream,
204             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
205             @NonNull Collection<Integer> vals) {
206         if (!dumpAsProto) {
207             dumpOutputStream.write(fieldName, fieldId, vals.toString());
208             return;
209         }
210         for (Integer val : vals) {
211             dumpOutputStream.write(fieldName, fieldId, val);
212         }
213     }
214 
215     /**
216      * Writes the given map from window ID to window type to a dump in text or proto format. In the
217      * former case, the window types are written as {@link AccessibilityWindowInfo} constants. In
218      * the latter case, the field must be a {@code map}.
219      */
writeWindowTypes(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull Map<Integer, Integer> map)220     static void writeWindowTypes(@NonNull DualDumpOutputStream dumpOutputStream,
221             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
222             @NonNull Map<Integer, Integer> map) {
223         if (!dumpAsProto) {
224             long fieldToken = dumpOutputStream.start(fieldName, fieldId);
225             for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
226                 dumpOutputStream.write(/* fieldName= */ entry.getKey().toString(), /* fieldId= */ 0,
227                         AccessibilityWindowInfo.typeToString(entry.getValue()));
228             }
229             dumpOutputStream.end(fieldToken);
230             return;
231         }
232         for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
233             long fieldToken = dumpOutputStream.start(fieldName, fieldId);
234             dumpOutputStream.write("key", /* fieldId= */ 1, entry.getKey());
235             dumpOutputStream.write("value", /* fieldId= */ 2, entry.getValue());
236             dumpOutputStream.end(fieldToken);
237         }
238     }
239 
240     /**
241      * Writes the given map from window ID to node to a dump in text or proto format. In both cases,
242      * the nodes are written as {@code toString}s. In the latter case, the field must be a {@code
243      * map}.
244      */
writeFocusedNodes(@onNull DualDumpOutputStream dumpOutputStream, boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull Map<Integer, AccessibilityNodeInfo> map)245     static void writeFocusedNodes(@NonNull DualDumpOutputStream dumpOutputStream,
246             boolean dumpAsProto, @NonNull String fieldName, long fieldId,
247             @NonNull Map<Integer, AccessibilityNodeInfo> map) {
248         if (!dumpAsProto) {
249             long fieldToken = dumpOutputStream.start(fieldName, fieldId);
250             for (Map.Entry<Integer, AccessibilityNodeInfo> entry : map.entrySet()) {
251                 dumpOutputStream.write(/* fieldName= */ entry.getKey().toString(), /* fieldId= */ 0,
252                         entry.getValue().toString());
253             }
254             dumpOutputStream.end(fieldToken);
255             return;
256         }
257         for (Map.Entry<Integer, AccessibilityNodeInfo> entry : map.entrySet()) {
258             long fieldToken = dumpOutputStream.start(fieldName, fieldId);
259             dumpOutputStream.write("key", /* fieldId= */ 1, entry.getKey());
260             dumpOutputStream.write("value", /* fieldId= */ 2, entry.getValue().toString());
261             dumpOutputStream.end(fieldToken);
262         }
263     }
264 }
265