blob: c0b5c50b288c20f6776cead322fbab0cecf6478f [file] [log] [blame]
/*
* Copyright (C) 2020 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.wm;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IDisplayWindowInsetsController;
import android.view.IWindowManager;
import android.view.InsetsController;
import android.view.InsetsState;
import android.view.WindowInsets;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.TransactionPool;
import com.android.systemui.dagger.qualifiers.Main;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to
* give system bar control to SystemUI.
* {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller
* takes control or not.
*/
@Singleton
public class DisplaySystemBarsController extends DisplayImeController {
private static final String TAG = "DisplaySystemBarsController";
private final Context mContext;
private final Handler mHandler;
private SparseArray<PerDisplay> mPerDisplaySparseArray;
@Inject
public DisplaySystemBarsController(
Context context,
IWindowManager wmService,
DisplayController displayController,
@Main Handler mainHandler,
TransactionPool transactionPool) {
super(wmService, displayController, mainHandler::post, transactionPool);
mContext = context;
mHandler = mainHandler;
}
@Override
public void onDisplayAdded(int displayId) {
PerDisplay pd = new PerDisplay(displayId);
pd.register();
// Lazy loading policy control filters instead of during boot.
if (mPerDisplaySparseArray == null) {
mPerDisplaySparseArray = new SparseArray<>();
BarControlPolicy.reloadFromSetting(mContext);
BarControlPolicy.registerContentObserver(mContext, mHandler, () -> {
int size = mPerDisplaySparseArray.size();
for (int i = 0; i < size; i++) {
mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets();
}
});
}
mPerDisplaySparseArray.put(displayId, pd);
}
@Override
public void onDisplayRemoved(int displayId) {
try {
mWmService.setDisplayWindowInsetsController(displayId, null);
} catch (RemoteException e) {
Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
}
mPerDisplaySparseArray.remove(displayId);
}
@VisibleForTesting
class PerDisplay extends DisplayImeController.PerDisplay {
int mDisplayId;
InsetsController mInsetsController;
InsetsState mInsetsState = new InsetsState();
String mPackageName;
PerDisplay(int displayId) {
super(displayId, mDisplayController.getDisplayLayout(displayId).rotation());
mDisplayId = displayId;
mInsetsController = new InsetsController(
new DisplaySystemBarsInsetsControllerHost(mHandler, mInsetsControllerImpl));
}
@Override
public void insetsChanged(InsetsState insetsState) {
super.insetsChanged(insetsState);
if (mInsetsState.equals(insetsState)) {
return;
}
mInsetsState.set(insetsState, true /* copySources */);
mInsetsController.onStateChanged(insetsState);
if (mPackageName != null) {
modifyDisplayWindowInsets();
}
}
@Override
public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
mInsetsController.hide(types);
} else {
super.hideInsets(types, fromIme);
}
}
@Override
public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
mInsetsController.show(types);
} else {
super.showInsets(types, fromIme);
}
}
@Override
public void topFocusedWindowChanged(String packageName) {
if (Objects.equals(mPackageName, packageName)) {
return;
}
mPackageName = packageName;
modifyDisplayWindowInsets();
}
private void modifyDisplayWindowInsets() {
if (mPackageName == null) {
return;
}
int[] barVisibilities = BarControlPolicy.getBarVisibilities(mPackageName);
updateInsetsState(barVisibilities[0], /* visible= */ true);
updateInsetsState(barVisibilities[1], /* visible= */ false);
showInsets(barVisibilities[0], /* fromIme= */ false);
hideInsets(barVisibilities[1], /* fromIme= */ false);
try {
mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
} catch (RemoteException e) {
Slog.w(TAG, "Unable to update window manager service.");
}
}
private void updateInsetsState(@WindowInsets.Type.InsetsType int types, boolean visible) {
ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible);
}
}
}
}