|  | /* | 
|  | * Copyright 2018 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 android.os; | 
|  |  | 
|  | import android.annotation.SystemApi; | 
|  | import android.util.Log; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  | import java.util.List; | 
|  |  | 
|  | /** | 
|  | * Container for statsd dimension value information, corresponding to a | 
|  | * stats_log.proto's DimensionValue. | 
|  | * | 
|  | * This consists of a field (an int representing a statsd atom field) | 
|  | * and a value (which may be one of a number of types). | 
|  | * | 
|  | * <p> | 
|  | * Only a single value is held, and it is necessarily one of the following types: | 
|  | * {@link String}, int, long, boolean, float, | 
|  | * or tuple (i.e. {@link List} of {@code StatsDimensionsValue}). | 
|  | * | 
|  | * The type of value held can be retrieved using {@link #getValueType()}, which returns one of the | 
|  | * following ints, depending on the type of value: | 
|  | * <ul> | 
|  | *  <li>{@link #STRING_VALUE_TYPE}</li> | 
|  | *  <li>{@link #INT_VALUE_TYPE}</li> | 
|  | *  <li>{@link #LONG_VALUE_TYPE}</li> | 
|  | *  <li>{@link #BOOLEAN_VALUE_TYPE}</li> | 
|  | *  <li>{@link #FLOAT_VALUE_TYPE}</li> | 
|  | *  <li>{@link #TUPLE_VALUE_TYPE}</li> | 
|  | * </ul> | 
|  | * Alternatively, this can be determined using {@link #isValueType(int)} with one of these constants | 
|  | * as a parameter. | 
|  | * The value itself can be retrieved using the correct get...Value() function for its type. | 
|  | * | 
|  | * <p> | 
|  | * The field is always an int, and always exists; it can be obtained using {@link #getField()}. | 
|  | * | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | @SystemApi | 
|  | public final class StatsDimensionsValue implements Parcelable { | 
|  | private static final String TAG = "StatsDimensionsValue"; | 
|  |  | 
|  | // Values of the value type correspond to stats_log.proto's DimensionValue fields. | 
|  | // Keep constants in sync with frameworks/base/cmds/statsd/src/HashableDimensionKey.cpp. | 
|  | /** Indicates that this holds a String. */ | 
|  | public static final int STRING_VALUE_TYPE = 2; | 
|  | /** Indicates that this holds an int. */ | 
|  | public static final int INT_VALUE_TYPE = 3; | 
|  | /** Indicates that this holds a long. */ | 
|  | public static final int LONG_VALUE_TYPE = 4; | 
|  | /** Indicates that this holds a boolean. */ | 
|  | public static final int BOOLEAN_VALUE_TYPE = 5; | 
|  | /** Indicates that this holds a float. */ | 
|  | public static final int FLOAT_VALUE_TYPE = 6; | 
|  | /** Indicates that this holds a List of StatsDimensionsValues. */ | 
|  | public static final int TUPLE_VALUE_TYPE = 7; | 
|  |  | 
|  | private final StatsDimensionsValueParcel mInner; | 
|  |  | 
|  | /** | 
|  | * Creates a {@code StatsDimensionValue} from a parcel. | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | public StatsDimensionsValue(Parcel in) { | 
|  | mInner = StatsDimensionsValueParcel.CREATOR.createFromParcel(in); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | public StatsDimensionsValue(StatsDimensionsValueParcel parcel) { | 
|  | mInner = parcel; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the field, i.e. the tag of a statsd atom. | 
|  | * | 
|  | * @return the field | 
|  | */ | 
|  | public int getField() { | 
|  | return mInner.field; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the String held, if any. | 
|  | * | 
|  | * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE}, | 
|  | *         null otherwise | 
|  | */ | 
|  | public String getStringValue() { | 
|  | if (mInner.valueType == STRING_VALUE_TYPE) { | 
|  | return mInner.stringValue; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not string."); | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the int held, if any. | 
|  | * | 
|  | * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise | 
|  | */ | 
|  | public int getIntValue() { | 
|  | if (mInner.valueType == INT_VALUE_TYPE) { | 
|  | return mInner.intValue; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not int."); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the long held, if any. | 
|  | * | 
|  | * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise | 
|  | */ | 
|  | public long getLongValue() { | 
|  | if (mInner.valueType == LONG_VALUE_TYPE) { | 
|  | return mInner.longValue; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not long."); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the boolean held, if any. | 
|  | * | 
|  | * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE}, | 
|  | *         false otherwise | 
|  | */ | 
|  | public boolean getBooleanValue() { | 
|  | if (mInner.valueType == BOOLEAN_VALUE_TYPE) { | 
|  | return mInner.boolValue; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not boolean."); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the float held, if any. | 
|  | * | 
|  | * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise | 
|  | */ | 
|  | public float getFloatValue() { | 
|  | if (mInner.valueType == FLOAT_VALUE_TYPE) { | 
|  | return mInner.floatValue; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not float."); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held, | 
|  | * if any. | 
|  | * | 
|  | * @return the {@link List} of {@link StatsDimensionsValue} held | 
|  | *         if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE}, | 
|  | *         null otherwise | 
|  | */ | 
|  | public List<StatsDimensionsValue> getTupleValueList() { | 
|  | if (mInner.valueType == TUPLE_VALUE_TYPE) { | 
|  | int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length; | 
|  | List<StatsDimensionsValue> tupleValues = new ArrayList<>(length); | 
|  | for (int i = 0; i < length; i++) { | 
|  | tupleValues.add(new StatsDimensionsValue(mInner.tupleValue[i])); | 
|  | } | 
|  | return tupleValues; | 
|  | } else { | 
|  | Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not tuple."); | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the constant representing the type of value stored, namely one of | 
|  | * <ul> | 
|  | *   <li>{@link #STRING_VALUE_TYPE}</li> | 
|  | *   <li>{@link #INT_VALUE_TYPE}</li> | 
|  | *   <li>{@link #LONG_VALUE_TYPE}</li> | 
|  | *   <li>{@link #BOOLEAN_VALUE_TYPE}</li> | 
|  | *   <li>{@link #FLOAT_VALUE_TYPE}</li> | 
|  | *   <li>{@link #TUPLE_VALUE_TYPE}</li> | 
|  | * </ul> | 
|  | * | 
|  | * @return the constant representing the type of value stored | 
|  | */ | 
|  | public int getValueType() { | 
|  | return mInner.valueType; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns whether the type of value stored is equal to the given type. | 
|  | * | 
|  | * @param valueType int representing the type of value stored, as used in {@link #getValueType} | 
|  | * @return true if {@link #getValueType()} is equal to {@code valueType}. | 
|  | */ | 
|  | public boolean isValueType(int valueType) { | 
|  | return mInner.valueType == valueType; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a String representing the information in this StatsDimensionValue. | 
|  | * No guarantees are made about the format of this String. | 
|  | * | 
|  | * @return String representation | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | // Follows the format of statsd's dimension.h toString. | 
|  | public String toString() { | 
|  | StringBuilder sb = new StringBuilder(); | 
|  | sb.append(mInner.field); | 
|  | sb.append(":"); | 
|  | switch (mInner.valueType) { | 
|  | case STRING_VALUE_TYPE: | 
|  | sb.append(mInner.stringValue); | 
|  | break; | 
|  | case INT_VALUE_TYPE: | 
|  | sb.append(String.valueOf(mInner.intValue)); | 
|  | break; | 
|  | case LONG_VALUE_TYPE: | 
|  | sb.append(String.valueOf(mInner.longValue)); | 
|  | break; | 
|  | case BOOLEAN_VALUE_TYPE: | 
|  | sb.append(String.valueOf(mInner.boolValue)); | 
|  | break; | 
|  | case FLOAT_VALUE_TYPE: | 
|  | sb.append(String.valueOf(mInner.floatValue)); | 
|  | break; | 
|  | case TUPLE_VALUE_TYPE: | 
|  | sb.append("{"); | 
|  | int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length; | 
|  | for (int i = 0; i < length; i++) { | 
|  | StatsDimensionsValue child = new StatsDimensionsValue(mInner.tupleValue[i]); | 
|  | sb.append(child.toString()); | 
|  | sb.append("|"); | 
|  | } | 
|  | sb.append("}"); | 
|  | break; | 
|  | default: | 
|  | Log.w(TAG, "Incorrect value type"); | 
|  | break; | 
|  | } | 
|  | return sb.toString(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parcelable Creator for StatsDimensionsValue. | 
|  | */ | 
|  | public static final @android.annotation.NonNull | 
|  | Parcelable.Creator<StatsDimensionsValue> CREATOR = new | 
|  | Parcelable.Creator<StatsDimensionsValue>() { | 
|  | public StatsDimensionsValue createFromParcel(Parcel in) { | 
|  | return new StatsDimensionsValue(in); | 
|  | } | 
|  |  | 
|  | public StatsDimensionsValue[] newArray(int size) { | 
|  | return new StatsDimensionsValue[size]; | 
|  | } | 
|  | }; | 
|  |  | 
|  | @Override | 
|  | public int describeContents() { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void writeToParcel(Parcel out, int flags) { | 
|  | mInner.writeToParcel(out, flags); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a string representation of the type of value stored. | 
|  | */ | 
|  | private String getValueTypeAsString() { | 
|  | switch (mInner.valueType) { | 
|  | case STRING_VALUE_TYPE: | 
|  | return "string"; | 
|  | case INT_VALUE_TYPE: | 
|  | return "int"; | 
|  | case LONG_VALUE_TYPE: | 
|  | return "long"; | 
|  | case BOOLEAN_VALUE_TYPE: | 
|  | return "boolean"; | 
|  | case FLOAT_VALUE_TYPE: | 
|  | return "float"; | 
|  | case TUPLE_VALUE_TYPE: | 
|  | return "tuple"; | 
|  | default: | 
|  | return "unknown"; | 
|  | } | 
|  | } | 
|  | } |