diff options
| author | 2024-10-23 17:31:07 +0000 | |
|---|---|---|
| committer | 2024-12-03 17:03:33 +0000 | |
| commit | 15d260fd734d43bfe3e9c1f8499e5212537b55d9 (patch) | |
| tree | a4a6f87c7569fccf2544ffd722e29e0be8943fa4 | |
| parent | 0aa21cca5b5489bf7257ffa4b1407ab4b3764df7 (diff) | |
DisplayTopology propagation to IM
Change-Id: I128a67de220a33bceb578e76ee5c76e83a1cf7aa
Bug: 364907904
Test: builds
Flag: com.android.server.display.feature.flags.display_topology
10 files changed, 281 insertions, 0 deletions
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index 54d0dd0eb8f8..1f7d426d9e6f 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -582,6 +582,15 @@ public final class DisplayTopology implements Parcelable { } } + /** Returns the graph representation of the topology */ + public DisplayTopologyGraph getGraph() { + // TODO(b/364907904): implement + return new DisplayTopologyGraph(mPrimaryDisplayId, + new DisplayTopologyGraph.DisplayNode[] { new DisplayTopologyGraph.DisplayNode( + mRoot == null ? Display.DEFAULT_DISPLAY : mRoot.mDisplayId, + new DisplayTopologyGraph.AdjacentDisplay[0])}); + } + /** * Tests whether two brightness float values are within a small enough tolerance * of each other. diff --git a/core/java/android/hardware/display/DisplayTopologyGraph.java b/core/java/android/hardware/display/DisplayTopologyGraph.java new file mode 100644 index 000000000000..938e6d108f5d --- /dev/null +++ b/core/java/android/hardware/display/DisplayTopologyGraph.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 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; + +/** + * Graph of the displays in {@link android.hardware.display.DisplayTopology} tree. + * + * @hide + */ +public record DisplayTopologyGraph(int primaryDisplayId, DisplayNode[] displayNodes) { + /** + * Display in the topology + */ + public record DisplayNode( + int displayId, + AdjacentDisplay[] adjacentDisplays) {} + + /** + * Edge to adjacent display + */ + public record AdjacentDisplay( + // The logical Id of this adjacent display + int displayId, + // Side of the other display which touches this adjacent display. + @DisplayTopology.TreeNode.Position + int position, + // How many px this display is shifted along the touchingSide, can be negative. + float offsetPx) {} +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index e22d9587093b..07c18caf6c34 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -220,6 +220,7 @@ cc_library_shared_for_libandroid_runtime { "android_hardware_camera2_utils_SurfaceUtils.cpp", "android_hardware_display_DisplayManagerGlobal.cpp", "android_hardware_display_DisplayViewport.cpp", + "android_hardware_display_DisplayTopology.cpp", "android_hardware_HardwareBuffer.cpp", "android_hardware_OverlayProperties.cpp", "android_hardware_SensorManager.cpp", diff --git a/core/jni/android_hardware_display_DisplayTopology.cpp b/core/jni/android_hardware_display_DisplayTopology.cpp new file mode 100644 index 000000000000..d9e802de81e0 --- /dev/null +++ b/core/jni/android_hardware_display_DisplayTopology.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2024 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. + */ + +#define LOG_TAG "DisplayTopology-JNI" + +#include <android_hardware_display_DisplayTopology.h> +#include <nativehelper/ScopedLocalRef.h> +#include <utils/Errors.h> + +#include "jni_wrappers.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + jfieldID primaryDisplayId; + jfieldID displayNodes; +} gDisplayTopologyGraphClassInfo; + +static struct { + jclass clazz; + jfieldID displayId; + jfieldID adjacentDisplays; +} gDisplayTopologyGraphNodeClassInfo; + +static struct { + jclass clazz; + jfieldID displayId; + jfieldID position; + jfieldID offsetPx; +} gDisplayTopologyGraphAdjacentDisplayClassInfo; + +// ---------------------------------------------------------------------------- + +status_t android_hardware_display_DisplayTopologyAdjacentDisplay_toNative( + JNIEnv* env, jobject adjacentDisplayObj, DisplayTopologyAdjacentDisplay* adjacentDisplay) { + adjacentDisplay->displayId = ui::LogicalDisplayId{ + env->GetIntField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.displayId)}; + adjacentDisplay->position = static_cast<DisplayTopologyPosition>( + env->GetIntField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.position)); + adjacentDisplay->offsetPx = + env->GetFloatField(adjacentDisplayObj, + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx); + return OK; +} + +status_t android_hardware_display_DisplayTopologyGraphNode_toNative( + JNIEnv* env, jobject nodeObj, + std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>& + graph) { + ui::LogicalDisplayId displayId = ui::LogicalDisplayId{ + env->GetIntField(nodeObj, gDisplayTopologyGraphNodeClassInfo.displayId)}; + + jobjectArray adjacentDisplaysArray = static_cast<jobjectArray>( + env->GetObjectField(nodeObj, gDisplayTopologyGraphNodeClassInfo.adjacentDisplays)); + + if (adjacentDisplaysArray) { + jsize length = env->GetArrayLength(adjacentDisplaysArray); + for (jsize i = 0; i < length; i++) { + ScopedLocalRef<jobject> + adjacentDisplayObj(env, env->GetObjectArrayElement(adjacentDisplaysArray, i)); + if (NULL != adjacentDisplayObj.get()) { + break; // found null element indicating end of used portion of the array + } + + DisplayTopologyAdjacentDisplay adjacentDisplay; + android_hardware_display_DisplayTopologyAdjacentDisplay_toNative(env, + adjacentDisplayObj + .get(), + &adjacentDisplay); + graph[displayId].push_back(adjacentDisplay); + } + } + return OK; +} + +DisplayTopologyGraph android_hardware_display_DisplayTopologyGraph_toNative(JNIEnv* env, + jobject topologyObj) { + DisplayTopologyGraph topology; + topology.primaryDisplayId = ui::LogicalDisplayId{ + env->GetIntField(topologyObj, gDisplayTopologyGraphClassInfo.primaryDisplayId)}; + + jobjectArray nodesArray = static_cast<jobjectArray>( + env->GetObjectField(topologyObj, gDisplayTopologyGraphClassInfo.displayNodes)); + + if (nodesArray) { + jsize length = env->GetArrayLength(nodesArray); + for (jsize i = 0; i < length; i++) { + ScopedLocalRef<jobject> nodeObj(env, env->GetObjectArrayElement(nodesArray, i)); + if (NULL != nodeObj.get()) { + break; // found null element indicating end of used portion of the array + } + + android_hardware_display_DisplayTopologyGraphNode_toNative(env, nodeObj.get(), + topology.graph); + } + } + return topology; +} + +// ---------------------------------------------------------------------------- + +int register_android_hardware_display_DisplayTopology(JNIEnv* env) { + jclass graphClazz = FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph"); + gDisplayTopologyGraphClassInfo.clazz = MakeGlobalRefOrDie(env, graphClazz); + + gDisplayTopologyGraphClassInfo.primaryDisplayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphClassInfo.clazz, "primaryDisplayId", "I"); + gDisplayTopologyGraphClassInfo.displayNodes = + GetFieldIDOrDie(env, gDisplayTopologyGraphClassInfo.clazz, "displayNodes", + "[Landroid/hardware/display/DisplayTopologyGraph$DisplayNode;"); + + jclass displayNodeClazz = + FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph$DisplayNode"); + gDisplayTopologyGraphNodeClassInfo.clazz = MakeGlobalRefOrDie(env, displayNodeClazz); + gDisplayTopologyGraphNodeClassInfo.displayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "displayId", "I"); + gDisplayTopologyGraphNodeClassInfo.adjacentDisplays = + GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "adjacentDisplays", + "[Landroid/hardware/display/DisplayTopologyGraph$AdjacentDisplay;"); + + jclass adjacentDisplayClazz = + FindClassOrDie(env, "android/hardware/display/DisplayTopologyGraph$AdjacentDisplay"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz = + MakeGlobalRefOrDie(env, adjacentDisplayClazz); + gDisplayTopologyGraphAdjacentDisplayClassInfo.displayId = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "displayId", + "I"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.position = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "position", + "I"); + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "offsetPx", + "F"); + return 0; +} + +} // namespace android diff --git a/core/jni/android_hardware_display_DisplayTopology.h b/core/jni/android_hardware_display_DisplayTopology.h new file mode 100644 index 000000000000..390191f827d8 --- /dev/null +++ b/core/jni/android_hardware_display_DisplayTopology.h @@ -0,0 +1,32 @@ +/* + * Copyright 2024 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. + */ + +#pragma once + +#include <input/DisplayTopologyGraph.h> + +#include "jni.h" + +namespace android { + +/** + * Copies the contents of a DVM DisplayTopology object to a new native DisplayTopology instance. + * Returns DisplayTopology. + */ +extern DisplayTopologyGraph android_hardware_display_DisplayTopologyGraph_toNative( + JNIEnv* env, jobject eventObj); + +} // namespace android diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java index 265e4531a10a..bc44fed21f2d 100644 --- a/services/core/java/com/android/server/input/InputManagerInternal.java +++ b/services/core/java/com/android/server/input/InputManagerInternal.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.graphics.PointF; +import android.hardware.display.DisplayTopology; import android.hardware.display.DisplayViewport; import android.hardware.input.KeyGestureEvent; import android.os.IBinder; @@ -47,6 +48,12 @@ public abstract class InputManagerInternal { public abstract void setDisplayViewports(List<DisplayViewport> viewports); /** + * Called by {@link com.android.server.display.DisplayManagerService} to inform InputManager + * about changes in the displays topology. + */ + public abstract void setDisplayTopology(DisplayTopology topology); + + /** * Called by the power manager to tell the input manager whether it should start * watching for wake events on given displays. * diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 4454dd41a3c1..663fc89f814e 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -51,6 +51,7 @@ import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors; import android.hardware.SensorPrivacyManagerInternal; import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayTopology; import android.hardware.display.DisplayViewport; import android.hardware.input.AidlInputGestureData; import android.hardware.input.HostUsiVersion; @@ -646,6 +647,10 @@ public class InputManagerService extends IInputManager.Stub mNative.setPointerDisplayId(mWindowManagerCallbacks.getPointerDisplayId()); } + private void setDisplayTopologyInternal(DisplayTopology topology) { + mNative.setDisplayTopology(topology.getGraph()); + } + /** * Gets the current state of a key or button by key code. * @param deviceId The input device id, or -1 to consult all devices. @@ -3447,6 +3452,11 @@ public class InputManagerService extends IInputManager.Stub } @Override + public void setDisplayTopology(DisplayTopology topology) { + setDisplayTopologyInternal(topology); + } + + @Override public void setDisplayInteractivities(SparseBooleanArray displayInteractivities) { boolean globallyInteractive = false; ArraySet<Integer> nonInteractiveDisplays = new ArraySet<>(); diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 935f0ffc36ac..c72f7c076a83 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -18,6 +18,7 @@ package com.android.server.input; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.display.DisplayTopologyGraph; import android.hardware.display.DisplayViewport; import android.hardware.input.InputSensorInfo; import android.hardware.lights.Light; @@ -42,6 +43,8 @@ interface NativeInputManagerService { void setDisplayViewports(DisplayViewport[] viewports); + void setDisplayTopology(DisplayTopologyGraph topologyGraph); + int getScanCodeState(int deviceId, int sourceMask, int scanCode); int getKeyCodeState(int deviceId, int sourceMask, int keyCode); @@ -323,6 +326,9 @@ interface NativeInputManagerService { public native void setDisplayViewports(DisplayViewport[] viewports); @Override + public native void setDisplayTopology(DisplayTopologyGraph topologyGraph); + + @Override public native int getScanCodeState(int deviceId, int sourceMask, int scanCode); @Override diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 943019429c3f..6b6919d82c3b 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -68,6 +68,7 @@ #include <map> #include <vector> +#include "android_hardware_display_DisplayTopology.h" #include "android_hardware_display_DisplayViewport.h" #include "android_hardware_input_InputApplicationHandle.h" #include "android_hardware_input_InputWindowHandle.h" @@ -321,6 +322,8 @@ public: void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray); + void setDisplayTopology(JNIEnv* env, jobject topologyGraph); + base::Result<std::unique_ptr<InputChannel>> createInputChannel(const std::string& name); base::Result<std::unique_ptr<InputChannel>> createInputMonitor(ui::LogicalDisplayId displayId, const std::string& name, @@ -640,6 +643,11 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO InputReaderConfiguration::Change::DISPLAY_INFO); } +void NativeInputManager::setDisplayTopology(JNIEnv* env, jobject topologyGraph) { + android_hardware_display_DisplayTopologyGraph_toNative(env, topologyGraph); + // TODO(b/367661489): Use the topology +} + base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel( const std::string& name) { ATRACE_CALL(); @@ -2092,6 +2100,12 @@ static void nativeSetDisplayViewports(JNIEnv* env, jobject nativeImplObj, im->setDisplayViewports(env, viewportObjArray); } +static void nativeSetDisplayTopology(JNIEnv* env, jobject nativeImplObj, + jobject displayTopologyObj) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + im->setDisplayTopology(env, displayTopologyObj); +} + static jint nativeGetScanCodeState(JNIEnv* env, jobject nativeImplObj, jint deviceId, jint sourceMask, jint scanCode) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); @@ -3148,6 +3162,8 @@ static const JNINativeMethod gInputManagerMethods[] = { {"start", "()V", (void*)nativeStart}, {"setDisplayViewports", "([Landroid/hardware/display/DisplayViewport;)V", (void*)nativeSetDisplayViewports}, + {"setDisplayTopology", "(Landroid/hardware/display/DisplayTopologyGraph;)V", + (void*)nativeSetDisplayTopology}, {"getScanCodeState", "(III)I", (void*)nativeGetScanCodeState}, {"getKeyCodeState", "(III)I", (void*)nativeGetKeyCodeState}, {"getSwitchState", "(III)I", (void*)nativeGetSwitchState}, diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index df37ec3ef037..09fd8d4ac02e 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -49,6 +49,7 @@ int register_android_server_Watchdog(JNIEnv* env); int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); +int register_android_hardware_display_DisplayTopology(JNIEnv* env); int register_android_server_am_OomConnection(JNIEnv* env); int register_android_server_am_CachedAppOptimizer(JNIEnv* env); int register_android_server_am_Freezer(JNIEnv* env); @@ -114,6 +115,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_storage_AppFuse(env); register_android_server_SyntheticPasswordManager(env); register_android_hardware_display_DisplayViewport(env); + register_android_hardware_display_DisplayTopology(env); register_android_server_am_OomConnection(env); register_android_server_am_CachedAppOptimizer(env); register_android_server_am_Freezer(env); |