/// <summary>
        /// Traverse AssistStructure and add ViewNode metadata to a flat list.
        /// </summary>
        /// <returns>The parse.</returns>
        /// <param name="forFill">If set to <c>true</c> for fill.</param>
        /// <param name="isManualRequest"></param>
        string Parse(bool forFill, bool isManualRequest)
        {
            Log.Debug(CommonUtil.Tag, "Parsing structure for " + Structure.ActivityComponent);
            var nodes = Structure.WindowNodeCount;

            ClientFormData = new FilledAutofillFieldCollection();
            String webDomain = null;

            _editTextsWithoutHint.Clear();

            for (int i = 0; i < nodes; i++)
            {
                var node = Structure.GetWindowNodeAt(i);
                var view = node.RootViewNode;
                ParseLocked(forFill, isManualRequest, view, ref webDomain);
            }



            if (AutofillFields.Empty)
            {
                var passwordFields = _editTextsWithoutHint
                                     .Where(IsPassword).ToList();
                if (!passwordFields.Any())
                {
                    passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList();
                }
                foreach (var passwordField in passwordFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(passwordField, new[] { View.AutofillHintPassword }));
                    var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
                    if (usernameField != null)
                    {
                        AutofillFields.Add(new AutofillFieldMetadata(usernameField, new[] { View.AutofillHintUsername }));
                    }
                }
                //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
                //let's assume it is a username field:
                if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(_editTextsWithoutHint.First(), new[] { View.AutofillHintUsername }));
                }
            }

            //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints)
            if (isManualRequest)
            {
                foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint)
                {
                    if (editText.IsFocused)
                    {
                        AutofillFields.Add(new AutofillFieldMetadata(editText, new[] { IsPassword(editText) || HasPasswordHint(editText) ? View.AutofillHintPassword : View.AutofillHintUsername }));
                        break;
                    }
                }
            }



            String packageName = Structure.ActivityComponent.PackageName;

            if (!string.IsNullOrEmpty(webDomain))
            {
                bool valid = Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, packageName);
                if (!valid)
                {
                    CommonUtil.loge($"DAL verification failed for {packageName}/{webDomain}");
                    webDomain = null;
                }
            }
            if (string.IsNullOrEmpty(webDomain))
            {
                webDomain = "androidapp://" + packageName;
                Log.Debug(CommonUtil.Tag, "no web domain. Using package name.");
            }
            return(webDomain);
        }
Beispiel #2
0
        /// <summary>
        /// Traverse AssistStructure and add ViewNode metadata to a flat list.
        /// </summary>
        /// <returns>The parse.</returns>
        /// <param name="forFill">If set to <c>true</c> for fill.</param>
        /// <param name="isManualRequest"></param>
        AutofillTargetId Parse(bool forFill, bool isManualRequest)
        {
            AutofillTargetId result = new AutofillTargetId();

            CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent);
            var nodes = Structure.WindowNodeCount;

            ClientFormData = new FilledAutofillFieldCollection();
            String webDomain = null;

            _editTextsWithoutHint.Clear();

            for (int i = 0; i < nodes; i++)
            {
                var node = Structure.GetWindowNodeAt(i);

                var view = node.RootViewNode;
                ParseLocked(forFill, isManualRequest, view, ref webDomain);
            }



            List <AssistStructure.ViewNode> passwordFields = new List <AssistStructure.ViewNode>();
            List <AssistStructure.ViewNode> usernameFields = new List <AssistStructure.ViewNode>();

            if (AutofillFields.Empty)
            {
                passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList();
                if (!passwordFields.Any())
                {
                    passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList();
                }

                usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList();

                if (usernameFields.Any() == false)
                {
                    foreach (var passwordField in passwordFields)
                    {
                        var usernameField = _editTextsWithoutHint
                                            .TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
                        if (usernameField != null)
                        {
                            usernameFields.Add(usernameField);
                        }
                    }
                }
                if (usernameFields.Any() == false)
                {
                    //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
                    //let's assume it is a username field:
                    if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
                    {
                        usernameFields.Add(_editTextsWithoutHint.First());
                    }
                }
            }

            //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints)
            if (isManualRequest)
            {
                foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint)
                {
                    if (editText.IsFocused)
                    {
                        if (IsPassword(editText) || HasPasswordHint(editText))
                        {
                            passwordFields.Add(editText);
                        }
                        else
                        {
                            usernameFields.Add(editText);
                        }
                        break;
                    }
                }
            }

            if (forFill)
            {
                foreach (var uf in usernameFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(uf, new[] { View.AutofillHintUsername }));
                }
                foreach (var pf in passwordFields)
                {
                    AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword }));
                }
            }
            else
            {
                foreach (var uf in usernameFields)
                {
                    ClientFormData.Add(new FilledAutofillField(uf, new[] { View.AutofillHintUsername }));
                }
                foreach (var pf in passwordFields)
                {
                    ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword }));
                }
            }


            result.WebDomain   = webDomain;
            result.PackageName = Structure.ActivityComponent.PackageName;
            if (!string.IsNullOrEmpty(webDomain))
            {
                result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName);
                if (result.IncompatiblePackageAndDomain)
                {
                    CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}");
                }
            }
            else
            {
                result.IncompatiblePackageAndDomain = false;
            }
            return(result);
        }