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.StatefulContainer; 14 import com.android.launcher3.util.window.WindowManagerProxy; 15 import com.android.launcher3.views.ActivityContext; 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 StatefulContainer mStatefulContainer; 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 mStatefulContainer = ActivityContext.lookupContext(context); 41 mSysUiScrim = new SysUiScrim(this); 42 } 43 handleSystemWindowInsets(Rect insets)44 private void handleSystemWindowInsets(Rect insets) { 45 // Update device profile before notifying the children. 46 mStatefulContainer.getDeviceProfile().updateInsets(insets); 47 boolean resetState = !insets.equals(mInsets); 48 setInsets(insets); 49 50 if (resetState) { 51 mStatefulContainer.getStateManager().reapplyState(true /* cancelCurrentAnimation */); 52 } 53 } 54 55 @Override onApplyWindowInsets(WindowInsets insets)56 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 57 mStatefulContainer.handleConfigurationChanged( 58 mStatefulContainer.asContext().getResources().getConfiguration()); 59 return updateInsets(insets); 60 } 61 updateInsets(WindowInsets insets)62 private WindowInsets updateInsets(WindowInsets insets) { 63 insets = WindowManagerProxy.INSTANCE.get(getContext()) 64 .normalizeWindowInsets(getContext(), insets, mTempRect); 65 handleSystemWindowInsets(mTempRect); 66 return insets; 67 } 68 69 @Override setInsets(Rect insets)70 public void setInsets(Rect insets) { 71 // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by 72 // modifying child layout params. 73 if (!insets.equals(mInsets)) { 74 super.setInsets(insets); 75 mSysUiScrim.onInsetsChanged(insets); 76 } 77 } 78 dispatchInsets()79 public void dispatchInsets() { 80 if (isAttachedToWindow()) { 81 updateInsets(getRootWindowInsets()); 82 } else { 83 mStatefulContainer.getDeviceProfile().updateInsets(mInsets); 84 } 85 super.setInsets(mInsets); 86 } 87 setWindowStateListener(WindowStateListener listener)88 public void setWindowStateListener(WindowStateListener listener) { 89 mWindowStateListener = listener; 90 } 91 92 @Override onWindowFocusChanged(boolean hasWindowFocus)93 public void onWindowFocusChanged(boolean hasWindowFocus) { 94 super.onWindowFocusChanged(hasWindowFocus); 95 if (mWindowStateListener != null) { 96 mWindowStateListener.onWindowFocusChanged(hasWindowFocus); 97 } 98 } 99 100 @Override onWindowVisibilityChanged(int visibility)101 protected void onWindowVisibilityChanged(int visibility) { 102 super.onWindowVisibilityChanged(visibility); 103 if (mWindowStateListener != null) { 104 mWindowStateListener.onWindowVisibilityChanged(visibility); 105 } 106 } 107 108 @Override dispatchDraw(Canvas canvas)109 protected void dispatchDraw(Canvas canvas) { 110 mSysUiScrim.draw(canvas); 111 super.dispatchDraw(canvas); 112 } 113 114 @Override onLayout(boolean changed, int l, int t, int r, int b)115 protected void onLayout(boolean changed, int l, int t, int r, int b) { 116 super.onLayout(changed, l, t, r, b); 117 SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b); 118 setDisallowBackGesture(mDisallowBackGesture); 119 mSysUiScrim.setSize(r - l, b - t); 120 } 121 setForceHideBackArrow(boolean forceHideBackArrow)122 public void setForceHideBackArrow(boolean forceHideBackArrow) { 123 this.mForceHideBackArrow = forceHideBackArrow; 124 setDisallowBackGesture(mDisallowBackGesture); 125 } 126 setDisallowBackGesture(boolean disallowBackGesture)127 public void setDisallowBackGesture(boolean disallowBackGesture) { 128 if (SEPARATE_RECENTS_ACTIVITY.get()) { 129 return; 130 } 131 mDisallowBackGesture = disallowBackGesture; 132 setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture) 133 ? SYSTEM_GESTURE_EXCLUSION_RECT 134 : Collections.emptyList()); 135 } 136 getSysUiScrim()137 public SysUiScrim getSysUiScrim() { 138 return mSysUiScrim; 139 } 140 141 public interface WindowStateListener { 142 onWindowFocusChanged(boolean hasFocus)143 void onWindowFocusChanged(boolean hasFocus); 144 onWindowVisibilityChanged(int visibility)145 void onWindowVisibilityChanged(int visibility); 146 } 147 } 148