1a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
3a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
4a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * you may not use this file except in compliance with the License.
6a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * You may obtain a copy of the License at
7a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
8a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes *
10a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * Unless required by applicable law or agreed to in writing, software
11a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * See the License for the specific language governing permissions and
14a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes * limitations under the License.
15a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes */
16a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.coordinatorlayout.widget;
1886be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY;
20a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
21eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikasimport android.graphics.Matrix;
22a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.graphics.Rect;
23eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikasimport android.graphics.RectF;
24a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.View;
25a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banesimport android.view.ViewGroup;
26eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikasimport android.view.ViewParent;
27a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
284464b955661a7c40f1dd16543f01ccef06fe011bAurimas Liutikasimport androidx.annotation.RestrictTo;
294464b955661a7c40f1dd16543f01ccef06fe011bAurimas Liutikas
3086be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov/**
3186be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov * @hide
3286be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov */
3386be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov@RestrictTo(LIBRARY)
3486be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikovpublic class ViewGroupUtils {
35eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas    private static final ThreadLocal<Matrix> sMatrix = new ThreadLocal<>();
36eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas    private static final ThreadLocal<RectF> sRectF = new ThreadLocal<>();
37a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
38a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
39a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * This is a port of the common
40a3f5b46ad2146979910e577297880ebbceab8858Kirill Grouchnikov     * {@link ViewGroup#offsetDescendantRectToMyCoords(View, Rect)}
41a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * from the framework, but adapted to take transformations into account. The result
42a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * will be the bounding rect of the real transformed rect.
43a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     *
44a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @param descendant view defining the original coordinate system of rect
45a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @param rect (in/out) the rect to offset from descendant to this view's coordinate system
46a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
47a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    static void offsetDescendantRect(ViewGroup parent, View descendant, Rect rect) {
48eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        Matrix m = sMatrix.get();
49eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        if (m == null) {
50eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            m = new Matrix();
51eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            sMatrix.set(m);
52eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        } else {
53eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            m.reset();
54eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        }
55eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas
56eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        offsetDescendantMatrix(parent, descendant, m);
57eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas
58eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        RectF rectF = sRectF.get();
59eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        if (rectF == null) {
60eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            rectF = new RectF();
61eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            sRectF.set(rectF);
62eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        }
63eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        rectF.set(rect);
64eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        m.mapRect(rectF);
65eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        rect.set((int) (rectF.left + 0.5f), (int) (rectF.top + 0.5f),
66eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas                (int) (rectF.right + 0.5f), (int) (rectF.bottom + 0.5f));
67a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
68a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
69a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    /**
70a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * Retrieve the transformed bounding rect of an arbitrary descendant view.
71a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * This does not need to be a direct child.
72a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     *
73a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @param descendant descendant view to reference
74a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     * @param out rect to set to the bounds of the descendant view
75a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes     */
7686be5dd64c0061b84b5a77d923d0a337d156937eKirill Grouchnikov    public static void getDescendantRect(ViewGroup parent, View descendant, Rect out) {
77a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        out.set(0, 0, descendant.getWidth(), descendant.getHeight());
78a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes        offsetDescendantRect(parent, descendant, out);
79a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes    }
80a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes
81eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas    private static void offsetDescendantMatrix(ViewParent target, View view, Matrix m) {
82eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        final ViewParent parent = view.getParent();
83eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        if (parent instanceof View && parent != target) {
84eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            final View vp = (View) parent;
85eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            offsetDescendantMatrix(target, vp, m);
86eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            m.preTranslate(-vp.getScrollX(), -vp.getScrollY());
87eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        }
88eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas
89eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        m.preTranslate(view.getLeft(), view.getTop());
90eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas
91eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        if (!view.getMatrix().isIdentity()) {
92eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas            m.preConcat(view.getMatrix());
93eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas        }
94eb316dbe383d6bba158527b2eafa9b7c982dbd99Aurimas Liutikas    }
950f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton
960f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton    private ViewGroupUtils() {
970f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton    }
98a6a508b2296730ca6954aaebcca52a9962a5cb55Chris Banes}
99