1 package com.android.launcher3;
2 
3 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
4 
5 import android.annotation.TargetApi;
6 import android.content.Context;
7 import android.graphics.Rect;
8 import android.os.Build;
9 import android.util.AttributeSet;
10 import android.view.ViewDebug;
11 import android.view.WindowInsets;
12 
13 import com.android.launcher3.statemanager.StatefulActivity;
14 
15 import java.util.Collections;
16 import java.util.List;
17 
18 public class LauncherRootView extends InsettableFrameLayout {
19 
20     private final Rect mTempRect = new Rect();
21 
22     private final StatefulActivity mActivity;
23 
24     @ViewDebug.ExportedProperty(category = "launcher")
25     private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
26             Collections.singletonList(new Rect());
27 
28     private WindowStateListener mWindowStateListener;
29     @ViewDebug.ExportedProperty(category = "launcher")
30     private boolean mDisallowBackGesture;
31     @ViewDebug.ExportedProperty(category = "launcher")
32     private boolean mForceHideBackArrow;
33 
LauncherRootView(Context context, AttributeSet attrs)34     public LauncherRootView(Context context, AttributeSet attrs) {
35         super(context, attrs);
36         mActivity = StatefulActivity.fromContext(context);
37     }
38 
handleSystemWindowInsets(Rect insets)39     private void handleSystemWindowInsets(Rect insets) {
40         // Update device profile before notifying th children.
41         mActivity.getDeviceProfile().updateInsets(insets);
42         boolean resetState = !insets.equals(mInsets);
43         setInsets(insets);
44 
45         if (resetState) {
46             mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
47         }
48     }
49 
50     @Override
onApplyWindowInsets(WindowInsets insets)51     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
52         mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
53                 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
54         handleSystemWindowInsets(mTempRect);
55         return insets;
56     }
57 
58     @Override
setInsets(Rect insets)59     public void setInsets(Rect insets) {
60         // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
61         // modifying child layout params.
62         if (!insets.equals(mInsets)) {
63             super.setInsets(insets);
64         }
65     }
66 
dispatchInsets()67     public void dispatchInsets() {
68         mActivity.getDeviceProfile().updateInsets(mInsets);
69         super.setInsets(mInsets);
70     }
71 
setWindowStateListener(WindowStateListener listener)72     public void setWindowStateListener(WindowStateListener listener) {
73         mWindowStateListener = listener;
74     }
75 
76     @Override
onWindowFocusChanged(boolean hasWindowFocus)77     public void onWindowFocusChanged(boolean hasWindowFocus) {
78         super.onWindowFocusChanged(hasWindowFocus);
79         if (mWindowStateListener != null) {
80             mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
81         }
82     }
83 
84     @Override
onWindowVisibilityChanged(int visibility)85     protected void onWindowVisibilityChanged(int visibility) {
86         super.onWindowVisibilityChanged(visibility);
87         if (mWindowStateListener != null) {
88             mWindowStateListener.onWindowVisibilityChanged(visibility);
89         }
90     }
91 
92     @Override
onLayout(boolean changed, int l, int t, int r, int b)93     protected void onLayout(boolean changed, int l, int t, int r, int b) {
94         super.onLayout(changed, l, t, r, b);
95         SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
96         setDisallowBackGesture(mDisallowBackGesture);
97     }
98 
99     @TargetApi(Build.VERSION_CODES.Q)
setForceHideBackArrow(boolean forceHideBackArrow)100     public void setForceHideBackArrow(boolean forceHideBackArrow) {
101         this.mForceHideBackArrow = forceHideBackArrow;
102         setDisallowBackGesture(mDisallowBackGesture);
103     }
104 
105     @TargetApi(Build.VERSION_CODES.Q)
setDisallowBackGesture(boolean disallowBackGesture)106     public void setDisallowBackGesture(boolean disallowBackGesture) {
107         if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
108             return;
109         }
110         mDisallowBackGesture = disallowBackGesture;
111         setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture)
112                 ? SYSTEM_GESTURE_EXCLUSION_RECT
113                 : Collections.emptyList());
114     }
115 
116     public interface WindowStateListener {
117 
onWindowFocusChanged(boolean hasFocus)118         void onWindowFocusChanged(boolean hasFocus);
119 
onWindowVisibilityChanged(int visibility)120         void onWindowVisibilityChanged(int visibility);
121     }
122 }