实现步骤
- 为了实现USB触摸屏(TP)的唤醒和旋转功能,我对Android系统的三个模块进行了修改:inputflinger、surfaceflinger和Settings。
- inputflinger是负责处理输入事件的服务,它接收来自硬件设备的原始输入事件,并将它们转换为Android系统可以理解的事件,如触摸等。
- surfaceflinger是负责管理显示输出的服务,它接收来自应用程序和系统服务的图形缓冲区,并将它们合成为最终的显示帧,然后发送给硬件设备。
- Settings应用程序,它提供了用户界面,让用户可以修改系统的各种设置等。
- 我在inputflinger中修改了TouchInputMapper类,这个类是负责将原始触摸事件映射到逻辑坐标系的类。我添加了两个系统属性:persist.sys.usbtpwake.enable和persist.sys.usbtp.rotation,分别用于控制USB TP是否可以唤醒设备和USB TP的方向。我根据这两个属性的值来调整触摸事件的处理逻辑,使得USB TP可以在不同的方向下正常工作,并且可以在设备休眠时唤醒设备。
- 我在surfaceflinger中修改了SurfaceFlinger类,这个类是负责管理显示层的类。我添加了一个系统属性:persist.sys.usbtp.rotation,用于控制USB TP的方向。我根据这个属性的值来调整显示层的旋转角度,使得USB TP可以与显示屏保持一致(这个地方也可以屏蔽不改, 使用我之前 链接: Android系统 添加动态控制屏幕方向、强制APP横竖屏方向 的属性。
- 我在Settings中添加了两个偏好设置:USB TP唤醒和USB TP方向,分别对应于persist.sys.usbtpwake.enable和persist.sys.usbtp.rotation这两个系统属性。我创建了两个偏好控制器:UsbTPWakePreferenceController和UsbTPRotatePreferenceController,分别用于监听和更新这两个偏好设置的值。在display_settings.xml中添加了这两个偏好设置的界面元素,这样可以在设置应用中看到并控制。
修改示例
surfaceflinger模块
- 需要在surfaceflinger模块的
SurfaceFlinger.cpp
文件中修改processDisplayHotplugEventsLocked()
函数,:
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp @@ -2482,6 +2482,27 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { continue; } + + char rotationvalue[PROPERTY_VALUE_MAX] = "";; + property_get("persist.sys.usbtp.rotation", rotationvalue, "-1"); + int rotation = atoi(rotationvalue); + ALOGI("Primary Display Orientation is set to rotation %2d.", rotation); + switch (rotation) { + case 0: + internalDisplayOrientation = ui::ROTATION_0; + break; + case 1: + internalDisplayOrientation = ui::ROTATION_90; + break; + case 2: + internalDisplayOrientation = ui::ROTATION_180; + break; + case 3: + internalDisplayOrientation = ui::ROTATION_270; + break; + default: + break; + } const DisplayId displayId = info->id;
- 这段代码的作用是从系统属性中读取USB触摸屏的方向值,并根据该值设置内部显示设备的方向。
inputflinger模块
- 我们需要在inputflinger模块的
TouchInputMapper.cpp
文件中修改以下三个函数:configureParameters()
、configureSurface()
和isPointInsideSurface()
:
frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -481,7 +481,17 @@ void TouchInputMapper::configureParameters() { // Initial downs on external touch devices should wake the device. // Normally we don't do this for internal touch screens to prevent them from waking // up in your pocket but you can enable it using the input device configuration. - mParameters.wake = getDeviceContext().isExternal(); + char wakevalue[PROPERTY_VALUE_MAX] = ""; + property_get("persist.sys.usbtpwake.enable", wakevalue, "false"); + + if (strcmp(wakevalue, "true") == 0) { + mParameters.wake = true; + }else{ + mParameters.wake = getDeviceContext().isExternal(); + } + + + getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); } @@ -651,14 +661,21 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { } // Get associated display dimensions. - std::optional<DisplayViewport> newViewport = findViewport(); - if (!newViewport) { - ALOGI("Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().c_str()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; + char wakevalue[PROPERTY_VALUE_MAX] = ""; + property_get("persist.sys.usbtpwake.enable", wakevalue, "false"); + + std::optional<DisplayViewport> newViewport; + + if (strcmp(wakevalue, "true") == 0) { + newViewport = findViewport(); + if (!newViewport) { + ALOGI("Touch device '%s' could not query the properties of its associated " + "display. The device will be inoperable until the display size " + "becomes available.", + getDeviceName().c_str()); + mDeviceMode = DEVICE_MODE_DISABLED; + return; + } } +++ b/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -22,6 +22,7 @@ #include "CursorScrollAccumulator.h" #include "TouchButtonAccumulator.h" #include "TouchCursorInputMapperCommon.h" +#include <cutils/properties.h> namespace android { @@ -664,6 +665,10 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t rawWidth = mRawPointerAxes.getRawWidth(); int32_t rawHeight = mRawPointerAxes.getRawHeight(); + char rotationvalue[PROPERTY_VALUE_MAX] = "";; + property_get("persist.sys.usbtp.rotation", rotationvalue, "0"); + int rotation = atoi(rotationvalue); + bool viewportChanged = mViewport != *newViewport; if (viewportChanged) { mViewport = *newViewport; @@ -674,7 +679,32 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t naturalPhysicalWidth, naturalPhysicalHeight; int32_t naturalPhysicalLeft, naturalPhysicalTop; int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { + int currentrotation = DISPLAY_ORIENTATION_0; + switch (rotation) { + case 0: + currentrotation = DISPLAY_ORIENTATION_0; + break; + case 90: + currentrotation = DISPLAY_ORIENTATION_90; + break; + case 180: + currentrotation = DISPLAY_ORIENTATION_180; + break; + case 270: + currentrotation = DISPLAY_ORIENTATION_270; + break; + default: + break; + } + + if(currentrotation == DISPLAY_ORIENTATION_0 && mViewport.orientation != currentrotation){ + rotation = mViewport.orientation; + currentrotation = mViewport.orientation; + } + + // switch (mViewport.orientation) { + switch (currentrotation) { + case DISPLAY_ORIENTATION_90: naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; @@ -752,6 +782,24 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { } } + ALOGI("Primary Display Orientation is set to rotation %2d.", rotation); + switch (rotation) { + case 0: + mSurfaceOrientation = DISPLAY_ORIENTATION_0; + break; + case 1: + mSurfaceOrientation = DISPLAY_ORIENTATION_90; + break; + case 2: + mSurfaceOrientation = DISPLAY_ORIENTATION_180; + break; + case 3: + mSurfaceOrientation = DISPLAY_ORIENTATION_270; + break; + default: + break; + } + // If moving between pointer modes, need to reset some state. bool deviceModeChanged = mDeviceMode != oldDeviceMode; if (deviceModeChanged) { @@ -3653,13 +3701,14 @@ void TouchInputMapper::rotateAndScale(float& x, float& y) { } bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale; - const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale; + //const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale; + //const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale; + //modify fix dual tp with sync display,second tp funtion is error + return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue + //&& scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth + && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; + //&& scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight; - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && - xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight && - y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && - yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom; }
Settings模块
packages/apps/Settings/res/values-zh-rCN/arrays.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string-array name="usbtp_totate_entries"> <item>0度</item> <item>90度</item> <item>180度</item> <item>270度</item> </string-array> <!-- Do not translate. --> <string-array name="usbtp_rotate_values" translatable="false"> <item>0</item> <item>1</item> <item>2</item> <item>3</item> </string-array> <string-array name="timezone_filters"> <item msgid="6657355508154731088">"美洲"</item> <item msgid="728005479339643412">"欧洲"</item>
- 定义了一个字符串数组usbtp_totate_entries,用于显示USB TP方向的选项。它有四个元素:0度、90度、180度和270度。
- 定义了一个字符串数组usbtp_rotate_values,用于存储USB TP方向的值。它有四个元素:0、1、2和3,分别对应于0度、90度、180度和270度。
- 创建一个列表偏好设置的,它们的长度必须相同,并且每个元素的位置必须一一对应。
packages/apps/Settings/res/values-zh-rCN/strings.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="usbtp_rotate_summary"> <xliff:g id="usbtprotate_description">%1$s</xliff:g> </string> <string name="ctrl_usbtp_wake" >"USB TP唤醒"</string> <string name="ctrl_usbtp_rotate">"USB TP方向"</string> <string name="ctrl_forceapp_rotate" >"APP旋转"</string> <string name="ctrl_screen_rotate">"屏幕旋转"</string> <string name="ctrl_statusbar">状态栏</string>
- 定义了三个字符串资源,用于显示USB TP相关的偏好设置的标题和摘要。
- usbtp_rotate_summary是一个带有占位符的字符串,用于显示USB TP方向的当前值。占位符%1$s会被替换为usbtp_totate_entries中对应的元素。
- ctrl_usbtp_wake是一个字符串,用于显示USB TP唤醒的开关偏好设置的标题。
- ctrl_usbtp_rotate是一个字符串,用于显示USB TP方向的列表偏好设置的标题。
packages/apps/Settings/res/values/arrays.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string-array name="usbtp_rotate_entries"> <item>0 Degrees</item> <item>90 Degrees</item> <item>180 Degrees</item> <item>270 Degrees</item> </string-array> <!-- Do not translate. --> <string-array name="usbtp_rotate_values" translatable="false"> <item>0</item> <item>1</item> <item>2</item> <item>3</item> </string-array> <!-- Choices for timezone picker first level. These values will be used as search terms for TimeZone displayName strings. --> <skip />
- 这段代码与上面的代码类似,只是用英文来表示USB TP方向的选项。这是为了适配不同语言环境的用户。
packages/apps/Settings/res/values/strings.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="usbtp_rotate_summary"> <xliff:g id="usbtprotate_description">%1$s</xliff:g> </string> <string name="ctrl_usbtp_wake" >"USB TP Wake"</string> <string name="ctrl_usbtp_rotate">"USB TP Rotate"</string>
- 与上面的代码类似,只是用英文来表示USB TP相关的偏好设置的标题和摘要。
packages/apps/Settings/res/xml/display_settings.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/display_settings" settings:keywords="@string/keywords_display" settings:initialExpandedChildrenCount="5"> <SwitchPreference android:key="ctrl_usbtpwake" android:title="@string/ctrl_usbtp_wake"/> <com.android.settings.display.UsbTPRotateListPreference android:key="usbtp_rotate" android:title="@string/ctrl_usbtp_rotate" android:summary="@string/summary_placeholder" android:entries="@array/usbtp_rotate_entries" android:entryValues="@array/usbtp_rotate_values"/> <com.android.settingslib.RestrictedPreference android:key="brightness" android:title="@string/brightness"
- 在显示设置界面中添加了两个偏好设置元素:一个开关偏好设置和一个列表偏好设置。
- 开关偏好设置的key属性是ctrl_usbtpwake,它与UsbTPWakePreferenceController类中定义的偏好键相对应。它的title属性是@string/ctrl_usbtp_wake,它引用了上面定义的字符串资源。当用户点击这个
packages/apps/Settings/src/com/android/settings/display/UsbTPRotateListPreference.java
package com.android.settings.display; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Log; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.AbstractPreferenceController; import android.app.Dialog; import java.util.ArrayList; import android.view.View; import androidx.appcompat.app.AlertDialog; import android.util.AttributeSet; import com.android.settings.R; import com.android.settings.RestrictedListPreference; import android.content.DialogInterface; public class UsbTPRotateListPreference extends RestrictedListPreference { private EnforcedAdmin mAdmin; private final CharSequence[] mInitialEntries; private final CharSequence[] mInitialValues; public UsbTPRotateListPreference(Context context, AttributeSet attrs) { super(context, attrs); mInitialEntries = getEntries(); mInitialValues = getEntryValues(); } @Override protected void onPrepareDialogBuilder(AlertDialog.Builder builder, DialogInterface.OnClickListener listener) { super.onPrepareDialogBuilder(builder, listener); if (mAdmin != null) { builder.setView(R.layout.admin_disabled_other_options_footer); } else { builder.setView(null); } } @Override protected void onDialogCreated(Dialog dialog) { super.onDialogCreated(dialog); dialog.create(); if (mAdmin != null) { View footerView = dialog.findViewById(R.id.admin_disabled_other_options); footerView.findViewById(R.id.admin_more_details_link).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { // getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); RestrictedLockUtils.sendShowAdminSupportDetailsIntent( getContext(), mAdmin); } }); } } public void removeUnusableRotates(long maxRotate, EnforcedAdmin admin) { final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService( Context.DEVICE_POLICY_SERVICE); if (dpm == null) { return; } if (admin == null && mAdmin == null && !isDisabledByAdmin()) { return; } if (admin == null) { maxRotate = Long.MAX_VALUE; } ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>(); ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>(); for (int i = 0; i < mInitialValues.length; ++i) { long rotate = Long.parseLong(mInitialValues[i].toString()); if (rotate <= maxRotate) { revisedEntries.add(mInitialEntries[i]); revisedValues.add(mInitialValues[i]); } } // If there are no possible options for the user, then set this preference as disabled // by admin, otherwise remove the padlock in case it was set earlier. if (revisedValues.size() == 0) { setDisabledByAdmin(admin); return; } else { setDisabledByAdmin(null); } if (revisedEntries.size() != getEntries().length) { final int userPreference = Integer.parseInt(getValue()); setEntries(revisedEntries.toArray(new CharSequence[0])); setEntryValues(revisedValues.toArray(new CharSequence[0])); mAdmin = admin; if (userPreference <= maxRotate) { setValue(String.valueOf(userPreference)); } else if (revisedValues.size() > 0 && Long.parseLong(revisedValues.get(revisedValues.size() - 1).toString()) == maxRotate) { // If the last one happens to be the same as the max rotate, select that setValue(String.valueOf(maxRotate)); } else { // There will be no highlighted selection since nothing in the list matches // maxRotate. The user can still select anything less than maxRotate. // TODO: maybe append maxRotate to the list and mark selected. } } } }
这个文件定义了USB TP方向旋转的列表偏好类 , 没啥好说的 写了几次之后发现都是一样的套路固定写法。
packages/apps/Settings/src/com/android/settings/display/UsbTPRotatePreferenceController.java
package com.android.settings.display; import android.content.Context; import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; import android.content.Intent; import android.util.Log; import com.android.settings.R; import android.os.SystemProperties; public class UsbTPRotatePreferenceController extends AbstractPreferenceController implements Preference.OnPreferenceChangeListener { private static final String TAG = "UsbTPRotatePrefContr"; /** If there is no setting in the provider, use this. */ public static final int FALLBACK_FORCE_APP_ROTATE_VALUE = 0; private final String mUsbTPRotateKey; public UsbTPRotatePreferenceController(Context context, String key) { super(context); mUsbTPRotateKey = key; } @Override public boolean isAvailable() { return true; } @Override public String getPreferenceKey() { return mUsbTPRotateKey; } @Override public void updateState(Preference preference) { final UsbTPRotateListPreference forceAppRotateListPreference = (UsbTPRotateListPreference) preference; long currentRotate = 0; currentRotate = SystemProperties.getInt("persist.sys.usbtp.rotation", 0); forceAppRotateListPreference.setValue(String.valueOf(currentRotate)); updateRotatePreferenceDescription(forceAppRotateListPreference, currentRotate); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { try { int value = Integer.parseInt((String) newValue); SystemProperties.set("persist.sys.usbtp.rotation", ""+value); updateRotatePreferenceDescription((UsbTPRotateListPreference) preference, value); } catch (NumberFormatException e) { Log.e(TAG, "could not persist force app rotate setting", e); } return true; } public static CharSequence getRotateDescription( long currentRotate, CharSequence[] entries, CharSequence[] values) { if (currentRotate < 0 || entries == null || values == null || values.length != entries.length) { return null; } for (int i = 0; i < values.length; i++) { long rotate = Long.parseLong(values[i].toString()); if (currentRotate == rotate) { return entries[i]; } } return null; } private void updateRotatePreferenceDescription(UsbTPRotateListPreference preference, long currentRotate) { final CharSequence[] entries = preference.getEntries(); final CharSequence[] values = preference.getEntryValues(); final String summary; if (preference.isDisabledByAdmin()) { summary = mContext.getString(com.android.settings.R.string.disabled_by_policy_title); } else { final CharSequence rotateDescription = getRotateDescription( currentRotate, entries, values); summary = rotateDescription == null ? "" : mContext.getString(R.string.forceapp_rotate_summary, rotateDescription); } preference.setSummary(summary); } }
- 新增一个UsbTPRotatePreferenceController类的实现,它是一个列表偏好控制器,用于控制USB TP的方向。
- 重写了getPreferenceKey方法,返回usbtp_rotate作为偏好键。
- 重写了isAvailable方法,返回true表示这个偏好控制器始终可用。
- 重写了updateState方法,用于更新这个偏好设置元素的状态。它首先获取系统属性persist.sys.usbtp.rotation的值,并将其转换为长整型,然后设置为列表偏好设置元素的值。然后,它调用updateRotatePreferenceDescription方法,用于更新列表偏好设置元素的摘要。这个方法会根据当前的方向值,在entries和values数组中找到对应的描述,并将其作为摘要显示。
- 重写了onPreferenceChange方法,用于响应用户的操作。它获取用户选择的新值,并将其转换为整型,然后设置为系统属性persist.sys.usbtp.rotation的值。它调用updateRotatePreferenceDescription方法,用于更新列表偏好设置元素显示。
packages/apps/Settings/src/com/android/settings/display/UsbTPWakePreferenceController.java
package com.android.settings.display; import android.content.Context; import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; import android.content.Intent; import android.util.Log; import android.os.SystemProperties; public class UsbTPWakePreferenceController extends AbstractPreferenceController implements Preference.OnPreferenceChangeListener { private static final String TAG = "UsbTPWakeCtrl"; private static final boolean DEBUG = true; private static final String KEY_USBTPWAKE = "ctrl_usbtpwake"; private static final String SYS_PROP_USBTPWAKE_ENABLE = "persist.sys.usbtpwake.enable"; public UsbTPWakePreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return KEY_USBTPWAKE; } @Override public boolean isAvailable() { return true; } @Override public void displayPreference(PreferenceScreen screen) { if (!isAvailable()) { setVisible(screen, KEY_USBTPWAKE, false); return; } final SwitchPreference mUsbTPWakePreference = screen.findPreference(KEY_USBTPWAKE); if (mUsbTPWakePreference != null) { String value = SystemProperties.get(SYS_PROP_USBTPWAKE_ENABLE, "false"); mUsbTPWakePreference.setChecked(value.equals("true")); mUsbTPWakePreference.setOnPreferenceChangeListener(this); } } @Override public void updateState(Preference preference) { String value = SystemProperties.get(SYS_PROP_USBTPWAKE_ENABLE, "false"); ((SwitchPreference) preference).setChecked(value.equals("true")); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean value = (Boolean) newValue; if (DEBUG) { Log.d(TAG, "key value " + value); } SystemProperties.set(SYS_PROP_USBTPWAKE_ENABLE, ""+value); return true; } }
packages/apps/Settings/src/com/android/settings/DisplaySettings.java
import com.android.settings.display.ExPlanPreferenceController; import com.android.settings.display.ForceAppRotatePreferenceController; import com.android.settings.display.ScreenRotatePreferenceController; +import com.android.settings.display.UsbTPWakePreferenceController; +import com.android.settings.display.UsbTPRotatePreferenceController; + import java.util.ArrayList; import java.util.List; @@ -102,6 +107,13 @@ public class DisplaySettings extends DashboardFragment { controllers.add(new ExPlanPreferenceController(context)); controllers.add(new ForceAppRotatePreferenceController(context,"forceapp_rotate")); controllers.add(new ScreenRotatePreferenceController(context,"screen_rotate")); + + controllers.add(new UsbTPWakePreferenceController(context)); + controllers.add(new UsbTPRotatePreferenceController(context,"usbtp_rotate")); + return controllers; }
测试结果
- 为了测试我的修改是否有效,我在我的设备上连接了一个USB TP设备。
- 进入设置应用,找到显示设置界面,控制USB TP唤醒和USB TP方向两个偏好设置。
- 尝试选择不同的USB TP方向,发现当我选择不同的方向时,USB TP的坐标系会随之旋转,并且与显示屏保持一致。可以在不同的方向下正常地使用USB TP触摸屏幕上的内容。
结语
- 通过对Android系统的三个模块进行修改,我实现了USB TP的唤醒和旋转功能,提高了客户和调试便利性。在Settings模块中添加了两个偏好设置元素,让客户可以在设置应用中看到并修改USB TP相关的功能。我在inputflinger和surfaceflinger模块中添加了两个系统属性,让USB TP可以在不同的方向下正常工作,并且可以在设备休眠时唤醒设备。