diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java new file mode 100644 index 0000000000000..6ad7faed16d8e --- /dev/null +++ b/core/java/android/hardware/display/DeviceProductInfo.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2020 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.hardware.display; + +import android.os.Parcel; +import android.os.Parcelable; + +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 { + final private String mName; + final private String mManufacturerPnpId; + final private String mProductId; + final private Integer mModelYear; + final private ManufactureDate mManufactureDate; + + public DeviceProductInfo( + String name, + String manufacturerPnpId, + String productCode, + Integer modelYear, + ManufactureDate manufactureDate) { + this.mName = name; + this.mManufacturerPnpId = manufacturerPnpId; + this.mProductId = productCode; + this.mModelYear = modelYear; + this.mManufactureDate = manufactureDate; + } + + private DeviceProductInfo(Parcel in) { + mName = in.readString(); + mManufacturerPnpId = in.readString(); + mProductId = (String) in.readValue(null); + mModelYear = (Integer) in.readValue(null); + mManufactureDate = (ManufactureDate) in.readValue(null); + } + + /** + * @return Display name. + */ + public String getName() { + return mName; + } + + /** + * @return Manufacturer Plug and Play ID. + */ + public String getManufacturerPnpId() { + return mManufacturerPnpId; + } + + /** + * @return Manufacturer product ID. + */ + public String getProductId() { + return mProductId; + } + + /** + * @return Model year of the device. Typically exactly one of model year or + * manufacture date will be present. + */ + public Integer getModelYear() { + return mModelYear; + } + + /** + * @return Manufacture date. Typically exactly one of model year or manufacture + * date will be present. + */ + public ManufactureDate getManufactureDate() { + return mManufactureDate; + } + + @Override + public String toString() { + return "DeviceProductInfo{" + + "name=" + + mName + + ", manufacturerPnpId=" + + mManufacturerPnpId + + ", productId=" + + mProductId + + ", modelYear=" + + mModelYear + + ", manufactureDate=" + + mManufactureDate + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceProductInfo that = (DeviceProductInfo) o; + return Objects.equals(mName, that.mName) + && Objects.equals(mManufacturerPnpId, that.mManufacturerPnpId) + && Objects.equals(mProductId, that.mProductId) + && Objects.equals(mModelYear, that.mModelYear) + && Objects.equals(mManufactureDate, that.mManufactureDate); + } + + @Override + public int hashCode() { + return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate); + } + + public static final Creator CREATOR = + new Creator() { + @Override + public DeviceProductInfo createFromParcel(Parcel in) { + return new DeviceProductInfo(in); + } + + @Override + public DeviceProductInfo[] newArray(int size) { + return new DeviceProductInfo[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mName); + dest.writeString(mManufacturerPnpId); + dest.writeValue(mProductId); + dest.writeValue(mModelYear); + dest.writeValue(mManufactureDate); + } + + /** + * Stores information about the date of manufacture. + * + * @hide + */ + public static class ManufactureDate implements Parcelable { + final private Integer mWeek; + final private Integer mYear; + + public ManufactureDate(Integer week, Integer year) { + mWeek = week; + mYear = year; + } + + protected ManufactureDate(Parcel in) { + mWeek = (Integer) in.readValue(null); + mYear = (Integer) in.readValue(null); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeValue(mWeek); + dest.writeValue(mYear); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = + new Creator() { + @Override + public ManufactureDate createFromParcel(Parcel in) { + return new ManufactureDate(in); + } + + @Override + public ManufactureDate[] newArray(int size) { + return new ManufactureDate[size]; + } + }; + + public int getYear() { + return mYear; + } + + public int getWeek() { + return mWeek; + } + + @Override + public String toString() { + return "ManufactureDate{week=" + mWeek + ", year=" + mYear + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ManufactureDate that = (ManufactureDate) o; + return Objects.equals(mWeek, that.mWeek) && Objects.equals(mYear, that.mYear); + } + + @Override + public int hashCode() { + return Objects.hash(mWeek, mYear); + } + } +} diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index b9868a7e14440..3047385410b03 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -28,6 +28,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Rect; +import android.hardware.display.DeviceProductInfo; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -69,6 +70,13 @@ public final class DisplayInfo implements Parcelable { */ public DisplayAddress address; + /** + * 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. + */ + public DeviceProductInfo deviceProductInfo; + /** * The human-readable name of the display. */ @@ -297,6 +305,7 @@ public final class DisplayInfo implements Parcelable { && type == other.type && displayId == other.displayId && Objects.equals(address, other.address) + && Objects.equals(deviceProductInfo, other.deviceProductInfo) && Objects.equals(uniqueId, other.uniqueId) && appWidth == other.appWidth && appHeight == other.appHeight @@ -336,6 +345,7 @@ public final class DisplayInfo implements Parcelable { type = other.type; displayId = other.displayId; address = other.address; + deviceProductInfo = other.deviceProductInfo; name = other.name; uniqueId = other.uniqueId; appWidth = other.appWidth; @@ -373,6 +383,7 @@ public final class DisplayInfo implements Parcelable { type = source.readInt(); displayId = source.readInt(); address = source.readParcelable(null); + deviceProductInfo = source.readParcelable(null); name = source.readString(); appWidth = source.readInt(); appHeight = source.readInt(); @@ -418,6 +429,7 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(type); dest.writeInt(displayId); dest.writeParcelable(address, flags); + dest.writeParcelable(deviceProductInfo, flags); dest.writeString(name); dest.writeInt(appWidth); dest.writeInt(appHeight); @@ -645,6 +657,8 @@ public final class DisplayInfo implements Parcelable { if (address != null) { sb.append(", address ").append(address); } + sb.append(", deviceProductInfo "); + sb.append(deviceProductInfo); sb.append(", state "); sb.append(Display.stateToString(state)); if (ownerUid != 0 || ownerPackageName != null) { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index cf48c52825e9f..29371b049b3cf 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -41,6 +41,7 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayedContentSample; import android.hardware.display.DisplayedContentSamplingAttributes; import android.os.Build; @@ -1286,12 +1287,14 @@ public final class SurfaceControl implements Parcelable { public boolean isInternal; public float density; public boolean secure; + public DeviceProductInfo deviceProductInfo; @Override public String toString() { return "DisplayInfo{isInternal=" + isInternal + ", density=" + density - + ", secure=" + secure + "}"; + + ", secure=" + secure + + ", deviceProductInfo=" + deviceProductInfo + "}"; } } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 3f81b112d9f16..741ce8291e57b 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,22 @@ static void doThrowIAE(JNIEnv* env, const char* msg = nullptr) { static const char* const OutOfResourcesException = "android/view/Surface$OutOfResourcesException"; +static struct { + jclass clazz; + jmethodID ctor; +} gIntegerClassInfo; + +static jobject toInteger(JNIEnv* env, int32_t i) { + return env->NewObject(gIntegerClassInfo.clazz, gIntegerClassInfo.ctor, i); +} + static struct { jclass clazz; jmethodID ctor; jfieldID isInternal; jfieldID density; jfieldID secure; + jfieldID deviceProductInfo; } gDisplayInfoClassInfo; static struct { @@ -109,6 +120,16 @@ static struct { jmethodID ctor; } gHdrCapabilitiesClassInfo; +static struct { + jclass clazz; + jmethodID ctor; +} gDeviceProductInfoClassInfo; + +static struct { + jclass clazz; + jmethodID ctor; +} gDeviceProductInfoManufactureDateClassInfo; + static struct { jclass clazz; jmethodID builder; @@ -773,6 +794,41 @@ static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, } } +static jobject convertDeviceProductInfoToJavaObject( + JNIEnv* env, const std::optional& info) { + using ModelYear = android::DeviceProductInfo::ModelYear; + using ManufactureYear = android::DeviceProductInfo::ManufactureYear; + using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear; + + if (!info) return nullptr; + jstring name = env->NewStringUTF(info->name.data()); + jstring manufacturerPnpId = env->NewStringUTF(info->manufacturerPnpId.data()); + jobject productId = env->NewStringUTF(info->productId.data()); + const auto& date = info->manufactureOrModelDate; + jobject modelYear, manufactureDate; + if (const auto* model = std::get_if(&date)) { + modelYear = toInteger(env, model->year); + manufactureDate = nullptr; + } else if (const auto* manufactureWeekAndYear = std::get_if(&date)) { + modelYear = nullptr; + manufactureDate = env->NewObject(gDeviceProductInfoManufactureDateClassInfo.clazz, + gDeviceProductInfoManufactureDateClassInfo.ctor, + toInteger(env, manufactureWeekAndYear->week), + toInteger(env, manufactureWeekAndYear->year)); + } else if (const auto* manufactureYear = std::get_if(&date)) { + modelYear = nullptr; + manufactureDate = env->NewObject(gDeviceProductInfoManufactureDateClassInfo.clazz, + gDeviceProductInfoManufactureDateClassInfo.ctor, + nullptr, + toInteger(env, manufactureYear->year)); + } else { + LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate"); + } + + return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name, + manufacturerPnpId, productId, modelYear, manufactureDate); +} + static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) { DisplayInfo info; if (const auto token = ibinderForJavaObject(env, tokenObj); @@ -785,6 +841,8 @@ static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) info.connectionType == DisplayConnectionType::Internal); env->SetFloatField(object, gDisplayInfoClassInfo.density, info.density); env->SetBooleanField(object, gDisplayInfoClassInfo.secure, info.secure); + env->SetObjectField(object, gDisplayInfoClassInfo.deviceProductInfo, + convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo)); return object; } @@ -1527,12 +1585,19 @@ int register_android_view_SurfaceControl(JNIEnv* env) int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl", sSurfaceControlMethods, NELEM(sSurfaceControlMethods)); + jclass integerClass = FindClassOrDie(env, "java/lang/Integer"); + gIntegerClassInfo.clazz = MakeGlobalRefOrDie(env, integerClass); + gIntegerClassInfo.ctor = GetMethodIDOrDie(env, gIntegerClassInfo.clazz, "", "(I)V"); + jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayInfo"); gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz); gDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "", "()V"); gDisplayInfoClassInfo.isInternal = GetFieldIDOrDie(env, infoClazz, "isInternal", "Z"); gDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F"); gDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z"); + gDisplayInfoClassInfo.deviceProductInfo = + GetFieldIDOrDie(env, infoClazz, "deviceProductInfo", + "Landroid/hardware/display/DeviceProductInfo;"); jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig"); gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz); @@ -1573,6 +1638,25 @@ int register_android_view_SurfaceControl(JNIEnv* env) gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "", "([IFFF)V"); + jclass deviceProductInfoClazz = + FindClassOrDie(env, "android/hardware/display/DeviceProductInfo"); + gDeviceProductInfoClassInfo.clazz = MakeGlobalRefOrDie(env, deviceProductInfoClazz); + gDeviceProductInfoClassInfo.ctor = + GetMethodIDOrDie(env, deviceProductInfoClazz, "", + "(Ljava/lang/String;" + "Ljava/lang/String;" + "Ljava/lang/String;" + "Ljava/lang/Integer;" + "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;)V"); + + jclass deviceProductInfoManufactureDateClazz = + FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate"); + gDeviceProductInfoManufactureDateClassInfo.clazz = + MakeGlobalRefOrDie(env, deviceProductInfoManufactureDateClazz); + gDeviceProductInfoManufactureDateClassInfo.ctor = + GetMethodIDOrDie(env, deviceProductInfoManufactureDateClazz, "", + "(Ljava/lang/Integer;Ljava/lang/Integer;)V"); + jclass graphicsBufferClazz = FindClassOrDie(env, "android/graphics/GraphicBuffer"); gGraphicBufferClassInfo.clazz = MakeGlobalRefOrDie(env, graphicsBufferClazz); gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz, diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index ac41434a1b5c9..18adc0ba27ee4 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -16,6 +16,7 @@ package com.android.server.display; +import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayViewport; import android.util.DisplayMetrics; import android.view.Display; @@ -287,6 +288,13 @@ final class DisplayDeviceInfo { */ public DisplayAddress address; + /** + * 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. + */ + public DeviceProductInfo deviceProductInfo; + /** * Display state. */ @@ -360,6 +368,7 @@ final class DisplayDeviceInfo { || rotation != other.rotation || type != other.type || !Objects.equals(address, other.address) + || !Objects.equals(deviceProductInfo, other.deviceProductInfo) || ownerUid != other.ownerUid || !Objects.equals(ownerPackageName, other.ownerPackageName)) { diff |= DIFF_OTHER; @@ -396,6 +405,7 @@ final class DisplayDeviceInfo { rotation = other.rotation; type = other.type; address = other.address; + deviceProductInfo = other.deviceProductInfo; state = other.state; ownerUid = other.ownerUid; ownerPackageName = other.ownerPackageName; @@ -429,6 +439,7 @@ final class DisplayDeviceInfo { if (address != null) { sb.append(", address ").append(address); } + sb.append(", deviceProductInfo ").append(deviceProductInfo); sb.append(", state ").append(Display.stateToString(state)); if (ownerUid != 0 || ownerPackageName != null) { sb.append(", owner ").append(ownerPackageName); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 4ebbddabd6dbf..e578ac1fcd42b 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -513,6 +513,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f); mInfo.xDpi = config.xDpi; mInfo.yDpi = config.yDpi; + mInfo.deviceProductInfo = mDisplayInfo.deviceProductInfo; // Assume that all built-in displays that have secure output (eg. HDCP) also // support compositing from gralloc protected buffers. @@ -891,8 +892,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println("mBacklight=" + mBacklight); pw.println("mAllmSupported=" + mAllmSupported); pw.println("mAllmRequested=" + mAllmRequested); - pw.println("mGameContentTypeSupported" + mGameContentTypeSupported); - pw.println("mGameContentTypeRequested" + mGameContentTypeRequested); + pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported); + pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested); pw.println("mDisplayInfo=" + mDisplayInfo); pw.println("mDisplayConfigs="); for (int i = 0; i < mDisplayConfigs.length; i++) { @@ -902,14 +903,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (int i = 0; i < mSupportedModes.size(); i++) { pw.println(" " + mSupportedModes.valueAt(i)); } - pw.print("mSupportedColorModes=["); - for (int i = 0; i < mSupportedColorModes.size(); i++) { - if (i != 0) { - pw.print(", "); - } - pw.print(mSupportedColorModes.get(i)); - } - pw.println("]"); + pw.print("mSupportedColorModes=" + mSupportedColorModes.toString()); } private int findDisplayConfigIdLocked(int modeId) { diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 0c9445a055513..ac81a6c813f79 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -269,6 +269,7 @@ final class LogicalDisplay { mBaseDisplayInfo.type = deviceInfo.type; mBaseDisplayInfo.address = deviceInfo.address; + mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo; mBaseDisplayInfo.name = deviceInfo.name; mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId; mBaseDisplayInfo.appWidth = maskedWidth;