Adding public API to expose DisplayInfo.deviceProductInfo

Changing class DeviceProductInfo to public class with hidden ctor to expose via
Display#getDeviceProductInfo. Removing the relative address and changing
to connectionToSinkType.

Bug: 179775994
Test: atest CtsDisplayTestCases
Change-Id: I92f32461a054244b75dc4d5ddfd30e9a7968f3dd
diff --git a/Android.bp b/Android.bp
index 908280e..20ca1b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -421,6 +421,7 @@
         ":resourcemanager_aidl",
         ":storaged_aidl",
         ":vold_aidl",
+        ":deviceproductinfoconstants_aidl",
 
         // For the generated R.java and Manifest.java
         ":framework-res{.aapt.srcjar}",
diff --git a/core/api/current.txt b/core/api/current.txt
index b063af5..9335e30 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18568,6 +18568,23 @@
 
 package android.hardware.display {
 
+  public final class DeviceProductInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConnectionToSinkType();
+    method public int getManufactureWeek();
+    method public int getManufactureYear();
+    method @NonNull public String getManufacturerPnpId();
+    method public int getModelYear();
+    method @Nullable public String getName();
+    method @NonNull public String getProductId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1
+    field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2
+    field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3
+    field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR;
+  }
+
   public final class DisplayManager {
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
@@ -46250,6 +46267,7 @@
     method public long getAppVsyncOffsetNanos();
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method @Nullable public android.view.DisplayCutout getCutout();
+    method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo();
     method public int getDisplayId();
     method public int getFlags();
     method public android.view.Display.HdrCapabilities getHdrCapabilities();
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 41126b7..9457d8f1 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -16,40 +16,69 @@
 
 package android.hardware.display;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Product-specific information about the display or the directly connected device on the
  * display chain. For example, if the display is transitively connected, this field may contain
  * product information about the intermediate device.
- * @hide
  */
 public final class DeviceProductInfo implements Parcelable {
+    /** @hide */
+    @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = {
+            CONNECTION_TO_SINK_UNKNOWN,
+            CONNECTION_TO_SINK_BUILT_IN,
+            CONNECTION_TO_SINK_DIRECT,
+            CONNECTION_TO_SINK_TRANSITIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ConnectionToSinkType { }
+
+    /** The device connection to the display sink is unknown. */
+    public static final int CONNECTION_TO_SINK_UNKNOWN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN;
+
+    /** The display sink is built-in to the device */
+    public static final int CONNECTION_TO_SINK_BUILT_IN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN;
+
+    /** The device is directly connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_DIRECT =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT;
+
+    /** The device is transitively connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_TRANSITIVE =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE;
+
     private final String mName;
     private final String mManufacturerPnpId;
     private final String mProductId;
     private final Integer mModelYear;
     private final ManufactureDate mManufactureDate;
-    private final int[] mRelativeAddress;
+    private final @ConnectionToSinkType int mConnectionToSinkType;
 
+    /** @hide */
     public DeviceProductInfo(
             String name,
             String manufacturerPnpId,
             String productId,
             Integer modelYear,
             ManufactureDate manufactureDate,
-            int[] relativeAddress) {
+            int connectionToSinkType) {
         this.mName = name;
         this.mManufacturerPnpId = manufacturerPnpId;
         this.mProductId = productId;
         this.mModelYear = modelYear;
         this.mManufactureDate = manufactureDate;
-        this.mRelativeAddress = relativeAddress;
+        this.mConnectionToSinkType = connectionToSinkType;
     }
 
     private DeviceProductInfo(Parcel in) {
@@ -58,12 +87,13 @@
         mProductId = (String) in.readValue(null);
         mModelYear = (Integer) in.readValue(null);
         mManufactureDate = (ManufactureDate) in.readValue(null);
-        mRelativeAddress = in.createIntArray();
+        mConnectionToSinkType = in.readInt();
     }
 
     /**
      * @return Display name.
      */
+    @Nullable
     public String getName() {
         return mName;
     }
@@ -71,6 +101,7 @@
     /**
      * @return Manufacturer Plug and Play ID.
      */
+    @NonNull
     public String getManufacturerPnpId() {
         return mManufacturerPnpId;
     }
@@ -78,32 +109,58 @@
     /**
      * @return Manufacturer product ID.
      */
+    @NonNull
     public String getProductId() {
         return mProductId;
     }
 
     /**
-     * @return Model year of the device. Typically exactly one of model year or
-     *      manufacture date will be present.
+     * @return Model year of the device. Return -1 if not available. Typically,
+     * one of model year or manufacture year is available.
      */
-    public Integer getModelYear() {
-        return mModelYear;
+    public int getModelYear()  {
+        return mModelYear != null ? mModelYear : -1;
+    }
+
+    /**
+     * @return The year of manufacture, or -1 it is not available. Typically,
+     * one of model year or manufacture year is available.
+     */
+    public int getManufactureYear()  {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1;
+    }
+
+    /**
+     * @return The week of manufacture, or -1 it is not available. Typically,
+     * not present if model year is available.
+     */
+    public int getManufactureWeek() {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mWeek != null ?  mManufactureDate.mWeek : -1;
     }
 
     /**
      * @return Manufacture date. Typically exactly one of model year or manufacture
      * date will be present.
+     *
+     * @hide
      */
     public ManufactureDate getManufactureDate() {
         return mManufactureDate;
     }
 
     /**
-     * @return Relative address in the display network. For example, for HDMI connected devices this
-     * can be its physical address. Each component of the address is in the range [0, 255].
+     * @return How the current device is connected to the display sink. For example, the display
+     * can be connected immediately to the device or there can be a receiver in between.
      */
-    public int[] getRelativeAddress() {
-        return mRelativeAddress;
+    @ConnectionToSinkType
+    public int getConnectionToSinkType() {
+        return mConnectionToSinkType;
     }
 
     @Override
@@ -119,8 +176,8 @@
                 + mModelYear
                 + ", manufactureDate="
                 + mManufactureDate
-                + ", relativeAddress="
-                + Arrays.toString(mRelativeAddress)
+                + ", connectionToSinkType="
+                + mConnectionToSinkType
                 + '}';
     }
 
@@ -134,16 +191,16 @@
                 && Objects.equals(mProductId, that.mProductId)
                 && Objects.equals(mModelYear, that.mModelYear)
                 && Objects.equals(mManufactureDate, that.mManufactureDate)
-                && Arrays.equals(mRelativeAddress, that.mRelativeAddress);
+                && mConnectionToSinkType == that.mConnectionToSinkType;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate,
-            Arrays.hashCode(mRelativeAddress));
+                mConnectionToSinkType);
     }
 
-    public static final Creator<DeviceProductInfo> CREATOR =
+    @NonNull public static final Creator<DeviceProductInfo> CREATOR =
             new Creator<DeviceProductInfo>() {
                 @Override
                 public DeviceProductInfo createFromParcel(Parcel in) {
@@ -162,13 +219,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mName);
         dest.writeString(mManufacturerPnpId);
         dest.writeValue(mProductId);
         dest.writeValue(mModelYear);
         dest.writeValue(mManufactureDate);
-        dest.writeIntArray(mRelativeAddress);
+        dest.writeInt(mConnectionToSinkType);
     }
 
     /**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0ba1dfe..8117c96 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -34,6 +34,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DeviceProductInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
@@ -1181,6 +1182,18 @@
     }
 
     /**
+     * Returns the product-specific information about the display or the directly connected
+     * device on the display chain.
+     * For example, if the display is transitively connected, this field may contain product
+     * information about the intermediate device.
+     * Returns {@code null} if product information is not available.
+     */
+    @Nullable
+    public DeviceProductInfo getDeviceProductInfo() {
+        return mDisplayInfo.deviceProductInfo;
+    }
+
+    /**
      * Gets display metrics that describe the size and density of this display.
      * The size returned by this method does not necessarily represent the
      * actual raw size (native resolution) of the display.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b485f0f..0371dc9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -51,6 +51,7 @@
         "android_util_XmlBlock.cpp",
         "android_util_jar_StrictJarFile.cpp",
         "com_android_internal_util_VirtualRefBasePtr.cpp",
+        ":deviceproductinfoconstants_aidl",
     ],
 
     include_dirs: [
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 451ea93..cbf4481 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -27,6 +27,7 @@
 #include <android-base/chrono_utils.h>
 #include <android/graphics/region.h>
 #include <android/gui/BnScreenCaptureListener.h>
+#include <android/hardware/display/IDeviceProductInfoConstants.h>
 #include <android/os/IInputConstants.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -1022,16 +1023,24 @@
     } else {
         LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
     }
-    auto relativeAddress = env->NewIntArray(info->relativeAddress.size());
-    auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr);
-    for (int i = 0; i < info->relativeAddress.size(); i++) {
-        relativeAddressData[i] = info->relativeAddress[i];
+    jint connectionToSinkType;
+    // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing
+    // for a 5–device-deep hierarchy. For more information, refer:
+    // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
+    using android::hardware::display::IDeviceProductInfoConstants;
+    if (info->relativeAddress.size() != 4) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+    } else if (info->relativeAddress[0] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
+    } else if (info->relativeAddress[1] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT;
+    } else {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE;
     }
-    env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0);
 
     return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
                           manufacturerPnpId, productId, modelYear, manufactureDate,
-                          relativeAddress);
+                          connectionToSinkType);
 }
 
 static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1970,7 +1979,7 @@
                              "Ljava/lang/String;"
                              "Ljava/lang/Integer;"
                              "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;"
-                             "[I)V");
+                             "I)V");
 
     jclass deviceProductInfoManufactureDateClazz =
             FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");