Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4a8c6d7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add physical port to DisplayViewport"

parents 7b841176 15a412d2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.hardware.display;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.text.TextUtils;

@@ -71,6 +72,9 @@ public final class DisplayViewport {
    // The ID used to uniquely identify this display.
    public String uniqueId;

    // The physical port that the associated display device is connected to.
    public @Nullable Byte physicalPort;

    public @ViewportType int type;

    public void copyFrom(DisplayViewport viewport) {
@@ -82,6 +86,7 @@ public final class DisplayViewport {
        deviceWidth = viewport.deviceWidth;
        deviceHeight = viewport.deviceHeight;
        uniqueId = viewport.uniqueId;
        physicalPort = viewport.physicalPort;
        type = viewport.type;
    }

@@ -113,6 +118,7 @@ public final class DisplayViewport {
              && deviceWidth == other.deviceWidth
              && deviceHeight == other.deviceHeight
              && TextUtils.equals(uniqueId, other.uniqueId)
              && physicalPort == other.physicalPort
              && type == other.type;
    }

@@ -128,6 +134,7 @@ public final class DisplayViewport {
        result += prime * result + deviceWidth;
        result += prime * result + deviceHeight;
        result += prime * result + uniqueId.hashCode();
        result += prime * result + physicalPort;
        result += prime * result + type;
        return result;
    }
@@ -139,6 +146,7 @@ public final class DisplayViewport {
                + ", valid=" + valid
                + ", displayId=" + displayId
                + ", uniqueId='" + uniqueId + "'"
                + ", physicalPort=" + physicalPort
                + ", orientation=" + orientation
                + ", logicalFrame=" + logicalFrame
                + ", physicalFrame=" + physicalFrame
+13 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ static struct {
    jfieldID deviceWidth;
    jfieldID deviceHeight;
    jfieldID uniqueId;
    jfieldID physicalPort;
    jfieldID type;
} gDisplayViewportClassInfo;

@@ -54,6 +55,9 @@ static struct {

status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject viewportObj,
        DisplayViewport* viewport) {
    static const jclass byteClass = FindClassOrDie(env, "java/lang/Byte");
    static const jmethodID byteValue = env->GetMethodID(byteClass, "byteValue", "()B");

    viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId);
    viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
    viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth);
@@ -65,6 +69,12 @@ status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject
        viewport->uniqueId = ScopedUtfChars(env, uniqueId).c_str();
    }

    viewport->physicalPort = std::nullopt;
    jobject physicalPort = env->GetObjectField(viewportObj, gDisplayViewportClassInfo.physicalPort);
    if (physicalPort != nullptr) {
        viewport->physicalPort = std::make_optional(env->CallByteMethod(physicalPort, byteValue));
    }

    viewport->type = static_cast<ViewportType>(env->GetIntField(viewportObj,
                gDisplayViewportClassInfo.type));

@@ -112,6 +122,9 @@ int register_android_hardware_display_DisplayViewport(JNIEnv* env) {
    gDisplayViewportClassInfo.uniqueId = GetFieldIDOrDie(env,
            gDisplayViewportClassInfo.clazz, "uniqueId", "Ljava/lang/String;");

    gDisplayViewportClassInfo.physicalPort = GetFieldIDOrDie(env,
            gDisplayViewportClassInfo.clazz, "physicalPort", "Ljava/lang/Byte;");

    gDisplayViewportClassInfo.type = GetFieldIDOrDie(env,
            gDisplayViewportClassInfo.clazz, "type", "I");

+2 −0
Original line number Diff line number Diff line
@@ -225,6 +225,8 @@ abstract class DisplayDevice {
        viewport.deviceHeight = isRotated ? info.width : info.height;

        viewport.uniqueId = info.uniqueId;
        // TODO(b/112898898) Use an actual port here.
        viewport.physicalPort = null;
    }

    /**
+121 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 com.android.server.input;

import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


class ConfigurationProcessor {
    private static final String TAG = "ConfigurationProcessor";

    static List<String> processExcludedDeviceNames(InputStream xml) throws Exception {
        List<String> names = new ArrayList<>();
        try (InputStreamReader confReader = new InputStreamReader(xml)) {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(confReader);
            XmlUtils.beginDocument(parser, "devices");
            while (true) {
                XmlUtils.nextElement(parser);
                if (!"device".equals(parser.getName())) {
                    break;
                }
                String name = parser.getAttributeValue(null, "name");
                if (name != null) {
                    names.add(name);
                }
            }
        }
        return names;
    }

    /**
     * Parse the configuration for input port associations.
     *
     * Configuration format:
     * <code>
     * &lt;ports>
     *     &lt;port display="0" input="usb-xhci-hcd.0.auto-1.4.3/input0" />
     *     &lt;port display="1" input="usb-xhci-hcd.0.auto-1.4.2/input0" />
     * &lt;/ports>
     * </code>
     *
     * In this example, any input device that has physical port of
     * "usb-xhci-hcd.0.auto-1.4.3/input0" will be associated with a display
     * that has the physical port "0". If such a display does not exist, the input device
     * will be disabled and no input events will be dispatched from that input device until a
     * matching display appears. Likewise, an input device that has port "..1.4.2.." will have
     * its input events forwarded to a display that has physical port of "1".
     *
     * Note: display port must be a numeric value, and this is checked at runtime for validity.
     * At the same time, it is specified as a string for simplicity.
     *
     * Note: do not confuse "display id" with "display port".
     * The "display port" is the physical port on which the display is connected. This could
     * be something like HDMI0, HDMI1, etc. For virtual displays, "display port" will be null.
     * The "display id" is a way to identify a particular display, and is not a stable API.
     * All displays, including virtual ones, will have a display id.
     *
     * Return the pairs of associations. The first item in the pair is the input port,
     * the second item in the pair is the display port.
     */
    @VisibleForTesting
    static List<Pair<String, String>> processInputPortAssociations(InputStream xml)
            throws Exception {
        List<Pair<String, String>> associations = new ArrayList<>();
        try (InputStreamReader confReader = new InputStreamReader(xml)) {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(confReader);
            XmlUtils.beginDocument(parser, "ports");

            while (true) {
                XmlUtils.nextElement(parser);
                String entryName = parser.getName();
                if (!"port".equals(entryName)) {
                    break;
                }
                String inputPort = parser.getAttributeValue(null, "input");
                String displayPort = parser.getAttributeValue(null, "display");
                if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPort)) {
                    // This is likely an error by an OEM during device configuration
                    Slog.wtf(TAG, "Ignoring incomplete entry");
                    continue;
                }
                try {
                    Integer.parseUnsignedInt(displayPort);
                } catch (NumberFormatException e) {
                    Slog.wtf(TAG, "Display port should be an integer");
                    continue;
                }
                associations.add(new Pair<>(inputPort, displayPort));
            }
        }
        return associations;
    }
}
+47 −30
Original line number Diff line number Diff line
@@ -64,18 +64,18 @@ import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
import android.view.IInputFilter;
import android.view.IInputFilterHost;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputApplicationHandle;
import android.view.InputWindowHandle;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputWindowHandle;
import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
@@ -97,14 +97,13 @@ import com.android.server.policy.WindowManagerPolicy;
import libcore.io.IoUtils;
import libcore.io.Streams;

import org.xmlpull.v1.XmlPullParser;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -124,6 +123,7 @@ public class InputManagerService extends IInputManager.Stub
    static final boolean DEBUG = false;

    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
    private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";

    private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
@@ -1852,11 +1852,9 @@ public class InputManagerService extends IInputManager.Stub
    }

    // Native callback.
    private String[] getExcludedDeviceNames() {
        ArrayList<String> names = new ArrayList<String>();

    private static String[] getExcludedDeviceNames() {
        List<String> names = new ArrayList<>();
        // Read partner-provided list of excluded input devices
        XmlPullParser parser = null;
        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
        final File[] baseDirs = {
            Environment.getRootDirectory(),
@@ -1864,33 +1862,52 @@ public class InputManagerService extends IInputManager.Stub
        };
        for (File baseDir: baseDirs) {
            File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
            FileReader confreader = null;
            try {
                confreader = new FileReader(confFile);
                parser = Xml.newPullParser();
                parser.setInput(confreader);
                XmlUtils.beginDocument(parser, "devices");

                while (true) {
                    XmlUtils.nextElement(parser);
                    if (!"device".equals(parser.getName())) {
                        break;
                    }
                    String name = parser.getAttributeValue(null, "name");
                    if (name != null) {
                        names.add(name);
                    }
                }
                InputStream stream = new FileInputStream(confFile);
                names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
            } catch (FileNotFoundException e) {
                // It's ok if the file does not exist.
            } catch (Exception e) {
                Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
            } finally {
                try { if (confreader != null) confreader.close(); } catch (IOException e) { }
                Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
            }
        }
        return names.toArray(new String[0]);
    }

        return names.toArray(new String[names.size()]);
    /**
     * Flatten a list of pairs into a list, with value positioned directly next to the key
     * @return Flattened list
     */
    private static <T> List<T> flatten(@NonNull List<Pair<T, T>> pairs) {
        List<T> list = new ArrayList<>(pairs.size() * 2);
        for (Pair<T, T> pair : pairs) {
            list.add(pair.first);
            list.add(pair.second);
        }
        return list;
    }

    /**
     * Ports are highly platform-specific, so only allow these to be specified in the vendor
     * directory.
     */
    // Native callback
    private static String[] getInputPortAssociations() {
        File baseDir = Environment.getVendorDirectory();
        File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);

        try {
            InputStream stream = new FileInputStream(confFile);
            List<Pair<String, String>> associations =
                    ConfigurationProcessor.processInputPortAssociations(stream);
            List<String> associationList = flatten(associations);
            return associationList.toArray(new String[0]);
        } catch (FileNotFoundException e) {
            // Most of the time, file will not exist, which is expected.
        } catch (Exception e) {
            Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
        }
        return new String[0];
    }

    // Native callback.
Loading