@@ -47,52 +47,52 @@ public class AccessibilityAPI {
4747 public static void onReceive (TermuxApiReceiver apiReceiver , final Context context , Intent intent ) {
4848 Logger .logDebug (LOG_TAG , "onReceive" );
4949
50- boolean isAccessibilityEnabled = isAccessibilityServiceEnabled (context , TermuxAccessibilityService .class );
51- if (!isAccessibilityEnabled ) {
52- Intent accessibilityIntent = new Intent (Settings .ACTION_ACCESSIBILITY_SETTINGS );
53- accessibilityIntent .addFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
54- context .startActivity (accessibilityIntent );
55- }
56-
57- ResultReturner .returnData (apiReceiver , intent , out -> {
58- final ContentResolver contentResolver = context .getContentResolver ();
59- if (intent .hasExtra ("dump" )) {
60- out .print (dump ());
61- } else if (intent .hasExtra ("click" )) {
62- click (intent .getIntExtra ("x" , 0 ), intent .getIntExtra ("y" , 0 ));
63- } else if (intent .hasExtra ("type" )) {
64- type (intent .getStringExtra ("type" ));
65- } else if (intent .hasExtra ("global-action" )) {
50+ boolean isAccessibilityEnabled = isAccessibilityServiceEnabled (context , TermuxAccessibilityService .class );
51+ if (!isAccessibilityEnabled ) {
52+ Intent accessibilityIntent = new Intent (Settings .ACTION_ACCESSIBILITY_SETTINGS );
53+ accessibilityIntent .addFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
54+ context .startActivity (accessibilityIntent );
55+ }
56+
57+ ResultReturner .returnData (apiReceiver , intent , out -> {
58+ final ContentResolver contentResolver = context .getContentResolver ();
59+ if (intent .hasExtra ("dump" )) {
60+ out .print (dump ());
61+ } else if (intent .hasExtra ("click" )) {
62+ click (intent .getIntExtra ("x" , 0 ), intent .getIntExtra ("y" , 0 ));
63+ } else if (intent .hasExtra ("type" )) {
64+ type (intent .getStringExtra ("type" ));
65+ } else if (intent .hasExtra ("global-action" )) {
6666 performGlobalAction (intent .getStringExtra ("global-action" ));
67- }
68- });
69- }
70-
71- // [The Stack Overflow answer 14923144](https://stackoverflow.com/a/14923144)
72- public static boolean isAccessibilityServiceEnabled (Context context , Class <? extends AccessibilityService > service ) {
73- AccessibilityManager am = (AccessibilityManager ) context .getSystemService (Context .ACCESSIBILITY_SERVICE );
74- List <AccessibilityServiceInfo > enabledServices = am .getEnabledAccessibilityServiceList (AccessibilityServiceInfo .FEEDBACK_ALL_MASK );
75-
76- for (AccessibilityServiceInfo enabledService : enabledServices ) {
77- ServiceInfo enabledServiceInfo = enabledService .getResolveInfo ().serviceInfo ;
78- if (enabledServiceInfo .packageName .equals (context .getPackageName ()) && enabledServiceInfo .name .equals (service .getName ()))
79- return true ;
80- }
81-
82- return false ;
83- }
84-
85- private static void click (int x , int y ) {
86- Path swipePath = new Path ();
87- swipePath .moveTo (x , y );
88- GestureDescription .Builder gestureBuilder = new GestureDescription .Builder ();
89- gestureBuilder .addStroke (new GestureDescription .StrokeDescription (swipePath , 0 , 1 ));
90- TermuxAccessibilityService .instance .dispatchGesture (gestureBuilder .build (), null , null );
91- }
92-
93- // The aim of this function is to give a compatible output with `adb` `uiautomator dump`.
94- private static String dump () throws TransformerException , ParserConfigurationException {
95- // Create a DocumentBuilder
67+ }
68+ });
69+ }
70+
71+ // [The Stack Overflow answer 14923144](https://stackoverflow.com/a/14923144)
72+ public static boolean isAccessibilityServiceEnabled (Context context , Class <? extends AccessibilityService > service ) {
73+ AccessibilityManager am = (AccessibilityManager ) context .getSystemService (Context .ACCESSIBILITY_SERVICE );
74+ List <AccessibilityServiceInfo > enabledServices = am .getEnabledAccessibilityServiceList (AccessibilityServiceInfo .FEEDBACK_ALL_MASK );
75+
76+ for (AccessibilityServiceInfo enabledService : enabledServices ) {
77+ ServiceInfo enabledServiceInfo = enabledService .getResolveInfo ().serviceInfo ;
78+ if (enabledServiceInfo .packageName .equals (context .getPackageName ()) && enabledServiceInfo .name .equals (service .getName ()))
79+ return true ;
80+ }
81+
82+ return false ;
83+ }
84+
85+ private static void click (int x , int y ) {
86+ Path swipePath = new Path ();
87+ swipePath .moveTo (x , y );
88+ GestureDescription .Builder gestureBuilder = new GestureDescription .Builder ();
89+ gestureBuilder .addStroke (new GestureDescription .StrokeDescription (swipePath , 0 , 1 ));
90+ TermuxAccessibilityService .instance .dispatchGesture (gestureBuilder .build (), null , null );
91+ }
92+
93+ // The aim of this function is to give a compatible output with `adb` `uiautomator dump`.
94+ private static String dump () throws TransformerException , ParserConfigurationException {
95+ // Create a DocumentBuilder
9696 DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance ();
9797 DocumentBuilder builder = factory .newDocumentBuilder ();
9898
@@ -103,92 +103,97 @@ private static String dump() throws TransformerException, ParserConfigurationExc
103103 Element root = document .createElement ("hierarchy" );
104104 document .appendChild (root );
105105
106- AccessibilityNodeInfo node = TermuxAccessibilityService .instance .getRootInActiveWindow ();
106+ AccessibilityNodeInfo node = TermuxAccessibilityService .instance .getRootInActiveWindow ();
107+ // Randomly faced [Benjamin_Loison/Voice_assistant/issues/84#issue-3661682](https://codeberg.org/Benjamin_Loison/Voice_assistant/issues/84#issue-3661682)
108+ if (node == null ) {
109+ return "" ;
110+ }
107111
108- dumpNodeAuxiliary (document , root , node );
112+ dumpNodeAuxiliary (document , root , node );
109113
110114 // Write as XML
111115 TransformerFactory transformerFactory = TransformerFactory .newInstance ();
112116 Transformer transformer = transformerFactory .newTransformer ();
113- transformer .setOutputProperty (OutputKeys .INDENT , "yes" );
114- transformer .setOutputProperty ("{http://xml.apache.org/xslt}indent-amount" , "2" );
117+ transformer .setOutputProperty (OutputKeys .INDENT , "yes" );
118+ transformer .setOutputProperty ("{http://xml.apache.org/xslt}indent-amount" , "2" );
115119 DOMSource source = new DOMSource (document );
116120
117- StringWriter sw = new StringWriter ();
121+ StringWriter sw = new StringWriter ();
118122 StreamResult result = new StreamResult (sw );
119123 transformer .transform (source , result );
120124
121- return sw .toString ();
122- }
123-
124- private static void dumpNodeAuxiliary (Document document , Element element , AccessibilityNodeInfo node ) {
125- for (int i = 0 ; i < node .getChildCount (); i ++) {
126- AccessibilityNodeInfo nodeChild = node .getChild (i );
127- // May be faced randomly, see [Benjamin-Loison/android/issues/28#issuecomment-3975714760](https://github.com/Benjamin-Loison/android/issues/28#issuecomment-3975714760)
128- if (nodeChild == null )
129- {
130- continue ;
131- }
132- Element elementChild = document .createElement ("node" );
133-
134- elementChild .setAttribute ("index" , String .valueOf (i ));
135-
136- elementChild .setAttribute ("text" , getCharSequenceAsString (nodeChild .getText ()));
137-
138- String nodeChildViewIdResourceName = nodeChild .getViewIdResourceName ();
139- elementChild .setAttribute ("resource-id" , nodeChildViewIdResourceName != null ? nodeChildViewIdResourceName : "" );
140-
141- elementChild .setAttribute ("class" , nodeChild .getClassName ().toString ());
142-
143- elementChild .setAttribute ("package" , nodeChild .getPackageName ().toString ());
144-
145- elementChild .setAttribute ("content-desc" , getCharSequenceAsString (nodeChild .getContentDescription ()));
146-
147- elementChild .setAttribute ("checkable" , String .valueOf (nodeChild .isCheckable ()));
148-
149- elementChild .setAttribute ("checked" , String .valueOf (nodeChild .isChecked ()));
150-
151- elementChild .setAttribute ("clickable" , String .valueOf (nodeChild .isClickable ()));
152-
153- elementChild .setAttribute ("enabled" , String .valueOf (nodeChild .isEnabled ()));
154-
155- elementChild .setAttribute ("focusable" , String .valueOf (nodeChild .isFocusable ()));
156-
157- elementChild .setAttribute ("focused" , String .valueOf (nodeChild .isFocused ()));
158-
159- elementChild .setAttribute ("scrollable" , String .valueOf (nodeChild .isScrollable ()));
160-
161- elementChild .setAttribute ("long-clickable" , String .valueOf (nodeChild .isLongClickable ()));
162-
163- elementChild .setAttribute ("password" , String .valueOf (nodeChild .isPassword ()));
164-
165- elementChild .setAttribute ("selected" , String .valueOf (nodeChild .isSelected ()));
166-
167- Rect nodeChildBounds = new Rect ();
168- nodeChild .getBoundsInScreen (nodeChildBounds );
169- elementChild .setAttribute ("bounds" , nodeChildBounds .toShortString ());
170-
171- elementChild .setAttribute ("drawing-order" , String .valueOf (nodeChild .getDrawingOrder ()));
172-
173- elementChild .setAttribute ("hint" , getCharSequenceAsString (nodeChild .getHintText ()));
174-
175- element .appendChild (elementChild );
125+ return sw .toString ();
126+ }
127+
128+ private static void dumpNodeAuxiliary (Document document , Element element , AccessibilityNodeInfo node ) {
129+ for (int i = 0 ; i < node .getChildCount (); i ++) {
130+ AccessibilityNodeInfo nodeChild = node .getChild (i );
131+ // May be faced randomly, see [Benjamin-Loison/android/issues/28#issuecomment-3975714760](https://github.com/Benjamin-Loison/android/issues/28#issuecomment-3975714760)
132+ if (nodeChild == null )
133+ {
134+ continue ;
135+ }
136+ Element elementChild = document .createElement ("node" );
137+
138+ elementChild .setAttribute ("index" , String .valueOf (i ));
139+
140+ elementChild .setAttribute ("text" , getCharSequenceAsString (nodeChild .getText ()));
141+ Logger .logInfo (LOG_TAG , getCharSequenceAsString (nodeChild .getText ()));
142+
143+ String nodeChildViewIdResourceName = nodeChild .getViewIdResourceName ();
144+ elementChild .setAttribute ("resource-id" , nodeChildViewIdResourceName != null ? nodeChildViewIdResourceName : "" );
145+
146+ elementChild .setAttribute ("class" , nodeChild .getClassName ().toString ());
147+
148+ elementChild .setAttribute ("package" , nodeChild .getPackageName ().toString ());
149+
150+ elementChild .setAttribute ("content-desc" , getCharSequenceAsString (nodeChild .getContentDescription ()));
151+
152+ elementChild .setAttribute ("checkable" , String .valueOf (nodeChild .isCheckable ()));
153+
154+ elementChild .setAttribute ("checked" , String .valueOf (nodeChild .isChecked ()));
155+
156+ elementChild .setAttribute ("clickable" , String .valueOf (nodeChild .isClickable ()));
157+
158+ elementChild .setAttribute ("enabled" , String .valueOf (nodeChild .isEnabled ()));
159+
160+ elementChild .setAttribute ("focusable" , String .valueOf (nodeChild .isFocusable ()));
161+
162+ elementChild .setAttribute ("focused" , String .valueOf (nodeChild .isFocused ()));
163+
164+ elementChild .setAttribute ("scrollable" , String .valueOf (nodeChild .isScrollable ()));
165+
166+ elementChild .setAttribute ("long-clickable" , String .valueOf (nodeChild .isLongClickable ()));
167+
168+ elementChild .setAttribute ("password" , String .valueOf (nodeChild .isPassword ()));
169+
170+ elementChild .setAttribute ("selected" , String .valueOf (nodeChild .isSelected ()));
171+
172+ Rect nodeChildBounds = new Rect ();
173+ nodeChild .getBoundsInScreen (nodeChildBounds );
174+ elementChild .setAttribute ("bounds" , nodeChildBounds .toShortString ());
175+
176+ elementChild .setAttribute ("drawing-order" , String .valueOf (nodeChild .getDrawingOrder ()));
177+
178+ elementChild .setAttribute ("hint" , getCharSequenceAsString (nodeChild .getHintText ()));
179+
180+ element .appendChild (elementChild );
176181 dumpNodeAuxiliary (document , elementChild , nodeChild );
177182 }
178- }
183+ }
179184
180- private static String getCharSequenceAsString (CharSequence charSequence ) {
181- return charSequence != null ? charSequence .toString () : "" ;
182- }
185+ private static String getCharSequenceAsString (CharSequence charSequence ) {
186+ return charSequence != null ? charSequence .toString () : "" ;
187+ }
183188
184- private static void type (String toType ) {
185- AccessibilityNodeInfo focusedNode = TermuxAccessibilityService .instance .getRootInActiveWindow ().findFocus (AccessibilityNodeInfo .FOCUS_INPUT );
189+ private static void type (String toType ) {
190+ AccessibilityNodeInfo focusedNode = TermuxAccessibilityService .instance .getRootInActiveWindow ().findFocus (AccessibilityNodeInfo .FOCUS_INPUT );
186191 Bundle arguments = new Bundle ();
187192 arguments .putCharSequence (AccessibilityNodeInfo .ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE , toType );
188193 focusedNode .performAction (AccessibilityNodeInfo .ACTION_SET_TEXT , arguments );
189- }
194+ }
190195
191- private static void performGlobalAction (String globalAction ) throws NoSuchFieldException , IllegalAccessException {
192- TermuxAccessibilityService .instance .performGlobalAction ((int )AccessibilityService .class .getDeclaredField ("GLOBAL_ACTION_" + globalAction ).get (null ));
193- }
196+ private static void performGlobalAction (String globalAction ) throws NoSuchFieldException , IllegalAccessException {
197+ TermuxAccessibilityService .instance .performGlobalAction ((int )AccessibilityService .class .getDeclaredField ("GLOBAL_ACTION_" + globalAction ).get (null ));
198+ }
194199}
0 commit comments