1 /* 2 * Copyright (C) 2021 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 package com.android.launcher3.taskbar; 17 18 import static android.view.Display.DEFAULT_DISPLAY; 19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 20 21 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; 22 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; 23 import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS; 24 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; 25 26 import android.content.Context; 27 import android.hardware.display.DisplayManager; 28 import android.inputmethodservice.InputMethodService; 29 import android.view.Display; 30 31 import androidx.annotation.Nullable; 32 33 import com.android.launcher3.BaseQuickstepLauncher; 34 import com.android.launcher3.DeviceProfile; 35 import com.android.launcher3.LauncherAppState; 36 import com.android.launcher3.config.FeatureFlags; 37 import com.android.launcher3.util.DisplayController; 38 import com.android.launcher3.util.DisplayController.Info; 39 import com.android.quickstep.SysUINavigationMode; 40 import com.android.quickstep.SysUINavigationMode.Mode; 41 import com.android.quickstep.TouchInteractionService; 42 43 /** 44 * Class to manager taskbar lifecycle 45 */ 46 public class TaskbarManager implements DisplayController.DisplayInfoChangeListener, 47 SysUINavigationMode.NavigationModeChangeListener { 48 49 private final Context mContext; 50 private final DisplayController mDisplayController; 51 private final SysUINavigationMode mSysUINavigationMode; 52 private final TaskbarNavButtonController mNavButtonController; 53 54 private TaskbarActivityContext mTaskbarActivityContext; 55 private BaseQuickstepLauncher mLauncher; 56 57 private static final int CHANGE_FLAGS = 58 CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS; 59 60 private boolean mUserUnlocked = false; 61 TaskbarManager(TouchInteractionService service)62 public TaskbarManager(TouchInteractionService service) { 63 mDisplayController = DisplayController.INSTANCE.get(service); 64 mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service); 65 Display display = 66 service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); 67 mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null); 68 mNavButtonController = new TaskbarNavButtonController(service); 69 70 mDisplayController.addChangeListener(this); 71 mSysUINavigationMode.addModeChangeListener(this); 72 recreateTaskbar(); 73 } 74 75 @Override onNavigationModeChanged(Mode newMode)76 public void onNavigationModeChanged(Mode newMode) { 77 recreateTaskbar(); 78 } 79 80 @Override onDisplayInfoChanged(Context context, Info info, int flags)81 public void onDisplayInfoChanged(Context context, Info info, int flags) { 82 if ((flags & CHANGE_FLAGS) != 0) { 83 recreateTaskbar(); 84 } 85 } 86 destroyExistingTaskbar()87 private void destroyExistingTaskbar() { 88 if (mTaskbarActivityContext != null) { 89 mTaskbarActivityContext.onDestroy(); 90 mTaskbarActivityContext = null; 91 } 92 } 93 94 /** 95 * Called when the user is unlocked 96 */ onUserUnlocked()97 public void onUserUnlocked() { 98 mUserUnlocked = true; 99 recreateTaskbar(); 100 } 101 102 /** 103 * Sets or clears a launcher to act as taskbar callback 104 */ setLauncher(@ullable BaseQuickstepLauncher launcher)105 public void setLauncher(@Nullable BaseQuickstepLauncher launcher) { 106 mLauncher = launcher; 107 if (mTaskbarActivityContext != null) { 108 mTaskbarActivityContext.setUIController(mLauncher == null 109 ? TaskbarUIController.DEFAULT 110 : new LauncherTaskbarUIController(launcher, mTaskbarActivityContext)); 111 } 112 } 113 recreateTaskbar()114 private void recreateTaskbar() { 115 destroyExistingTaskbar(); 116 if (!FeatureFlags.ENABLE_TASKBAR.get()) { 117 return; 118 } 119 if (!mUserUnlocked) { 120 return; 121 } 122 DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext); 123 if (!dp.isTaskbarPresent) { 124 return; 125 } 126 mTaskbarActivityContext = new TaskbarActivityContext( 127 mContext, dp.copy(mContext), mNavButtonController); 128 mTaskbarActivityContext.init(); 129 if (mLauncher != null) { 130 mTaskbarActivityContext.setUIController( 131 new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext)); 132 } 133 } 134 135 /** 136 * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags} 137 * @param systemUiStateFlags The latest SystemUiStateFlags 138 */ onSystemUiFlagsChanged(int systemUiStateFlags)139 public void onSystemUiFlagsChanged(int systemUiStateFlags) { 140 boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0; 141 if (mTaskbarActivityContext != null) { 142 mTaskbarActivityContext.setImeIsVisible(isImeVisible); 143 } 144 } 145 146 /** 147 * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from 148 * instantiating at all, which is what's responsible for sending sysui state flags over. 149 * 150 * @param vis IME visibility flag 151 * @param backDisposition Used to determine back button behavior for software keyboard 152 * See BACK_DISPOSITION_* constants in {@link InputMethodService} 153 */ updateImeStatus(int displayId, int vis, int backDisposition, boolean showImeSwitcher)154 public void updateImeStatus(int displayId, int vis, int backDisposition, 155 boolean showImeSwitcher) { 156 if (mTaskbarActivityContext != null) { 157 mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher); 158 } 159 } 160 161 /** 162 * Called when the manager is no longer needed 163 */ destroy()164 public void destroy() { 165 destroyExistingTaskbar(); 166 mDisplayController.removeChangeListener(this); 167 mSysUINavigationMode.removeModeChangeListener(this); 168 } 169 } 170