blob: 8eccc04fa647fe9d5a375ad83ff2ddd4a426a2d4 [file] [log] [blame]
Adam Powell769b8632019-02-04 11:28:22 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.graphics.Rect;
22
23import java.lang.ref.WeakReference;
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.Iterator;
27import java.util.List;
28
29/**
30 * Used by {@link ViewRootImpl} to track system gesture exclusion rects reported by views.
31 */
32class GestureExclusionTracker {
33 private boolean mGestureExclusionViewsChanged = false;
34 private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>();
35 private List<Rect> mGestureExclusionRects = Collections.emptyList();
36
37 public void updateRectsForView(@NonNull View view) {
38 boolean found = false;
39 final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator();
40 while (i.hasNext()) {
41 final GestureExclusionViewInfo info = i.next();
42 final View v = info.getView();
43 if (v == null || !v.isAttachedToWindow()) {
44 mGestureExclusionViewsChanged = true;
45 i.remove();
46 continue;
47 }
48 if (v == view) {
49 found = true;
50 info.mDirty = true;
51 break;
52 }
53 }
54 if (!found && view.isAttachedToWindow()) {
55 mGestureExclusionViewInfos.add(new GestureExclusionViewInfo(view));
56 mGestureExclusionViewsChanged = true;
57 }
58 }
59
60 @Nullable
61 public List<Rect> computeChangedRects() {
62 boolean changed = false;
63 final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator();
64 final List<Rect> rects = new ArrayList<>();
65 while (i.hasNext()) {
66 final GestureExclusionViewInfo info = i.next();
67 switch (info.update()) {
68 case GestureExclusionViewInfo.CHANGED:
69 changed = true;
70 // Deliberate fall-through
71 case GestureExclusionViewInfo.UNCHANGED:
72 rects.addAll(info.mExclusionRects);
73 break;
74 case GestureExclusionViewInfo.GONE:
75 mGestureExclusionViewsChanged = true;
76 i.remove();
77 break;
78 }
79 }
80 if (changed || mGestureExclusionViewsChanged) {
81 mGestureExclusionViewsChanged = false;
82 if (!mGestureExclusionRects.equals(rects)) {
83 mGestureExclusionRects = rects;
84 return rects;
85 }
86 }
87 return null;
88 }
89
90 private static class GestureExclusionViewInfo {
91 public static final int CHANGED = 0;
92 public static final int UNCHANGED = 1;
93 public static final int GONE = 2;
94
95 private final WeakReference<View> mView;
96 boolean mDirty = true;
97 List<Rect> mExclusionRects = Collections.emptyList();
98
99 GestureExclusionViewInfo(View view) {
100 mView = new WeakReference<>(view);
101 }
102
103 public View getView() {
104 return mView.get();
105 }
106
107 public int update() {
108 final View excludedView = getView();
109 if (excludedView == null || !excludedView.isAttachedToWindow()) return GONE;
110 final List<Rect> localRects = excludedView.getSystemGestureExclusionRects();
111 final List<Rect> newRects = new ArrayList<>(localRects.size());
112 for (Rect src : localRects) {
113 Rect mappedRect = new Rect(src);
114 ViewParent p = excludedView.getParent();
115 if (p != null && p.getChildVisibleRect(excludedView, mappedRect, null)) {
116 newRects.add(mappedRect);
117 }
118 }
119
120 if (mExclusionRects.equals(localRects)) return UNCHANGED;
121 mExclusionRects = newRects;
122 return CHANGED;
123 }
124 }
125}