content: /*
   * 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.view.inspector;
  
  import android.annotation.AnyRes;
  import android.annotation.ColorInt;
  import android.annotation.ColorLong;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.graphics.Color;
  
  /**
   * An interface for reading the properties of an inspectable object.
   *
   * {@code PropertyReader} is defined as an interface that will be called by
   * {@link InspectionCompanion#readProperties(Object, PropertyReader)}. This approach allows a
   * client inspector to read the values of primitive properties without the overhead of
   * instantiating a class to hold the property values for each inspection pass. If an inspectable
   * remains unchanged between reading passes, it should be possible for a {@code PropertyReader} to
   * avoid new allocations for subsequent reading passes.
   *
   * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
   * implementation is able to work with primitives. Implementations should be prepared to accept
   * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
   *
   * @see InspectionCompanion#readProperties(Object, PropertyReader)
   */
  public interface PropertyReader {
      /**
       * Read a primitive boolean property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code boolean}
       */
      void readBoolean(int id, boolean value);
  
      /**
       * Read a primitive byte property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code byte}
       */
      void readByte(int id, byte value);
  
      /**
       * Read a primitive character property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code char}
       */
      void readChar(int id, char value);
  
      /**
       * Read a read a primitive double property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code double}
       */
      void readDouble(int id, double value);
  
      /**
       * Read a primitive float property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code float}
       */
      void readFloat(int id, float value);
  
      /**
       * Read a primitive integer property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as an {@code int}
       */
      void readInt(int id, int value);
  
      /**
       * Read a primitive long property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code long}
       */
      void readLong(int id, long value);
  
      /**
       * Read a primitive short property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code short}
       */
      void readShort(int id, short value);
  
      /**
       * Read any object as a property.
       *
       * If value is null, the property is marked as empty.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
       */
      void readObject(int id, @Nullable Object value);
  
      /**
       * Read a color packed into a {@link ColorInt} as a property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
       */
      void readColor(int id, @ColorInt int value);
  
      /**
       * Read a color packed into a {@code ColorLong} as a property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property packed as a {@code ColorLong}. See the
       *              {@link Color} class for details of the packing.
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
       */
      void readColor(int id, @ColorLong long value);
  
      /**
       * Read a {@link Color} object as a property.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
       */
      void readColor(int id, @Nullable Color value);
  
      /**
       * Read {@link android.view.Gravity} packed into an primitive {@code int}.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a gravity property
       */
      void readGravity(int id, int value);
  
      /**
       * Read an enumeration packed into a primitive {@code int}.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
       */
      void readIntEnum(int id, int value);
  
      /**
       * Read a flag packed into a primitive {@code int}.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
       */
      void readIntFlag(int id, int value);
  
      /**
       * Read an integer that contains a resource ID.
       *
       * @param id Identifier of the property from a {@link PropertyMapper}
       * @param value Value of the property
       * @throws PropertyTypeMismatchException If the property ID is not mapped as a resource ID.
       */
      void readResourceId(int id, @AnyRes int value);
  
      /**
       * Thrown if a client calls a typed read method for a property of a different type.
       */
      class PropertyTypeMismatchException extends RuntimeException {
          public PropertyTypeMismatchException(
                  int id,
                  @NonNull String expectedPropertyType,
                  @NonNull String actualPropertyType,
                  @Nullable String propertyName) {
              super(formatMessage(id, expectedPropertyType, actualPropertyType, propertyName));
          }
  
          public PropertyTypeMismatchException(
                  int id,
                  @NonNull String expectedPropertyType,
                  @NonNull String actualPropertyType) {
              super(formatMessage(id, expectedPropertyType, actualPropertyType, null));
          }
  
          private static @NonNull String formatMessage(
                  int id,
                  @NonNull String expectedPropertyType,
                  @NonNull String actualPropertyType,
                  @Nullable String propertyName) {
  
              if (propertyName == null) {
                  return String.format(
                          "Attempted to read property with ID 0x%08X as type %s, "
                              + "but the ID is of type %s.",
                          id,
                          expectedPropertyType,
                          actualPropertyType
                  );
              } else {
                  return String.format(
                          "Attempted to read property \"%s\" with ID 0x%08X as type %s, "
                              + "but the ID is of type %s.",
                          propertyName,
                          id,
                          expectedPropertyType,
                          actualPropertyType
                  );
              }
          }
      }
  }
  