All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.commands.uinput.Event Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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 com.android.commands.uinput;

import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
import android.util.SparseArray;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;

import src.com.android.commands.uinput.InputAbsInfo;

/**
 * An event is a JSON file defined action event to instruct uinput to perform a command like
 * device registration or uinput events injection.
 */
public class Event {
    private static final String TAG = "UinputEvent";

    public static final String COMMAND_REGISTER = "register";
    public static final String COMMAND_DELAY = "delay";
    public static final String COMMAND_INJECT = "inject";
    private static final int ABS_CNT = 64;

    // These constants come from "include/uapi/linux/input.h" in the kernel
    enum Bus {
        USB(0x03), BLUETOOTH(0x05);
        private final int mValue;

        Bus(int value) {
            mValue = value;
        }

        int getValue() {
            return mValue;
        }
    }

    private int mId;
    private String mCommand;
    private String mName;
    private int mVid;
    private int mPid;
    private Bus mBus;
    private int[] mInjections;
    private SparseArray mConfiguration;
    private int mDuration;
    private int mFfEffectsMax = 0;
    private SparseArray mAbsInfo;

    public int getId() {
        return mId;
    }

    public String getCommand() {
        return mCommand;
    }

    public String getName() {
        return mName;
    }

    public int getVendorId() {
        return mVid;
    }

    public int getProductId() {
        return mPid;
    }

    public int getBus() {
        return mBus.getValue();
    }

    public int[] getInjections() {
        return mInjections;
    }

    public SparseArray getConfiguration() {
        return mConfiguration;
    }

    public int getDuration() {
        return mDuration;
    }

    public int getFfEffectsMax() {
        return mFfEffectsMax;
    }

    public SparseArray  getAbsInfo() {
        return mAbsInfo;
    }

    /**
     * Convert an event to String.
     */
    public String toString() {
        return "Event{id=" + mId
            + ", command=" + mCommand
            + ", name=" + mName
            + ", vid=" + mVid
            + ", pid=" + mPid
            + ", bus=" + mBus
            + ", events=" + Arrays.toString(mInjections)
            + ", configuration=" + mConfiguration
            + ", duration=" + mDuration
            + ", ff_effects_max=" + mFfEffectsMax
            + "}";
    }

    private static class Builder {
        private Event mEvent;

        Builder() {
            mEvent = new Event();
        }

        public void setId(int id) {
            mEvent.mId = id;
        }

        private void setCommand(String command) {
            mEvent.mCommand = command;
        }

        public void setName(String name) {
            mEvent.mName = name;
        }

        public void setInjections(int[] events) {
            mEvent.mInjections = events;
        }

        public void setConfiguration(SparseArray configuration) {
            mEvent.mConfiguration = configuration;
        }

        public void setVid(int vid) {
            mEvent.mVid = vid;
        }

        public void setPid(int pid) {
            mEvent.mPid = pid;
        }

        public void setBus(Bus bus) {
            mEvent.mBus = bus;
        }

        public void setDuration(int duration) {
            mEvent.mDuration = duration;
        }

        public void setFfEffectsMax(int ffEffectsMax) {
            mEvent.mFfEffectsMax = ffEffectsMax;
        }

        public void setAbsInfo(SparseArray absInfo) {
            mEvent.mAbsInfo = absInfo;
        }

        public Event build() {
            if (mEvent.mId == -1) {
                throw new IllegalStateException("No event id");
            } else if (mEvent.mCommand == null) {
                throw new IllegalStateException("Event does not contain a command");
            }
            if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
                if (mEvent.mConfiguration == null) {
                    throw new IllegalStateException(
                            "Device registration is missing configuration");
                }
            } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
                if (mEvent.mDuration <= 0) {
                    throw new IllegalStateException("Delay has missing or invalid duration");
                }
            } else if (COMMAND_INJECT.equals(mEvent.mCommand)) {
                if (mEvent.mInjections  == null) {
                    throw new IllegalStateException("Inject command is missing injection data");
                }
            } else {
                throw new IllegalStateException("Unknown command " + mEvent.mCommand);
            }
            return mEvent;
        }
    }

    /**
     *  A class that parses the JSON event format from an input stream to build device events.
     */
    public static class Reader {
        private JsonReader mReader;

        public Reader(InputStreamReader in) {
            mReader = new JsonReader(in);
            mReader.setLenient(true);
        }

        /**
         * Get next event entry from JSON file reader.
         */
        public Event getNextEvent() throws IOException {
            Event e = null;
            while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) {
                Event.Builder eb = new Event.Builder();
                try {
                    mReader.beginObject();
                    while (mReader.hasNext()) {
                        String name = mReader.nextName();
                        switch (name) {
                            case "id":
                                eb.setId(readInt());
                                break;
                            case "command":
                                eb.setCommand(mReader.nextString());
                                break;
                            case "name":
                                eb.setName(mReader.nextString());
                                break;
                            case "vid":
                                eb.setVid(readInt());
                                break;
                            case "pid":
                                eb.setPid(readInt());
                                break;
                            case "bus":
                                eb.setBus(readBus());
                                break;
                            case "events":
                                int[] injections = readIntList().stream()
                                            .mapToInt(Integer::intValue).toArray();
                                eb.setInjections(injections);
                                break;
                            case "configuration":
                                eb.setConfiguration(readConfiguration());
                                break;
                            case "ff_effects_max":
                                eb.setFfEffectsMax(readInt());
                                break;
                            case "abs_info":
                                eb.setAbsInfo(readAbsInfoArray());
                                break;
                            case "duration":
                                eb.setDuration(readInt());
                                break;
                            default:
                                mReader.skipValue();
                        }
                    }
                    mReader.endObject();
                } catch (IllegalStateException ex) {
                    error("Error reading in object, ignoring.", ex);
                    consumeRemainingElements();
                    mReader.endObject();
                    continue;
                }
                e = eb.build();
            }

            return e;
        }

        private ArrayList readIntList() throws IOException {
            ArrayList data = new ArrayList();
            try {
                mReader.beginArray();
                while (mReader.hasNext()) {
                    data.add(Integer.decode(mReader.nextString()));
                }
                mReader.endArray();
            } catch (IllegalStateException | NumberFormatException e) {
                consumeRemainingElements();
                mReader.endArray();
                throw new IllegalStateException("Encountered malformed data.", e);
            }
            return data;
        }

        private byte[] readData() throws IOException {
            ArrayList data = readIntList();
            byte[] rawData = new byte[data.size()];
            for (int i = 0; i < data.size(); i++) {
                int d = data.get(i);
                if ((d & 0xFF) != d) {
                    throw new IllegalStateException("Invalid data, all values must be byte-sized");
                }
                rawData[i] = (byte) d;
            }
            return rawData;
        }

        private int readInt() throws IOException {
            String val = mReader.nextString();
            return Integer.decode(val);
        }

        private Bus readBus() throws IOException {
            String val = mReader.nextString();
            return Bus.valueOf(val.toUpperCase());
        }

        private SparseArray readConfiguration()
                throws IllegalStateException, IOException {
            SparseArray configuration = new SparseArray<>();
            try {
                mReader.beginArray();
                while (mReader.hasNext()) {
                    int type = 0;
                    int[] data = null;
                    mReader.beginObject();
                    while (mReader.hasNext()) {
                        String name = mReader.nextName();
                        switch (name) {
                            case "type":
                                type = readInt();
                                break;
                            case "data":
                                data = readIntList().stream()
                                            .mapToInt(Integer::intValue).toArray();
                                break;
                            default:
                                consumeRemainingElements();
                                mReader.endObject();
                                throw new IllegalStateException(
                                        "Invalid key in device configuration: " + name);
                        }
                    }
                    mReader.endObject();
                    if (data != null) {
                        configuration.put(type, data);
                    }
                }
                mReader.endArray();
            } catch (IllegalStateException | NumberFormatException e) {
                consumeRemainingElements();
                mReader.endArray();
                throw new IllegalStateException("Encountered malformed data.", e);
            }
            return configuration;
        }

        private InputAbsInfo readAbsInfo() throws IllegalStateException, IOException {
            InputAbsInfo absInfo = new InputAbsInfo();
            try {
                mReader.beginObject();
                while (mReader.hasNext()) {
                    String name = mReader.nextName();
                    switch (name) {
                        case "value":
                            absInfo.value = readInt();
                            break;
                        case "minimum":
                            absInfo.minimum = readInt();
                            break;
                        case "maximum":
                            absInfo.maximum = readInt();
                            break;
                        case "fuzz":
                            absInfo.fuzz = readInt();
                            break;
                        case "flat":
                            absInfo.flat = readInt();
                            break;
                        case "resolution":
                            absInfo.resolution = readInt();
                            break;
                        default:
                            consumeRemainingElements();
                            mReader.endObject();
                            throw new IllegalStateException("Invalid key in abs info: " + name);
                    }
                }
                mReader.endObject();
            } catch (IllegalStateException | NumberFormatException e) {
                consumeRemainingElements();
                mReader.endObject();
                throw new IllegalStateException("Encountered malformed data.", e);
            }
            return absInfo;
        }

        private SparseArray readAbsInfoArray()
                throws IllegalStateException, IOException {
            SparseArray infoArray = new SparseArray<>();
            try {
                mReader.beginArray();
                while (mReader.hasNext()) {
                    int type = 0;
                    InputAbsInfo absInfo = null;
                    mReader.beginObject();
                    while (mReader.hasNext()) {
                        String name = mReader.nextName();
                        switch (name) {
                            case "code":
                                type = readInt();
                                break;
                            case "info":
                                absInfo = readAbsInfo();
                                break;
                            default:
                                consumeRemainingElements();
                                mReader.endObject();
                                throw new IllegalStateException("Invalid key in abs info array: "
                                        + name);
                        }
                    }
                    mReader.endObject();
                    if (absInfo != null) {
                        infoArray.put(type, absInfo);
                    }
                }
                mReader.endArray();
            } catch (IllegalStateException | NumberFormatException e) {
                consumeRemainingElements();
                mReader.endArray();
                throw new IllegalStateException("Encountered malformed data.", e);
            }
            return infoArray;
        }

        private void consumeRemainingElements() throws IOException {
            while (mReader.hasNext()) {
                mReader.skipValue();
            }
        }
    }

    private static void error(String msg, Exception e) {
        System.out.println(msg);
        Log.e(TAG, msg);
        if (e != null) {
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy