com.android.utils.WindowManager.java Source code

Java tutorial

Introduction

Here is the source code for com.android.utils.WindowManager.java

Source

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.android.utils;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;

import com.android.talkback.R;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class WindowManager {

    public static final int WRONG_WINDOW_TYPE = -1;
    private static final int WRONG_INDEX = -1;

    private static final int PREVIOUS = -1;
    private static final int CURRENT = 0;
    private static final int NEXT = 1;

    private final boolean mIsInRTL;
    private final List<AccessibilityWindowInfo> mWindows = new ArrayList<AccessibilityWindowInfo>();

    public static class WindowPositionComparator implements Comparator<AccessibilityWindowInfo> {

        private final boolean mIsInRTL;
        private Rect mRectA = new Rect();
        private Rect mRectB = new Rect();

        public WindowPositionComparator(boolean isInRTL) {
            mIsInRTL = isInRTL;
        }

        @Override
        public int compare(AccessibilityWindowInfo windowA, AccessibilityWindowInfo windowB) {
            windowA.getBoundsInScreen(mRectA);
            windowB.getBoundsInScreen(mRectB);

            if (mRectA.top != mRectB.top) {
                return mRectA.top - mRectB.top;
            } else {
                return mIsInRTL ? mRectB.right - mRectA.right : mRectA.left - mRectB.left;
            }
        }

    }

    public WindowManager(boolean isInRTL) {
        mIsInRTL = isInRTL;
    }

    /**
     * Set windows that would be used by WindowManager
     * @param windows Set the windows on the screen.
     */
    public void setWindows(List<AccessibilityWindowInfo> windows) {
        // Copy list not to sort the original one.
        mWindows.clear();
        mWindows.addAll(windows);

        Collections.sort(mWindows, new WindowPositionComparator(mIsInRTL));
    }

    /**
     * Returns whether accessibility focused window has AccessibilityWindowInfo.TYPE_APPLICATION
     * type.
     */
    public boolean isApplicationWindowFocused() {
        return isFocusedWindowType(AccessibilityWindowInfo.TYPE_APPLICATION);
    }

    /**
     * Returns whether accessibility focused window has
     * AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER type.
     */
    public boolean isSplitScreenDividerFocused() {
        return isFocusedWindowType(AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER);
    }

    private boolean isFocusedWindowType(int windowType) {
        AccessibilityWindowInfo info = getCurrentWindow(false /* useInputFocus */);
        return info != null && info.getType() == windowType;
    }

    /**
     * returns true if there is no window with windowType after baseWindow
     */
    public boolean isLastWindow(AccessibilityWindowInfo baseWindow, int windowType) {
        int index = getWindowIndex(baseWindow);
        if (index == WRONG_INDEX) {
            return true;
        }

        int count = mWindows.size();
        for (int i = index + 1; i < count; i++) {
            AccessibilityWindowInfo window = mWindows.get(i);
            if (window != null && window.getType() == windowType) {
                return false;
            }
        }

        return true;
    }

    /**
     * returns true if there is no window with windowType before baseWindow
     */
    public boolean isFirstWindow(AccessibilityWindowInfo baseWindow, int windowType) {
        int index = getWindowIndex(baseWindow);
        if (index <= 0) {
            return true;
        }

        for (int i = index - 1; i > 0; i--) {
            AccessibilityWindowInfo window = mWindows.get(i);
            if (window != null && window.getType() == windowType) {
                return false;
            }
        }

        return true;
    }

    /**
     * @return window that currently accessibilityFocused window.
     * If there is no accessibility focused window it returns first window that has TYPE_APPLICATION
     * or null if there is no window with TYPE_APPLICATION type
     */
    public AccessibilityWindowInfo getCurrentWindow(boolean useInputFocus) {
        int currentWindowIndex = getFocusedWindowIndex(mWindows, AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
        if (currentWindowIndex != WRONG_INDEX) {
            return mWindows.get(currentWindowIndex);
        }

        if (!useInputFocus) {
            return null;
        }

        currentWindowIndex = getFocusedWindowIndex(mWindows, AccessibilityNodeInfo.FOCUS_INPUT);
        if (currentWindowIndex != WRONG_INDEX) {
            return mWindows.get(currentWindowIndex);
        }

        return null;
    }

    /**
     * @return window that is previous relatively currently accessibilityFocused window.
     * If there is no accessibility focused window it returns first window that has TYPE_APPLICATION
     * or null if there is no window with TYPE_APPLICATION type
     */
    public AccessibilityWindowInfo getPreviousWindow(AccessibilityWindowInfo pivotWindow) {
        return getWindow(pivotWindow, PREVIOUS);
    }

    /**
     * Gets the window whose anchor equals the given node.
     */
    public AccessibilityWindowInfo getAnchoredWindow(@Nullable AccessibilityNodeInfoCompat targetAnchor) {
        if (!BuildCompat.isAtLeastN() || targetAnchor == null) {
            return null;
        }

        int windowCount = mWindows.size();
        for (int i = 0; i < windowCount; ++i) {
            AccessibilityWindowInfo window = mWindows.get(i);
            if (window != null) {
                AccessibilityNodeInfo anchor = window.getAnchor();
                if (anchor != null) {
                    try {
                        if (anchor.equals(targetAnchor.getInfo())) {
                            return window;
                        }
                    } finally {
                        anchor.recycle();
                    }
                }
            }
        }

        return null;
    }

    public boolean isInputWindowOnScreen() {
        if (mWindows == null) {
            return false;
        }

        for (AccessibilityWindowInfo window : mWindows) {
            if (window != null && window.getType() == AccessibilityWindowInfo.TYPE_INPUT_METHOD) {
                return true;
            }
        }

        return false;
    }

    public int getWindowType(int windowId) {
        if (mWindows != null) {
            for (AccessibilityWindowInfo window : mWindows) {
                if (window != null && window.getId() == windowId) {
                    return window.getType();
                }
            }
        }

        return WRONG_WINDOW_TYPE;
    }

    public boolean isStatusBar(int windowId) {
        if (mWindows == null || mWindows.size() == 0) {
            return false;
        }

        return mWindows.get(0).getId() == windowId
                && mWindows.get(0).getType() == AccessibilityWindowInfo.TYPE_SYSTEM;
    }

    public boolean isNavigationBar(int windowId) {
        if (mWindows == null || mWindows.size() < 2) {
            return false;
        }

        int lastIndex = mWindows.size() - 1;
        return mWindows.get(lastIndex).getId() == windowId
                && mWindows.get(lastIndex).getType() == AccessibilityWindowInfo.TYPE_SYSTEM;
    }

    /**
     * @return window that is next relatively currently accessibilityFocused window.
     * If there is no accessibility focused window it returns first window that has TYPE_APPLICATION
     * or null if there is no window with TYPE_APPLICATION type
     */
    public AccessibilityWindowInfo getNextWindow(AccessibilityWindowInfo pivotWindow) {
        return getWindow(pivotWindow, NEXT);
    }

    private AccessibilityWindowInfo getWindow(AccessibilityWindowInfo pivotWindow, int direction) {
        if (mWindows == null || pivotWindow == null || (direction != NEXT && direction != PREVIOUS)) {
            return null;
        }

        int currentWindowIndex = getWindowIndex(pivotWindow);
        int resultIndex;
        if (direction == NEXT) {
            resultIndex = getNextWindowIndex(currentWindowIndex);
        } else {
            resultIndex = getPreviousWindowIndex(currentWindowIndex);
        }

        if (resultIndex == WRONG_INDEX) {
            return null;
        }

        return mWindows.get(resultIndex);
    }

    private int getNextWindowIndex(int currentIndex) {
        int size = mWindows.size();
        if (size == 0 || currentIndex < 0 || currentIndex >= size) {
            return WRONG_INDEX;
        }

        currentIndex++;
        if (currentIndex > size - 1) {
            currentIndex = 0;
        }
        return currentIndex;
    }

    private int getPreviousWindowIndex(int currentIndex) {
        int size = mWindows.size();
        if (size == 0 || currentIndex < 0 || currentIndex >= size) {
            return WRONG_INDEX;
        }

        currentIndex--;
        if (currentIndex < 0) {
            currentIndex = size - 1;
        }
        return currentIndex;
    }

    private int getWindowIndex(AccessibilityWindowInfo windowInfo) {
        if (mWindows == null || windowInfo == null) {
            return WRONG_INDEX;
        }

        int windowSize = mWindows.size();
        for (int i = 0; i < windowSize; i++) {
            if (windowInfo.equals(mWindows.get(i))) {
                return i;
            }
        }

        return WRONG_INDEX;
    }

    private static int getFocusedWindowIndex(List<AccessibilityWindowInfo> windows, int focusType) {
        if (windows == null) {
            return WRONG_INDEX;
        }

        for (int i = 0, size = windows.size(); i < size; i++) {
            AccessibilityWindowInfo window = windows.get(i);
            if (window == null) {
                continue;
            }

            if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY && window.isAccessibilityFocused()) {
                return i;
            } else if (focusType == AccessibilityNodeInfo.FOCUS_INPUT && window.isFocused()) {
                return i;
            }
        }

        return WRONG_INDEX;
    }

    private static AccessibilityWindowInfo getDefaultWindow(List<AccessibilityWindowInfo> windows) {
        if (windows.size() == 0) {
            return null;
        }

        for (AccessibilityWindowInfo window : windows) {
            if (window != null && window.getType() == AccessibilityWindowInfo.TYPE_APPLICATION) {
                return window;
            }
        }

        return windows.get(0);
    }

    public static CharSequence formatWindowTitleForFeedback(CharSequence windowTitle, Context context) {
        if (windowTitle == null) {
            return context.getString(R.string.untitled_window);
        }

        return windowTitle;
    }
}