• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Canvas;
8 import android.graphics.Rect;
9 import android.os.Build;
10 import android.util.AttributeSet;
11 import android.view.ViewDebug;
12 import android.view.WindowInsets;
13 
14 import com.android.launcher3.graphics.SysUiScrim;
15 import com.android.launcher3.statemanager.StatefulActivity;
16 
17 import java.util.Collections;
18 import java.util.List;
19 
20 public class LauncherRootView extends InsettableFrameLayout {
21 
22     private final Rect mTempRect = new Rect();
23 
24     private final StatefulActivity mActivity;
25 
26     @ViewDebug.ExportedProperty(category = "launcher")
27     private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
28             Collections.singletonList(new Rect());
29 
30     private WindowStateListener mWindowStateListener;
31     @ViewDebug.ExportedProperty(category = "launcher")
32     private boolean mDisallowBackGesture;
33     @ViewDebug.ExportedProperty(category = "launcher")
34     private boolean mForceHideBackArrow;
35 
36     private final SysUiScrim mSysUiScrim;
37 
LauncherRootView(Context context, AttributeSet attrs)38     public LauncherRootView(Context context, AttributeSet attrs) {
39         super(context, attrs);
40         mActivity = StatefulActivity.fromContext(context);
41         mSysUiScrim = new SysUiScrim(this);
42     }
43 
handleSystemWindowInsets(Rect insets)44     private void handleSystemWindowInsets(Rect insets) {
45         DeviceProfile dp = mActivity.getDeviceProfile();
46 
47         // Taskbar provides insets, but we don't want that for most Launcher elements so remove it.
48         mTempRect.set(insets);
49         insets = mTempRect;
50         insets.bottom = Math.max(0, insets.bottom - dp.nonOverlappingTaskbarInset);
51 
52         // Update device profile before notifying the children.
53         dp.updateInsets(insets);
54         boolean resetState = !insets.equals(mInsets);
55         setInsets(insets);
56 
57         if (resetState) {
58             mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
59         }
60     }
61 
62     @Override
onApplyWindowInsets(WindowInsets insets)63     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
64         mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
65                 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
66         handleSystemWindowInsets(mTempRect);
67         return insets;
68     }
69 
70     @Override
setInsets(Rect insets)71     public void setInsets(Rect insets) {
72         // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
73         // modifying child layout params.
74         if (!insets.equals(mInsets)) {
75             super.setInsets(insets);
76             mSysUiScrim.onInsetsChanged(insets);
77         }
78     }
79 
dispatchInsets()80     public void dispatchInsets() {
81         mActivity.getDeviceProfile().updateInsets(mInsets);
82         super.setInsets(mInsets);
83     }
84 
setWindowStateListener(WindowStateListener listener)85     public void setWindowStateListener(WindowStateListener listener) {
86         mWindowStateListener = listener;
87     }
88 
89     @Override
onWindowFocusChanged(boolean hasWindowFocus)90     public void onWindowFocusChanged(boolean hasWindowFocus) {
91         super.onWindowFocusChanged(hasWindowFocus);
92         if (mWindowStateListener != null) {
93             mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
94         }
95     }
96 
97     @Override
onWindowVisibilityChanged(int visibility)98     protected void onWindowVisibilityChanged(int visibility) {
99         super.onWindowVisibilityChanged(visibility);
100         if (mWindowStateListener != null) {
101             mWindowStateListener.onWindowVisibilityChanged(visibility);
102         }
103     }
104 
105     @Override
dispatchDraw(Canvas canvas)106     protected void dispatchDraw(Canvas canvas) {
107         mSysUiScrim.draw(canvas);
108         super.dispatchDraw(canvas);
109     }
110 
111     @Override
onLayout(boolean changed, int l, int t, int r, int b)112     protected void onLayout(boolean changed, int l, int t, int r, int b) {
113         super.onLayout(changed, l, t, r, b);
114         SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
115         setDisallowBackGesture(mDisallowBackGesture);
116         mSysUiScrim.setSize(r - l, b - t);
117     }
118 
119     @TargetApi(Build.VERSION_CODES.Q)
setForceHideBackArrow(boolean forceHideBackArrow)120     public void setForceHideBackArrow(boolean forceHideBackArrow) {
121         this.mForceHideBackArrow = forceHideBackArrow;
122         setDisallowBackGesture(mDisallowBackGesture);
123     }
124 
125     @TargetApi(Build.VERSION_CODES.Q)
setDisallowBackGesture(boolean disallowBackGesture)126     public void setDisallowBackGesture(boolean disallowBackGesture) {
127         if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
128             return;
129         }
130         mDisallowBackGesture = disallowBackGesture;
131         setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture)
132                 ? SYSTEM_GESTURE_EXCLUSION_RECT
133                 : Collections.emptyList());
134     }
135 
getSysUiScrim()136     public SysUiScrim getSysUiScrim() {
137         return mSysUiScrim;
138     }
139 
140     public interface WindowStateListener {
141 
onWindowFocusChanged(boolean hasFocus)142         void onWindowFocusChanged(boolean hasFocus);
143 
onWindowVisibilityChanged(int visibility)144         void onWindowVisibilityChanged(int visibility);
145     }
146 }
147