柚子快報(bào)激活碼778899分享:Android無(wú)障礙服務(wù)
柚子快報(bào)激活碼778899分享:Android無(wú)障礙服務(wù)
Hi I’m Shendi
Android無(wú)障礙服務(wù)
最近想制作一個(gè)記錄點(diǎn)擊操作并重復(fù)播放的工具,用以解放雙手,因現(xiàn)在的Android高版本基本上難以Root,所以選擇了使用無(wú)障礙來(lái)實(shí)現(xiàn),在這里記錄下來(lái)。
Android無(wú)障礙
可參考文檔:https://informationaccessibilityassociation.github.io/androidAccessibility/services.htm
https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityService
配置
首先需要在清單文件(AndroidManifest.xml)中進(jìn)行配置
xmlns:tools="http://schemas.android.com/tools"> tools:ignore="ProtectedPermissions,WrongManifestParent" /> android:label="@string/accessibility_service_label" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:exported="true"> android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" />
上面首先聲明了權(quán)限,然后在 application 中注冊(cè)了服務(wù)。
其中服務(wù)有一個(gè) label,這個(gè)label的內(nèi)容與無(wú)障礙中應(yīng)用名稱是一致的,例如我的名稱為 AutoImitate - 自動(dòng)模擬,在手機(jī)的無(wú)障礙設(shè)置頁(yè)面中,會(huì)出現(xiàn)下面這樣的東西
上面還配置了一個(gè)配置文件 @xml/accessibility_service_config,資源文件夾xml下的accessibility_service_config.xml
其中內(nèi)容大致如下
android:description="@string/accessibility_service_description" android:packageNames="com.example.android.apis" android:accessibilityEventTypes="typeAllMask" android:accessibilityFlags="flagDefault" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:canRetrieveWindowContent="true" android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity">
上面這種指定文件的方式是從 Android 4.0 開(kāi)始被支持的。
除了這種指定文件的方式,還可以使用 AccessibilityServiceInfo 來(lái)動(dòng)態(tài)設(shè)置,但這種方法并不能配置所有的配置項(xiàng)。
對(duì)于哪些配置可以動(dòng)態(tài)設(shè)置,參考:https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityServiceInfo.html
至于上面的配置,功能如下:
android:description
描述信息,會(huì)在無(wú)障礙頁(yè)面點(diǎn)擊本應(yīng)用后的最下方顯示,如下紅色方框部分所示
android:packageNames
接收指定包名的事件,多個(gè)用英文逗號(hào)分隔,不設(shè)置則接收所有。
android:accessibilityEventTypes
定義服務(wù)接收的事件類型,多個(gè)使用|分隔。
類型描述typeViewClicked點(diǎn)擊了某個(gè)視圖typeViewFocused某個(gè)視圖獲得了焦點(diǎn)typeViewLongClicked用戶長(zhǎng)按了某個(gè)視圖typeViewSelected某個(gè)視圖被選中,例如在列表或網(wǎng)格中選擇了一個(gè)項(xiàng)目typeWindowStateChanged一個(gè)窗口的狀態(tài)發(fā)生了變化,例如一個(gè)新的活動(dòng)(Activity)被打開(kāi)或關(guān)閉typeNotificationStateChanged系統(tǒng)的通知狀態(tài)發(fā)生了變化,例如新的通知到達(dá)typeAllMask所有事件
android:accessibilityFlags
定義一些特殊的行為標(biāo)志,多個(gè)使用 | 分隔
標(biāo)志描述flagDefault當(dāng)不設(shè)置其他特定標(biāo)志時(shí),使用這個(gè)標(biāo)志可以保持輔助功能的默認(rèn)行為。flagIncludeNotImportantViews此標(biāo)志指示輔助功能服務(wù)也應(yīng)接收那些被標(biāo)記為“不重要”的視圖的事件flagRequestTouchExplorationMode請(qǐng)求系統(tǒng)啟用觸摸探索模式,也就是手勢(shì)監(jiān)聽(tīng)。flagRequestEnhancedWebAccessibility請(qǐng)求增強(qiáng)的網(wǎng)頁(yè)無(wú)障礙功能。這通常意味著在WebView中提供更詳細(xì)和更準(zhǔn)確的無(wú)障礙信息flagRequestFilterKeyEvents請(qǐng)求能夠過(guò)濾鍵事件,這意味著輔助功能服務(wù)可以捕獲并處理鍵盤(pán)輸入事件
android:accessibilityFeedbackType
定義該服務(wù)如何為用戶提供反饋,多個(gè)使用|分隔。
名稱描述feedbackSpoken語(yǔ)音反饋,文本轉(zhuǎn)語(yǔ)音(TTS)feedbackHaptic觸覺(jué)反饋,通常是通過(guò)設(shè)備振動(dòng)來(lái)提供反饋feedbackSound聲音反饋feedbackVisual視覺(jué)反饋,在屏幕上顯示額外的視覺(jué)元素來(lái)提供反饋,如閃爍的邊框或圖標(biāo)。feedbackGeneric一個(gè)通用的反饋類型,可能包含上述多種反饋方式的組合。當(dāng)開(kāi)發(fā)者不確定或想要保持靈活性,不具體到某一種反饋方式時(shí),可以選擇這個(gè)選項(xiàng)。這樣,服務(wù)可以根據(jù)實(shí)際情況選擇最合適的反饋方式。feedbackAllMask所有反饋
android:notificationTimeout
定義在連續(xù)接收兩個(gè)相同類型的事件之間服務(wù)應(yīng)等待的毫秒數(shù)。這有助于防止服務(wù)被頻繁觸發(fā)。
android:canRetrieveWindowContent
是否允許無(wú)障礙服務(wù)訪問(wèn)活動(dòng)窗口的內(nèi)容。這對(duì)于實(shí)現(xiàn)自動(dòng)化點(diǎn)擊等功能至關(guān)重要,true或false。
android:settingsActivity
指定一個(gè)用于配置無(wú)障礙服務(wù)的Activity。
更多的可以在這個(gè)頁(yè)面查閱:https://developer.android.google.cn/reference/android/R.styleable.html
無(wú)障礙服務(wù)
在上面的配置中,注冊(cè)了服務(wù),而服務(wù)名稱為 MyAccessibilityService
無(wú)障礙服務(wù)必須繼承AccessibilityService 類,重寫(xiě)該類的函數(shù),有兩個(gè)函數(shù)必須重寫(xiě)。一般重寫(xiě)下面四個(gè)函數(shù)
/**
* 自動(dòng)模擬服務(wù).
* 創(chuàng)建時(shí)間:2024/5/4
* @author 砷碲
*/
public class MyAccessibilityService extends AccessibilityService {
private static SLog log = SLog.getLogger(Application.class.getName());
/** 當(dāng)前服務(wù)的對(duì)象,為空代表當(dāng)前服務(wù)未啟動(dòng) */
public static MyAccessibilityService instance;
@Override
protected void onServiceConnected() {
super.onServiceConnected();
instance = this;
log.d("accessibility connect");
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
log.d("accessibility event");
}
@Override
public void onInterrupt() {
log.d("accessibility interrupt");
}
@Override
public boolean onUnbind(Intent intent) {
log.d("accessibility unbind");
instance = null;
return super.onUnbind(intent);
}
}
onServiceConnected 在打開(kāi)當(dāng)前無(wú)障礙服務(wù)時(shí)執(zhí)行(即手機(jī)的無(wú)障礙設(shè)置頁(yè)面打開(kāi)當(dāng)前無(wú)障礙)
onUnbind 在關(guān)閉當(dāng)前無(wú)障礙服務(wù)時(shí)執(zhí)行(即手機(jī)的無(wú)障礙設(shè)置頁(yè)面關(guān)閉當(dāng)前無(wú)障礙)
下圖是打開(kāi)關(guān)閉當(dāng)前無(wú)障礙服務(wù)的輸出信息
onAccessibilityEvent(必選)
當(dāng)系統(tǒng)檢測(cè)到一個(gè)符合無(wú)障礙服務(wù)設(shè)定的無(wú)障礙事件過(guò)濾參數(shù)的事件時(shí),該方法被系統(tǒng)回調(diào)。例如,當(dāng)用戶在應(yīng)用程序中點(diǎn)擊一個(gè)按鈕或聚焦一個(gè)用戶界面控件時(shí),你的無(wú)障礙服務(wù)會(huì)為此應(yīng)用程序提供反饋。此時(shí),系統(tǒng)調(diào)用這個(gè)方法,傳遞相關(guān)聯(lián)的無(wú)障礙事件,無(wú)障礙服務(wù)就可以翻譯和使用該事件為用戶提供反饋。在無(wú)障礙服務(wù)的生命周期中,該方法會(huì)被調(diào)用多次。
onInterrupt(必選)
當(dāng)系統(tǒng)想要打斷無(wú)障礙服務(wù)提供的反饋時(shí)該方法被調(diào)用,一般情況下是響應(yīng)用戶操作,如移動(dòng)焦點(diǎn)到一個(gè)不同的控件。在無(wú)障礙服務(wù)的生命周期中,該方法會(huì)被調(diào)用很多次。
檢測(cè)服務(wù)是否打開(kāi)
通過(guò)上面的信息,要檢測(cè)當(dāng)前無(wú)障礙服務(wù)是否開(kāi)啟就很簡(jiǎn)單了,使用一個(gè)全局變量,存儲(chǔ)當(dāng)前對(duì)象,在onServiceConnected 時(shí)賦值,onUnbind 置空。
接下來(lái),判斷就像下面這樣就可以了,當(dāng)為空代表未開(kāi)啟,跳轉(zhuǎn)無(wú)障礙頁(yè)面,跳轉(zhuǎn)失敗就跳設(shè)置頁(yè)面
/** 校驗(yàn)無(wú)障礙是否開(kāi)啟,未開(kāi)啟則跳轉(zhuǎn)開(kāi)啟頁(yè)面. */
public static void checkAccessibility(Context context) {
if (MyAccessibilityService.instance == null) {
try {
context.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
} catch (Exception e) {
context.startActivity(new Intent(Settings.ACTION_SETTINGS));
e.printStackTrace();
}
Toast.makeText(context, "請(qǐng)開(kāi)啟本軟件的無(wú)障礙服務(wù):" + context.getString(R.string.accessibility_service_label), Toast.LENGTH_LONG).show();
}
}
獲取事件詳情
當(dāng)監(jiān)聽(tīng)到事件時(shí)(如點(diǎn)擊,滑動(dòng)等),會(huì)觸發(fā) onAccessibilityEvent 函數(shù),函數(shù)接收一個(gè) AccessibilityEvent 對(duì)象作為參數(shù)。
Android系統(tǒng)通過(guò)AccessibilityEvent對(duì)象為無(wú)障礙服務(wù)提供用戶界面交互的信息。在Android4.0之前,可從無(wú)障礙事件中獲得信息,且無(wú)障礙事件能夠提供用戶所選擇的界面控件的大量詳細(xì)信息,但這些信息僅包含有限的上下文信息。在很多情況下,丟失的上下文信息可能是理解已選定控件的意義的關(guān)鍵。
通常,我們需要根據(jù)事件來(lái)進(jìn)行后面的操作,例如用戶點(diǎn)擊某按鈕,就自動(dòng)化做一些操作之類的。
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
// ...
}
}
上面的 event.getEventType() 是獲取當(dāng)前事件類型,而 AccessibilityEvent.TYPE_VIEW_CLICKED 代表點(diǎn)擊事件,值是1。當(dāng)有任意元素(可以被點(diǎn)擊的)點(diǎn)擊后執(zhí)行(按下+抬起),所以通常需要拿到當(dāng)前事件對(duì)應(yīng)的元素,分析是否是我們需要關(guān)注的,根據(jù)這個(gè),再進(jìn)行下一步。
常用的提取元素信息代碼如下
// 獲得事件的資源節(jié)點(diǎn)
AccessibilityNodeInfo nodeInfo = event.getSource();
if (nodeInfo != null) {
// 元素基本信息
System.out.println("元素文本:" + nodeInfo.getText()
+ "\n元素描述:" + nodeInfo.getContentDescription()
+ "\nID資源名稱:" + nodeInfo.getViewIdResourceName()
+ "\n元素類名:" + nodeInfo.getClassName()
+ "\n應(yīng)用包名:" + nodeInfo.getPackageName()
+ "\n是否可點(diǎn)擊:" + nodeInfo.isClickable()
+ "\n是否支持長(zhǎng)按:" + nodeInfo.isLongClickable()
+ "\n是否對(duì)用戶可見(jiàn):" + nodeInfo.isVisibleToUser());
// ...
// 位置信息,x,y就是點(diǎn)擊中心
Rect rect = new Rect();
nodeInfo.getBoundsInScreen(rect);
System.out.println("[" + rect.centerX() + "," + rect.centerY() + "], 寬:" + (rect.right - rect.left) + ",高:" + (rect.bottom - rect.top));
// 元素查找操作
// 找到指定id的所有元素
List
// 找到指定文本內(nèi)容的所有元素
List
// 父元素
AccessibilityNodeInfo parentNode = nodeInfo.getParent();
// 子元素操作
int childCount = nodeInfo.getChildCount();
AccessibilityNodeInfo child = nodeInfo.getChild(0);
// 釋放資源
nodeInfo.recycle();
}
除了上面所說(shuō)的,還有一些當(dāng)前無(wú)障礙服務(wù)對(duì)象提供的函數(shù),例如getRootInActiveWindow,獲取當(dāng)前活動(dòng)窗口的根節(jié)點(diǎn),返回AccessibilityNodeInfo對(duì)象
判斷元素類型
可以通過(guò) getClassName 獲取到當(dāng)前元素的全類名,例如判斷是否為按鈕
boolean isBtn = "android.widget.Button".equals(nodeInfo.getClassName());
還可以通過(guò)是否可以點(diǎn)擊,是否可輸入等來(lái)進(jìn)行判斷。
手勢(shì)監(jiān)聽(tīng)
Android 4.1(API級(jí)別16)引入了手勢(shì)監(jiān)聽(tīng)功能,允許無(wú)障礙服務(wù)監(jiān)聽(tīng)特定手勢(shì),并代表用戶響應(yīng)這些手勢(shì)。
要使用此功能,無(wú)障礙服務(wù)需要請(qǐng)求激活觸摸探索(Explore by Touch)特性,通過(guò)在其AccessibilityServiceInfo實(shí)例的flags成員中設(shè)置FLAG_REQUEST_TOUCH_EXPLORATION_MODE來(lái)實(shí)現(xiàn)。
激活觸摸探索
需要在配置文件的 accessibilityFlags 增加 flagRequestTouchExplorationMode 或者在服務(wù)中動(dòng)態(tài)設(shè)置
官方文檔中有描述,當(dāng)版本是Android4.3(API 18)及之后版本,那么還需要配置 canRequestTouchExplorationMode 為 true,否則忽略
配置設(shè)置
android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode" android:canRequestTouchExplorationMode="true">
動(dòng)態(tài)設(shè)置
@Override
protected void onServiceConnected() {
super.onServiceConnected();
instance = this;
log.d("accessibility connect");
// 在 onServiceConnected 中 getServiceInfo 不為null,在onCreate則有可能為null
if (getServiceInfo() != null) {
getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
}
}
配置成功的話,在用戶打開(kāi)無(wú)障礙服務(wù)的時(shí)候,彈出的對(duì)話框會(huì)新增一項(xiàng)觸摸探索…
開(kāi)啟后,交互操作有所改變,比如滑動(dòng)變成了雙指滑動(dòng),點(diǎn)擊變成了雙指點(diǎn)擊等
接收手勢(shì)通知
通過(guò)重寫(xiě) onGesture 函數(shù)來(lái)實(shí)現(xiàn)接收。
Android API 31之前,使用 onGesture(int),而31及之后,使用 onGesture(AccessibilityGestureEvent)
需要注意的是,API31后,如果回調(diào)函數(shù)內(nèi)參數(shù)對(duì)象的 getDisplayId() == Display.DEFAULT_DISPLAY,那么依然使用onGesture(int)
我使用的是逍遙模擬器,API小于31,所以結(jié)果如下圖所示
這部分是給真正需要使用無(wú)障礙的人使用的,包括上面的觸摸探索,所以這里就不深挖了。
操作
從Android4.0(API級(jí)別14)開(kāi)始,無(wú)障礙服務(wù)可以代表用戶操作,包含改變輸入焦點(diǎn)和選擇(激活)用戶界面元素。在Android4.1(API級(jí)別16),操作的范圍被擴(kuò)展至包含滾動(dòng)列表和與文本域交互。無(wú)障礙服務(wù)也可采取全局操作,如導(dǎo)航到主界面、按返回按鈕、打開(kāi)屏幕通知和最近應(yīng)用列表。Android4.1也包含新焦點(diǎn)類型,無(wú)障礙焦點(diǎn),該焦點(diǎn)類型可讓所有視覺(jué)元素能夠被無(wú)障礙服務(wù)所選擇。
這些新的能力讓開(kāi)發(fā)者能夠開(kāi)發(fā)替代導(dǎo)航模式,如手勢(shì)導(dǎo)航,提高殘障用戶對(duì)Android設(shè)備的控制。
使用AccessibilityNodeInfo對(duì)象你的無(wú)障礙服務(wù)可以瀏覽視圖層次來(lái)判定采取什么操作并使用performAction()為用戶操作。AccessibilityNodeInfo 對(duì)象可以通過(guò) event.getSource() 獲取。
除此之外,還可以通過(guò) AccessibilityService 的 performGlobalAction 進(jìn)行全局操作,示例如下
// 全局操作,以 GLOBAL 開(kāi)頭的都是全局,例如點(diǎn)擊主頁(yè)按鈕,返回按鈕
performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
// 給元素發(fā)送操作,ACTION_之類的,大致操作將后面的翻譯一下就知道了
// 還可以通過(guò)元素父級(jí)子級(jí)等獲取其他元素來(lái)操作其他元素
// 例如給當(dāng)前元素的父級(jí)元素的第一個(gè)子元素發(fā)送點(diǎn)擊事件
AccessibilityNodeInfo nodeInfo = event.getSource();
nodeInfo.getParent().getChild(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
文本輸入操作,AccessibilityNodeInfo需要是EditText之類的
Bundle textBundle = new Bundle();
textBundle.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "輸入的文本-砷碲");
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, textBundle);
滾動(dòng)操作,是滾動(dòng)一頁(yè),一個(gè)往前滾動(dòng),一個(gè)往后滾動(dòng)
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
一般這樣夠用了,但是需要精確滾動(dòng)的話,可以使用模擬手勢(shì)
模擬手勢(shì)
有的時(shí)候有需求,在指定屏幕位置進(jìn)行點(diǎn)擊等各種操作,而不是對(duì)組件,這個(gè)時(shí)候可以使用模擬手勢(shì)
模擬手勢(shì)是通過(guò)編程方式模擬用戶在屏幕上的觸摸和滑動(dòng)操作
Android API 24及以上可用(即Android 7.0 Nougat)
首先是無(wú)障礙中要配置canPerformGestures權(quán)限,這樣在啟動(dòng)無(wú)障礙服務(wù)時(shí)會(huì)增加一項(xiàng)執(zhí)行手勢(shì),代碼如下
android:canPerformGestures="true">
兩個(gè)步驟,構(gòu)建手勢(shì)描述(GestureDescription)和發(fā)送手勢(shì)(dispatchGesture)
下面列出點(diǎn)擊,長(zhǎng)按,滑動(dòng)的示例
Path path = new Path();
path.moveTo(100, 100);
// 長(zhǎng)按位置
Path longPath = new Path();
longPath.moveTo(100, 100);
// 滑動(dòng)位置, 從100,100到300,300
Path scrollPath = new Path();
scrollPath.moveTo(100, 100);
scrollPath.lineTo(300, 300);
// 可以多次addStroke來(lái)實(shí)現(xiàn)組合動(dòng)作
// * 但實(shí)測(cè),只建議單個(gè)addStroke,多個(gè)可能會(huì)導(dǎo)致APP和系統(tǒng)崩潰...
// StrokeDescription中,第二個(gè)參數(shù)是開(kāi)始時(shí)間,第三個(gè)參數(shù)是持續(xù)多久,單位毫秒
GestureDescription gd = new GestureDescription.Builder()
// 點(diǎn)擊屏幕,坐標(biāo) x=100, y=100。
.addStroke(new GestureDescription.StrokeDescription(path, 0, 100))
// 點(diǎn)擊完長(zhǎng)按屏幕
.addStroke(new GestureDescription.StrokeDescription(longPath, 100, 10000))
// 點(diǎn)擊,長(zhǎng)按完,滑動(dòng)
.addStroke(new GestureDescription.StrokeDescription(scrollPath, 1100, 300))
// 構(gòu)建
.build();
// 發(fā)送手勢(shì),返回手勢(shì)是否成功發(fā)送到了系統(tǒng)以進(jìn)行執(zhí)行
// 第二個(gè)參數(shù)是GestureResultCallback,可選,用來(lái)接收手勢(shì)執(zhí)行的結(jié)果,當(dāng)手勢(shì)執(zhí)行完成后,系統(tǒng)會(huì)調(diào)用這個(gè)回調(diào)接口中的方法,并傳遞一個(gè)GestureResult對(duì)象作為參數(shù),該對(duì)象包含了手勢(shì)執(zhí)行的結(jié)果信息。通過(guò)實(shí)現(xiàn)這個(gè)接口,你可以在應(yīng)用程序中處理手勢(shì)執(zhí)行的結(jié)果,例如根據(jù)結(jié)果更新UI或執(zhí)行其他操作。
// 第三個(gè)參數(shù)Handler,可選,如果你提供了Handler對(duì)象,那么GestureResultCallback的回調(diào)方法將在該Handler指定的線程中執(zhí)行。這允許你控制回調(diào)方法在哪個(gè)線程中運(yùn)行,以便更好地管理線程和避免潛在的線程沖突問(wèn)題。如果你沒(méi)有提供Handler對(duì)象,那么回調(diào)方法將在系統(tǒng)默認(rèn)的UI線程中執(zhí)行。
boolean isRun = dispatchGesture(gd, new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
System.out.println("手勢(shì)完成");
super.onCompleted(gestureDescription);
}
@Override
public void onCancelled(GestureDescription gestureDescription) {
System.out.println("手勢(shì)取消");
super.onCancelled(gestureDescription);
}
}, null);
System.out.println(isRun);
踩坑
開(kāi)關(guān)無(wú)障礙服務(wù)函數(shù)沒(méi)有被調(diào)用
當(dāng)將一切都配置好,本來(lái)可以調(diào)用,莫名其妙突然無(wú)法調(diào)用。我的問(wèn)題出現(xiàn)場(chǎng)景大概是我將無(wú)障礙服務(wù)的類名修改,然后重新運(yùn)行,發(fā)現(xiàn)再次開(kāi)啟無(wú)障礙服務(wù),沒(méi)有任何效果(即不會(huì)觸發(fā)服務(wù)的函數(shù))
最后猜到是模擬器問(wèn)題,將其重啟后就解決了。
END
柚子快報(bào)激活碼778899分享:Android無(wú)障礙服務(wù)
相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。