AccessibilityService изменяет EditText из AlertDialog

Я создал AccessibilityService в Android, где я хочу отобразить AlertDialog после фокусировки на EditText на странице (Примечание: EditText может быть из другого приложения, например, экрана входа в систему, поэтому я не всегда буду знать идентификатор). Когда вы нажимаете кнопку «подтвердить» в AlertDialog, он заполняет этот EditText текстом.

У меня выполнены все шаги, кроме последней части... Я не могу понять, как заполнить EditText текстом. Я предполагаю, что есть способ где-то применить метод findViewByID(), но я не знаю, как найти идентификатор EditText (см. выше, EditText может быть из другого приложения). Смотрите код ниже, я далеко? Приведенный ниже код всегда сообщает мне о проблеме с запечатанным экземпляром (невозможно выполнить это действие на незапечатанном экземпляре).

public void onAccessibilityEvent(final AccessibilityEvent event) {
    final AccessibilityNodeInfo source = event.getSource();

    if ((event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) && CLASS_NAME_EDIT_TEXT.equals(event.getClassName())) {

        AlertDialog.Builder mSuspendDialog = new AlertDialog.Builder(getApplicationContext())
                .setTitle(R.string.str_have_password_question)
                .setPositiveButton(R.string.str_decision_use_password, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        if (event.getSource() != null & event.getClassName().equals("android.widget.EditView")) {
                            Bundle arguments = new Bundle();
                            arguments.putCharSequence(AccessibilityNodeInfo
                                    .ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "newtexttopopulateedittext");
                            event.getSource().performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
                        }
                    }
                })
                .setNegativeButton(R.string.str_decision_close, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        // User cancelled the dialog
                    }
                });

        AlertDialog alert11 = mSuspendDialog.create();

        // Ensure we can show the dialog from this service.
        alert11.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        alert11.show();  

person Huge    schedule 08.04.2015    source источник


Ответы (1)


1) Когда начинается какое-либо действие, создайте List (или что-то еще) из идентификаторов всех EditText на экране.

2) При создании списка (или позже) снова выполните итерацию по списку и проверьте, доступно ли значение для этого представления в вашей базе данных SQLite.

3) Если значение доступно, используйте ACTION_PASTE для вставки текста в этот EditText.

ArrayList<AccessibilityNodeInfo> inputViewsList = new ArrayList<AccessibilityNodeInfo>();
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
refreshChildViewsList(rootNode);
for(AccessibilityNodeInfo mNode : inputViewsList){
    String viewId = mNode.getViewIdResourceName();
    Cursor cr = db.rawQuery(-----your database parameters----);
    if(cr.moveToFirst()){
        //this means you have a value for that ET
        ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
        ClipData clipData =ClipData.newPlainText("MyAppName", cr.getString(--Your column number--));
        clipboardManager.setPrimaryClip(clipData);
        mNode.performAction(AccessibilityNodeInfo.ACTION_PASTE);
    }
}

База данных должна использоваться так, чтобы вы могли постоянно помнить значения. Идентификатор, который я получаю выше, является полным идентификатором с именем пакета приложения и идентификатором представления. Таким образом, он остается уникальным для всей системы.

Теперь о методе refreshChildViews():

private void refreshChildViews(AccessibilityNodeInfo rootNode){
    int childCount = rootNode.getChildCount();
    for(int i=0; i<childCount ; i++){
        AccessibilityNodeInfo tmpNode = rootNode.getChildAt(i);
        int subChildCount = tmpNode.getChildCount();
        if(subChildCount==0){
            if(tmpNode.getClassName().toString().contentEquals("android.widget.EditText"){
                inputViewsList.add(tmpNode);
            }
            return;
        }
        if(subChildCount>0){
            refreshChildViews(tmpNode);
        }
    }
}

Не забудьте очистить событие inputViewsList на TYPE_WINDOW_STATE_CHANGED!

Позвольте мне знать, если вам нужно что-нибудь еще.

person Prasad Pawar    schedule 20.10.2015
comment
Используемое здесь действие ACTION_PASTE требует API 18 и выше. Для API 21 и выше есть еще один ACTION_SET_TEXT, который работает более эффективно. - person Prasad Pawar; 20.10.2015
comment
Я думаю, что всякий раз, когда для вставки текста в текст редактирования вызывается событие onAccessibilityEvent, и цикл продолжает проверяться на Marshmallow с помощью ClipboardManager - person Ganesh Jogam; 06.09.2017