blob: fffb323e6d500b24bc8de43efee65f2c2907018b [file] [log] [blame]
/*
* Copyright (C) 2019 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 android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Used by {@link ViewRootImpl} to track system gesture exclusion rects reported by views.
*/
class GestureExclusionTracker {
private boolean mGestureExclusionViewsChanged = false;
private boolean mRootGestureExclusionRectsChanged = false;
private List<Rect> mRootGestureExclusionRects = Collections.emptyList();
private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>();
private List<Rect> mGestureExclusionRects = Collections.emptyList();
public void updateRectsForView(@NonNull View view) {
boolean found = false;
final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator();
while (i.hasNext()) {
final GestureExclusionViewInfo info = i.next();
final View v = info.getView();
if (v == null || !v.isAttachedToWindow() || !v.isAggregatedVisible()) {
mGestureExclusionViewsChanged = true;
i.remove();
continue;
}
if (v == view) {
found = true;
info.mDirty = true;
break;
}
}
if (!found && view.isAttachedToWindow()) {
mGestureExclusionViewInfos.add(new GestureExclusionViewInfo(view));
mGestureExclusionViewsChanged = true;
}
}
@Nullable
public List<Rect> computeChangedRects() {
boolean changed = mRootGestureExclusionRectsChanged;
final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator();
final List<Rect> rects = new ArrayList<>(mRootGestureExclusionRects);
while (i.hasNext()) {
final GestureExclusionViewInfo info = i.next();
switch (info.update()) {
case GestureExclusionViewInfo.CHANGED:
changed = true;
// Deliberate fall-through
case GestureExclusionViewInfo.UNCHANGED:
rects.addAll(info.mExclusionRects);
break;
case GestureExclusionViewInfo.GONE:
mGestureExclusionViewsChanged = true;
i.remove();
break;
}
}
if (changed || mGestureExclusionViewsChanged) {
mGestureExclusionViewsChanged = false;
mRootGestureExclusionRectsChanged = false;
if (!mGestureExclusionRects.equals(rects)) {
mGestureExclusionRects = rects;
return rects;
}
}
return null;
}
public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
Preconditions.checkNotNull(rects, "rects must not be null");
mRootGestureExclusionRects = rects;
mRootGestureExclusionRectsChanged = true;
}
@NonNull
public List<Rect> getRootSystemGestureExclusionRects() {
return mRootGestureExclusionRects;
}
private static class GestureExclusionViewInfo {
public static final int CHANGED = 0;
public static final int UNCHANGED = 1;
public static final int GONE = 2;
private final WeakReference<View> mView;
boolean mDirty = true;
List<Rect> mExclusionRects = Collections.emptyList();
GestureExclusionViewInfo(View view) {
mView = new WeakReference<>(view);
}
public View getView() {
return mView.get();
}
public int update() {
final View excludedView = getView();
if (excludedView == null || !excludedView.isAttachedToWindow()
|| !excludedView.isAggregatedVisible()) return GONE;
final List<Rect> localRects = excludedView.getSystemGestureExclusionRects();
final List<Rect> newRects = new ArrayList<>(localRects.size());
for (Rect src : localRects) {
Rect mappedRect = new Rect(src);
ViewParent p = excludedView.getParent();
if (p != null && p.getChildVisibleRect(excludedView, mappedRect, null)) {
newRects.add(mappedRect);
}
}
if (mExclusionRects.equals(localRects)) return UNCHANGED;
mExclusionRects = newRects;
return CHANGED;
}
}
}