| package foo.bar.filled; |
| |
| import android.annotation.Nullable; |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.graphics.Rect; |
| import android.text.TextUtils; |
| import android.util.AttributeSet; |
| import android.util.SparseArray; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewStructure; |
| import android.view.autofill.AutofillManager; |
| import android.view.autofill.AutofillValue; |
| import android.widget.EditText; |
| import android.widget.LinearLayout; |
| import android.widget.TextView; |
| |
| public class CustomLinearLayout extends LinearLayout { |
| static final boolean VIRTUAL = false; |
| |
| public CustomLinearLayout(Context context, @Nullable AttributeSet attrs) { |
| super(context, attrs); |
| if (VIRTUAL) { |
| getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> { |
| AutofillManager autofillManager = getContext().getSystemService( |
| AutofillManager.class); |
| if (oldFocus != null) { |
| autofillManager.notifyViewExited(CustomLinearLayout.this, |
| oldFocus.getAccessibilityViewId()); |
| } |
| if (newFocus != null) { |
| Rect bounds = new Rect(); |
| newFocus.getBoundsOnScreen(bounds); |
| autofillManager.notifyViewEntered(CustomLinearLayout.this, |
| newFocus.getAccessibilityViewId(), bounds); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) { |
| if (!VIRTUAL) { |
| super.dispatchProvideAutofillStructure(structure, flags); |
| } else { |
| onProvideAutofillVirtualStructure(structure, flags); |
| } |
| } |
| |
| @Override |
| public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { |
| if (!VIRTUAL) { |
| return; |
| } |
| populateViewStructure(this, structure); |
| onProvideAutofillVirtualStructureRecursive(this, structure); |
| } |
| |
| @Override |
| public void autofill(SparseArray<AutofillValue> values) { |
| final int valueCount = values.size(); |
| for (int i = 0; i < valueCount; i++) { |
| final int virtualId = values.keyAt(i); |
| final AutofillValue value = values.valueAt(i); |
| View view = findViewByAccessibilityIdTraversal(virtualId); |
| if (view instanceof EditText && !TextUtils.isEmpty(value.getTextValue())) { |
| EditText editText = (EditText) view; |
| editText.setText(value.getTextValue()); |
| |
| } |
| } |
| } |
| |
| private void onProvideAutofillVirtualStructureRecursive(View view, ViewStructure node) { |
| if (node == null) { |
| return; |
| } |
| if (view instanceof ViewGroup) { |
| ViewGroup viewGroup = (ViewGroup) view; |
| final int childCount = viewGroup.getChildCount(); |
| node.setChildCount(childCount); |
| for (int i = 0; i < childCount; i++) { |
| View child = viewGroup.getChildAt(i); |
| ViewStructure chlidNode = node.newChild(i); |
| chlidNode.setAutofillId(node, child.getAccessibilityViewId()); |
| populateViewStructure(child, chlidNode); |
| onProvideAutofillVirtualStructureRecursive(child, chlidNode); |
| } |
| } |
| } |
| |
| private void populateViewStructure(View view, ViewStructure structure) { |
| if (view.getId() != NO_ID) { |
| String pkg, type, entry; |
| try { |
| final Resources res = getResources(); |
| entry = res.getResourceEntryName(view.getId()); |
| type = res.getResourceTypeName(view.getId()); |
| pkg = res.getResourcePackageName(view.getId()); |
| } catch (Resources.NotFoundException e) { |
| entry = type = pkg = null; |
| } |
| structure.setId(view.getId(), pkg, type, entry); |
| } else { |
| structure.setId(view.getId(), null, null, null); |
| } |
| Rect rect = structure.getTempRect(); |
| view.getDrawingRect(rect); |
| structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); |
| structure.setVisibility(VISIBLE); |
| structure.setEnabled(view.isEnabled()); |
| if (view.isClickable()) { |
| structure.setClickable(true); |
| } |
| if (view.isFocusable()) { |
| structure.setFocusable(true); |
| } |
| if (view.isFocused()) { |
| structure.setFocused(true); |
| } |
| if (view.isAccessibilityFocused()) { |
| structure.setAccessibilityFocused(true); |
| } |
| if (view.isSelected()) { |
| structure.setSelected(true); |
| } |
| if (view.isLongClickable()) { |
| structure.setLongClickable(true); |
| } |
| CharSequence cname = view.getClass().getName(); |
| structure.setClassName(cname != null ? cname.toString() : null); |
| structure.setContentDescription(view.getContentDescription()); |
| if (view instanceof TextView) { |
| TextView textView = (TextView) view; |
| structure.setText(textView.getText(), textView.getSelectionStart(), |
| textView.getSelectionEnd()); |
| } |
| structure.setAutofillHints(view.getAutofillHints()); |
| structure.setAutofillType(view.getAutofillType()); |
| structure.setAutofillValue(view.getAutofillValue()); |
| } |
| } |