blob: 9c91fa349bd8d4a1bea9508ef4863c961944ff4c [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.rotary;
import android.content.ComponentName;
import android.graphics.Rect;
import android.view.KeyEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.util.dump.DualDumpOutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
/** Utility methods for dumpsys. */
final class DumpUtils {
private DumpUtils() {}
/** Writes {@code focusDirection} to a dump in text or proto format. */
static void writeFocusDirection(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@View.FocusRealDirection int focusDirection) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, Navigator.directionToString(focusDirection));
return;
}
int val;
switch (focusDirection) {
case View.FOCUS_LEFT:
val = RotaryProtos.FOCUS_LEFT;
break;
case View.FOCUS_UP:
val = RotaryProtos.FOCUS_UP;
break;
case View.FOCUS_RIGHT:
val = RotaryProtos.FOCUS_RIGHT;
break;
case View.FOCUS_DOWN:
val = RotaryProtos.FOCUS_DOWN;
break;
default:
throw new IllegalArgumentException("Invalid direction: " + focusDirection);
}
dumpOutputStream.write(fieldName, fieldId, val);
}
/** Writes {@code rect} to a dump in text or proto format. */
static void writeRect(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull Rect rect,
@NonNull String fieldName, long fieldId) {
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("left", RotaryProtos.Rect.LEFT, rect.left);
dumpOutputStream.write("top", RotaryProtos.Rect.TOP, rect.top);
dumpOutputStream.write("right", RotaryProtos.Rect.RIGHT, rect.right);
dumpOutputStream.write("bottom", RotaryProtos.Rect.BOTTOM, rect.bottom);
dumpOutputStream.end(fieldToken);
}
/** Writes {@code afterScrollAction} to a dump in text or proto format. */
static void writeAfterScrollAction(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@RotaryService.AfterScrollAction int afterScrollAction) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, afterScrollAction);
return;
}
int val;
switch (afterScrollAction) {
case RotaryService.NONE:
val = RotaryProtos.AFTER_SCROLL_DO_NOTHING;
break;
case RotaryService.FOCUS_PREVIOUS:
val = RotaryProtos.AFTER_SCROLL_FOCUS_PREVIOUS;
break;
case RotaryService.FOCUS_NEXT:
val = RotaryProtos.AFTER_SCROLL_FOCUS_NEXT;
break;
case RotaryService.FOCUS_FIRST:
val = RotaryProtos.AFTER_SCROLL_FOCUS_FIRST;
break;
case RotaryService.FOCUS_LAST:
val = RotaryProtos.AFTER_SCROLL_FOCUS_LAST;
break;
default:
throw new IllegalArgumentException(
"Invalid after scroll action: " + afterScrollAction);
}
dumpOutputStream.write(fieldName, fieldId, val);
}
/** Writes {@code componentName} to a dump in text or proto format. */
static void writeComponentNameToString(@NonNull DualDumpOutputStream dumpOutputStream,
@NonNull String fieldName, long fieldId, @Nullable ComponentName componentName) {
dumpOutputStream.write(fieldName, fieldId,
componentName == null ? null : componentName.flattenToShortString());
}
/** Writes {@code object.toString()} to a dump in text or proto format. */
static void writeObject(@NonNull DualDumpOutputStream dumpOutputStream,
@NonNull String fieldName, long fieldId, @Nullable Object object) {
dumpOutputStream.write(fieldName, fieldId, object == null ? null : object.toString());
}
/**
* Writes the result of {@link Object#toString} on each of {@code objects}' elements to a dump
* in text or proto format. In the latter case, the field must be {@code repeated}.
*/
static void writeObjects(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@NonNull Object[] objects) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, Arrays.toString(objects));
return;
}
for (Object object : objects) {
writeObject(dumpOutputStream, fieldName, fieldId, object);
}
}
/**
* Writes the given integers to a dump in text or proto format. In the latter case, the field
* must be {@code repeated}.
*/
static void writeInts(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, Arrays.toString(vals));
return;
}
for (int val : vals) {
dumpOutputStream.write(fieldName, fieldId, val);
}
}
/**
* Writes the given keycodes to a dump in text or proto format. In the former case, the keycodes
* are written as {@link KeyCode} constants. In the latter case, the field must be {@code
* repeated}.
*/
static void writeKeyCodes(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId, @NonNull int[] vals) {
if (!dumpAsProto) {
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = 0; i < vals.length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(KeyEvent.keyCodeToString(vals[i]));
}
sb.append(']');
dumpOutputStream.write(fieldName, fieldId, sb.toString());
return;
}
for (int val : vals) {
dumpOutputStream.write(fieldName, fieldId, val);
}
}
/**
* Writes the given CharSequences to a dump in text or proto format, converting them to strings.
* In the latter case, the field must be {@code repeated}.
*/
static void writeCharSequences(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@NonNull Collection<CharSequence> vals) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, vals.toString());
return;
}
for (CharSequence val : vals) {
dumpOutputStream.write(fieldName, fieldId, val.toString());
}
}
/**
* Writes the given integers to a dump in text or proto format. In the latter case, the field
* must be {@code repeated}.
*/
static void writeIntegers(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@NonNull Collection<Integer> vals) {
if (!dumpAsProto) {
dumpOutputStream.write(fieldName, fieldId, vals.toString());
return;
}
for (Integer val : vals) {
dumpOutputStream.write(fieldName, fieldId, val);
}
}
/**
* Writes the given map from window ID to window type to a dump in text or proto format. In the
* former case, the window types are written as {@link AccessibilityWindowInfo} constants. In
* the latter case, the field must be a {@code map}.
*/
static void writeWindowTypes(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@NonNull Map<Integer, Integer> map) {
if (!dumpAsProto) {
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
dumpOutputStream.write(/* fieldName= */ entry.getKey().toString(), /* fieldId= */ 0,
AccessibilityWindowInfo.typeToString(entry.getValue()));
}
dumpOutputStream.end(fieldToken);
return;
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("key", /* fieldId= */ 1, entry.getKey());
dumpOutputStream.write("value", /* fieldId= */ 2, entry.getValue());
dumpOutputStream.end(fieldToken);
}
}
/**
* Writes the given map from window ID to node to a dump in text or proto format. In both cases,
* the nodes are written as {@code toString}s. In the latter case, the field must be a {@code
* map}.
*/
static void writeFocusedNodes(@NonNull DualDumpOutputStream dumpOutputStream,
boolean dumpAsProto, @NonNull String fieldName, long fieldId,
@NonNull Map<Integer, AccessibilityNodeInfo> map) {
if (!dumpAsProto) {
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
for (Map.Entry<Integer, AccessibilityNodeInfo> entry : map.entrySet()) {
dumpOutputStream.write(/* fieldName= */ entry.getKey().toString(), /* fieldId= */ 0,
entry.getValue().toString());
}
dumpOutputStream.end(fieldToken);
return;
}
for (Map.Entry<Integer, AccessibilityNodeInfo> entry : map.entrySet()) {
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("key", /* fieldId= */ 1, entry.getKey());
dumpOutputStream.write("value", /* fieldId= */ 2, entry.getValue().toString());
dumpOutputStream.end(fieldToken);
}
}
}