You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
7.4 KiB
207 lines
7.4 KiB
package com.android.launcher3;
|
|
|
|
import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
|
|
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
|
|
|
|
import android.annotation.TargetApi;
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Insets;
|
|
import android.graphics.Rect;
|
|
import android.os.Build;
|
|
import android.util.AttributeSet;
|
|
import android.view.ViewDebug;
|
|
import android.view.WindowInsets;
|
|
|
|
import androidx.annotation.RequiresApi;
|
|
|
|
import com.android.launcher3.graphics.SysUiScrim;
|
|
import com.android.launcher3.statemanager.StatefulActivity;
|
|
import com.android.launcher3.uioverrides.ApiWrapper;
|
|
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
public class LauncherRootView extends InsettableFrameLayout {
|
|
|
|
private final Rect mTempRect = new Rect();
|
|
|
|
private final StatefulActivity mActivity;
|
|
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
|
Collections.singletonList(new Rect());
|
|
|
|
private WindowStateListener mWindowStateListener;
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mDisallowBackGesture;
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mForceHideBackArrow;
|
|
|
|
private final SysUiScrim mSysUiScrim;
|
|
|
|
public LauncherRootView(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
mActivity = StatefulActivity.fromContext(context);
|
|
mSysUiScrim = new SysUiScrim(this);
|
|
}
|
|
|
|
private void handleSystemWindowInsets(Rect insets) {
|
|
// Update device profile before notifying the children.
|
|
mActivity.getDeviceProfile().updateInsets(insets);
|
|
boolean resetState = !insets.equals(mInsets);
|
|
setInsets(insets);
|
|
|
|
if (resetState) {
|
|
mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
|
if (Utilities.ATLEAST_R) {
|
|
insets = updateInsetsDueToTaskbar(insets);
|
|
Insets systemWindowInsets = insets.getInsetsIgnoringVisibility(
|
|
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
|
|
mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
|
|
systemWindowInsets.bottom);
|
|
} else {
|
|
mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
|
|
insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
|
|
}
|
|
handleSystemWindowInsets(mTempRect);
|
|
return insets;
|
|
}
|
|
|
|
/**
|
|
* Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately,
|
|
* and can be destroyed and recreated. Thus, instead of relying on taskbar being present to
|
|
* get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
|
|
* is currently attached.
|
|
*
|
|
* @param oldInsets The system-provided insets, which we are modifying.
|
|
* @return The updated insets.
|
|
*/
|
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
|
private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) {
|
|
if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) {
|
|
// 3P launchers based on Launcher3 should still be inset like normal.
|
|
return oldInsets;
|
|
}
|
|
|
|
WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
|
|
|
|
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
Resources resources = getResources();
|
|
|
|
Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
|
|
Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
|
|
oldNavInsets.bottom);
|
|
|
|
if (dp.isLandscape) {
|
|
boolean isGesturalMode = ResourceUtils.getIntegerByName(
|
|
"config_navBarInteractionMode",
|
|
resources,
|
|
INVALID_RESOURCE_HANDLE) == 2;
|
|
if (dp.isTablet || isGesturalMode) {
|
|
newNavInsets.bottom = ResourceUtils.getNavbarSize(
|
|
"navigation_bar_height_landscape", resources);
|
|
} else {
|
|
int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
|
|
if (dp.isSeascape()) {
|
|
newNavInsets.left = navWidth;
|
|
} else {
|
|
newNavInsets.right = navWidth;
|
|
}
|
|
}
|
|
} else {
|
|
newNavInsets.bottom = ResourceUtils.getNavbarSize("navigation_bar_height", resources);
|
|
}
|
|
updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
|
|
updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
|
|
Insets.of(newNavInsets));
|
|
|
|
mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets);
|
|
|
|
return updatedInsetsBuilder.build();
|
|
}
|
|
|
|
@Override
|
|
public void setInsets(Rect insets) {
|
|
// If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
|
|
// modifying child layout params.
|
|
if (!insets.equals(mInsets)) {
|
|
super.setInsets(insets);
|
|
mSysUiScrim.onInsetsChanged(insets);
|
|
}
|
|
}
|
|
|
|
public void dispatchInsets() {
|
|
mActivity.getDeviceProfile().updateInsets(mInsets);
|
|
super.setInsets(mInsets);
|
|
}
|
|
|
|
public void setWindowStateListener(WindowStateListener listener) {
|
|
mWindowStateListener = listener;
|
|
}
|
|
|
|
@Override
|
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
|
super.onWindowFocusChanged(hasWindowFocus);
|
|
if (mWindowStateListener != null) {
|
|
mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onWindowVisibilityChanged(int visibility) {
|
|
super.onWindowVisibilityChanged(visibility);
|
|
if (mWindowStateListener != null) {
|
|
mWindowStateListener.onWindowVisibilityChanged(visibility);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void dispatchDraw(Canvas canvas) {
|
|
mSysUiScrim.draw(canvas);
|
|
super.dispatchDraw(canvas);
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
super.onLayout(changed, l, t, r, b);
|
|
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
|
|
setDisallowBackGesture(mDisallowBackGesture);
|
|
mSysUiScrim.setSize(r - l, b - t);
|
|
}
|
|
|
|
@TargetApi(Build.VERSION_CODES.Q)
|
|
public void setForceHideBackArrow(boolean forceHideBackArrow) {
|
|
this.mForceHideBackArrow = forceHideBackArrow;
|
|
setDisallowBackGesture(mDisallowBackGesture);
|
|
}
|
|
|
|
@TargetApi(Build.VERSION_CODES.Q)
|
|
public void setDisallowBackGesture(boolean disallowBackGesture) {
|
|
if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
|
|
return;
|
|
}
|
|
mDisallowBackGesture = disallowBackGesture;
|
|
setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture)
|
|
? SYSTEM_GESTURE_EXCLUSION_RECT
|
|
: Collections.emptyList());
|
|
}
|
|
|
|
public SysUiScrim getSysUiScrim() {
|
|
return mSysUiScrim;
|
|
}
|
|
|
|
public interface WindowStateListener {
|
|
|
|
void onWindowFocusChanged(boolean hasFocus);
|
|
|
|
void onWindowVisibilityChanged(int visibility);
|
|
}
|
|
}
|