【干货】Android系统定制基础篇:第十五部分(Android支持鼠标右键返回、GPIO 控制方案、属性标识USB摄像头的VID与PID)

news2024/11/24 18:34:59

1、修改 frameworks/native/services/inputflinger/InputReader.cpp 如下:

diff --git a/frameworks/native/services/inputflinger/InputReader.cpp b/frameworks/native/services/inputflinger/Inp
index 7207a83..2721800 100755
--- a/frameworks/native/services/inputflinger/InputReader.cpp
+++ b/frameworks/native/services/inputflinger/InputReader.cpp
@@ -1422,6 +1422,7 @@ uint32_t CursorButtonAccumulator::getButtonState() const {
         result |= AMOTION_EVENT_BUTTON_PRIMARY;
     }
     if (mBtnRight) {
+        /*
         char targetProduct[PROPERTY_VALUE_MAX] = {0};
         property_get("ro.target.product", targetProduct, "");
         if (strcmp(targetProduct, "box") == 0) {
@@ -1429,6 +1430,9 @@ uint32_t CursorButtonAccumulator::getButtonState() const {
         } else {
             result |= AMOTION_EVENT_BUTTON_SECONDARY;
         }
+        */
+        
+        result |= AMOTION_EVENT_BUTTON_BACK;
     }
     if (mBtnMiddle) {
         result |= AMOTION_EVENT_BUTTON_TERTIARY;

二、Android GPIO 控制方案
GPIO 功能在 Android Framework 中增加 GPIO 相关 API,让 APP 可以直接通过 JAVA API 操控 GPIO。支持 输入、输出、模拟按键 三种模式。做为输入时可以用于app获取外部设备的电平状态。做为输出时可以输出高低电平,用于控制外设。当做为模拟按键时,此 GPIO 低电平时 APP 会收到对应的键值。

移植
参考项目 Android-GPIOControlDriver,移植驱动和 Framework 代码。
使用
1.在 APP 源码 aidl/android/os/ 目录下新建 IGpioService.aidl,如下:

package android.os;
 
/** {@hide} */
interface IGpioService
{
	int gpioWrite(int gpio, int value);
	int gpioRead(int gpio);
	int gpioDirection(int gpio, int direction, int value);
	int gpioRegKeyEvent(int gpio);
	int gpioUnregKeyEvent(int gpio);
	int gpioGetNumber();
}

2.参考下面源码调用 GPIO 相关 API:

package com.ayst.sample.items.gpio;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.IBinder;
import android.os.IGpioService;
import android.os.RemoteException;

import java.lang.reflect.Method;

/**
 * Created by Administrator on 2018/11/6.
 */
public class Gpio {
    private IGpioService mGpioService;

    @SuppressLint("WrongConstant")
    public Gpio(Context context) {
        Method method = null;
        try {
            method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
            IBinder binder = (IBinder) method.invoke(null, new Object[]{"gpio"});
            mGpioService = IGpioService.Stub.asInterface(binder);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * GPIO write
     *
     * @param gpio  0~Number
     * @param value 0: Low 1: High
     */
    public void gpioWrite(int gpio, int value) {
        if (null != mGpioService) {
            try {
                mGpioService.gpioWrite(gpio, value);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * GPIO read
     *
     * @param gpio 0~Number
     * @return 0: Low 1: High other:error
     */
    public int gpioRead(int gpio) {
        if (null != mGpioService) {
            try {
                return mGpioService.gpioRead(gpio);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return -1;
    }

    /**
     * GPIO direction
     *
     * @param gpio      0~Number
     * @param direction 0: input 1: output
     * @param value     0: Low 1: High
     */
    public void gpioDirection(int gpio, int direction, int value) {
        if (null != mGpioService) {
            try {
                mGpioService.gpioDirection(gpio, direction, value);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * GPIO register key event
     *
     * @param gpio 0~Number
     */
    public void gpioRegKeyEvent(int gpio) {
        if (null != mGpioService) {
            try {
                mGpioService.gpioRegKeyEvent(gpio);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * GPIO unregister key event
     *
     * @param gpio 0~Number
     */
    public void gpioUnregKeyEvent(int gpio) {
        if (null != mGpioService) {
            try {
                mGpioService.gpioUnregKeyEvent(gpio);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Get GPIO number
     *
     * @return <0: error other: GPIO number
     */
    public int gpioGetNumber() {
        if (null != mGpioService) {
            try {
                return mGpioService.gpioGetNumber();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return -1;
    }
}

输入

// 将GPIO_0设置为输入
gpio.gpioDirection(0, 0, 0);
// 读GPIO_0电平
int level = gpio.gpioRead(0);

输出

// 将GPIO_0设置为输出,并默认输出低电平
gpio.gpioDirection(0, 1, 0);
// GPIO_0输出高电平
gpio.gpioWrite(0, 1);

按键模式

/* 将GPIO_0设置按键模式
当GPIO_0为低电平时将收到KeyEvent.KEYCODE_GPIO_0 KeyEvent.ACTION_DOWN,
当GPIO_0为高电平时收到KeyEvent.KEYCODE_GPIO_0 KeyEvent.ACTION_UP
*/
gpio.gpioRegKeyEvent(0);

在这里插入图片描述完整 DEMO 源码请参考:https://github.com/aystshen/topband_sample

三、属性标识USB摄像头的VID与PID

Android 在使用多个 USB 摄像头时,根据加载顺序不同他们的设备文件顺序不同,比如:“video0, video1, video2”,每次启动它们的顺序都可能不同,这样 APP 就无法知道哪个设备文件对应的是哪个摄像头,因此下面方案增加属性来标识设备文件与摄像头 VID、PID 的关系,这样就解决了上面的问题。
实现

diff --git a/frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 26d5ac9..cfd8479 100755
--- a/frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -51,6 +51,7 @@ import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Pair;
 import android.util.Slog;
 
@@ -61,8 +62,10 @@ import com.android.internal.os.SomeArgs;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.FgThread;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -95,6 +98,10 @@ public class UsbDeviceManager {
      * The non-persistent property which stores the current USB actual state.
      */
     private static final String USB_STATE_PROPERTY = "sys.usb.state";
+    
+    private static final String USB_CAMERA_PROPERTY_PRE = "topband.dev.";
+
+    private static final String USB_CAMERA_CLASS_PATH = "/sys/class/video4linux";
 
     /**
      * ro.bootmode value when phone boots into usual Android.
@@ -215,15 +222,29 @@ public class UsbDeviceManager {
             if (devPath != null && devPath.contains("/devices/platform")) {
                 if ("video4linux".equals(subSystem)) {
                     Intent intent = new Intent(Intent.ACTION_USB_CAMERA);
+
                     String action = event.get("ACTION");
+                    String name = event.get("DEVNAME");
+                    String idProduct = searchAndReadFileBackward("/sys" + devPath, "idProduct");
+                    String idVendor = searchAndReadFileBackward("/sys" + devPath, "idVendor");
+
+                    if (DEBUG) Slog.d(TAG, action + " usb camera: " + name + " [" + idVendor + ":" + idProduct + "]");
                     if ("remove".equals(action)){
                         Slog.d(TAG,"usb camera removed");
                         intent.setFlags(Intent.FLAG_USB_CAMERA_REMOVE);
                         SystemProperties.set("persist.sys.usbcamera.status","remove");
+
+                        if (!name.isEmpty()) {
+                            SystemProperties.set(USB_CAMERA_PROPERTY_PRE + name, "");
+                        }
                     } else if ("add".equals(action)) {
                         Slog.d(TAG,"usb camera added");
                         intent.setFlags(Intent.FLAG_USB_CAMERA_ADD);
                         SystemProperties.set("persist.sys.usbcamera.status","add");
+
+                        if (!name.isEmpty() && !idProduct.isEmpty() && !idVendor.isEmpty()) {
+                            SystemProperties.set(USB_CAMERA_PROPERTY_PRE + name, idVendor + ":" + idProduct);
+                        }
                     }
 
                     int num = android.hardware.Camera.getNumberOfCameras();
@@ -243,6 +264,99 @@ public class UsbDeviceManager {
             }
         }
     };
+    
+    private void initUsbCameraProperty() {
+        File filePath = new File(USB_CAMERA_CLASS_PATH);
+        File[] files = filePath.listFiles();
+        if (null != files) {
+            for (File file : files) {
+                if (file.isDirectory()) {
+                    String idProduct = searchAndReadFileForward(file.getPath() + "/device/input", "product");
+                    String idVendor = searchAndReadFileForward(file.getPath() + "/device/input", "vendor");
+                    if (!TextUtils.isEmpty(idProduct) || !idVendor.isEmpty()) {
+                        if (DEBUG) Slog.v(TAG, "initUsbCameraProperty, add camera property: " + idVendor + ":" + idProduct);
+                        SystemProperties.set(USB_CAMERA_PROPERTY_PRE + file.getName(), idVendor + ":" + idProduct);
+                    }
+                }
+            }
+        }
+    }
+
+    private String searchAndReadFileForward(String filePath, String fileName) {
+        if (TextUtils.isEmpty(filePath) || TextUtils.isEmpty(fileName)) {
+            return "";
+        }
+
+        return searchAndReadFileForward(new File(filePath), fileName);
+    }
+
+    private String searchAndReadFileForward(File filePath, String fileName) {
+        if (null != filePath && !TextUtils.isEmpty(fileName)) {
+            Slog.v(TAG, "searchAndReadFileForward, path: " + filePath.getPath());
+
+            File file = new File(filePath.getPath() + "/" + fileName);
+            if (file.exists()) {
+                return readFileByLines(file.getPath());
+            }
+
+            File[] files = filePath.listFiles();
+            if (null != files) {
+                for (File subfile : files) {
+                    if (subfile.isDirectory()) {
+                        return searchAndReadFileForward(subfile, fileName);
+                    }
+                }
+            }
+        }
+
+        return "";
+    }
+
+    private String searchAndReadFileBackward(String filePath, String fileName) {
+        if (TextUtils.isEmpty(filePath) || TextUtils.isEmpty(fileName)) {
+            return "";
+        }
+
+        return searchAndReadFileBackward(new File(filePath), fileName);
+    }
+
+    private String searchAndReadFileBackward(File filePath, String fileName) {
+        if (null != filePath && !TextUtils.isEmpty(fileName)) {
+            File file = new File(filePath.getPath() + "/" + fileName);
+            if (file.exists()) {
+                return readFileByLines(file.getPath());
+            }
+
+            searchAndReadFileBackward(filePath.getParentFile(), fileName);
+        }
+
+        return "";
+    }
+
+    private static String readFileByLines(String fileName) {
+        File file = new File(fileName);
+        BufferedReader reader = null;
+        StringBuilder builder = new StringBuilder();
+        try {
+            reader = new BufferedReader(new FileReader(file));
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                builder.append(tempString);
+            }
+            reader.close();
+            return builder.toString();
+        } catch (IOException e) {
+            Slog.e(TAG, "readFileByLines, " + e.getMessage());
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException ignored) {
+                }
+            }
+        }
+        return "";
+    }
 
     public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
             UsbSettingsManager settingsManager) {
@@ -494,7 +608,7 @@ public class UsbDeviceManager {
                             		UsbManager.removeFunction(UsbManager.removeFunction(persisted,
                                     	UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
                 	}
		}	
 
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
@@ -548,7 +662,7 @@ public class UsbDeviceManager {
             } else if ("CONFIGURED".equals(state)) {
                 connected = 1;
                 configured = 1;
		if ("true".equals(SystemProperties.get("ro.usb.default_mtp")) &&
 		UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP))
                 	mUsbDataUnlocked = true;
             } else {
@@ -1030,6 +1144,7 @@ public class UsbDeviceManager {
                     updateUsbNotification(false);
                     updateAdbNotification(false);
                     updateUsbFunctions();
+                    initUsbCameraProperty();
                     break;
                 case MSG_LOCALE_CHANGED:
                     updateAdbNotification(true);

验证
编译运行后,读取属性如下:

[topband.dev.video0]: [0bda:2714]
[topband.dev.video1]: [0bda:b321]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/667218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字图像处理 基于matlab、opencv计算图像的梯度方向和梯度幅值

一、图像的梯度 1、简述 图像可以被视为标量场(即二维函数)。 通过微分将标量场转换为矢量场。 梯度是一个向量,描述了在x或y方向上移动时,图像变化的速度。我们使用导数来回答这样的问题,图像梯度的大小告诉图像变化的速度,而梯度的方向告诉图像变化最…

两轮车造爆款,爱玛的时尚战略胜算几何?

市场越卷&#xff0c;爆款的意义越大。 电动车行业就是这样&#xff08;本文仅指两轮电动车&#xff0c;如电动自行车、电动摩托车等出行工具&#xff09;&#xff0c;在CR2>45%、CR8>80%的市场格局下&#xff0c;行业竞争早已进入巷战阶段。 对头部的几个品牌&#xf…

leetcode 2090. K Radius Subarray Averages(半径为k的子数组的平均)

k半径长度的子数组表示以数组下标 i 为中心&#xff0c;[i-k, ik]范围内的子数组。 返回和数组nums一样长度的数组res&#xff0c;res[i] [i-k, ik]范围内的元素和 / 元素个数2k1 如果 i-k 或者 ik 超出了数组范围&#xff0c;res[i] -1. 思路&#xff1a; 如果[i - k, ik]…

荔枝集团出席扬帆出海PAGC 探讨AI在音频场景落地技术

近年来&#xff0c;中国企业的身影正不断活跃在全球商业版图上&#xff0c;无论是新兴技术的运用还是创新模式的尝试&#xff0c;其全球化的步履不停。近日,由扬帆出海主办的 2023产品与增长大会(简称PAGC)在广州广交会展馆召开&#xff0c;共同探索未来出海趋势和机遇&#xf…

6月20日作业

我实现的功能&#xff0c;执行一次应用程序led灯 亮&#xff0c;再次执行应用程序led灯灭。 内核模块&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h&…

中职网络搭建(服务器)—Linux LVM(标准答案)

题目要求如下 使用fdisk-l查看磁盘信息 我们添加的磁盘分别是sdb和sdc Fdisk /dev/sdb 依次输入n,p,1&#xff0c;回车,2G &#xff08;新建2G的主分区&#xff09; 依次输入n,e,2&#xff0c;回车&#xff0c;回车&#xff08;使用剩余的全部空间建立扩展分区&#xff09; 依…

软件工程——第2章可行性研究知识点整理

本专栏是博主个人笔记&#xff0c;主要目的是利用碎片化的时间来记忆软工知识点&#xff0c;特此声明&#xff01; 文章目录 1.可行性研究的目的&#xff1f; 2.可行性研究的实质&#xff1f; 3.从哪些方面研究逻辑模型的解法可行性&#xff1f; 4.可行性研究最根本的任务是…

6个免费音效、配乐素材网站,无版权,可商用。

分享几个网站&#xff0c;配乐、音效素材都有&#xff0c;还是免费可商用的&#xff0c;希望能帮到大家&#xff0c;建议收藏起来~ 菜鸟图库 https://www.sucai999.com/audio.html?vNTYxMjky 虽然这是一个设计素材网站&#xff0c;但涵盖的素材非常广泛&#xff0c;想视频素材…

Git系列:运用Git创建空白分支进行项目相关文档管理

文章目录 起因一、为什么会选择Git分支二、Git分支的简单介绍和好处三、本次的具体操作1.$git checkout --orphan XXX2.删除当前分支里的内容3.提交新的分支 总结 起因 项目管理过程中没有做好相关文档管理&#xff0c;比如需求&#xff0c;开发&#xff0c;测试等文档&#x…

【Mysql】索引数据结构深入研究(一)

索引 1.什么是索引 数据库概论老师说&#xff1a;索引就是教科书的目录页&#xff0c;你要查哪个内容你就去目录页查询内容在哪。Mysql官网&#xff1a;索引是帮助Mysql高效获取数据的排好序的数据结构。 2.索引的数据结构 二叉树红黑树Hash表B-Tree 2.1 二叉树 我们先看…

右向辅助产品需求及交互策略说明书

介绍 Introduction 此文档的范围和目的 Scope and Purpose of This Document 定义并描述功能&#xff0c;功能逻辑&#xff0c;功能与驾驶员、环境和其它要素的依赖性和相互影响。为充分理解功能提供支持&#xff0c;以便支持后续阶段的研发活动。 To define and describe …

Prompt的技巧持续总结

Prompt 有很多网站已经收录了&#xff0c;比如&#xff1a;aimappro 有些直接抄上述网站的作业即可&#xff0c;不过也来看看&#xff0c; 有一些日常提问大概的咒语该怎么写。 1 三种微调下的提示写法 chatgpt时代的创新&#xff1a;LLM的应用模式比较 实际案例说明AI时代大…

在 Navicat Premium 中管理 MySQL 用户-第 1 部分:保护 Root 帐号

第 1 部分&#xff1a;保护 Root 帐号 管理数据库用户是数据库管理员&#xff08;DBA&#xff09;的主要职责之一。协调组织中的用户访问数据库的方式通常需要执行许多单独的任务&#xff0c;包括添加新用户&#xff0c;阻止已离开组织的用户的访问权限以及帮助无法登录的用户…

三、MNIST手写数字分类任务项目实战

分类任务和回归任务本质上并没有太大的区别&#xff0c;只是最终得到的结果和损失函数不同而已。 MNIST手写数字分类任务&#xff0c;最终得到的是10个值&#xff0c;也类似一个one-hot编码格式&#xff0c;表示该图片是0-9数字的概率&#xff0c;概率值最大的就是预测的最终结…

如何搭建企业内部Wiki?

企业内部wiki是一种基于web的知识管理系统&#xff0c;它可以帮助企业高效地管理和分享内部的知识和信息。搭建一个企业内部wiki需要考虑很多方面&#xff0c;包括选择合适的wiki软件、搭建服务器、设置权限、培训员工等。本文将介绍如何搭建企业内部wiki&#xff0c;以及如何管…

在职读研填充知识库,人大女王金融硕士项目是获取知识的有效途径

在工作中忙忙碌碌&#xff0c;等休息放空时&#xff0c;反而发现没有以前的快乐了。认识的人越来越多&#xff0c;反而觉得越来越孤独。或许这就是成长的代价。身在职场的我们距退休还有好久&#xff0c;这么漫长的时间不获取新知识怎么能行呢&#xff0c;让我们打开探索的窗户…

IO流(C++)

IO流C C语言的输入与输出流是什么CIO流C标准IO流C文件IO流二进制读写文本读写 stringstream的简单介绍 C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据&#xff0c;并将值存放在变量中。printf():…

QtCreator屏蔽指定警告:如C4819等

QtCreator 频繁报出warning: C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失。 方法一&#xff1a;&#xff08;屏蔽此警告&#xff09; 在工程文件.pro里面添加 # disable C4819 warning QMAKE_CXXFLAGS_WARN_ON -wd481…

【Linux】常用指令快速掌握

Linux常用指令 指令登录添加和删除普通用户ls 指令pwd & cd 指令touch 指令mkdir 指令tree 指令rm 指令man 指令nano 指令cp 指令mv 指令cat & tac 指令echo 指令more 指令less 指令head & tail 指令date & cal 指令find 指令which & whereis 指令alias 指…

【正项级数】敛散性判别(二)

【正项级数】敛散性判别&#xff08;二&#xff09; 比值判别法和根植判别法比值判别法和根植判别法例题比值/根植判别法失效时&#xff0c;该怎么处理&#xff1f;例题 比值判别法和根植判别法 比值判别法和根植判别法 例题 例1 一般遇到阶乘&#xff0c;为了方便约分&…