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