1 /* 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 17 package android.view; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.graphics.Rect; 22 23 import com.android.internal.util.Preconditions; 24 25 import java.lang.ref.WeakReference; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.Iterator; 29 import java.util.List; 30 31 /** 32 * Used by {@link ViewRootImpl} to track system gesture exclusion rects reported by views. 33 */ 34 class GestureExclusionTracker { 35 private boolean mGestureExclusionViewsChanged = false; 36 private boolean mRootGestureExclusionRectsChanged = false; 37 private List<Rect> mRootGestureExclusionRects = Collections.emptyList(); 38 private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>(); 39 private List<Rect> mGestureExclusionRects = Collections.emptyList(); 40 updateRectsForView(@onNull View view)41 public void updateRectsForView(@NonNull View view) { 42 boolean found = false; 43 final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator(); 44 while (i.hasNext()) { 45 final GestureExclusionViewInfo info = i.next(); 46 final View v = info.getView(); 47 if (v == null || !v.isAttachedToWindow() || !v.isAggregatedVisible()) { 48 mGestureExclusionViewsChanged = true; 49 i.remove(); 50 continue; 51 } 52 if (v == view) { 53 found = true; 54 info.mDirty = true; 55 break; 56 } 57 } 58 if (!found && view.isAttachedToWindow()) { 59 mGestureExclusionViewInfos.add(new GestureExclusionViewInfo(view)); 60 mGestureExclusionViewsChanged = true; 61 } 62 } 63 64 @Nullable computeChangedRects()65 public List<Rect> computeChangedRects() { 66 boolean changed = mRootGestureExclusionRectsChanged; 67 final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator(); 68 final List<Rect> rects = new ArrayList<>(mRootGestureExclusionRects); 69 while (i.hasNext()) { 70 final GestureExclusionViewInfo info = i.next(); 71 switch (info.update()) { 72 case GestureExclusionViewInfo.CHANGED: 73 changed = true; 74 // Deliberate fall-through 75 case GestureExclusionViewInfo.UNCHANGED: 76 rects.addAll(info.mExclusionRects); 77 break; 78 case GestureExclusionViewInfo.GONE: 79 mGestureExclusionViewsChanged = true; 80 i.remove(); 81 break; 82 } 83 } 84 if (changed || mGestureExclusionViewsChanged) { 85 mGestureExclusionViewsChanged = false; 86 mRootGestureExclusionRectsChanged = false; 87 if (!mGestureExclusionRects.equals(rects)) { 88 mGestureExclusionRects = rects; 89 return rects; 90 } 91 } 92 return null; 93 } 94 setRootSystemGestureExclusionRects(@onNull List<Rect> rects)95 public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { 96 Preconditions.checkNotNull(rects, "rects must not be null"); 97 mRootGestureExclusionRects = rects; 98 mRootGestureExclusionRectsChanged = true; 99 } 100 101 @NonNull getRootSystemGestureExclusionRects()102 public List<Rect> getRootSystemGestureExclusionRects() { 103 return mRootGestureExclusionRects; 104 } 105 106 private static class GestureExclusionViewInfo { 107 public static final int CHANGED = 0; 108 public static final int UNCHANGED = 1; 109 public static final int GONE = 2; 110 111 private final WeakReference<View> mView; 112 boolean mDirty = true; 113 List<Rect> mExclusionRects = Collections.emptyList(); 114 GestureExclusionViewInfo(View view)115 GestureExclusionViewInfo(View view) { 116 mView = new WeakReference<>(view); 117 } 118 getView()119 public View getView() { 120 return mView.get(); 121 } 122 update()123 public int update() { 124 final View excludedView = getView(); 125 if (excludedView == null || !excludedView.isAttachedToWindow() 126 || !excludedView.isAggregatedVisible()) return GONE; 127 final List<Rect> localRects = excludedView.getSystemGestureExclusionRects(); 128 final List<Rect> newRects = new ArrayList<>(localRects.size()); 129 for (Rect src : localRects) { 130 Rect mappedRect = new Rect(src); 131 ViewParent p = excludedView.getParent(); 132 if (p != null && p.getChildVisibleRect(excludedView, mappedRect, null)) { 133 newRects.add(mappedRect); 134 } 135 } 136 137 if (mExclusionRects.equals(localRects)) return UNCHANGED; 138 mExclusionRects = newRects; 139 return CHANGED; 140 } 141 } 142 } 143