• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.car.window;
18 
19 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
20 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
21 
22 import android.content.Context;
23 import android.graphics.PixelFormat;
24 import android.os.Binder;
25 import android.view.Gravity;
26 import android.view.LayoutInflater;
27 import android.view.MotionEvent;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.WindowInsets;
31 import android.view.WindowManager;
32 
33 import com.android.systemui.R;
34 import com.android.systemui.dagger.SysUISingleton;
35 import com.android.systemui.statusbar.policy.ConfigurationController;
36 
37 import javax.inject.Inject;
38 
39 /**
40  * Controls the expansion state of the primary window which will contain all of the fullscreen sysui
41  * behavior. This window still has a collapsed state in order to watch for swipe events to expand
42  * this window for the notification panel.
43  */
44 @SysUISingleton
45 public class SystemUIOverlayWindowController implements
46         ConfigurationController.ConfigurationListener {
47 
48     /**
49      * Touch listener to get touches on the view.
50      */
51     public interface OnTouchListener {
52 
53         /**
54          * Called when a touch happens on the view.
55          */
onTouch(View v, MotionEvent event)56         void onTouch(View v, MotionEvent event);
57     }
58 
59     private final Context mContext;
60     private final WindowManager mWindowManager;
61 
62     private ViewGroup mBaseLayout;
63     private WindowManager.LayoutParams mLp;
64     private WindowManager.LayoutParams mLpChanged;
65     private boolean mIsAttached = false;
66     private boolean mVisible = false;
67     private boolean mFocusable = false;
68     private boolean mUsingStableInsets = false;
69 
70     @Inject
SystemUIOverlayWindowController( Context context, WindowManager windowManager, ConfigurationController configurationController)71     public SystemUIOverlayWindowController(
72             Context context,
73             WindowManager windowManager,
74             ConfigurationController configurationController) {
75         mContext = context;
76         mWindowManager = windowManager;
77 
78         mLpChanged = new WindowManager.LayoutParams();
79         mBaseLayout = (ViewGroup) LayoutInflater.from(context)
80                 .inflate(R.layout.sysui_overlay_window, /* root= */ null, false);
81         configurationController.addCallback(this);
82     }
83 
84     /**
85      * Register to {@link OnTouchListener}
86      */
registerOutsideTouchListener(OnTouchListener listener)87     public void registerOutsideTouchListener(OnTouchListener listener) {
88         mBaseLayout.setOnTouchListener(new View.OnTouchListener() {
89             @Override
90             public boolean onTouch(View v, MotionEvent event) {
91                 listener.onTouch(v, event);
92                 return false;
93             }
94         });
95     }
96 
97     /** Returns the base view of the primary window. */
getBaseLayout()98     public ViewGroup getBaseLayout() {
99         return mBaseLayout;
100     }
101 
102     /** Returns {@code true} if the window is already attached. */
isAttached()103     public boolean isAttached() {
104         return mIsAttached;
105     }
106 
107     /** Attaches the window to the window manager. */
attach()108     public void attach() {
109         if (mIsAttached) {
110             return;
111         }
112         mIsAttached = true;
113         // Now that the status bar window encompasses the sliding panel and its
114         // translucent backdrop, the entire thing is made TRANSLUCENT and is
115         // hardware-accelerated.
116         mLp = new WindowManager.LayoutParams(
117                 ViewGroup.LayoutParams.MATCH_PARENT,
118                 ViewGroup.LayoutParams.MATCH_PARENT,
119                 WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE,
120                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
121                         | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
122                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
123                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
124                         | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
125                 PixelFormat.TRANSLUCENT);
126         mLp.token = new Binder();
127         mLp.gravity = Gravity.TOP;
128         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
129         mLp.setTitle("SystemUIOverlayWindow");
130         mLp.packageName = mContext.getPackageName();
131         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
132         mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
133 
134         mWindowManager.addView(mBaseLayout, mLp);
135         mLpChanged.copyFrom(mLp);
136         setWindowVisible(false);
137     }
138 
139     /** Sets the types of insets to fit. Note: This should be rarely used. */
setFitInsetsTypes(@indowInsets.Type.InsetsType int types)140     public void setFitInsetsTypes(@WindowInsets.Type.InsetsType int types) {
141         mLpChanged.setFitInsetsTypes(types);
142         mLpChanged.setFitInsetsIgnoringVisibility(mUsingStableInsets);
143         updateWindow();
144     }
145 
146     /** Sets the sides of system bar insets to fit. Note: This should be rarely used. */
setFitInsetsSides(@indowInsets.Side.InsetsSide int sides)147     public void setFitInsetsSides(@WindowInsets.Side.InsetsSide int sides) {
148         mLpChanged.setFitInsetsSides(sides);
149         mLpChanged.setFitInsetsIgnoringVisibility(mUsingStableInsets);
150         updateWindow();
151     }
152 
153     /** Sets the window to the visible state. */
setWindowVisible(boolean visible)154     public void setWindowVisible(boolean visible) {
155         mVisible = visible;
156         if (visible) {
157             mBaseLayout.setVisibility(View.VISIBLE);
158         } else {
159             mBaseLayout.setVisibility(View.INVISIBLE);
160         }
161         updateWindow();
162     }
163 
164     /** Sets the window to be focusable. */
setWindowFocusable(boolean focusable)165     public void setWindowFocusable(boolean focusable) {
166         mFocusable = focusable;
167         if (focusable) {
168             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
169         } else {
170             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
171         }
172         updateWindow();
173     }
174 
175     /** Sets the window to enable IME. */
setWindowNeedsInput(boolean needsInput)176     public void setWindowNeedsInput(boolean needsInput) {
177         if (needsInput) {
178             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
179         } else {
180             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
181         }
182         updateWindow();
183     }
184 
185     /** Returns {@code true} if the window is visible */
isWindowVisible()186     public boolean isWindowVisible() {
187         return mVisible;
188     }
189 
isWindowFocusable()190     public boolean isWindowFocusable() {
191         return mFocusable;
192     }
193 
setUsingStableInsets(boolean useStableInsets)194     protected void setUsingStableInsets(boolean useStableInsets) {
195         mUsingStableInsets = useStableInsets;
196     }
197 
updateWindow()198     private void updateWindow() {
199         if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
200             if (isAttached()) {
201                 mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
202                 mWindowManager.updateViewLayout(mBaseLayout, mLp);
203             }
204         }
205     }
206 }
207