blob: 5ef3690ddfa693f280b3e9031fca74434b417f07 [file] [log] [blame]
Adam Cohena6d04922014-10-23 17:28:30 -07001package com.android.launcher3;
2
Alex Chaubbe6cf32021-10-12 15:52:36 +01003import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
Sunny Goyala314d5a2020-05-20 20:34:04 -07004import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
Sunny Goyaled2d2bc2018-04-19 12:34:43 -07005
Sunny Goyal93264612015-11-23 11:47:50 -08006import android.annotation.TargetApi;
Adam Cohena6d04922014-10-23 17:28:30 -07007import android.content.Context;
Tony Wickham7eb5b532021-09-17 17:08:46 -07008import android.content.res.Resources;
Adam Cohen501e1392021-02-02 16:45:07 -08009import android.graphics.Canvas;
Tony Wickham7eb5b532021-09-17 17:08:46 -070010import android.graphics.Insets;
Adam Cohena6d04922014-10-23 17:28:30 -070011import android.graphics.Rect;
Tony Wickham12e8a342019-04-23 11:28:54 -070012import android.os.Build;
Adam Cohena6d04922014-10-23 17:28:30 -070013import android.util.AttributeSet;
Sunny Goyal4ffec482016-02-09 11:28:52 -080014import android.view.ViewDebug;
Sunny Goyal022b1822019-06-12 08:44:09 -070015import android.view.WindowInsets;
Adam Cohena6d04922014-10-23 17:28:30 -070016
Tony Wickham7eb5b532021-09-17 17:08:46 -070017import androidx.annotation.RequiresApi;
18
Adam Cohen501e1392021-02-02 16:45:07 -080019import com.android.launcher3.graphics.SysUiScrim;
Sunny Goyal9d89f752020-06-19 11:09:24 -070020import com.android.launcher3.statemanager.StatefulActivity;
Tony Wickham7eb5b532021-09-17 17:08:46 -070021import com.android.launcher3.uioverrides.ApiWrapper;
Sunny Goyal9d89f752020-06-19 11:09:24 -070022
Tony Wickham12e8a342019-04-23 11:28:54 -070023import java.util.Collections;
24import java.util.List;
25
Adam Cohena6d04922014-10-23 17:28:30 -070026public class LauncherRootView extends InsettableFrameLayout {
Sunny Goyal0abb36f2015-06-23 10:53:59 -070027
Sunny Goyal022b1822019-06-12 08:44:09 -070028 private final Rect mTempRect = new Rect();
29
Sunny Goyal9d89f752020-06-19 11:09:24 -070030 private final StatefulActivity mActivity;
Sunny Goyal07b69292018-01-08 14:19:34 -080031
Sunny Goyal745df7c2019-04-03 15:25:00 -070032 @ViewDebug.ExportedProperty(category = "launcher")
Tony Wickham12e8a342019-04-23 11:28:54 -070033 private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
34 Collections.singletonList(new Rect());
35
Sunny Goyal7185dd62018-03-14 17:51:49 -070036 private WindowStateListener mWindowStateListener;
Tony Wickham12e8a342019-04-23 11:28:54 -070037 @ViewDebug.ExportedProperty(category = "launcher")
38 private boolean mDisallowBackGesture;
Vinit Nayak9a846212019-09-05 11:47:12 -070039 @ViewDebug.ExportedProperty(category = "launcher")
40 private boolean mForceHideBackArrow;
Sunny Goyal93264612015-11-23 11:47:50 -080041
Sunny Goyal4ed0fb52021-04-26 09:52:47 -070042 private final SysUiScrim mSysUiScrim;
Adam Cohen501e1392021-02-02 16:45:07 -080043
Adam Cohena6d04922014-10-23 17:28:30 -070044 public LauncherRootView(Context context, AttributeSet attrs) {
45 super(context, attrs);
Sunny Goyal9d89f752020-06-19 11:09:24 -070046 mActivity = StatefulActivity.fromContext(context);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -070047 mSysUiScrim = new SysUiScrim(this);
Adam Cohena6d04922014-10-23 17:28:30 -070048 }
49
Sunny Goyal022b1822019-06-12 08:44:09 -070050 private void handleSystemWindowInsets(Rect insets) {
Tony Wickham145b7fd2021-03-11 10:03:12 -080051 // Update device profile before notifying the children.
Tony Wickham21970cc2021-09-15 15:44:05 -070052 mActivity.getDeviceProfile().updateInsets(insets);
Sunny Goyalce8809a2018-01-18 14:02:47 -080053 boolean resetState = !insets.equals(mInsets);
Sunny Goyal906c6b22017-08-18 00:35:52 -070054 setInsets(insets);
55
Sunny Goyalce8809a2018-01-18 14:02:47 -080056 if (resetState) {
Sunny Goyal9d89f752020-06-19 11:09:24 -070057 mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
Sunny Goyalce8809a2018-01-18 14:02:47 -080058 }
Sunny Goyal022b1822019-06-12 08:44:09 -070059 }
Sunny Goyal0abb36f2015-06-23 10:53:59 -070060
Sunny Goyal022b1822019-06-12 08:44:09 -070061 @Override
62 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Tony Wickham7eb5b532021-09-17 17:08:46 -070063 if (Utilities.ATLEAST_R) {
64 insets = updateInsetsDueToTaskbar(insets);
65 Insets systemWindowInsets = insets.getInsetsIgnoringVisibility(
66 WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
67 mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
68 systemWindowInsets.bottom);
69 } else {
70 mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
71 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
72 }
Sunny Goyal022b1822019-06-12 08:44:09 -070073 handleSystemWindowInsets(mTempRect);
Sunny Goyal786940a2020-06-02 02:31:31 -070074 return insets;
Adam Cohena6d04922014-10-23 17:28:30 -070075 }
Sunny Goyal0abb36f2015-06-23 10:53:59 -070076
Tony Wickham7eb5b532021-09-17 17:08:46 -070077 /**
78 * Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately,
79 * and can be destroyed and recreated. Thus, instead of relying on taskbar being present to
80 * get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
81 * is currently attached.
82 *
Tony Wickham7eb5b532021-09-17 17:08:46 -070083 * @param oldInsets The system-provided insets, which we are modifying.
84 * @return The updated insets.
85 */
86 @RequiresApi(api = Build.VERSION_CODES.R)
87 private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) {
88 if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) {
89 // 3P launchers based on Launcher3 should still be inset like normal.
90 return oldInsets;
91 }
92
93 WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
94
95 DeviceProfile dp = mActivity.getDeviceProfile();
96 Resources resources = getResources();
97
98 Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
99 Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
100 oldNavInsets.bottom);
Tony Wickham21970cc2021-09-15 15:44:05 -0700101
102 if (dp.isLandscape) {
Alex Chaubbe6cf32021-10-12 15:52:36 +0100103 boolean isGesturalMode = ResourceUtils.getIntegerByName(
104 "config_navBarInteractionMode",
105 resources,
106 INVALID_RESOURCE_HANDLE) == 2;
107 if (dp.isTablet || isGesturalMode) {
Tony Wickham7eb5b532021-09-17 17:08:46 -0700108 newNavInsets.bottom = ResourceUtils.getNavbarSize(
109 "navigation_bar_height_landscape", resources);
110 } else {
111 int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
112 if (dp.isSeascape()) {
113 newNavInsets.left = navWidth;
114 } else {
115 newNavInsets.right = navWidth;
116 }
117 }
118 } else {
119 newNavInsets.bottom = ResourceUtils.getNavbarSize("navigation_bar_height", resources);
120 }
121 updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
122 updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
123 Insets.of(newNavInsets));
124
125 mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets);
126
127 return updatedInsetsBuilder.build();
128 }
129
Jon Mirandade43a712018-01-18 11:35:10 -0800130 @Override
131 public void setInsets(Rect insets) {
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800132 // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
133 // modifying child layout params.
134 if (!insets.equals(mInsets)) {
135 super.setInsets(insets);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700136 mSysUiScrim.onInsetsChanged(insets);
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800137 }
Jon Mirandade43a712018-01-18 11:35:10 -0800138 }
139
Sunny Goyal07b69292018-01-08 14:19:34 -0800140 public void dispatchInsets() {
Sunny Goyal9d89f752020-06-19 11:09:24 -0700141 mActivity.getDeviceProfile().updateInsets(mInsets);
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800142 super.setInsets(mInsets);
Sunny Goyal07b69292018-01-08 14:19:34 -0800143 }
144
Sunny Goyal7185dd62018-03-14 17:51:49 -0700145 public void setWindowStateListener(WindowStateListener listener) {
146 mWindowStateListener = listener;
147 }
148
149 @Override
150 public void onWindowFocusChanged(boolean hasWindowFocus) {
151 super.onWindowFocusChanged(hasWindowFocus);
152 if (mWindowStateListener != null) {
153 mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
154 }
155 }
156
157 @Override
158 protected void onWindowVisibilityChanged(int visibility) {
159 super.onWindowVisibilityChanged(visibility);
160 if (mWindowStateListener != null) {
161 mWindowStateListener.onWindowVisibilityChanged(visibility);
162 }
163 }
164
Adam Cohen501e1392021-02-02 16:45:07 -0800165 @Override
166 protected void dispatchDraw(Canvas canvas) {
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700167 mSysUiScrim.draw(canvas);
Adam Cohen501e1392021-02-02 16:45:07 -0800168 super.dispatchDraw(canvas);
169 }
170
Sunny Goyal745df7c2019-04-03 15:25:00 -0700171 @Override
Tony Wickham12e8a342019-04-23 11:28:54 -0700172 protected void onLayout(boolean changed, int l, int t, int r, int b) {
173 super.onLayout(changed, l, t, r, b);
174 SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
175 setDisallowBackGesture(mDisallowBackGesture);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700176 mSysUiScrim.setSize(r - l, b - t);
Tony Wickham12e8a342019-04-23 11:28:54 -0700177 }
178
179 @TargetApi(Build.VERSION_CODES.Q)
Vinit Nayak9a846212019-09-05 11:47:12 -0700180 public void setForceHideBackArrow(boolean forceHideBackArrow) {
181 this.mForceHideBackArrow = forceHideBackArrow;
182 setDisallowBackGesture(mDisallowBackGesture);
183 }
184
185 @TargetApi(Build.VERSION_CODES.Q)
Tony Wickham12e8a342019-04-23 11:28:54 -0700186 public void setDisallowBackGesture(boolean disallowBackGesture) {
Sunny Goyala314d5a2020-05-20 20:34:04 -0700187 if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
Tony Wickham12e8a342019-04-23 11:28:54 -0700188 return;
189 }
190 mDisallowBackGesture = disallowBackGesture;
Vinit Nayak9a846212019-09-05 11:47:12 -0700191 setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture)
Tony Wickham12e8a342019-04-23 11:28:54 -0700192 ? SYSTEM_GESTURE_EXCLUSION_RECT
193 : Collections.emptyList());
194 }
195
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700196 public SysUiScrim getSysUiScrim() {
197 return mSysUiScrim;
198 }
199
Sunny Goyal7185dd62018-03-14 17:51:49 -0700200 public interface WindowStateListener {
201
202 void onWindowFocusChanged(boolean hasFocus);
203
204 void onWindowVisibilityChanged(int visibility);
205 }
Adam Cohen501e1392021-02-02 16:45:07 -0800206}