mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 00:06:47 +00:00
Bug: 231648761
Fixes: 269392826
Test: Unable to reproduce 269392826, but verified this doesn't
break existing paths to adjust the insets
Change-Id: I8aa82f3fb77e627ac02352ef31b788b81c2ca901
264 lines
11 KiB
Kotlin
264 lines
11 KiB
Kotlin
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.android.launcher3.taskbar
|
|
|
|
import android.graphics.Insets
|
|
import android.graphics.Region
|
|
import android.view.InsetsFrameProvider
|
|
import android.view.InsetsFrameProvider.SOURCE_DISPLAY
|
|
import android.view.InsetsFrameProvider.SOURCE_FRAME
|
|
import android.view.InsetsState
|
|
import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
|
|
import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT
|
|
import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
|
|
import android.view.InsetsState.ITYPE_LEFT_GESTURES
|
|
import android.view.InsetsState.ITYPE_RIGHT_GESTURES
|
|
import android.view.ViewTreeObserver
|
|
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
|
|
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
|
|
import android.view.WindowManager
|
|
import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
|
|
import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
|
|
import com.android.internal.policy.GestureNavigationSettingsObserver
|
|
import com.android.launcher3.AbstractFloatingView
|
|
import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
|
|
import com.android.launcher3.DeviceProfile
|
|
import com.android.launcher3.R
|
|
import com.android.launcher3.anim.AlphaUpdateListener
|
|
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
|
|
import java.io.PrintWriter
|
|
|
|
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
|
|
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
|
|
|
|
/** The bottom insets taskbar provides to the IME when IME is visible. */
|
|
val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
|
|
private val touchableRegion: Region = Region()
|
|
private val deviceProfileChangeListener = { _: DeviceProfile ->
|
|
onTaskbarWindowHeightOrInsetsChanged()
|
|
}
|
|
private val gestureNavSettingsObserver =
|
|
GestureNavigationSettingsObserver(context.mainThreadHandler, context,
|
|
this::onTaskbarWindowHeightOrInsetsChanged)
|
|
|
|
// Initialized in init.
|
|
private lateinit var controllers: TaskbarControllers
|
|
private lateinit var windowLayoutParams: WindowManager.LayoutParams
|
|
|
|
fun init(controllers: TaskbarControllers) {
|
|
this.controllers = controllers
|
|
windowLayoutParams = context.windowLayoutParams
|
|
|
|
setProvidesInsetsTypes(
|
|
windowLayoutParams,
|
|
intArrayOf(
|
|
ITYPE_EXTRA_NAVIGATION_BAR,
|
|
ITYPE_BOTTOM_TAPPABLE_ELEMENT,
|
|
ITYPE_BOTTOM_MANDATORY_GESTURES,
|
|
ITYPE_LEFT_GESTURES,
|
|
ITYPE_RIGHT_GESTURES,
|
|
),
|
|
intArrayOf(
|
|
SOURCE_FRAME,
|
|
SOURCE_FRAME,
|
|
SOURCE_FRAME,
|
|
SOURCE_DISPLAY,
|
|
SOURCE_DISPLAY
|
|
)
|
|
)
|
|
|
|
onTaskbarWindowHeightOrInsetsChanged()
|
|
|
|
windowLayoutParams.insetsRoundedCornerFrame = true
|
|
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
|
|
gestureNavSettingsObserver.registerForCallingUser()
|
|
}
|
|
|
|
fun onDestroy() {
|
|
context.removeOnDeviceProfileChangeListener(deviceProfileChangeListener)
|
|
gestureNavSettingsObserver.unregister()
|
|
}
|
|
|
|
fun onTaskbarWindowHeightOrInsetsChanged() {
|
|
val touchableHeight = controllers.taskbarStashController.touchableHeight
|
|
touchableRegion.set(
|
|
0,
|
|
windowLayoutParams.height - touchableHeight,
|
|
context.deviceProfile.widthPx,
|
|
windowLayoutParams.height
|
|
)
|
|
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
|
|
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
|
|
val res = context.resources;
|
|
for (provider in windowLayoutParams.providedInsets) {
|
|
if (
|
|
provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
|
|
provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES
|
|
) {
|
|
provider.insetsSize = getInsetsByNavMode(contentHeight)
|
|
} else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
|
|
provider.insetsSize = getInsetsByNavMode(tappableHeight)
|
|
} else if (provider.type == ITYPE_LEFT_GESTURES) {
|
|
provider.insetsSize =
|
|
Insets.of(
|
|
gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res),
|
|
0,
|
|
0,
|
|
0
|
|
)
|
|
} else if (provider.type == ITYPE_RIGHT_GESTURES) {
|
|
provider.insetsSize =
|
|
Insets.of(
|
|
0,
|
|
0,
|
|
gestureNavSettingsObserver.getRightSensitivityForCallingUser(res),
|
|
0
|
|
)
|
|
}
|
|
}
|
|
|
|
val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
|
|
val insetsSizeOverride =
|
|
arrayOf(
|
|
InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
|
|
)
|
|
// Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
|
|
val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0)
|
|
val insetsSizeOverrideForGestureNavTappableElement =
|
|
arrayOf(
|
|
InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
|
|
InsetsFrameProvider.InsetsSizeOverride(
|
|
TYPE_VOICE_INTERACTION,
|
|
visInsetsSizeForGestureNavTappableElement
|
|
),
|
|
)
|
|
for (provider in windowLayoutParams.providedInsets) {
|
|
if (context.isGestureNav && provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
|
|
provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
|
|
} else {
|
|
provider.insetsSizeOverrides = insetsSizeOverride
|
|
}
|
|
}
|
|
context.notifyUpdateLayoutParams()
|
|
}
|
|
|
|
/**
|
|
* @return [Insets] where the [bottomInset] is either used as a bottom inset or
|
|
* ```
|
|
* right/left inset if using 3 button nav
|
|
* ```
|
|
*/
|
|
private fun getInsetsByNavMode(bottomInset: Int): Insets {
|
|
val devicePortrait = !context.deviceProfile.isLandscape
|
|
if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
|
|
// Taskbar or portrait phone mode
|
|
return Insets.of(0, 0, 0, bottomInset)
|
|
}
|
|
|
|
// TODO(b/230394142): seascape
|
|
return Insets.of(0, 0, bottomInset, 0)
|
|
}
|
|
|
|
/**
|
|
* Sets {@param providesInsetsTypes} as the inset types provided by {@param params}.
|
|
* @param params The window layout params.
|
|
* @param providesInsetsTypes The inset types we would like this layout params to provide.
|
|
*/
|
|
fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray,
|
|
providesInsetsSources: IntArray) {
|
|
params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
|
|
for (i in providesInsetsTypes.indices) {
|
|
params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i],
|
|
providesInsetsSources[i], null, null)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called to update the touchable insets.
|
|
* @see InternalInsetsInfo.setTouchableInsets
|
|
*/
|
|
fun updateInsetsTouchability(insetsInfo: ViewTreeObserver.InternalInsetsInfo) {
|
|
insetsInfo.touchableRegion.setEmpty()
|
|
// Always have nav buttons be touchable
|
|
controllers.navbarButtonsViewController.addVisibleButtonsRegion(
|
|
context.dragLayer,
|
|
insetsInfo.touchableRegion
|
|
)
|
|
var insetsIsTouchableRegion = true
|
|
if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
|
|
// Let touches pass through us.
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
} else if (
|
|
controllers.navbarButtonsViewController.isImeVisible &&
|
|
controllers.taskbarStashController.isStashed()
|
|
) {
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
} else if (!controllers.uiController.isTaskbarTouchable) {
|
|
// Let touches pass through us.
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
} else if (controllers.taskbarDragController.isSystemDragInProgress) {
|
|
// Let touches pass through us.
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
} else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_OVERLAY_PROXY)) {
|
|
// Let touches pass through us if icons are hidden.
|
|
if (controllers.taskbarViewController.areIconsVisible()) {
|
|
insetsInfo.touchableRegion.set(touchableRegion)
|
|
}
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
} else if (
|
|
controllers.taskbarViewController.areIconsVisible() ||
|
|
AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) ||
|
|
context.isNavBarKidsModeActive
|
|
) {
|
|
// Taskbar has some touchable elements, take over the full taskbar area
|
|
insetsInfo.setTouchableInsets(
|
|
if (context.isTaskbarWindowFullscreen) {
|
|
TOUCHABLE_INSETS_FRAME
|
|
} else {
|
|
insetsInfo.touchableRegion.set(touchableRegion)
|
|
TOUCHABLE_INSETS_REGION
|
|
}
|
|
)
|
|
insetsIsTouchableRegion = false
|
|
} else {
|
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
|
|
}
|
|
context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
|
|
}
|
|
|
|
override fun dumpLogs(prefix: String, pw: PrintWriter) {
|
|
pw.println(prefix + "TaskbarInsetsController:")
|
|
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
|
|
for (provider in windowLayoutParams.providedInsets) {
|
|
pw.print(
|
|
"$prefix\tprovidedInsets: (type=" +
|
|
InsetsState.typeToString(provider.type) +
|
|
" insetsSize=" +
|
|
provider.insetsSize
|
|
)
|
|
if (provider.insetsSizeOverrides != null) {
|
|
pw.print(" insetsSizeOverrides={")
|
|
for ((i, overrideSize) in provider.insetsSizeOverrides.withIndex()) {
|
|
if (i > 0) pw.print(", ")
|
|
pw.print(overrideSize)
|
|
}
|
|
pw.print("})")
|
|
}
|
|
pw.println()
|
|
}
|
|
}
|
|
}
|