1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.wm; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.RemoteException; 22 import android.util.ArraySet; 23 import android.util.Slog; 24 import android.util.SparseArray; 25 import android.view.IDisplayWindowInsetsController; 26 import android.view.IWindowManager; 27 import android.view.InsetsController; 28 import android.view.InsetsSourceControl; 29 import android.view.InsetsState; 30 import android.view.WindowInsets; 31 32 import androidx.annotation.VisibleForTesting; 33 34 import com.android.systemui.dagger.qualifiers.Main; 35 import com.android.wm.shell.common.DisplayController; 36 import com.android.wm.shell.common.DisplayImeController; 37 import com.android.wm.shell.common.TransactionPool; 38 39 import java.util.Objects; 40 41 /** 42 * Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to 43 * give system bar control to SystemUI. 44 * {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller 45 * takes control or not. 46 */ 47 public class DisplaySystemBarsController extends DisplayImeController { 48 49 private static final String TAG = "DisplaySystemBarsController"; 50 51 private final Context mContext; 52 private final DisplayController mDisplayController; 53 private final Handler mHandler; 54 private SparseArray<PerDisplay> mPerDisplaySparseArray; 55 DisplaySystemBarsController( Context context, IWindowManager wmService, DisplayController displayController, @Main Handler mainHandler, TransactionPool transactionPool)56 public DisplaySystemBarsController( 57 Context context, 58 IWindowManager wmService, 59 DisplayController displayController, 60 @Main Handler mainHandler, 61 TransactionPool transactionPool) { 62 super(wmService, displayController, (r) -> mainHandler.post(r), transactionPool); 63 mContext = context; 64 mDisplayController = displayController; 65 mHandler = mainHandler; 66 } 67 68 @Override onDisplayAdded(int displayId)69 public void onDisplayAdded(int displayId) { 70 PerDisplay pd = new PerDisplay(displayId); 71 pd.register(); 72 // Lazy loading policy control filters instead of during boot. 73 if (mPerDisplaySparseArray == null) { 74 mPerDisplaySparseArray = new SparseArray<>(); 75 BarControlPolicy.reloadFromSetting(mContext); 76 BarControlPolicy.registerContentObserver(mContext, mHandler, () -> { 77 int size = mPerDisplaySparseArray.size(); 78 for (int i = 0; i < size; i++) { 79 mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets(); 80 } 81 }); 82 } 83 mPerDisplaySparseArray.put(displayId, pd); 84 } 85 86 @Override onDisplayRemoved(int displayId)87 public void onDisplayRemoved(int displayId) { 88 try { 89 mWmService.setDisplayWindowInsetsController(displayId, null); 90 } catch (RemoteException e) { 91 Slog.w(TAG, "Unable to remove insets controller on display " + displayId); 92 } 93 mPerDisplaySparseArray.remove(displayId); 94 } 95 96 @VisibleForTesting 97 class PerDisplay extends DisplayImeController.PerDisplay { 98 99 int mDisplayId; 100 InsetsController mInsetsController; 101 InsetsState mInsetsState = new InsetsState(); 102 String mPackageName; 103 PerDisplay(int displayId)104 PerDisplay(int displayId) { 105 super(displayId, mDisplayController.getDisplayLayout(displayId).rotation()); 106 mDisplayId = displayId; 107 mInsetsController = new InsetsController( 108 new DisplaySystemBarsInsetsControllerHost(mHandler, mInsetsControllerImpl)); 109 } 110 111 @Override insetsChanged(InsetsState insetsState)112 public void insetsChanged(InsetsState insetsState) { 113 super.insetsChanged(insetsState); 114 if (mInsetsState.equals(insetsState)) { 115 return; 116 } 117 mInsetsState.set(insetsState, true /* copySources */); 118 mInsetsController.onStateChanged(insetsState); 119 if (mPackageName != null) { 120 modifyDisplayWindowInsets(); 121 } 122 } 123 124 @Override hideInsets(@indowInsets.Type.InsetsType int types, boolean fromIme)125 public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { 126 if ((types & WindowInsets.Type.ime()) == 0) { 127 mInsetsController.hide(types); 128 } else { 129 super.hideInsets(types, fromIme); 130 } 131 132 } 133 134 @Override showInsets(@indowInsets.Type.InsetsType int types, boolean fromIme)135 public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { 136 if ((types & WindowInsets.Type.ime()) == 0) { 137 mInsetsController.show(types); 138 } else { 139 super.showInsets(types, fromIme); 140 } 141 142 } 143 144 @Override topFocusedWindowChanged(String packageName)145 public void topFocusedWindowChanged(String packageName) { 146 if (Objects.equals(mPackageName, packageName)) { 147 return; 148 } 149 mPackageName = packageName; 150 modifyDisplayWindowInsets(); 151 } 152 modifyDisplayWindowInsets()153 private void modifyDisplayWindowInsets() { 154 if (mPackageName == null) { 155 return; 156 } 157 int[] barVisibilities = BarControlPolicy.getBarVisibilities(mPackageName); 158 updateInsetsState(barVisibilities[0], /* visible= */ true); 159 updateInsetsState(barVisibilities[1], /* visible= */ false); 160 showInsets(barVisibilities[0], /* fromIme= */ false); 161 hideInsets(barVisibilities[1], /* fromIme= */ false); 162 try { 163 mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); 164 } catch (RemoteException e) { 165 Slog.w(TAG, "Unable to update window manager service."); 166 } 167 } 168 updateInsetsState(@indowInsets.Type.InsetsType int types, boolean visible)169 private void updateInsetsState(@WindowInsets.Type.InsetsType int types, boolean visible) { 170 ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); 171 for (int i = internalTypes.size() - 1; i >= 0; i--) { 172 mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible); 173 } 174 } 175 } 176 } 177