/* * 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 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 internalTypes = InsetsState.toInternalType(types); for (int i = internalTypes.size() - 1; i >= 0; i--) { mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible); } } } }