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