• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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