mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 02:38:20 +00:00
* changes: Update taskbar to add extra hotseat items instead of recent apps Add support for having more hotseat icons in the DB than we show
437 lines
17 KiB
Java
437 lines
17 KiB
Java
/*
|
|
* Copyright (C) 2019 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;
|
|
|
|
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
|
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
|
|
import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
|
|
import static com.android.launcher3.LauncherState.NORMAL;
|
|
import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_SIZE;
|
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
|
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
|
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
|
|
|
|
import android.animation.AnimatorSet;
|
|
import android.animation.ValueAnimator;
|
|
import android.content.Intent;
|
|
import android.content.IntentSender;
|
|
import android.os.Bundle;
|
|
import android.os.CancellationSignal;
|
|
import android.view.View;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.android.launcher3.config.FeatureFlags;
|
|
import com.android.launcher3.dragndrop.DragOptions;
|
|
import com.android.launcher3.model.WellbeingModel;
|
|
import com.android.launcher3.popup.SystemShortcut;
|
|
import com.android.launcher3.proxy.ProxyActivityStarter;
|
|
import com.android.launcher3.proxy.StartActivityParams;
|
|
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
|
|
import com.android.launcher3.statehandlers.DepthController;
|
|
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
|
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
|
import com.android.launcher3.taskbar.TaskbarController;
|
|
import com.android.launcher3.taskbar.TaskbarStateHandler;
|
|
import com.android.launcher3.taskbar.TaskbarView;
|
|
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
|
import com.android.launcher3.util.ActivityOptionsWrapper;
|
|
import com.android.launcher3.util.DisplayController;
|
|
import com.android.launcher3.util.UiThreadHelper;
|
|
import com.android.quickstep.RecentsModel;
|
|
import com.android.quickstep.SysUINavigationMode;
|
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
|
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
|
import com.android.quickstep.SystemUiProxy;
|
|
import com.android.quickstep.TaskUtils;
|
|
import com.android.quickstep.util.RemoteAnimationProvider;
|
|
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
|
|
import com.android.quickstep.util.SplitSelectStateController;
|
|
import com.android.quickstep.views.OverviewActionsView;
|
|
import com.android.quickstep.views.RecentsView;
|
|
import com.android.quickstep.views.SplitPlaceholderView;
|
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
|
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
|
|
|
import java.util.List;
|
|
import java.util.stream.Stream;
|
|
|
|
/**
|
|
* Extension of Launcher activity to provide quickstep specific functionality
|
|
*/
|
|
public abstract class BaseQuickstepLauncher extends Launcher
|
|
implements NavigationModeChangeListener {
|
|
|
|
private DepthController mDepthController = new DepthController(this);
|
|
private QuickstepTransitionManager mAppTransitionManager;
|
|
|
|
/**
|
|
* Reusable command for applying the back button alpha on the background thread.
|
|
*/
|
|
public static final UiThreadHelper.AsyncCommand SET_BACK_BUTTON_ALPHA =
|
|
(context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setNavBarButtonAlpha(
|
|
Float.intBitsToFloat(arg1), arg2 != 0);
|
|
|
|
private OverviewActionsView mActionsView;
|
|
|
|
private @Nullable TaskbarController mTaskbarController;
|
|
private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
|
|
// Will be updated when dragging from taskbar.
|
|
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
|
|
private SplitPlaceholderView mSplitPlaceholderView;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
|
|
addMultiWindowModeChangedListener(mDepthController);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
mAppTransitionManager.onActivityDestroyed();
|
|
|
|
SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
|
|
if (mTaskbarController != null) {
|
|
mTaskbarController.cleanup();
|
|
mTaskbarController = null;
|
|
}
|
|
|
|
super.onDestroy();
|
|
}
|
|
|
|
public QuickstepTransitionManager getAppTransitionManager() {
|
|
return mAppTransitionManager;
|
|
}
|
|
|
|
@Override
|
|
public void onNavigationModeChanged(Mode newMode) {
|
|
getDragLayer().recreateControllers();
|
|
if (mActionsView != null) {
|
|
mActionsView.updateVerticalMargin(newMode);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEnterAnimationComplete() {
|
|
super.onEnterAnimationComplete();
|
|
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
|
|
// as a part of quickstep, so that high-res thumbnails can load the next time we enter
|
|
// overview
|
|
RecentsModel.INSTANCE.get(this).getThumbnailCache()
|
|
.getHighResLoadingState().setVisible(true);
|
|
}
|
|
|
|
@Override
|
|
protected void handleGestureContract(Intent intent) {
|
|
if (FeatureFlags.SEPARATE_RECENTS_ACTIVITY.get()) {
|
|
super.handleGestureContract(intent);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onTrimMemory(int level) {
|
|
super.onTrimMemory(level);
|
|
RecentsModel.INSTANCE.get(this).onTrimMemory(level);
|
|
}
|
|
|
|
@Override
|
|
protected void onUiChangedWhileSleeping() {
|
|
// Remove the snapshot because the content view may have obvious changes.
|
|
UI_HELPER_EXECUTOR.execute(
|
|
() -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this));
|
|
}
|
|
|
|
@Override
|
|
public void startIntentSenderForResult(IntentSender intent, int requestCode,
|
|
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
|
|
if (requestCode != -1) {
|
|
mPendingActivityRequestCode = requestCode;
|
|
StartActivityParams params = new StartActivityParams(this, requestCode);
|
|
params.intentSender = intent;
|
|
params.fillInIntent = fillInIntent;
|
|
params.flagsMask = flagsMask;
|
|
params.flagsValues = flagsValues;
|
|
params.extraFlags = extraFlags;
|
|
params.options = options;
|
|
startActivity(ProxyActivityStarter.getLaunchIntent(this, params));
|
|
} else {
|
|
super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
|
|
flagsValues, extraFlags, options);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
|
if (requestCode != -1) {
|
|
mPendingActivityRequestCode = requestCode;
|
|
StartActivityParams params = new StartActivityParams(this, requestCode);
|
|
params.intent = intent;
|
|
params.options = options;
|
|
startActivity(ProxyActivityStarter.getLaunchIntent(this, params));
|
|
} else {
|
|
super.startActivityForResult(intent, requestCode, options);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onDeferredResumed() {
|
|
super.onDeferredResumed();
|
|
handlePendingActivityRequest();
|
|
}
|
|
|
|
@Override
|
|
public void onStateSetEnd(LauncherState state) {
|
|
super.onStateSetEnd(state);
|
|
handlePendingActivityRequest();
|
|
}
|
|
|
|
private void handlePendingActivityRequest() {
|
|
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)
|
|
&& ((getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) {
|
|
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
|
|
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
|
|
// ProxyActivityStarter is started with clear task to reset the task after which it
|
|
// removes the task itself.
|
|
startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void setupViews() {
|
|
super.setupViews();
|
|
|
|
SysUINavigationMode.INSTANCE.get(this).updateMode();
|
|
mActionsView = findViewById(R.id.overview_actions_view);
|
|
mSplitPlaceholderView = findViewById(R.id.split_placeholder);
|
|
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
|
|
mSplitPlaceholderView.init(
|
|
new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this))
|
|
);
|
|
overviewPanel.init(mActionsView, mSplitPlaceholderView);
|
|
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
|
|
|
|
mAppTransitionManager = new QuickstepTransitionManager(this);
|
|
mAppTransitionManager.registerRemoteAnimations();
|
|
|
|
addTaskbarIfNecessary();
|
|
addOnDeviceProfileChangeListener(newDp -> addTaskbarIfNecessary());
|
|
}
|
|
|
|
@Override
|
|
public void onDisplayInfoChanged(DisplayController.Info info, int flags) {
|
|
super.onDisplayInfoChanged(info, flags);
|
|
if ((flags & CHANGE_SIZE) != 0) {
|
|
addTaskbarIfNecessary();
|
|
}
|
|
}
|
|
|
|
private void addTaskbarIfNecessary() {
|
|
if (mTaskbarController != null) {
|
|
mTaskbarController.cleanup();
|
|
mTaskbarController = null;
|
|
}
|
|
if (mDeviceProfile.isTaskbarPresent) {
|
|
TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView();
|
|
TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this);
|
|
mTaskbarController = new TaskbarController(this,
|
|
taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome);
|
|
mTaskbarController.init();
|
|
}
|
|
}
|
|
|
|
public <T extends OverviewActionsView> T getActionsView() {
|
|
return (T) mActionsView;
|
|
}
|
|
|
|
public SplitPlaceholderView getSplitPlaceholderView() {
|
|
return mSplitPlaceholderView;
|
|
}
|
|
|
|
@Override
|
|
protected void closeOpenViews(boolean animate) {
|
|
super.closeOpenViews(animate);
|
|
TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
|
|
}
|
|
|
|
@Override
|
|
protected void collectStateHandlers(List<StateHandler> out) {
|
|
super.collectStateHandlers(out);
|
|
out.add(getDepthController());
|
|
out.add(new RecentsViewStateController(this));
|
|
out.add(new BackButtonAlphaHandler(this));
|
|
out.add(getTaskbarStateHandler());
|
|
}
|
|
|
|
public DepthController getDepthController() {
|
|
return mDepthController;
|
|
}
|
|
|
|
public @Nullable TaskbarController getTaskbarController() {
|
|
return mTaskbarController;
|
|
}
|
|
|
|
public TaskbarStateHandler getTaskbarStateHandler() {
|
|
return mTaskbarStateHandler;
|
|
}
|
|
|
|
@Override
|
|
public boolean isViewInTaskbar(View v) {
|
|
return mTaskbarController != null && mTaskbarController.isViewInTaskbar(v);
|
|
}
|
|
|
|
public boolean supportsAdaptiveIconAnimation(View clickedView) {
|
|
return mAppTransitionManager.hasControlRemoteAppTransitionPermission()
|
|
&& FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM.get()
|
|
&& !isViewInTaskbar(clickedView);
|
|
}
|
|
|
|
@Override
|
|
public DragOptions getDefaultWorkspaceDragOptions() {
|
|
if (mNextWorkspaceDragOptions != null) {
|
|
DragOptions options = mNextWorkspaceDragOptions;
|
|
mNextWorkspaceDragOptions = null;
|
|
return options;
|
|
}
|
|
return super.getDefaultWorkspaceDragOptions();
|
|
}
|
|
|
|
public void setNextWorkspaceDragOptions(DragOptions dragOptions) {
|
|
mNextWorkspaceDragOptions = dragOptions;
|
|
}
|
|
|
|
@Override
|
|
public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
|
|
QuickstepTransitionManager appTransitionManager = getAppTransitionManager();
|
|
appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
|
|
@Override
|
|
public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
|
|
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
|
|
|
// On the first call clear the reference.
|
|
signal.cancel();
|
|
|
|
ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
|
|
fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets,
|
|
wallpaperTargets));
|
|
AnimatorSet anim = new AnimatorSet();
|
|
anim.play(fadeAnimation);
|
|
return anim;
|
|
}
|
|
}, signal);
|
|
}
|
|
|
|
@Override
|
|
public float[] getNormalOverviewScaleAndOffset() {
|
|
return SysUINavigationMode.getMode(this).hasGestures
|
|
? new float[] {1, 1} : new float[] {1.1f, 0};
|
|
}
|
|
|
|
@Override
|
|
public float getNormalTaskbarScale() {
|
|
if (mTaskbarController != null) {
|
|
return mTaskbarController.getTaskbarScaleOnHome();
|
|
}
|
|
return super.getNormalTaskbarScale();
|
|
}
|
|
|
|
@Override
|
|
public void onDragLayerHierarchyChanged() {
|
|
onLauncherStateOrFocusChanged();
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityFlagsChanged(int changeBits) {
|
|
if ((changeBits
|
|
& (ACTIVITY_STATE_WINDOW_FOCUSED | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) {
|
|
onLauncherStateOrFocusChanged();
|
|
}
|
|
|
|
if ((changeBits & ACTIVITY_STATE_STARTED) != 0) {
|
|
mDepthController.setActivityStarted(isStarted());
|
|
}
|
|
|
|
if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) {
|
|
if (mTaskbarController != null) {
|
|
mTaskbarController.onLauncherResumedOrPaused(hasBeenResumed());
|
|
}
|
|
}
|
|
|
|
super.onActivityFlagsChanged(changeBits);
|
|
}
|
|
|
|
public boolean shouldBackButtonBeHidden(LauncherState toState) {
|
|
Mode mode = SysUINavigationMode.getMode(this);
|
|
boolean shouldBackButtonBeHidden = mode.hasGestures
|
|
&& toState.hasFlag(FLAG_HIDE_BACK_BUTTON)
|
|
&& hasWindowFocus()
|
|
&& (getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0;
|
|
if (shouldBackButtonBeHidden) {
|
|
// Show the back button if there is a floating view visible.
|
|
shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(this,
|
|
TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null;
|
|
}
|
|
return shouldBackButtonBeHidden;
|
|
}
|
|
|
|
/**
|
|
* Sets the back button visibility based on the current state/window focus.
|
|
*/
|
|
private void onLauncherStateOrFocusChanged() {
|
|
boolean shouldBackButtonBeHidden = shouldBackButtonBeHidden(getStateManager().getState());
|
|
if (SysUINavigationMode.getMode(this) == TWO_BUTTONS) {
|
|
UiThreadHelper.setBackButtonAlphaAsync(this, SET_BACK_BUTTON_ALPHA,
|
|
shouldBackButtonBeHidden ? 0f : 1f, true /* animate */);
|
|
}
|
|
if (getDragLayer() != null) {
|
|
getRootView().setDisallowBackGesture(shouldBackButtonBeHidden);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void finishBindingItems(int pageBoundFirst) {
|
|
super.finishBindingItems(pageBoundFirst);
|
|
// Instantiate and initialize WellbeingModel now that its loading won't interfere with
|
|
// populating workspace.
|
|
// TODO: Find a better place for this
|
|
WellbeingModel.INSTANCE.get(this);
|
|
}
|
|
|
|
@Override
|
|
public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
|
|
return Stream.concat(super.getSupportedShortcuts(),
|
|
Stream.of(WellbeingModel.SHORTCUT_FACTORY));
|
|
}
|
|
|
|
@Override
|
|
public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
|
|
ActivityOptionsWrapper activityOptions =
|
|
mAppTransitionManager.hasControlRemoteAppTransitionPermission()
|
|
? mAppTransitionManager.getActivityLaunchOptions(this, v)
|
|
: super.getActivityLaunchOptions(v);
|
|
if (mLastTouchUpTime > 0) {
|
|
ActivityOptionsCompat.setLauncherSourceInfo(
|
|
activityOptions.options, mLastTouchUpTime);
|
|
}
|
|
return activityOptions;
|
|
}
|
|
|
|
public void setHintUserWillBeActive() {
|
|
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
|
|
}
|
|
}
|