Snap for 8082780 from f2172eba8c to tm-release
Change-Id: I516d737b5d3b878c9bc3b500c69a4b3693e9a740
This commit is contained in:
@@ -36,6 +36,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
@@ -55,9 +56,11 @@ import android.util.Property;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnHoverListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -68,10 +71,13 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.systemui.shared.rotation.FloatingRotationButton;
|
||||
import com.android.systemui.shared.rotation.RotationButton;
|
||||
import com.android.systemui.shared.rotation.RotationButtonController;
|
||||
import com.android.systemui.shared.system.ViewTreeObserverWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.IntPredicate;
|
||||
@@ -98,6 +104,8 @@ public class NavbarButtonsViewController {
|
||||
|
||||
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
|
||||
|
||||
private static final String NAV_BUTTONS_SEPARATE_WINDOW_TITLE = "Taskbar Nav Buttons";
|
||||
|
||||
private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
|
||||
private final ArrayList<ImageView> mAllButtons = new ArrayList<>();
|
||||
private int mState;
|
||||
@@ -134,6 +142,12 @@ public class NavbarButtonsViewController {
|
||||
private View mHomeButton;
|
||||
private FloatingRotationButton mFloatingRotationButton;
|
||||
|
||||
// Variables for moving nav buttons to a separate window above IME
|
||||
private boolean mAreNavButtonsInSeparateWindow = false;
|
||||
private BaseDragLayer<TaskbarActivityContext> mSeparateWindowParent; // Initialized in init.
|
||||
private final ViewTreeObserverWrapper.OnComputeInsetsListener mSeparateWindowInsetsComputer =
|
||||
this::onComputeInsetsForSeparateWindow;
|
||||
|
||||
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
|
||||
mContext = context;
|
||||
mNavButtonsView = navButtonsView;
|
||||
@@ -321,6 +335,21 @@ public class NavbarButtonsViewController {
|
||||
R.id.notifications_button);
|
||||
}
|
||||
|
||||
// Initialize things needed to move nav buttons to separate window.
|
||||
mSeparateWindowParent = new BaseDragLayer<TaskbarActivityContext>(mContext, null, 0) {
|
||||
@Override
|
||||
public void recreateControllers() {
|
||||
mControllers = new TouchController[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canFindActiveController() {
|
||||
// We don't have any controllers, but we don't want any floating views such as
|
||||
// folder to intercept, either. This ensures nav buttons can always be pressed.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
mSeparateWindowParent.recreateControllers();
|
||||
}
|
||||
|
||||
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
|
||||
@@ -456,7 +485,7 @@ public class NavbarButtonsViewController {
|
||||
/**
|
||||
* Adds the bounds corresponding to all visible buttons to provided region
|
||||
*/
|
||||
public void addVisibleButtonsRegion(TaskbarDragLayer parent, Region outRegion) {
|
||||
public void addVisibleButtonsRegion(BaseDragLayer<?> parent, Region outRegion) {
|
||||
int count = mAllButtons.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View button = mAllButtons.get(i);
|
||||
@@ -561,6 +590,59 @@ public class NavbarButtonsViewController {
|
||||
if (mFloatingRotationButton != null) {
|
||||
mFloatingRotationButton.hide();
|
||||
}
|
||||
|
||||
moveNavButtonsBackToTaskbarWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves mNavButtonsView from TaskbarDragLayer to a placeholder BaseDragLayer on a new window.
|
||||
*/
|
||||
public void moveNavButtonsToNewWindow() {
|
||||
if (mAreNavButtonsInSeparateWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSeparateWindowParent.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View view) {
|
||||
ViewTreeObserverWrapper.addOnComputeInsetsListener(
|
||||
mSeparateWindowParent.getViewTreeObserver(), mSeparateWindowInsetsComputer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View view) {
|
||||
mSeparateWindowParent.removeOnAttachStateChangeListener(this);
|
||||
ViewTreeObserverWrapper.removeOnComputeInsetsListener(
|
||||
mSeparateWindowInsetsComputer);
|
||||
}
|
||||
});
|
||||
|
||||
mAreNavButtonsInSeparateWindow = true;
|
||||
mContext.getDragLayer().removeView(mNavButtonsView);
|
||||
mSeparateWindowParent.addView(mNavButtonsView);
|
||||
WindowManager.LayoutParams windowLayoutParams = mContext.createDefaultWindowLayoutParams();
|
||||
windowLayoutParams.setTitle(NAV_BUTTONS_SEPARATE_WINDOW_TITLE);
|
||||
mContext.addWindowView(mSeparateWindowParent, windowLayoutParams);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves mNavButtonsView from its temporary window and reattaches it to TaskbarDragLayer.
|
||||
*/
|
||||
public void moveNavButtonsBackToTaskbarWindow() {
|
||||
if (!mAreNavButtonsInSeparateWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAreNavButtonsInSeparateWindow = false;
|
||||
mContext.removeWindowView(mSeparateWindowParent);
|
||||
mSeparateWindowParent.removeView(mNavButtonsView);
|
||||
mContext.getDragLayer().addView(mNavButtonsView);
|
||||
}
|
||||
|
||||
private void onComputeInsetsForSeparateWindow(ViewTreeObserverWrapper.InsetsInfo insetsInfo) {
|
||||
addVisibleButtonsRegion(mSeparateWindowParent, insetsInfo.touchableRegion);
|
||||
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
|
||||
}
|
||||
|
||||
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
|
||||
|
||||
@@ -189,21 +190,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
||||
|
||||
public void init(TaskbarSharedState sharedState) {
|
||||
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
|
||||
mWindowLayoutParams = new WindowManager.LayoutParams(
|
||||
MATCH_PARENT,
|
||||
mLastRequestedNonFullscreenHeight,
|
||||
TYPE_NAVIGATION_BAR_PANEL,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_SLIPPERY,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
mWindowLayoutParams.setTitle(WINDOW_TITLE);
|
||||
mWindowLayoutParams.packageName = getPackageName();
|
||||
mWindowLayoutParams.gravity = Gravity.BOTTOM;
|
||||
mWindowLayoutParams.setFitInsetsTypes(0);
|
||||
mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
mWindowLayoutParams.privateFlags =
|
||||
WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
|
||||
mWindowLayoutParams = createDefaultWindowLayoutParams();
|
||||
|
||||
WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
|
||||
wmWrapper.setProvidesInsetsTypes(
|
||||
@@ -224,6 +211,27 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
||||
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
|
||||
}
|
||||
|
||||
/** Creates LayoutParams for adding a view directly to WindowManager as a new window */
|
||||
public WindowManager.LayoutParams createDefaultWindowLayoutParams() {
|
||||
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
|
||||
MATCH_PARENT,
|
||||
mLastRequestedNonFullscreenHeight,
|
||||
TYPE_NAVIGATION_BAR_PANEL,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_SLIPPERY,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
windowLayoutParams.setTitle(WINDOW_TITLE);
|
||||
windowLayoutParams.packageName = getPackageName();
|
||||
windowLayoutParams.gravity = Gravity.BOTTOM;
|
||||
windowLayoutParams.setFitInsetsTypes(0);
|
||||
windowLayoutParams.receiveInsetsIgnoringZOrder = true;
|
||||
windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||
windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
windowLayoutParams.privateFlags =
|
||||
WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
|
||||
return windowLayoutParams;
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(@Config int configChanges) {
|
||||
mControllers.onConfigurationChanged(configChanges);
|
||||
}
|
||||
@@ -270,14 +278,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
||||
return mViewCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIme() {
|
||||
// Currently we don't support IME because we have FLAG_NOT_FOCUSABLE. We can remove that
|
||||
// flag when opening a floating view that needs IME (such as Folder), but then that means
|
||||
// Taskbar will be below IME and thus users can't click the back button.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View.OnClickListener getItemOnClickListener() {
|
||||
return this::onTaskbarIconClicked;
|
||||
@@ -505,6 +505,42 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
||||
return mTaskbarHeightForIme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
|
||||
* window.
|
||||
*/
|
||||
public void setTaskbarWindowFocusable(boolean focusable) {
|
||||
if (focusable) {
|
||||
mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
|
||||
} else {
|
||||
mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
|
||||
}
|
||||
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
|
||||
* window. If we're now focusable, also move nav buttons to a separate window above IME.
|
||||
*/
|
||||
public void setTaskbarWindowFocusableForIme(boolean focusable) {
|
||||
if (focusable) {
|
||||
mControllers.navbarButtonsViewController.moveNavButtonsToNewWindow();
|
||||
} else {
|
||||
mControllers.navbarButtonsViewController.moveNavButtonsBackToTaskbarWindow();
|
||||
}
|
||||
setTaskbarWindowFocusable(focusable);
|
||||
}
|
||||
|
||||
/** Adds the given view to WindowManager with the provided LayoutParams (creates new window). */
|
||||
public void addWindowView(View view, WindowManager.LayoutParams windowLayoutParams) {
|
||||
mWindowManager.addView(view, windowLayoutParams);
|
||||
}
|
||||
|
||||
/** Removes the given view from WindowManager. See {@link #addWindowView}. */
|
||||
public void removeWindowView(View view) {
|
||||
mWindowManager.removeViewImmediate(view);
|
||||
}
|
||||
|
||||
protected void onTaskbarIconClicked(View view) {
|
||||
Object tag = view.getTag();
|
||||
if (tag instanceof Task) {
|
||||
@@ -514,6 +550,17 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
||||
} else if (tag instanceof FolderInfo) {
|
||||
FolderIcon folderIcon = (FolderIcon) view;
|
||||
Folder folder = folderIcon.getFolder();
|
||||
|
||||
folder.setOnFolderStateChangedListener(newState -> {
|
||||
if (newState == Folder.STATE_OPEN) {
|
||||
setTaskbarWindowFocusableForIme(true);
|
||||
} else if (newState == Folder.STATE_CLOSED) {
|
||||
// Defer by a frame to ensure we're no longer fullscreen and thus won't jump.
|
||||
getDragLayer().post(() -> setTaskbarWindowFocusableForIme(false));
|
||||
folder.setOnFolderStateChangedListener(null);
|
||||
}
|
||||
});
|
||||
|
||||
setTaskbarWindowFullscreen(true);
|
||||
|
||||
getDragLayer().post(() -> {
|
||||
|
||||
@@ -15,17 +15,22 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static android.view.KeyEvent.ACTION_UP;
|
||||
import static android.view.KeyEvent.KEYCODE_BACK;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
@@ -187,4 +192,17 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
|
||||
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
/** Called while Taskbar window is focusable, e.g. when pressing back while a folder is open */
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
|
||||
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
|
||||
if (topView != null && topView.onBackPressed()) {
|
||||
// Handled by the floating view.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.animation.ObjectAnimator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
@@ -256,6 +257,10 @@ import java.util.function.Supplier;
|
||||
|
||||
if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) {
|
||||
boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING);
|
||||
if (goingToLauncher) {
|
||||
// Handle closing open popups when going home/overview
|
||||
AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext);
|
||||
}
|
||||
animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1)
|
||||
.setDuration(duration));
|
||||
}
|
||||
|
||||
@@ -154,6 +154,15 @@ public class TaskbarPopupController {
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList()));
|
||||
container.requestFocus();
|
||||
|
||||
// Make focusable to receive back events
|
||||
mControllers.taskbarActivityContext.setTaskbarWindowFocusable(true);
|
||||
container.setOnCloseCallback(() -> {
|
||||
mControllers.taskbarActivityContext.getDragLayer().post(
|
||||
() -> mControllers.taskbarActivityContext.setTaskbarWindowFocusable(false));
|
||||
container.setOnCloseCallback(null);
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
@@ -1410,7 +1410,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
.setContext(mContext)
|
||||
.setTaskId(runningTaskTarget.taskId)
|
||||
.setComponentName(taskInfo.topActivity)
|
||||
.setLeash(runningTaskTarget.leash.getSurfaceControl())
|
||||
.setLeash(runningTaskTarget.leash)
|
||||
.setSourceRectHint(
|
||||
runningTaskTarget.taskInfo.pictureInPictureParams.getSourceRectHint())
|
||||
.setAppBounds(taskInfo.configuration.windowConfiguration.getBounds())
|
||||
|
||||
@@ -419,7 +419,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
|
||||
RemoteAnimationTargets targets = new RemoteAnimationTargets(
|
||||
appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
|
||||
for (RemoteAnimationTargetCompat app : targets.apps) {
|
||||
new Transaction().setAlpha(app.leash.getSurfaceControl(), 1).apply();
|
||||
new Transaction().setAlpha(app.leash, 1).apply();
|
||||
}
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(controller.getAnimationPlayer());
|
||||
|
||||
@@ -469,7 +469,7 @@ public final class TaskViewUtils {
|
||||
for (RemoteAnimationTargetCompat appTarget : appTargets) {
|
||||
final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1;
|
||||
final int mode = appTarget.mode;
|
||||
final SurfaceControl leash = appTarget.leash.getSurfaceControl();
|
||||
final SurfaceControl leash = appTarget.leash;
|
||||
if (leash == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -484,7 +484,7 @@ public final class TaskViewUtils {
|
||||
}
|
||||
|
||||
for (int i = 0; i < nonAppTargets.length; ++i) {
|
||||
final SurfaceControl leash = appTargets[i].leash.getSurfaceControl();
|
||||
final SurfaceControl leash = appTargets[i].leash;
|
||||
if (nonAppTargets[i].windowType == TYPE_DOCK_DIVIDER && leash != null) {
|
||||
openingTargets.add(leash);
|
||||
}
|
||||
@@ -611,7 +611,7 @@ public final class TaskViewUtils {
|
||||
boolean hasSurfaceToAnimate = false;
|
||||
for (int i = 0; i < nonApps.length; ++i) {
|
||||
final RemoteAnimationTargetCompat targ = nonApps[i];
|
||||
final SurfaceControl leash = targ.leash.getSurfaceControl();
|
||||
final SurfaceControl leash = targ.leash;
|
||||
if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) {
|
||||
auxiliarySurfaces.add(leash);
|
||||
hasSurfaceToAnimate = true;
|
||||
|
||||
@@ -174,10 +174,10 @@ public class TransformParams {
|
||||
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
|
||||
if (app.mode == targets.targetMode) {
|
||||
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS) {
|
||||
return app.leash.getSurfaceControl();
|
||||
return app.leash;
|
||||
}
|
||||
} else {
|
||||
return app.leash.getSurfaceControl();
|
||||
return app.leash;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -187,6 +187,10 @@
|
||||
<attr name="minCellHeight" format="float" />
|
||||
<attr name="minCellWidth" format="float" />
|
||||
<!-- defaults to minCellHeight, if not specified -->
|
||||
<attr name="minCellHeightLandscape" format="float" />
|
||||
<!-- defaults to minCellWidth, if not specified -->
|
||||
<attr name="minCellWidthLandscape" format="float" />
|
||||
<!-- defaults to minCellHeight, if not specified -->
|
||||
<attr name="minCellHeightTwoPanelPortrait" format="float" />
|
||||
<!-- defaults to minCellWidth, if not specified -->
|
||||
<attr name="minCellWidthTwoPanelPortrait" format="float" />
|
||||
@@ -244,6 +248,8 @@
|
||||
<!-- defaults to borderSpaceDps, if not specified -->
|
||||
<attr name="hotseatBorderSpace" format="float" />
|
||||
<!-- defaults to hotseatBorderSpace, if not specified -->
|
||||
<attr name="hotseatBorderSpaceLandscape" format="float" />
|
||||
<!-- defaults to hotseatBorderSpace, if not specified -->
|
||||
<attr name="hotseatBorderSpaceTwoPanelLandscape" format="float" />
|
||||
<!-- defaults to hotseatBorderSpace, if not specified -->
|
||||
<attr name="hotseatBorderSpaceTwoPanelPortrait" format="float" />
|
||||
@@ -270,6 +276,8 @@
|
||||
<!-- Margin on left and right of the workspace when GridDisplayOption#isScalable is true -->
|
||||
<attr name="horizontalMargin" format="float"/>
|
||||
<!-- defaults to horizontalMargin if not specified -->
|
||||
<attr name="horizontalMarginLandscape" format="float"/>
|
||||
<!-- defaults to horizontalMargin if not specified -->
|
||||
<attr name="horizontalMarginTwoPanelLandscape" format="float"/>
|
||||
<!-- defaults to horizontalMargin if not specified -->
|
||||
<attr name="horizontalMarginTwoPanelPortrait" format="float"/>
|
||||
|
||||
@@ -238,9 +238,19 @@ public class CellLayout extends ViewGroup {
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
|
||||
|
||||
mBorderSpace = mContainerType == FOLDER
|
||||
? new Point(deviceProfile.folderCellLayoutBorderSpacePx)
|
||||
: new Point(deviceProfile.cellLayoutBorderSpacePx);
|
||||
switch (mContainerType) {
|
||||
case FOLDER:
|
||||
mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
|
||||
break;
|
||||
case HOTSEAT:
|
||||
mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
|
||||
deviceProfile.hotseatBorderSpace);
|
||||
break;
|
||||
case WORKSPACE:
|
||||
default:
|
||||
mBorderSpace = new Point(deviceProfile.cellLayoutBorderSpacePx);
|
||||
break;
|
||||
}
|
||||
|
||||
mCellWidth = mCellHeight = -1;
|
||||
mFixedCellWidth = mFixedCellHeight = -1;
|
||||
|
||||
@@ -161,7 +161,7 @@ public class DeviceProfile {
|
||||
public final int hotseatBarSidePaddingStartPx;
|
||||
public final int hotseatBarSidePaddingEndPx;
|
||||
public final int hotseatQsbHeight;
|
||||
public final int hotseatBorderSpace;
|
||||
public int hotseatBorderSpace;
|
||||
|
||||
public final float qsbBottomMarginOriginalPx;
|
||||
public int qsbBottomMarginPx;
|
||||
@@ -716,6 +716,7 @@ public class DeviceProfile {
|
||||
}
|
||||
|
||||
// Hotseat
|
||||
hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics, scale);
|
||||
updateHotseatIconSize(iconSizePx);
|
||||
|
||||
if (!isVerticalLayout) {
|
||||
|
||||
@@ -794,6 +794,11 @@ public class InvariantDeviceProfile {
|
||||
x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidth, 0);
|
||||
y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeight, 0);
|
||||
minCellSize[INDEX_DEFAULT] = new PointF(x, y);
|
||||
|
||||
x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthLandscape,
|
||||
minCellSize[INDEX_DEFAULT].x);
|
||||
y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightLandscape,
|
||||
minCellSize[INDEX_DEFAULT].y);
|
||||
minCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
|
||||
|
||||
x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthTwoPanelPortrait,
|
||||
@@ -896,7 +901,9 @@ public class InvariantDeviceProfile {
|
||||
|
||||
horizontalMargin[INDEX_DEFAULT] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_horizontalMargin, 0);
|
||||
horizontalMargin[INDEX_LANDSCAPE] = horizontalMargin[INDEX_DEFAULT];
|
||||
horizontalMargin[INDEX_LANDSCAPE] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_horizontalMarginLandscape,
|
||||
horizontalMargin[INDEX_DEFAULT]);
|
||||
horizontalMargin[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelLandscape,
|
||||
horizontalMargin[INDEX_DEFAULT]);
|
||||
@@ -906,7 +913,9 @@ public class InvariantDeviceProfile {
|
||||
|
||||
hotseatBorderSpaces[INDEX_DEFAULT] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_hotseatBorderSpace, borderSpace);
|
||||
hotseatBorderSpaces[INDEX_LANDSCAPE] = hotseatBorderSpaces[INDEX_DEFAULT];
|
||||
hotseatBorderSpaces[INDEX_LANDSCAPE] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_hotseatBorderSpaceLandscape,
|
||||
hotseatBorderSpaces[INDEX_DEFAULT]);
|
||||
hotseatBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
|
||||
R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelLandscape,
|
||||
hotseatBorderSpaces[INDEX_DEFAULT]);
|
||||
|
||||
@@ -229,7 +229,7 @@ public final class Utilities {
|
||||
offsetPoints(coord, v.getLeft(), v.getTop());
|
||||
scale *= v.getScaleX();
|
||||
|
||||
v = (View) v.getParent();
|
||||
v = v.getParent() instanceof View ? (View) v.getParent() : null;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import android.view.animation.AnimationUtils;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
@@ -101,6 +102,8 @@ import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.views.ClipPathView;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -130,10 +133,13 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
*/
|
||||
private static final int MIN_CONTENT_DIMEN = 5;
|
||||
|
||||
static final int STATE_NONE = -1;
|
||||
static final int STATE_SMALL = 0;
|
||||
static final int STATE_ANIMATING = 1;
|
||||
static final int STATE_OPEN = 2;
|
||||
public static final int STATE_CLOSED = 0;
|
||||
public static final int STATE_ANIMATING = 1;
|
||||
public static final int STATE_OPEN = 2;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({STATE_CLOSED, STATE_ANIMATING, STATE_OPEN})
|
||||
public @interface FolderState {}
|
||||
|
||||
/**
|
||||
* Time for which the scroll hint is shown before automatically changing page.
|
||||
@@ -198,13 +204,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher",
|
||||
mapping = {
|
||||
@ViewDebug.IntToString(from = STATE_NONE, to = "STATE_NONE"),
|
||||
@ViewDebug.IntToString(from = STATE_SMALL, to = "STATE_SMALL"),
|
||||
@ViewDebug.IntToString(from = STATE_CLOSED, to = "STATE_CLOSED"),
|
||||
@ViewDebug.IntToString(from = STATE_ANIMATING, to = "STATE_ANIMATING"),
|
||||
@ViewDebug.IntToString(from = STATE_OPEN, to = "STATE_OPEN"),
|
||||
})
|
||||
@Thunk
|
||||
int mState = STATE_NONE;
|
||||
private int mState = STATE_CLOSED;
|
||||
private OnFolderStateChangedListener mOnFolderStateChangedListener;
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mRearrangeOnClose = false;
|
||||
boolean mItemsInvalidated = false;
|
||||
@@ -277,19 +282,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mPageIndicator = findViewById(R.id.folder_page_indicator);
|
||||
mFolderName = findViewById(R.id.folder_name);
|
||||
mFolderName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp.folderLabelTextSizePx);
|
||||
if (mActivityContext.supportsIme()) {
|
||||
mFolderName.setOnBackKeyListener(this);
|
||||
mFolderName.setOnFocusChangeListener(this);
|
||||
mFolderName.setOnEditorActionListener(this);
|
||||
mFolderName.setSelectAllOnFocus(true);
|
||||
mFolderName.setInputType(mFolderName.getInputType()
|
||||
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
|
||||
mFolderName.forceDisableSuggestions(true);
|
||||
} else {
|
||||
mFolderName.setEnabled(false);
|
||||
}
|
||||
mFolderName.setOnBackKeyListener(this);
|
||||
mFolderName.setOnFocusChangeListener(this);
|
||||
mFolderName.setOnEditorActionListener(this);
|
||||
mFolderName.setSelectAllOnFocus(true);
|
||||
mFolderName.setInputType(mFolderName.getInputType()
|
||||
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
|
||||
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
|
||||
mFolderName.forceDisableSuggestions(true);
|
||||
|
||||
mFooter = findViewById(R.id.folder_footer);
|
||||
mFooterHeight = getResources().getDimensionPixelSize(R.dimen.folder_label_height);
|
||||
@@ -561,7 +562,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
a.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mState = STATE_ANIMATING;
|
||||
setState(STATE_ANIMATING);
|
||||
mCurrentAnimator = a;
|
||||
}
|
||||
|
||||
@@ -686,7 +687,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mState = STATE_OPEN;
|
||||
setState(STATE_OPEN);
|
||||
announceAccessibilityChanges();
|
||||
AccessibilityManagerCompat.sendFolderOpenedEventToTest(getContext());
|
||||
|
||||
@@ -862,7 +863,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
mSuppressFolderDeletion = false;
|
||||
clearDragInfo();
|
||||
mState = STATE_SMALL;
|
||||
setState(STATE_CLOSED);
|
||||
mContent.setCurrentPage(0);
|
||||
}
|
||||
|
||||
@@ -1655,4 +1656,21 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
return windowBottomPx - folderBottomPx;
|
||||
}
|
||||
|
||||
private void setState(@FolderState int newState) {
|
||||
mState = newState;
|
||||
if (mOnFolderStateChangedListener != null) {
|
||||
mOnFolderStateChangedListener.onFolderStateChanged(mState);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnFolderStateChangedListener(@Nullable OnFolderStateChangedListener listener) {
|
||||
mOnFolderStateChangedListener = listener;
|
||||
}
|
||||
|
||||
/** Listener that can be registered via {@link Folder#setOnFolderStateChangedListener} */
|
||||
public interface OnFolderStateChangedListener {
|
||||
/** See {@link Folder.FolderState} */
|
||||
void onFolderStateChanged(@FolderState int newState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import android.view.ViewTreeObserver;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
@@ -120,7 +120,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
||||
private final GradientDrawable mRoundedTop;
|
||||
private final GradientDrawable mRoundedBottom;
|
||||
|
||||
private Runnable mOnCloseCallback = () -> { };
|
||||
@Nullable private Runnable mOnCloseCallback = null;
|
||||
|
||||
// The rect string of the view that the arrow is attached to, in screen reference frame.
|
||||
protected int mArrowColor;
|
||||
@@ -766,7 +766,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void animateClose() {
|
||||
if (!mIsOpen) {
|
||||
return;
|
||||
@@ -816,7 +815,9 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
||||
mDeferContainerRemoval = false;
|
||||
getPopupContainer().removeView(this);
|
||||
getPopupContainer().removeView(mArrow);
|
||||
mOnCloseCallback.run();
|
||||
if (mOnCloseCallback != null) {
|
||||
mOnCloseCallback.run();
|
||||
}
|
||||
if (mColorExtractors != null) {
|
||||
mColorExtractors.forEach(e -> e.setListener(null));
|
||||
}
|
||||
@@ -825,7 +826,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
||||
/**
|
||||
* Callback to be called when the popup is closed
|
||||
*/
|
||||
public void setOnCloseCallback(@NonNull Runnable callback) {
|
||||
public void setOnCloseCallback(@Nullable Runnable callback) {
|
||||
mOnCloseCallback = callback;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.os.Message;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
/**
|
||||
@@ -56,7 +55,7 @@ public class UiThreadHelper {
|
||||
STATS_LOGGER_KEY,
|
||||
Message.obtain(
|
||||
HANDLER.get(root.getContext()),
|
||||
() -> BaseActivity.fromContext(root.getContext())
|
||||
() -> ActivityContext.lookupContext(root.getContext())
|
||||
.getStatsLogManager()
|
||||
.logger()
|
||||
.log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED)
|
||||
|
||||
@@ -124,13 +124,6 @@ public interface ActivityContext {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we can show the IME for elements hosted by this ActivityContext.
|
||||
*/
|
||||
default boolean supportsIme() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called just before logging the given item.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user