Почему постоянно переходит только в первую группу?
Пытаюсь создать постер в фейсбуке, но столкнулся с проблемой что постоянно переходит в первую группу и публикует только в ней
package com.arturio.facebookautoposter;
import android.accessibilityservice.AccessibilityService;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import java.util.*;
/**
* AccessibilityService для автоматизації дій у Facebook-групах:
* пошук → вибір групи → відкриття поля посту → вставка тексту.
*/
public class AutomationService extends AccessibilityService {
public static String queryText = "";
public static String postText = "";
private static final String TAG = "FBPoster";
public static boolean searchIconClicked;
public static boolean textInserted;
private boolean groupsTabClicked = false;
private boolean imageClicked = false;
private boolean postFieldClicked = false;
private int currentGroupIndex = 0;
private List<AccessibilityNodeInfo> groupImages = new ArrayList<>();
private boolean isPostingInProgress = false;
private final Handler handler = new Handler(Looper.getMainLooper());
private int postTextCheckAttempts = 0;
private static final int MAX_ATTEMPTS = 10;
private final Set<String> postFieldHints = new HashSet<>(Arrays.asList(
"Напишите что-нибудь", "Напишіть щось",
"Create a public post", "What's on your mind",
"Опубликовать как Анонимный участник"
));
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
final AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) return;
if (!searchIconClicked) {
if (clickSearchIcon(root)) {
searchIconClicked = true;
Log.d(TAG, "🔍 Клік по іконці пошуку");
}
return;
}
if (searchIconClicked && !textInserted) {
AccessibilityNodeInfo input = findFirstEditable(root);
if (input != null) {
pasteTextFromClipboard(input, queryText);
textInserted = true;
Log.d(TAG, "🔤 Вставлено текст: " + queryText);
}
return;
}
if (textInserted && !groupsTabClicked) {
if (clickGroupsTab(root)) {
groupsTabClicked = true;
Log.d(TAG, "📁 Клік по вкладці 'Групи'");
}
return;
}
if (groupsTabClicked && groupImages.isEmpty()) {
groupImages = findAllGroupImages(root);
if (groupImages.isEmpty()) {
showToast("⚠️ Не знайдено жодної групи");
Log.d(TAG, "⚠️ Не знайдено жодної групи");
return;
}
Log.d(TAG, "🔢 Знайдено груп: " + groupImages.size());
}
if (groupsTabClicked && !imageClicked && !isPostingInProgress && !groupImages.isEmpty()) {
if (currentGroupIndex >= groupImages.size()) {
showToast("✅ Усі групи пройдено");
Log.d(TAG, "✅ Усі групи пройдено");
return;
}
Log.d(TAG, "clickNextGroup currentGroupIndex = " + currentGroupIndex + ", total groups = " + groupImages.size());
clickNextGroup();
return;
}
if (imageClicked && !postFieldClicked && !isPostingInProgress) {
postFieldClicked = true;
isPostingInProgress = true;
checkForPostField();
}
}
private boolean clickSearchIcon(AccessibilityNodeInfo root) {
List<AccessibilityNodeInfo> icons = new ArrayList<>();
icons.addAll(root.findAccessibilityNodeInfosByText("Поиск"));
icons.addAll(root.findAccessibilityNodeInfosByText("Search"));
for (AccessibilityNodeInfo node : icons) {
if (node.isClickable()) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
return false;
}
private boolean clickGroupsTab(AccessibilityNodeInfo root) {
List<AccessibilityNodeInfo> tabs = new ArrayList<>();
tabs.addAll(root.findAccessibilityNodeInfosByText("Группы"));
tabs.addAll(root.findAccessibilityNodeInfosByText("Групи"));
tabs.addAll(root.findAccessibilityNodeInfosByText("Groups"));
for (AccessibilityNodeInfo tab : tabs) {
if (tab.isClickable()) {
tab.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
return false;
}
private AccessibilityNodeInfo findFirstEditable(AccessibilityNodeInfo root) {
if (root == null) return null;
if ("android.widget.EditText".contentEquals(root.getClassName())) return root;
for (int i = 0; i < root.getChildCount(); i++) {
AccessibilityNodeInfo res = findFirstEditable(root.getChild(i));
if (res != null) return res;
}
return null;
}
private void pasteTextFromClipboard(AccessibilityNodeInfo node, String text) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label", text);
clipboard.setPrimaryClip(clip);
if (node == null) return;
node.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
node.performAction(AccessibilityNodeInfo.ACTION_PASTE);
showToast("📋 Вставлено через буфер обміну");
}
private List<AccessibilityNodeInfo> findAllGroupImages(AccessibilityNodeInfo root) {
List<AccessibilityNodeInfo> results = new ArrayList<>();
findAllImagesRecursive(root, results);
return results;
}
private void findAllImagesRecursive(AccessibilityNodeInfo node, List<AccessibilityNodeInfo> list) {
if (node == null) return;
if ("android.widget.ImageView".contentEquals(node.getClassName()) && node.isVisibleToUser()) {
if (isInsideTargetContainer(node, "android.view.ViewGroup")) {
list.add(node);
}
}
for (int i = 0; i < node.getChildCount(); i++) {
findAllImagesRecursive(node.getChild(i), list);
}
}
private boolean clickGroupContainer(AccessibilityNodeInfo node) {
if (node == null) return false;
AccessibilityNodeInfo current = node;
while (current != null) {
if (current.isClickable()) {
Log.d(TAG, "Клікаємо по клікабельному вузлу: " + current.getClassName() +
", desc=" + current.getContentDescription());
boolean clicked = current.performAction(AccessibilityNodeInfo.ACTION_CLICK);
if (clicked) return true;
else Log.w(TAG, "Спроба клікнути не вдалася");
}
current = current.getParent();
}
Log.w(TAG, "Не знайдено клікабельний батьківський вузол для кліку");
return false;
}
private boolean isInsideTargetContainer(AccessibilityNodeInfo node, String containerClassName) {
AccessibilityNodeInfo parent = node.getParent();
while (parent != null) {
if (containerClassName.equals(parent.getClassName())) {
return true;
}
parent = parent.getParent();
}
return false;
}
private void clickNextGroup() {
if (currentGroupIndex >= groupImages.size()) {
showToast("✅ Усі групи пройдено");
Log.d(TAG, "✅ Усі групи пройдено");
return;
}
AccessibilityNodeInfo groupImage = groupImages.get(currentGroupIndex);
boolean clicked = clickGroupContainer(groupImage);
if (clicked) {
imageClicked = true;
showToast("✅ Клік по групі #" + (currentGroupIndex + 1));
Log.d(TAG, "✅ Клік по групі #" + (currentGroupIndex + 1));
// Збільшуємо індекс після успішного кліку
currentGroupIndex++;
} else {
Log.w(TAG, "Не вдалося клікнути по групі #" + (currentGroupIndex + 1));
currentGroupIndex++;
clickNextGroup();
}
}
private void checkForPostField() {
postTextCheckAttempts++;
Log.d(TAG, "🔁 Спроба #" + postTextCheckAttempts);
showToast("🔁 Спроба #" + postTextCheckAttempts);
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
if (rootNode == null) return;
AccessibilityNodeInfo postFieldNode = findNodeWithTextHintRecursive(rootNode, postFieldHints);
if (postFieldNode != null) {
clickNodeOrParent(postFieldNode);
Log.d(TAG, "✅ Знайдено поле для публікації!");
showToast("✅ Знайдено поле для публікації!");
handler.postDelayed(this::waitForEditorAndInsertPostText, 1500);
postTextCheckAttempts = 0;
} else {
if (postTextCheckAttempts >= MAX_ATTEMPTS) {
Log.d(TAG, "⛔ Не знайдено поле для публікації після " + MAX_ATTEMPTS + " спроб");
showToast("⛔ Не знайдено поле для публікації після " + MAX_ATTEMPTS + " спроб");
postTextCheckAttempts = 0;
} else {
handler.postDelayed(this::checkForPostField, 1500);
}
}
}
private void waitForEditorAndInsertPostText() {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) {
handler.postDelayed(this::waitForEditorAndInsertPostText, 1000);
return;
}
AccessibilityNodeInfo editTextNode = findFirstEditable(root);
if (editTextNode != null) {
if (editTextNode.isClickable()) {
editTextNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else {
AccessibilityNodeInfo parent = editTextNode.getParent();
while (parent != null && !parent.isClickable()) {
parent = parent.getParent();
}
if (parent != null) {
parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
handler.postDelayed(() -> {
pasteTextFromClipboard(editTextNode, postText);
Log.d(TAG, "✅ Вставлено postText: " + postText);
showToast("✅ Вставлено текст для публікації");
handler.postDelayed(this::clickPublishButton, 1500);
}, 1000);
} else {
handler.postDelayed(this::waitForEditorAndInsertPostText, 1000);
}
}
private AccessibilityNodeInfo findNodeWithTextHintRecursive(AccessibilityNodeInfo node, Set<String> targets) {
if (node == null) return null;
List<CharSequence> fields = Arrays.asList(
node.getText(),
node.getContentDescription(),
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? node.getHintText() : null
);
for (CharSequence field : fields) {
if (field != null) {
for (String target : targets) {
if (field.toString().contains(target)) return node;
}
}
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo result = findNodeWithTextHintRecursive(node.getChild(i), targets);
if (result != null) return result;
}
return null;
}
private void clickNodeOrParent(AccessibilityNodeInfo node) {
AccessibilityNodeInfo clickableNode = node;
while (clickableNode != null && !clickableNode.isClickable()) {
clickableNode = clickableNode.getParent();
}
if (clickableNode != null) {
clickableNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else {
Log.d(TAG, "⚠️ Не знайдено клікабельний батьківський вузол");
showToast("⚠️ Не знайдено клікабельний батьківський вузол");
}
}
private void clickPublishButton() {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) return;
List<String> publishTexts = Arrays.asList("ОПУБЛИКОВАТЬ", "Опублікувати", "Post");
List<AccessibilityNodeInfo> candidates = new ArrayList<>();
for (String text : publishTexts) {
candidates.addAll(root.findAccessibilityNodeInfosByText(text));
}
for (AccessibilityNodeInfo node : candidates) {
if (node != null && node.isVisibleToUser()) {
AccessibilityNodeInfo clickable = node;
while (clickable != null && !clickable.isClickable()) {
clickable = clickable.getParent();
}
if (clickable != null && clickable.performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
Log.d(TAG, "✅ Натиснуто кнопку: " + (node.getText() != null ? node.getText() : "без тексту"));
showToast("✅ Натиснуто кнопку: " + (node.getText() != null ? node.getText() : "без тексту"));
handler.postDelayed(this::returnToGroupList, 3000);
return;
}
}
}
Log.w(TAG, "⛔ Кнопку 'ОПУБЛИКОВАТЬ' не знайдено");
showToast("⛔ Кнопку 'ОПУБЛИКОВАТЬ' не знайдено");
}
private void returnToGroupList() {
handler.postDelayed(() -> {
performGlobalAction(GLOBAL_ACTION_BACK);
resetStateAndContinue();
}, 2000);
}
private void resetStateAndContinue() {
handler.postDelayed(() -> {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root == null) {
showToast("⚠️ Не вдалося оновити інтерфейс");
return;
}
imageClicked = false;
postFieldClicked = false;
isPostingInProgress = false;
postTextCheckAttempts = 0;
// НЕ оновлюємо groupImages тут!
Log.d(TAG, "Поточний індекс групи: " + currentGroupIndex + " з " + groupImages.size());
if (currentGroupIndex >= groupImages.size()) {
showToast("✅ Усі групи пройдено");
Log.d(TAG, "✅ Усі групи пройдено");
return;
}
clickNextGroup();
}, 3000);
}
private void showToast(String text) {
handler.post(() -> Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show());
}
@Override
public void onInterrupt() {
Log.d(TAG, "⛔ Сервіс перервано");
}
}
Источник: Stack Overflow на русском