1 /* 2 * Copyright (C) 2019 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.statusbar.phone; 18 19 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 20 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; 21 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; 22 23 import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE; 24 import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE; 25 import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE; 26 import static com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN; 27 28 import android.content.Context; 29 import android.content.res.Resources; 30 import android.graphics.PixelFormat; 31 import android.graphics.Rect; 32 import android.os.Binder; 33 import android.os.RemoteException; 34 import android.util.Log; 35 import android.view.Gravity; 36 import android.view.IWindowManager; 37 import android.view.ViewGroup; 38 import android.view.WindowManager; 39 40 import com.android.systemui.R; 41 import com.android.systemui.dagger.SysUISingleton; 42 import com.android.systemui.dagger.qualifiers.Main; 43 import com.android.systemui.statusbar.SuperStatusBarViewFactory; 44 45 import javax.inject.Inject; 46 47 /** 48 * Encapsulates all logic for the status bar window state management. 49 */ 50 @SysUISingleton 51 public class StatusBarWindowController { 52 private static final String TAG = "StatusBarWindowController"; 53 private static final boolean DEBUG = false; 54 55 private final Context mContext; 56 private final WindowManager mWindowManager; 57 private final IWindowManager mIWindowManager; 58 private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; 59 private final StatusBarContentInsetsProvider mContentInsetsProvider; 60 private final Resources mResources; 61 private int mBarHeight = -1; 62 private final State mCurrentState = new State(); 63 64 private ViewGroup mStatusBarView; 65 private ViewGroup mLaunchAnimationContainer; 66 private WindowManager.LayoutParams mLp; 67 private final WindowManager.LayoutParams mLpChanged; 68 69 @Inject StatusBarWindowController( Context context, WindowManager windowManager, IWindowManager iWindowManager, SuperStatusBarViewFactory superStatusBarViewFactory, StatusBarContentInsetsProvider contentInsetsProvider, @Main Resources resources)70 public StatusBarWindowController( 71 Context context, 72 WindowManager windowManager, 73 IWindowManager iWindowManager, 74 SuperStatusBarViewFactory superStatusBarViewFactory, 75 StatusBarContentInsetsProvider contentInsetsProvider, 76 @Main Resources resources) { 77 mContext = context; 78 mWindowManager = windowManager; 79 mIWindowManager = iWindowManager; 80 mContentInsetsProvider = contentInsetsProvider; 81 mSuperStatusBarViewFactory = superStatusBarViewFactory; 82 mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView(); 83 mLaunchAnimationContainer = mStatusBarView.findViewById( 84 R.id.status_bar_launch_animation_container); 85 mLpChanged = new WindowManager.LayoutParams(); 86 mResources = resources; 87 88 if (mBarHeight < 0) { 89 mBarHeight = mResources.getDimensionPixelSize( 90 com.android.internal.R.dimen.status_bar_height); 91 } 92 } 93 getStatusBarHeight()94 public int getStatusBarHeight() { 95 return mBarHeight; 96 } 97 98 /** 99 * Rereads the status_bar_height from configuration and reapplys the current state if the height 100 * is different. 101 */ refreshStatusBarHeight()102 public void refreshStatusBarHeight() { 103 int heightFromConfig = mResources.getDimensionPixelSize( 104 com.android.internal.R.dimen.status_bar_height); 105 106 if (mBarHeight != heightFromConfig) { 107 mBarHeight = heightFromConfig; 108 apply(mCurrentState); 109 } 110 111 if (DEBUG) Log.v(TAG, "defineSlots"); 112 } 113 114 /** 115 * Adds the status bar view to the window manager. 116 */ attach()117 public void attach() { 118 // Now that the status bar window encompasses the sliding panel and its 119 // translucent backdrop, the entire thing is made TRANSLUCENT and is 120 // hardware-accelerated. 121 mLp = new WindowManager.LayoutParams( 122 ViewGroup.LayoutParams.MATCH_PARENT, 123 mBarHeight, 124 WindowManager.LayoutParams.TYPE_STATUS_BAR, 125 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 126 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 127 | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, 128 PixelFormat.TRANSLUCENT); 129 mLp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; 130 mLp.token = new Binder(); 131 mLp.gravity = Gravity.TOP; 132 mLp.setFitInsetsTypes(0 /* types */); 133 mLp.setTitle("StatusBar"); 134 mLp.packageName = mContext.getPackageName(); 135 mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 136 137 mWindowManager.addView(mStatusBarView, mLp); 138 mLpChanged.copyFrom(mLp); 139 140 mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations); 141 calculateStatusBarLocationsForAllRotations(); 142 } 143 calculateStatusBarLocationsForAllRotations()144 private void calculateStatusBarLocationsForAllRotations() { 145 Rect[] bounds = new Rect[4]; 146 bounds[0] = mContentInsetsProvider 147 .getBoundingRectForPrivacyChipForRotation(ROTATION_NONE); 148 bounds[1] = mContentInsetsProvider 149 .getBoundingRectForPrivacyChipForRotation(ROTATION_LANDSCAPE); 150 bounds[2] = mContentInsetsProvider 151 .getBoundingRectForPrivacyChipForRotation(ROTATION_UPSIDE_DOWN); 152 bounds[3] = mContentInsetsProvider 153 .getBoundingRectForPrivacyChipForRotation(ROTATION_SEASCAPE); 154 155 try { 156 mIWindowManager.updateStaticPrivacyIndicatorBounds(mContext.getDisplayId(), bounds); 157 } catch (RemoteException e) { 158 //Swallow 159 } 160 } 161 162 /** Set force status bar visible. */ setForceStatusBarVisible(boolean forceStatusBarVisible)163 public void setForceStatusBarVisible(boolean forceStatusBarVisible) { 164 mCurrentState.mForceStatusBarVisible = forceStatusBarVisible; 165 apply(mCurrentState); 166 } 167 168 /** 169 * Return the container in which we should run launch animations started from the status bar and 170 * expanding into the opening window. 171 * 172 * @see #setLaunchAnimationRunning 173 */ getLaunchAnimationContainer()174 public ViewGroup getLaunchAnimationContainer() { 175 return mLaunchAnimationContainer; 176 } 177 178 /** 179 * Set whether a launch animation is currently running. If true, this will ensure that the 180 * window matches its parent height so that the animation is not clipped by the normal status 181 * bar height. 182 */ setLaunchAnimationRunning(boolean isLaunchAnimationRunning)183 public void setLaunchAnimationRunning(boolean isLaunchAnimationRunning) { 184 if (isLaunchAnimationRunning == mCurrentState.mIsLaunchAnimationRunning) { 185 return; 186 } 187 188 mCurrentState.mIsLaunchAnimationRunning = isLaunchAnimationRunning; 189 apply(mCurrentState); 190 } 191 applyHeight(State state)192 private void applyHeight(State state) { 193 mLpChanged.height = 194 state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : mBarHeight; 195 } 196 apply(State state)197 private void apply(State state) { 198 applyForceStatusBarVisibleFlag(state); 199 applyHeight(state); 200 if (mLp != null && mLp.copyFrom(mLpChanged) != 0) { 201 mWindowManager.updateViewLayout(mStatusBarView, mLp); 202 } 203 } 204 205 private static class State { 206 boolean mForceStatusBarVisible; 207 boolean mIsLaunchAnimationRunning; 208 } 209 applyForceStatusBarVisibleFlag(State state)210 private void applyForceStatusBarVisibleFlag(State state) { 211 if (state.mForceStatusBarVisible || state.mIsLaunchAnimationRunning) { 212 mLpChanged.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; 213 } else { 214 mLpChanged.privateFlags &= ~PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; 215 } 216 } 217 } 218