private static int GetSystemResourceDimenPx(AccessibilityService service, string resName)
        {
            var resourceId = service.Resources.GetIdentifier(resName, "dimen", "android");

            if (resourceId > 0)
            {
                return(service.Resources.GetDimensionPixelSize(resourceId));
            }
            return(0);
        }
        public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorView,
                                                     int overlayViewHeight, bool isOverlayAboveAnchor)
        {
            var anchorViewRect = new Rect();

            anchorView.GetBoundsInScreen(anchorViewRect);
            var anchorViewX = anchorViewRect.Left;
            var anchorViewY = isOverlayAboveAnchor ? anchorViewRect.Top : anchorViewRect.Bottom;

            anchorViewRect.Dispose();

            if (isOverlayAboveAnchor)
            {
                anchorViewY -= overlayViewHeight;
            }
            anchorViewY -= GetStatusBarHeight(service);

            return(new Point(anchorViewX, anchorViewY));
        }
 private static int GetNavigationBarHeight(AccessibilityService service)
 {
     return(GetSystemResourceDimenPx(service, "navigation_bar_height"));
 }
 private static int GetStatusBarHeight(AccessibilityService service)
 {
     return(GetSystemResourceDimenPx(service, "status_bar_height"));
 }
        public static Point GetOverlayAnchorPosition(AccessibilityService service, AccessibilityNodeInfo anchorNode,
                                                     AccessibilityNodeInfo root, IEnumerable <AccessibilityWindowInfo> windows, int overlayViewHeight,
                                                     bool isOverlayAboveAnchor)
        {
            Point point = null;

            if (anchorNode != null)
            {
                // Update node's info since this is still a reference from an older event
                anchorNode.Refresh();
                if (!anchorNode.VisibleToUser)
                {
                    return(new Point(-1, -1));
                }
                if (!anchorNode.Focused)
                {
                    return(null);
                }

                // node.VisibleToUser doesn't always give us exactly what we want, so attempt to tighten up the range
                // of visibility
                var inputMethodHeight = 0;
                if (windows != null)
                {
                    if (IsStatusBarExpanded(windows))
                    {
                        return(new Point(-1, -1));
                    }
                    inputMethodHeight = GetInputMethodHeight(windows);
                }
                var minY           = 0;
                var rootNodeHeight = GetNodeHeight(root);
                if (rootNodeHeight == -1)
                {
                    return(null);
                }
                var maxY = rootNodeHeight - GetNavigationBarHeight(service) - GetStatusBarHeight(service) -
                           inputMethodHeight;

                point = GetOverlayAnchorPosition(service, anchorNode, overlayViewHeight, isOverlayAboveAnchor);
                if (point.Y < minY)
                {
                    if (isOverlayAboveAnchor)
                    {
                        // view nearing bounds, anchor to bottom
                        point.X = -1;
                        point.Y = 0;
                    }
                    else
                    {
                        // view out of bounds, hide overlay
                        point.X = -1;
                        point.Y = -1;
                    }
                }
                else if (point.Y > (maxY - overlayViewHeight))
                {
                    if (isOverlayAboveAnchor)
                    {
                        // view out of bounds, hide overlay
                        point.X = -1;
                        point.Y = -1;
                    }
                    else
                    {
                        // view nearing bounds, anchor to top
                        point.X = 0;
                        point.Y = -1;
                    }
                }
                else if (isOverlayAboveAnchor && point.Y < (maxY - (overlayViewHeight * 2) - GetNodeHeight(anchorNode)))
                {
                    // This else block forces the overlay to return to bottom alignment as soon as space is available
                    // below the anchor view. Removing this will change the behavior to wait until there isn't enough
                    // space above the anchor view before returning to bottom alignment.
                    point.X = -1;
                    point.Y = 0;
                }
            }
            return(point);
        }