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