blob: e949ade28b59727bcaa33bd4b31f5f91602a9b3c [file] [log] [blame]
/*
* Copyright (C) 2019 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.systemui.statusbar.phone;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import com.android.systemui.Dependency;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
/**
* Manages what parts of the status bar are touchable. Clients are primarily UI that displays in the
* status bar even though the UI doesn't look like part of the status bar.
*/
public final class StatusBarTouchableRegionManager implements
OnComputeInternalInsetsListener, ConfigurationListener {
private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
private final Context mContext;
private final HeadsUpManagerPhone mHeadsUpManager;
private boolean mIsStatusBarExpanded = false;
private boolean mShouldAdjustInsets = false;
private final StatusBar mStatusBar;
private int mStatusBarHeight;
private final View mStatusBarWindowView;
private boolean mForceCollapsedUntilLayout = false;
public StatusBarTouchableRegionManager(@NonNull Context context,
HeadsUpManagerPhone headsUpManager,
@NonNull StatusBar statusBar,
@NonNull View statusBarWindowView) {
mContext = context;
mHeadsUpManager = headsUpManager;
mStatusBar = statusBar;
mStatusBarWindowView = statusBarWindowView;
initResources();
mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
updateTouchableRegion();
});
Dependency.get(ConfigurationController.class).addCallback(this);
}
/**
* Set the touchable portion of the status bar based on what elements are visible.
*/
public void updateTouchableRegion() {
boolean hasCutoutInset = (mStatusBarWindowView != null)
&& (mStatusBarWindowView.getRootWindowInsets() != null)
&& (mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null);
boolean shouldObserve =
mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpManager.isHeadsUpGoingAway()
|| mBubbleController.hasBubbles()
|| mForceCollapsedUntilLayout
|| hasCutoutInset;
if (shouldObserve == mShouldAdjustInsets) {
return;
}
if (shouldObserve) {
mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
mStatusBarWindowView.requestLayout();
} else {
mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
}
mShouldAdjustInsets = shouldObserve;
}
/**
* Calls {@code updateTouchableRegion()} after a layout pass completes.
*/
public void updateTouchableRegionAfterLayout() {
mForceCollapsedUntilLayout = true;
mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft,
int oldTop, int oldRight, int oldBottom) {
if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
mStatusBarWindowView.removeOnLayoutChangeListener(this);
mForceCollapsedUntilLayout = false;
updateTouchableRegion();
}
}
});
}
/**
* Notify that the status bar panel gets expanded or collapsed.
*
* @param isExpanded True to notify expanded, false to notify collapsed.
*/
public void setIsStatusBarExpanded(boolean isExpanded) {
if (isExpanded != mIsStatusBarExpanded) {
mIsStatusBarExpanded = isExpanded;
if (isExpanded) {
// make sure our state is sane
mForceCollapsedUntilLayout = false;
}
updateTouchableRegion();
}
}
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
if (mIsStatusBarExpanded || mStatusBar.isBouncerShowing()) {
// The touchable region is always the full area when expanded
return;
}
mHeadsUpManager.updateTouchableRegion(info);
Rect bubbleRect = mBubbleController.getTouchableRegion();
if (bubbleRect != null) {
info.touchableRegion.union(bubbleRect);
}
}
@Override
public void onConfigChanged(Configuration newConfig) {
initResources();
}
@Override
public void onDensityOrFontScaleChanged() {
initResources();
}
@Override
public void onOverlayChanged() {
initResources();
}
private void initResources() {
Resources resources = mContext.getResources();
mStatusBarHeight = resources.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
}
}