/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.taskbar; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; import android.content.Context; import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.view.Display; import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.Info; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TouchInteractionService; /** * Class to manager taskbar lifecycle */ public class TaskbarManager implements DisplayController.DisplayInfoChangeListener, SysUINavigationMode.NavigationModeChangeListener { private final Context mContext; private final DisplayController mDisplayController; private final SysUINavigationMode mSysUINavigationMode; private final TaskbarNavButtonController mNavButtonController; private TaskbarActivityContext mTaskbarActivityContext; private BaseQuickstepLauncher mLauncher; private static final int CHANGE_FLAGS = CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS; private boolean mUserUnlocked = false; public TaskbarManager(TouchInteractionService service) { mDisplayController = DisplayController.INSTANCE.get(service); mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service); Display display = service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null); mNavButtonController = new TaskbarNavButtonController(service); mDisplayController.addChangeListener(this); mSysUINavigationMode.addModeChangeListener(this); recreateTaskbar(); } @Override public void onNavigationModeChanged(Mode newMode) { recreateTaskbar(); } @Override public void onDisplayInfoChanged(Context context, Info info, int flags) { if ((flags & CHANGE_FLAGS) != 0) { recreateTaskbar(); } } private void destroyExistingTaskbar() { if (mTaskbarActivityContext != null) { mTaskbarActivityContext.onDestroy(); mTaskbarActivityContext = null; } } /** * Called when the user is unlocked */ public void onUserUnlocked() { mUserUnlocked = true; recreateTaskbar(); } /** * Sets or clears a launcher to act as taskbar callback */ public void setLauncher(@Nullable BaseQuickstepLauncher launcher) { mLauncher = launcher; if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController(mLauncher == null ? TaskbarUIController.DEFAULT : new LauncherTaskbarUIController(launcher, mTaskbarActivityContext)); } } private void recreateTaskbar() { destroyExistingTaskbar(); if (!FeatureFlags.ENABLE_TASKBAR.get()) { return; } if (!mUserUnlocked) { return; } DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext); if (!dp.isTaskbarPresent) { return; } mTaskbarActivityContext = new TaskbarActivityContext( mContext, dp.copy(mContext), mNavButtonController); mTaskbarActivityContext.init(); if (mLauncher != null) { mTaskbarActivityContext.setUIController( new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext)); } } /** * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags} * @param systemUiStateFlags The latest SystemUiStateFlags */ public void onSystemUiFlagsChanged(int systemUiStateFlags) { boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0; if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setImeIsVisible(isImeVisible); } } /** * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from * instantiating at all, which is what's responsible for sending sysui state flags over. * * @param vis IME visibility flag * @param backDisposition Used to determine back button behavior for software keyboard * See BACK_DISPOSITION_* constants in {@link InputMethodService} */ public void updateImeStatus(int displayId, int vis, int backDisposition, boolean showImeSwitcher) { if (mTaskbarActivityContext != null) { mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher); } } /** * Called when the manager is no longer needed */ public void destroy() { destroyExistingTaskbar(); mDisplayController.removeChangeListener(this); mSysUINavigationMode.removeModeChangeListener(this); } }