blob: 28afc5768bf23559f821c8daa1740c2672b51613 [file] [log] [blame]
Adam Cohena6d04922014-10-23 17:28:30 -07001package com.android.launcher3;
2
Sunny Goyala314d5a2020-05-20 20:34:04 -07003import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
Sunny Goyaled2d2bc2018-04-19 12:34:43 -07004
Sunny Goyal93264612015-11-23 11:47:50 -08005import android.annotation.TargetApi;
Adam Cohena6d04922014-10-23 17:28:30 -07006import android.content.Context;
Tony Wickham7eb5b532021-09-17 17:08:46 -07007import android.content.res.Resources;
Adam Cohen501e1392021-02-02 16:45:07 -08008import android.graphics.Canvas;
Tony Wickham7eb5b532021-09-17 17:08:46 -07009import android.graphics.Insets;
Adam Cohena6d04922014-10-23 17:28:30 -070010import android.graphics.Rect;
Tony Wickham12e8a342019-04-23 11:28:54 -070011import android.os.Build;
Adam Cohena6d04922014-10-23 17:28:30 -070012import android.util.AttributeSet;
Sunny Goyal4ffec482016-02-09 11:28:52 -080013import android.view.ViewDebug;
Sunny Goyal022b1822019-06-12 08:44:09 -070014import android.view.WindowInsets;
Adam Cohena6d04922014-10-23 17:28:30 -070015
Tony Wickham7eb5b532021-09-17 17:08:46 -070016import androidx.annotation.RequiresApi;
17
Adam Cohen501e1392021-02-02 16:45:07 -080018import com.android.launcher3.graphics.SysUiScrim;
Sunny Goyal9d89f752020-06-19 11:09:24 -070019import com.android.launcher3.statemanager.StatefulActivity;
Tony Wickham7eb5b532021-09-17 17:08:46 -070020import com.android.launcher3.uioverrides.ApiWrapper;
Sunny Goyal9d89f752020-06-19 11:09:24 -070021
Tony Wickham12e8a342019-04-23 11:28:54 -070022import java.util.Collections;
23import java.util.List;
24
Adam Cohena6d04922014-10-23 17:28:30 -070025public class LauncherRootView extends InsettableFrameLayout {
Sunny Goyal0abb36f2015-06-23 10:53:59 -070026
Sunny Goyal022b1822019-06-12 08:44:09 -070027 private final Rect mTempRect = new Rect();
28
Sunny Goyal9d89f752020-06-19 11:09:24 -070029 private final StatefulActivity mActivity;
Sunny Goyal07b69292018-01-08 14:19:34 -080030
Sunny Goyal745df7c2019-04-03 15:25:00 -070031 @ViewDebug.ExportedProperty(category = "launcher")
Tony Wickham12e8a342019-04-23 11:28:54 -070032 private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
33 Collections.singletonList(new Rect());
34
Sunny Goyal7185dd62018-03-14 17:51:49 -070035 private WindowStateListener mWindowStateListener;
Tony Wickham12e8a342019-04-23 11:28:54 -070036 @ViewDebug.ExportedProperty(category = "launcher")
37 private boolean mDisallowBackGesture;
Vinit Nayak9a846212019-09-05 11:47:12 -070038 @ViewDebug.ExportedProperty(category = "launcher")
39 private boolean mForceHideBackArrow;
Sunny Goyal93264612015-11-23 11:47:50 -080040
Sunny Goyal4ed0fb52021-04-26 09:52:47 -070041 private final SysUiScrim mSysUiScrim;
Adam Cohen501e1392021-02-02 16:45:07 -080042
Adam Cohena6d04922014-10-23 17:28:30 -070043 public LauncherRootView(Context context, AttributeSet attrs) {
44 super(context, attrs);
Sunny Goyal9d89f752020-06-19 11:09:24 -070045 mActivity = StatefulActivity.fromContext(context);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -070046 mSysUiScrim = new SysUiScrim(this);
Adam Cohena6d04922014-10-23 17:28:30 -070047 }
48
Sunny Goyal022b1822019-06-12 08:44:09 -070049 private void handleSystemWindowInsets(Rect insets) {
Tony Wickham145b7fd2021-03-11 10:03:12 -080050 DeviceProfile dp = mActivity.getDeviceProfile();
51
52 // Taskbar provides insets, but we don't want that for most Launcher elements so remove it.
53 mTempRect.set(insets);
54 insets = mTempRect;
55 insets.bottom = Math.max(0, insets.bottom - dp.nonOverlappingTaskbarInset);
56
57 // Update device profile before notifying the children.
58 dp.updateInsets(insets);
Sunny Goyalce8809a2018-01-18 14:02:47 -080059 boolean resetState = !insets.equals(mInsets);
Sunny Goyal906c6b22017-08-18 00:35:52 -070060 setInsets(insets);
61
Sunny Goyalce8809a2018-01-18 14:02:47 -080062 if (resetState) {
Sunny Goyal9d89f752020-06-19 11:09:24 -070063 mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
Sunny Goyalce8809a2018-01-18 14:02:47 -080064 }
Sunny Goyal022b1822019-06-12 08:44:09 -070065 }
Sunny Goyal0abb36f2015-06-23 10:53:59 -070066
Sunny Goyal022b1822019-06-12 08:44:09 -070067 @Override
68 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Tony Wickham7eb5b532021-09-17 17:08:46 -070069 if (Utilities.ATLEAST_R) {
70 insets = updateInsetsDueToTaskbar(insets);
71 Insets systemWindowInsets = insets.getInsetsIgnoringVisibility(
72 WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
73 mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
74 systemWindowInsets.bottom);
75 } else {
76 mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
77 insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
78 }
Sunny Goyal022b1822019-06-12 08:44:09 -070079 handleSystemWindowInsets(mTempRect);
Sunny Goyal786940a2020-06-02 02:31:31 -070080 return insets;
Adam Cohena6d04922014-10-23 17:28:30 -070081 }
Sunny Goyal0abb36f2015-06-23 10:53:59 -070082
Tony Wickham7eb5b532021-09-17 17:08:46 -070083 /**
84 * Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately,
85 * and can be destroyed and recreated. Thus, instead of relying on taskbar being present to
86 * get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
87 * is currently attached.
88 *
89 * TODO(b/198798034): Currently we always calculate nav insets as taskbarSize, but then we
90 * subtract nonOverlappingTaskbarInset in handleSystemWindowInsets(). Instead, we should just
91 * calculate the normal nav bar height here, and remove nonOverlappingTaskbarInset altogether.
92 *
93 * @param oldInsets The system-provided insets, which we are modifying.
94 * @return The updated insets.
95 */
96 @RequiresApi(api = Build.VERSION_CODES.R)
97 private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) {
98 if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) {
99 // 3P launchers based on Launcher3 should still be inset like normal.
100 return oldInsets;
101 }
102
103 WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
104
105 DeviceProfile dp = mActivity.getDeviceProfile();
106 Resources resources = getResources();
107
108 Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
109 Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
110 oldNavInsets.bottom);
111 if (dp.isTaskbarPresent) {
112 // TODO (see javadoc): Remove this block and fall into the next one instead.
113 newNavInsets.bottom = dp.taskbarSize;
114 } else if (dp.isLandscape) {
115 if (dp.isTablet) {
116 newNavInsets.bottom = ResourceUtils.getNavbarSize(
117 "navigation_bar_height_landscape", resources);
118 } else {
119 int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
120 if (dp.isSeascape()) {
121 newNavInsets.left = navWidth;
122 } else {
123 newNavInsets.right = navWidth;
124 }
125 }
126 } else {
127 newNavInsets.bottom = ResourceUtils.getNavbarSize("navigation_bar_height", resources);
128 }
129 updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
130 updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
131 Insets.of(newNavInsets));
132
133 mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets);
134
135 return updatedInsetsBuilder.build();
136 }
137
Jon Mirandade43a712018-01-18 11:35:10 -0800138 @Override
139 public void setInsets(Rect insets) {
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800140 // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
141 // modifying child layout params.
142 if (!insets.equals(mInsets)) {
143 super.setInsets(insets);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700144 mSysUiScrim.onInsetsChanged(insets);
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800145 }
Jon Mirandade43a712018-01-18 11:35:10 -0800146 }
147
Sunny Goyal07b69292018-01-08 14:19:34 -0800148 public void dispatchInsets() {
Sunny Goyal9d89f752020-06-19 11:09:24 -0700149 mActivity.getDeviceProfile().updateInsets(mInsets);
Sunny Goyalf8d56fc2018-01-31 15:18:11 -0800150 super.setInsets(mInsets);
Sunny Goyal07b69292018-01-08 14:19:34 -0800151 }
152
Sunny Goyal7185dd62018-03-14 17:51:49 -0700153 public void setWindowStateListener(WindowStateListener listener) {
154 mWindowStateListener = listener;
155 }
156
157 @Override
158 public void onWindowFocusChanged(boolean hasWindowFocus) {
159 super.onWindowFocusChanged(hasWindowFocus);
160 if (mWindowStateListener != null) {
161 mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
162 }
163 }
164
165 @Override
166 protected void onWindowVisibilityChanged(int visibility) {
167 super.onWindowVisibilityChanged(visibility);
168 if (mWindowStateListener != null) {
169 mWindowStateListener.onWindowVisibilityChanged(visibility);
170 }
171 }
172
Adam Cohen501e1392021-02-02 16:45:07 -0800173 @Override
174 protected void dispatchDraw(Canvas canvas) {
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700175 mSysUiScrim.draw(canvas);
Adam Cohen501e1392021-02-02 16:45:07 -0800176 super.dispatchDraw(canvas);
177 }
178
Sunny Goyal745df7c2019-04-03 15:25:00 -0700179 @Override
Tony Wickham12e8a342019-04-23 11:28:54 -0700180 protected void onLayout(boolean changed, int l, int t, int r, int b) {
181 super.onLayout(changed, l, t, r, b);
182 SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
183 setDisallowBackGesture(mDisallowBackGesture);
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700184 mSysUiScrim.setSize(r - l, b - t);
Tony Wickham12e8a342019-04-23 11:28:54 -0700185 }
186
187 @TargetApi(Build.VERSION_CODES.Q)
Vinit Nayak9a846212019-09-05 11:47:12 -0700188 public void setForceHideBackArrow(boolean forceHideBackArrow) {
189 this.mForceHideBackArrow = forceHideBackArrow;
190 setDisallowBackGesture(mDisallowBackGesture);
191 }
192
193 @TargetApi(Build.VERSION_CODES.Q)
Tony Wickham12e8a342019-04-23 11:28:54 -0700194 public void setDisallowBackGesture(boolean disallowBackGesture) {
Sunny Goyala314d5a2020-05-20 20:34:04 -0700195 if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
Tony Wickham12e8a342019-04-23 11:28:54 -0700196 return;
197 }
198 mDisallowBackGesture = disallowBackGesture;
Vinit Nayak9a846212019-09-05 11:47:12 -0700199 setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture)
Tony Wickham12e8a342019-04-23 11:28:54 -0700200 ? SYSTEM_GESTURE_EXCLUSION_RECT
201 : Collections.emptyList());
202 }
203
Sunny Goyal4ed0fb52021-04-26 09:52:47 -0700204 public SysUiScrim getSysUiScrim() {
205 return mSysUiScrim;
206 }
207
Sunny Goyal7185dd62018-03-14 17:51:49 -0700208 public interface WindowStateListener {
209
210 void onWindowFocusChanged(boolean hasFocus);
211
212 void onWindowVisibilityChanged(int visibility);
213 }
Adam Cohen501e1392021-02-02 16:45:07 -0800214}