Merge "Taskbar layout update" into sc-v2-dev am: a72e9e20bf
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/14722697 Change-Id: Ib5ec5655ecc29ff8a98528dffed2cef76f6cf8a9
This commit is contained in:
@@ -13,12 +13,12 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<com.android.launcher3.taskbar.TaskbarDragLayer
|
<com.android.launcher3.taskbar.TaskbarDragLayer
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/taskbar_container"
|
android:id="@+id/taskbar_container"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="false">
|
||||||
|
|
||||||
<com.android.launcher3.taskbar.TaskbarView
|
<com.android.launcher3.taskbar.TaskbarView
|
||||||
android:id="@+id/taskbar_view"
|
android:id="@+id/taskbar_view"
|
||||||
@@ -26,39 +26,32 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:forceHasOverlappingRendering="false"
|
android:forceHasOverlappingRendering="false"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:clipChildren="false" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/navbuttons_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom" >
|
android:layout_gravity="bottom" >
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/nav_button_layout"
|
android:id="@+id/start_nav_buttons"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
|
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
|
||||||
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
|
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
|
||||||
android:forceHasOverlappingRendering="false"
|
android:gravity="center_vertical"
|
||||||
android:gravity="center" />
|
android:layout_gravity="start"/>
|
||||||
|
|
||||||
<LinearLayout
|
<FrameLayout
|
||||||
android:id="@+id/hotseat_icons_layout"
|
android:id="@+id/end_nav_buttons"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:forceHasOverlappingRendering="false"
|
|
||||||
android:gravity="center" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/contextual_button_layout"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
|
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
|
||||||
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
|
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
|
||||||
android:forceHasOverlappingRendering="false"
|
android:gravity="center_vertical"
|
||||||
android:gravity="center" />
|
android:layout_gravity="end"/>
|
||||||
|
</FrameLayout>
|
||||||
</com.android.launcher3.taskbar.TaskbarView>
|
|
||||||
|
|
||||||
<com.android.launcher3.taskbar.ImeBarView
|
|
||||||
android:id="@+id/ime_bar_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
</com.android.launcher3.taskbar.TaskbarDragLayer>
|
</com.android.launcher3.taskbar.TaskbarDragLayer>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ImageView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="@dimen/taskbar_nav_buttons_size"
|
||||||
|
android:layout_height="@dimen/taskbar_nav_buttons_size"
|
||||||
|
android:background="@drawable/taskbar_icon_click_feedback_roundrect"
|
||||||
|
android:scaleType="center"/>
|
||||||
@@ -148,11 +148,9 @@
|
|||||||
|
|
||||||
<!-- Taskbar -->
|
<!-- Taskbar -->
|
||||||
<dimen name="taskbar_size">60dp</dimen>
|
<dimen name="taskbar_size">60dp</dimen>
|
||||||
<dimen name="taskbar_icon_size">44dp</dimen>
|
|
||||||
<dimen name="taskbar_icon_touch_size">48dp</dimen>
|
<dimen name="taskbar_icon_touch_size">48dp</dimen>
|
||||||
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
|
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
|
||||||
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
|
||||||
<dimen name="taskbar_icon_spacing">8dp</dimen>
|
|
||||||
<dimen name="taskbar_folder_margin">16dp</dimen>
|
<dimen name="taskbar_folder_margin">16dp</dimen>
|
||||||
<dimen name="taskbar_nav_buttons_spacing">16dp</dimen>
|
<dimen name="taskbar_nav_buttons_spacing">16dp</dimen>
|
||||||
|
<dimen name="taskbar_nav_buttons_size">48dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -350,14 +350,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
|
? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getNormalTaskbarScale() {
|
|
||||||
if (mTaskbarUIController != null) {
|
|
||||||
return mTaskbarUIController.getTaskbarScaleOnHome();
|
|
||||||
}
|
|
||||||
return super.getNormalTaskbarScale();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDragLayerHierarchyChanged() {
|
public void onDragLayerHierarchyChanged() {
|
||||||
onLauncherStateOrFocusChanged();
|
onLauncherStateOrFocusChanged();
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I
|
|||||||
mSampleHotseat = findViewById(R.id.sample_prediction);
|
mSampleHotseat = findViewById(R.id.sample_prediction);
|
||||||
|
|
||||||
DeviceProfile grid = mActivityContext.getDeviceProfile();
|
DeviceProfile grid = mActivityContext.getDeviceProfile();
|
||||||
Rect padding = grid.getHotseatLayoutPadding();
|
Rect padding = grid.getHotseatLayoutPadding(getContext());
|
||||||
|
|
||||||
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
|
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
|
||||||
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
|
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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 com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
|
|
||||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
|
|
||||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
|
|
||||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
|
|
||||||
|
|
||||||
import android.annotation.DrawableRes;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
|
||||||
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
|
||||||
import com.android.launcher3.taskbar.contextual.RotationContextButton;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates Buttons for Taskbar for 3 button nav.
|
|
||||||
* Can add animations and state management for buttons in this class as things progress.
|
|
||||||
*/
|
|
||||||
public class ButtonProvider {
|
|
||||||
|
|
||||||
private final int mMarginLeftRight;
|
|
||||||
private final TaskbarActivityContext mContext;
|
|
||||||
|
|
||||||
public ButtonProvider(TaskbarActivityContext context) {
|
|
||||||
mContext = context;
|
|
||||||
mMarginLeftRight = context.getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getBack() {
|
|
||||||
// Back button
|
|
||||||
return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getDown() {
|
|
||||||
// Ime down button
|
|
||||||
return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getHome() {
|
|
||||||
// Home button
|
|
||||||
return getButtonForDrawable(R.drawable.ic_sysbar_home, BUTTON_HOME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getRecents() {
|
|
||||||
// Recents button
|
|
||||||
return getButtonForDrawable(R.drawable.ic_sysbar_recent, BUTTON_RECENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getImeSwitcher() {
|
|
||||||
// IME Switcher Button
|
|
||||||
return getButtonForDrawable(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RotationContextButton getContextualRotation() {
|
|
||||||
// Rotation suggestion button
|
|
||||||
return new RotationContextButton(mContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
private View getButtonForDrawable(@DrawableRes int drawableId, @TaskbarButton int buttonType) {
|
|
||||||
ImageView buttonView = new ImageView(mContext);
|
|
||||||
buttonView.setImageResource(drawableId);
|
|
||||||
buttonView.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
|
|
||||||
buttonView.setPadding(mMarginLeftRight, 0, mMarginLeftRight, 0);
|
|
||||||
buttonView.setOnClickListener(view -> mContext.onNavigationButtonClick(buttonType));
|
|
||||||
return buttonView;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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 android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
|
|
||||||
import com.android.launcher3.views.ActivityContext;
|
|
||||||
|
|
||||||
public class ImeBarView extends RelativeLayout {
|
|
||||||
|
|
||||||
private View mImeView;
|
|
||||||
|
|
||||||
public ImeBarView(Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImeBarView(Context context, AttributeSet attrs) {
|
|
||||||
this(context, attrs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImeBarView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
||||||
super(context, attrs, defStyleAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(ButtonProvider buttonProvider) {
|
|
||||||
// TODO (b/187966005), maybe need to replace ime switcher button with
|
|
||||||
// RotationContextButton when device rotates
|
|
||||||
ActivityContext context = getActivityContext();
|
|
||||||
RelativeLayout.LayoutParams imeParams = new RelativeLayout.LayoutParams(
|
|
||||||
context.getDeviceProfile().iconSizePx,
|
|
||||||
context.getDeviceProfile().iconSizePx
|
|
||||||
);
|
|
||||||
RelativeLayout.LayoutParams downParams = new RelativeLayout.LayoutParams(imeParams);
|
|
||||||
|
|
||||||
imeParams.addRule(ALIGN_PARENT_END);
|
|
||||||
imeParams.setMarginEnd(context.getDeviceProfile().iconSizePx);
|
|
||||||
downParams.setMarginStart(context.getDeviceProfile().iconSizePx);
|
|
||||||
downParams.addRule(ALIGN_PARENT_START);
|
|
||||||
|
|
||||||
// Down Arrow
|
|
||||||
View downView = buttonProvider.getDown();
|
|
||||||
downView.setLayoutParams(downParams);
|
|
||||||
downView.setRotation(-90);
|
|
||||||
addView(downView);
|
|
||||||
|
|
||||||
// IME switcher button
|
|
||||||
mImeView = buttonProvider.getImeSwitcher();
|
|
||||||
mImeView.setLayoutParams(imeParams);
|
|
||||||
addView(mImeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImeSwitcherVisibility(boolean show) {
|
|
||||||
mImeView.setVisibility(show ? VISIBLE : GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Context & ActivityContext> T getActivityContext() {
|
|
||||||
return ActivityContext.lookupContext(getContext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,42 +15,42 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.BaseQuickstepLauncher;
|
import com.android.launcher3.BaseQuickstepLauncher;
|
||||||
import com.android.launcher3.DeviceProfile;
|
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.QuickstepTransitionManager;
|
import com.android.launcher3.QuickstepTransitionManager;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.anim.AnimatorListeners;
|
||||||
import com.android.launcher3.anim.PendingAnimation;
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.states.StateAnimationConfig;
|
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||||
|
import com.android.quickstep.AnimatedFloat;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data source which integrates with a Launcher instance
|
* A data source which integrates with a Launcher instance
|
||||||
* TODO: Rename to have Launcher prefix
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class LauncherTaskbarUIController extends TaskbarUIController {
|
public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||||
|
|
||||||
private final BaseQuickstepLauncher mLauncher;
|
private final BaseQuickstepLauncher mLauncher;
|
||||||
private final TaskbarStateHandler mTaskbarStateHandler;
|
private final TaskbarStateHandler mTaskbarStateHandler;
|
||||||
private final TaskbarAnimationController mTaskbarAnimationController;
|
|
||||||
private final TaskbarHotseatController mHotseatController;
|
private final TaskbarHotseatController mHotseatController;
|
||||||
|
|
||||||
private final TaskbarActivityContext mContext;
|
private final TaskbarActivityContext mContext;
|
||||||
final TaskbarDragLayer mTaskbarDragLayer;
|
final TaskbarDragLayer mTaskbarDragLayer;
|
||||||
final TaskbarView mTaskbarView;
|
final TaskbarView mTaskbarView;
|
||||||
|
|
||||||
|
private AnimatedFloat mTaskBarAlpha;
|
||||||
|
private AlphaProperty mIconAlphaForHome;
|
||||||
private @Nullable Animator mAnimator;
|
private @Nullable Animator mAnimator;
|
||||||
private boolean mIsAnimatingToLauncher;
|
private boolean mIsAnimatingToLauncher;
|
||||||
private ContextualRotationNotifier mContextualRotationNotifier;
|
|
||||||
|
|
||||||
public LauncherTaskbarUIController(
|
public LauncherTaskbarUIController(
|
||||||
BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
|
BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
|
||||||
@@ -60,20 +60,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
|
|
||||||
mLauncher = launcher;
|
mLauncher = launcher;
|
||||||
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
|
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
|
||||||
mTaskbarAnimationController = new TaskbarAnimationController(mLauncher,
|
|
||||||
createTaskbarAnimationControllerCallbacks());
|
|
||||||
mHotseatController = new TaskbarHotseatController(
|
mHotseatController = new TaskbarHotseatController(
|
||||||
mLauncher, mTaskbarView::updateHotseatItems);
|
mLauncher, mTaskbarView::updateHotseatItems);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(ContextualRotationNotifier notifier) {
|
protected void init(AnimatedFloat taskBarAlpha, AlphaProperty iconAlphaForLauncherState,
|
||||||
mContextualRotationNotifier = notifier;
|
AlphaProperty iconAlphaForHome) {
|
||||||
mTaskbarStateHandler.setAnimationController(mTaskbarAnimationController);
|
mTaskBarAlpha = taskBarAlpha;
|
||||||
mTaskbarAnimationController.init();
|
mIconAlphaForHome = iconAlphaForHome;
|
||||||
|
mTaskbarStateHandler.setAnimationController(iconAlphaForLauncherState);
|
||||||
mHotseatController.init();
|
mHotseatController.init();
|
||||||
setTaskbarViewVisible(!mLauncher.hasBeenResumed());
|
setTaskbarViewVisible(!mLauncher.hasBeenResumed());
|
||||||
alignRealHotseatWithTaskbar();
|
|
||||||
mLauncher.setTaskbarUIController(this);
|
mLauncher.setTaskbarUIController(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,9 +82,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
// End this first, in case it relies on properties that are about to be cleaned up.
|
// End this first, in case it relies on properties that are about to be cleaned up.
|
||||||
mAnimator.end();
|
mAnimator.end();
|
||||||
}
|
}
|
||||||
mContextualRotationNotifier = null;
|
|
||||||
mTaskbarStateHandler.setAnimationController(null);
|
mTaskbarStateHandler.setAnimationController(null);
|
||||||
mTaskbarAnimationController.cleanup();
|
|
||||||
mHotseatController.cleanup();
|
mHotseatController.cleanup();
|
||||||
setTaskbarViewVisible(true);
|
setTaskbarViewVisible(true);
|
||||||
mLauncher.getHotseat().setIconsAlpha(1f);
|
mLauncher.getHotseat().setIconsAlpha(1f);
|
||||||
@@ -97,46 +94,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
return !mIsAnimatingToLauncher;
|
return !mIsAnimatingToLauncher;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
|
|
||||||
return new TaskbarAnimationControllerCallbacks() {
|
|
||||||
@Override
|
|
||||||
public void updateTaskbarBackgroundAlpha(float alpha) {
|
|
||||||
mTaskbarDragLayer.setTaskbarBackgroundAlpha(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTaskbarVisibilityAlpha(float alpha) {
|
|
||||||
mTaskbarView.setAlpha(alpha);
|
|
||||||
if (mContextualRotationNotifier != null) {
|
|
||||||
mContextualRotationNotifier.onTaskbarVisibilityChanged(alpha == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateImeBarVisibilityAlpha(float alpha) {
|
|
||||||
mTaskbarDragLayer.updateImeBarVisibilityAlpha(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTaskbarScale(float scale) {
|
|
||||||
mTaskbarView.setScaleX(scale);
|
|
||||||
mTaskbarView.setScaleY(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateTaskbarTranslationY(float translationY) {
|
|
||||||
if (translationY < 0) {
|
|
||||||
// Resize to accommodate the max translation we'll reach.
|
|
||||||
mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize
|
|
||||||
+ mLauncher.getHotseat().getTaskbarOffsetY());
|
|
||||||
} else {
|
|
||||||
mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize);
|
|
||||||
}
|
|
||||||
mTaskbarView.setTranslationY(translationY);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
|
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
|
||||||
*/
|
*/
|
||||||
@@ -146,7 +103,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
mAnimator.cancel();
|
mAnimator.cancel();
|
||||||
}
|
}
|
||||||
if (isResumed) {
|
if (isResumed) {
|
||||||
mAnimator = createAnimToLauncher(null, duration);
|
mAnimator = createAnimToLauncher(mLauncher.getStateManager().getState(), duration);
|
||||||
} else {
|
} else {
|
||||||
mAnimator = createAnimToApp(duration);
|
mAnimator = createAnimToApp(duration);
|
||||||
}
|
}
|
||||||
@@ -162,20 +119,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
/**
|
/**
|
||||||
* Create Taskbar animation when going from an app to Launcher.
|
* Create Taskbar animation when going from an app to Launcher.
|
||||||
* @param toState If known, the state we will end up in when reaching Launcher.
|
* @param toState If known, the state we will end up in when reaching Launcher.
|
||||||
|
* TODO: Move this and createAnimToApp to TaskbarStateHandler using the BACKGROUND state
|
||||||
*/
|
*/
|
||||||
public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
|
public Animator createAnimToLauncher(@NonNull LauncherState toState, long duration) {
|
||||||
PendingAnimation anim = new PendingAnimation(duration);
|
PendingAnimation anim = new PendingAnimation(duration);
|
||||||
anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration));
|
mTaskbarStateHandler.setState(toState, anim);
|
||||||
if (toState != null) {
|
|
||||||
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
|
anim.setFloat(mTaskBarAlpha, AnimatedFloat.VALUE, 0, LINEAR);
|
||||||
}
|
mTaskbarView.alignIconsWithLauncher(mLauncher.getDeviceProfile(), anim);
|
||||||
|
|
||||||
anim.addListener(new AnimatorListenerAdapter() {
|
anim.addListener(new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(Animator animation) {
|
public void onAnimationStart(Animator animation) {
|
||||||
mIsAnimatingToLauncher = true;
|
mIsAnimatingToLauncher = true;
|
||||||
mTaskbarView.setHolesAllowedInLayout(true);
|
|
||||||
mTaskbarView.updateHotseatItemsVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -190,27 +146,17 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
|
|
||||||
private Animator createAnimToApp(long duration) {
|
private Animator createAnimToApp(long duration) {
|
||||||
PendingAnimation anim = new PendingAnimation(duration);
|
PendingAnimation anim = new PendingAnimation(duration);
|
||||||
anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration));
|
anim.setFloat(mTaskBarAlpha, AnimatedFloat.VALUE, 1, LINEAR);
|
||||||
|
anim.addListener(AnimatorListeners.forEndCallback(mTaskbarView.resetIconPosition(anim)));
|
||||||
anim.addListener(new AnimatorListenerAdapter() {
|
anim.addListener(new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(Animator animation) {
|
public void onAnimationStart(Animator animation) {
|
||||||
mTaskbarView.updateHotseatItemsVisibility();
|
|
||||||
setTaskbarViewVisible(true);
|
setTaskbarViewVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
mTaskbarView.setHolesAllowedInLayout(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return anim.buildAnim();
|
return anim.buildAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onImeVisible(TaskbarDragLayer containerView, boolean isVisible) {
|
|
||||||
mTaskbarAnimationController.animateToVisibilityForIme(isVisible ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called when one or more items in the Hotseat have changed.
|
* Should be called when one or more items in the Hotseat have changed.
|
||||||
*/
|
*/
|
||||||
@@ -230,55 +176,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
|||||||
return mContext.getDragController().isDragging();
|
return mContext.getDragController().isDragging();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void alignRealHotseatWithTaskbar() {
|
|
||||||
Rect hotseatBounds = new Rect();
|
|
||||||
DeviceProfile grid = mLauncher.getDeviceProfile();
|
|
||||||
int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize;
|
|
||||||
int taskbarOffset = mLauncher.getHotseat().getTaskbarOffsetY();
|
|
||||||
int hotseatTopDiff = hotseatHeight - grid.taskbarSize - taskbarOffset;
|
|
||||||
int hotseatBottomDiff = taskbarOffset;
|
|
||||||
|
|
||||||
RectF hotseatBoundsF = mTaskbarView.getHotseatBounds();
|
|
||||||
Utilities.scaleRectFAboutPivot(hotseatBoundsF, getTaskbarScaleOnHome(),
|
|
||||||
mTaskbarView.getPivotX(), mTaskbarView.getPivotY());
|
|
||||||
hotseatBoundsF.round(hotseatBounds);
|
|
||||||
mLauncher.getHotseat().setPadding(hotseatBounds.left,
|
|
||||||
hotseatBounds.top + hotseatTopDiff,
|
|
||||||
mTaskbarView.getWidth() - hotseatBounds.right,
|
|
||||||
mTaskbarView.getHeight() - hotseatBounds.bottom + hotseatBottomDiff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the ratio of the taskbar icon size on home vs in an app.
|
|
||||||
*/
|
|
||||||
public float getTaskbarScaleOnHome() {
|
|
||||||
DeviceProfile inAppDp = mContext.getDeviceProfile();
|
|
||||||
DeviceProfile onHomeDp = mLauncher.getDeviceProfile();
|
|
||||||
return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTaskbarViewVisible(boolean isVisible) {
|
void setTaskbarViewVisible(boolean isVisible) {
|
||||||
mTaskbarView.setIconsVisibility(isVisible);
|
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
|
||||||
mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
|
mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains methods that TaskbarAnimationController can call to interface with
|
|
||||||
* TaskbarController.
|
|
||||||
*/
|
|
||||||
protected interface TaskbarAnimationControllerCallbacks {
|
|
||||||
void updateTaskbarBackgroundAlpha(float alpha);
|
|
||||||
void updateTaskbarVisibilityAlpha(float alpha);
|
|
||||||
void updateImeBarVisibilityAlpha(float alpha);
|
|
||||||
void updateTaskbarScale(float scale);
|
|
||||||
void updateTaskbarTranslationY(float translationY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ContextualRotationNotifier {
|
|
||||||
void onTaskbarVisibilityChanged(boolean showing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
|
||||||
|
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
|
||||||
|
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
|
||||||
|
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.annotation.DrawableRes;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Region;
|
||||||
|
import android.graphics.Region.Op;
|
||||||
|
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||||
|
import android.util.Property;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.View.OnHoverListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.android.launcher3.LauncherAnimUtils;
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||||
|
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
||||||
|
import com.android.launcher3.taskbar.contextual.RotationButton;
|
||||||
|
import com.android.launcher3.taskbar.contextual.RotationButtonController;
|
||||||
|
import com.android.launcher3.util.MultiValueAlpha;
|
||||||
|
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||||
|
import com.android.quickstep.AnimatedFloat;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.function.IntPredicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for managing nav bar buttons in taskbar
|
||||||
|
*/
|
||||||
|
public class NavbarButtonUIController {
|
||||||
|
|
||||||
|
private final Rect mTempRect = new Rect();
|
||||||
|
|
||||||
|
private static final int FLAG_SWITCHER_SUPPORTED = 1 << 0;
|
||||||
|
private static final int FLAG_IME_VISIBLE = 1 << 1;
|
||||||
|
private static final int FLAG_ROTATION_BUTTON_VISIBLE = 1 << 2;
|
||||||
|
|
||||||
|
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
|
||||||
|
|
||||||
|
private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
|
||||||
|
private final ArrayList<View> mAllButtons = new ArrayList<>();
|
||||||
|
private int mState;
|
||||||
|
|
||||||
|
private final TaskbarActivityContext mContext;
|
||||||
|
|
||||||
|
public NavbarButtonUIController(TaskbarActivityContext context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the controller
|
||||||
|
*/
|
||||||
|
public void init(TaskbarDragLayer dragLayer,
|
||||||
|
TaskbarNavButtonController navButtonController,
|
||||||
|
RotationButtonController rotationButtonController,
|
||||||
|
AnimatedFloat taskbarBackgroundAlpha, AlphaProperty taskbarIconAlpha) {
|
||||||
|
FrameLayout buttonController = dragLayer.findViewById(R.id.navbuttons_view);
|
||||||
|
buttonController.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
|
||||||
|
|
||||||
|
if (mContext.canShowNavButtons()) {
|
||||||
|
ViewGroup startContainer = buttonController.findViewById(R.id.start_nav_buttons);
|
||||||
|
ViewGroup endContainer = buttonController.findViewById(R.id.end_nav_buttons);
|
||||||
|
|
||||||
|
initButtons(startContainer, endContainer, navButtonController);
|
||||||
|
|
||||||
|
// Animate taskbar background when IME shows
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(taskbarBackgroundAlpha,
|
||||||
|
flags -> (flags & FLAG_IME_VISIBLE) == 0,
|
||||||
|
AnimatedFloat.VALUE, 0, 1));
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(
|
||||||
|
taskbarIconAlpha, flags -> (flags & FLAG_IME_VISIBLE) == 0,
|
||||||
|
MultiValueAlpha.VALUE, 1, 0));
|
||||||
|
|
||||||
|
// Rotation button
|
||||||
|
RotationButton rotationButton = new RotationButtonImpl(addButton(endContainer));
|
||||||
|
rotationButton.hide();
|
||||||
|
rotationButtonController.setRotationButton(rotationButton);
|
||||||
|
} else {
|
||||||
|
rotationButtonController.setRotationButton(new RotationButton() { });
|
||||||
|
}
|
||||||
|
|
||||||
|
applyState();
|
||||||
|
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initButtons(ViewGroup startContainer, ViewGroup endContainer,
|
||||||
|
TaskbarNavButtonController navButtonController) {
|
||||||
|
|
||||||
|
View backButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
|
||||||
|
startContainer, navButtonController);
|
||||||
|
// Rotate when Ime visible
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(backButton,
|
||||||
|
flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0,
|
||||||
|
Utilities.isRtl(mContext.getResources()) ? 90 : -90));
|
||||||
|
|
||||||
|
// home and recents buttons
|
||||||
|
View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, startContainer,
|
||||||
|
navButtonController);
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(homeButton,
|
||||||
|
flags -> (flags & FLAG_IME_VISIBLE) == 0));
|
||||||
|
View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
|
||||||
|
startContainer, navButtonController);
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(recentsButton,
|
||||||
|
flags -> (flags & FLAG_IME_VISIBLE) == 0));
|
||||||
|
|
||||||
|
// IME switcher
|
||||||
|
View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
|
||||||
|
endContainer, navButtonController);
|
||||||
|
mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
|
||||||
|
flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
|
||||||
|
&& ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
|
||||||
|
*/
|
||||||
|
public void setImeIsVisible(boolean isImeVisible) {
|
||||||
|
if (isImeVisible) {
|
||||||
|
mState |= FLAG_IME_VISIBLE;
|
||||||
|
} else {
|
||||||
|
mState &= ~FLAG_IME_VISIBLE;
|
||||||
|
}
|
||||||
|
applyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if IME bar is visible
|
||||||
|
*/
|
||||||
|
public boolean isImeVisible() {
|
||||||
|
return (mState & FLAG_IME_VISIBLE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the bounds corresponding to all visible buttons to provided region
|
||||||
|
*/
|
||||||
|
public void addVisibleButtonsRegion(TaskbarDragLayer parent, Region outRegion) {
|
||||||
|
int count = mAllButtons.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View button = mAllButtons.get(i);
|
||||||
|
if (button.getVisibility() == View.VISIBLE) {
|
||||||
|
parent.getDescendantRectRelativeToSelf(button, mTempRect);
|
||||||
|
outRegion.op(mTempRect, Op.UNION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if ime switcher is visible or not when ime is visible
|
||||||
|
*/
|
||||||
|
public void setImeSwitcherVisible(boolean imeSwitcherVisible) {
|
||||||
|
if (imeSwitcherVisible) {
|
||||||
|
mState |= FLAG_SWITCHER_SUPPORTED;
|
||||||
|
} else {
|
||||||
|
mState &= ~FLAG_SWITCHER_SUPPORTED;
|
||||||
|
}
|
||||||
|
applyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyState() {
|
||||||
|
int count = mPropertyHolders.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
mPropertyHolders.get(i).setState(mState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
|
||||||
|
ViewGroup parent, TaskbarNavButtonController navButtonController) {
|
||||||
|
ImageView buttonView = addButton(parent);
|
||||||
|
buttonView.setImageResource(drawableId);
|
||||||
|
buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType));
|
||||||
|
return buttonView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageView addButton(ViewGroup parent) {
|
||||||
|
ImageView buttonView = (ImageView) mContext.getLayoutInflater()
|
||||||
|
.inflate(R.layout.taskbar_nav_button, parent, false);
|
||||||
|
parent.addView(buttonView);
|
||||||
|
mAllButtons.add(buttonView);
|
||||||
|
return buttonView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RotationButtonImpl implements RotationButton {
|
||||||
|
|
||||||
|
private final ImageView mButton;
|
||||||
|
private AnimatedVectorDrawable mImageDrawable;
|
||||||
|
|
||||||
|
RotationButtonImpl(ImageView button) {
|
||||||
|
mButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRotationButtonController(RotationButtonController rotationButtonController) {
|
||||||
|
// TODO(b/187754252) UI polish, different icons based on light/dark context, etc
|
||||||
|
mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
|
||||||
|
.getDrawable(rotationButtonController.getIconResId());
|
||||||
|
mButton.setImageDrawable(mImageDrawable);
|
||||||
|
mImageDrawable.setCallback(mButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getCurrentView() {
|
||||||
|
return mButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void show() {
|
||||||
|
mButton.setVisibility(View.VISIBLE);
|
||||||
|
mState |= FLAG_ROTATION_BUTTON_VISIBLE;
|
||||||
|
applyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hide() {
|
||||||
|
mButton.setVisibility(View.GONE);
|
||||||
|
mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
|
||||||
|
applyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisible() {
|
||||||
|
return mButton.getVisibility() == View.VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateIcon(int lightIconColor, int darkIconColor) {
|
||||||
|
// TODO(b/187754252): UI Polish
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnClickListener(OnClickListener onClickListener) {
|
||||||
|
mButton.setOnClickListener(onClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnHoverListener(OnHoverListener onHoverListener) {
|
||||||
|
mButton.setOnHoverListener(onHoverListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatedVectorDrawable getImageDrawable() {
|
||||||
|
return mImageDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDarkIntensity(float darkIntensity) {
|
||||||
|
// TODO(b/187754252) UI polish
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptRotationProposal() {
|
||||||
|
return mButton.isAttachedToWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StatePropertyHolder {
|
||||||
|
|
||||||
|
private final float mEnabledValue, mDisabledValue;
|
||||||
|
private final ObjectAnimator mAnimator;
|
||||||
|
private final IntPredicate mEnableCondition;
|
||||||
|
|
||||||
|
private boolean mIsEnabled = true;
|
||||||
|
|
||||||
|
StatePropertyHolder(View view, IntPredicate enableCondition) {
|
||||||
|
this(view, enableCondition, LauncherAnimUtils.VIEW_ALPHA, 1, 0);
|
||||||
|
mAnimator.addListener(new AlphaUpdateListener(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
<T> StatePropertyHolder(T target, IntPredicate enabledCondition,
|
||||||
|
Property<T, Float> property, float enabledValue, float disabledValue) {
|
||||||
|
mEnableCondition = enabledCondition;
|
||||||
|
mEnabledValue = enabledValue;
|
||||||
|
mDisabledValue = disabledValue;
|
||||||
|
mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(int flags) {
|
||||||
|
boolean isEnabled = mEnableCondition.test(flags);
|
||||||
|
if (mIsEnabled != isEnabled) {
|
||||||
|
mIsEnabled = isEnabled;
|
||||||
|
mAnimator.cancel();
|
||||||
|
mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
|
||||||
|
mAnimator.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endAnimation() {
|
||||||
|
if (mAnimator.isRunning()) {
|
||||||
|
mAnimator.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.LauncherApps;
|
import android.content.pm.LauncherApps;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.inputmethodservice.InputMethodService;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -53,10 +54,12 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
|
|||||||
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
||||||
import com.android.launcher3.taskbar.contextual.RotationButtonController;
|
import com.android.launcher3.taskbar.contextual.RotationButtonController;
|
||||||
import com.android.launcher3.touch.ItemClickHandler;
|
import com.android.launcher3.touch.ItemClickHandler;
|
||||||
|
import com.android.launcher3.util.MultiValueAlpha;
|
||||||
import com.android.launcher3.util.PackageManagerHelper;
|
import com.android.launcher3.util.PackageManagerHelper;
|
||||||
import com.android.launcher3.util.Themes;
|
import com.android.launcher3.util.Themes;
|
||||||
import com.android.launcher3.util.TraceHelper;
|
import com.android.launcher3.util.TraceHelper;
|
||||||
import com.android.launcher3.views.ActivityContext;
|
import com.android.launcher3.views.ActivityContext;
|
||||||
|
import com.android.quickstep.AnimatedFloat;
|
||||||
import com.android.quickstep.SysUINavigationMode;
|
import com.android.quickstep.SysUINavigationMode;
|
||||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||||
import com.android.systemui.shared.recents.model.Task;
|
import com.android.systemui.shared.recents.model.Task;
|
||||||
@@ -76,11 +79,16 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
|
|
||||||
private static final String WINDOW_TITLE = "Taskbar";
|
private static final String WINDOW_TITLE = "Taskbar";
|
||||||
|
|
||||||
|
private static final int ALPHA_INDEX_HOME = 0;
|
||||||
|
private static final int ALPHA_INDEX_LAUNCHER_STATE = 1;
|
||||||
|
private static final int ALPHA_INDEX_IME = 2;
|
||||||
|
|
||||||
private final DeviceProfile mDeviceProfile;
|
private final DeviceProfile mDeviceProfile;
|
||||||
private final LayoutInflater mLayoutInflater;
|
private final LayoutInflater mLayoutInflater;
|
||||||
private final TaskbarDragLayer mDragLayer;
|
private final TaskbarDragLayer mDragLayer;
|
||||||
private final TaskbarIconController mIconController;
|
private final TaskbarIconController mIconController;
|
||||||
private final TaskbarDragController mDragController;
|
private final TaskbarDragController mDragController;
|
||||||
|
private final NavbarButtonUIController mNavbarButtonUIController;
|
||||||
|
|
||||||
private final WindowManager mWindowManager;
|
private final WindowManager mWindowManager;
|
||||||
private WindowManager.LayoutParams mWindowLayoutParams;
|
private WindowManager.LayoutParams mWindowLayoutParams;
|
||||||
@@ -89,7 +97,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
private int mLastRequestedNonFullscreenHeight;
|
private int mLastRequestedNonFullscreenHeight;
|
||||||
|
|
||||||
private final SysUINavigationMode.Mode mNavMode;
|
private final SysUINavigationMode.Mode mNavMode;
|
||||||
private final SystemTaskbarNotificationManager mSystemTaskbarNotificationManager;
|
|
||||||
private final TaskbarNavButtonController mNavButtonController;
|
private final TaskbarNavButtonController mNavButtonController;
|
||||||
private final RotationButtonController mRotationButtonController;
|
private final RotationButtonController mRotationButtonController;
|
||||||
|
|
||||||
@@ -101,43 +108,18 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
private final View.OnClickListener mOnTaskbarIconClickListener;
|
private final View.OnClickListener mOnTaskbarIconClickListener;
|
||||||
private final View.OnLongClickListener mOnTaskbarIconLongClickListener;
|
private final View.OnLongClickListener mOnTaskbarIconLongClickListener;
|
||||||
|
|
||||||
private final TaskbarManager.SystemTaskbarNotifier mSystemTaskbarNotifier =
|
// Alpha property for task bar
|
||||||
new TaskbarManager.SystemTaskbarNotifier() {
|
private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
|
||||||
@Override
|
private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha);
|
||||||
public void updateImeStatus(int displayId, int vis, int backDisposition,
|
|
||||||
boolean showImeSwitcher) {
|
|
||||||
/*
|
|
||||||
* When in 3 button nav, sysui flags don't get called since we prevent
|
|
||||||
* sysui nav bar from instantiating at all, which is what's responsible for
|
|
||||||
* sending sysui state flags over.
|
|
||||||
*/
|
|
||||||
mIconController.updateImeStatus(displayId, vis, showImeSwitcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private final MultiValueAlpha mTaskbarIconAlpha;
|
||||||
public void onRotationProposal(int rotation, boolean isValid) {
|
|
||||||
mRotationButtonController.onRotationProposal(rotation, isValid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disable(int displayId, int state1, int state2, boolean animate) {
|
|
||||||
mRotationButtonController.onDisable2FlagChanged(state2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSystemBarAttributesChanged(int displayId, int behavior) {
|
|
||||||
mRotationButtonController.onBehaviorChanged(displayId, behavior);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
|
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
|
||||||
TaskbarNavButtonController buttonController,
|
TaskbarNavButtonController buttonController) {
|
||||||
SystemTaskbarNotificationManager systemTaskbarNotificationManager) {
|
|
||||||
super(windowContext, Themes.getActivityThemeRes(windowContext));
|
super(windowContext, Themes.getActivityThemeRes(windowContext));
|
||||||
mDeviceProfile = dp;
|
mDeviceProfile = dp;
|
||||||
mNavButtonController = buttonController;
|
mNavButtonController = buttonController;
|
||||||
mNavMode = SysUINavigationMode.getMode(windowContext);
|
mNavMode = SysUINavigationMode.getMode(windowContext);
|
||||||
mSystemTaskbarNotificationManager = systemTaskbarNotificationManager;
|
|
||||||
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
|
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
|
||||||
() -> getPackageManager().isSafeMode());
|
() -> getPackageManager().isSafeMode());
|
||||||
|
|
||||||
@@ -146,23 +128,26 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
mOnTaskbarIconClickListener = this::onTaskbarIconClicked;
|
mOnTaskbarIconClickListener = this::onTaskbarIconClicked;
|
||||||
|
|
||||||
float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
|
float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
|
||||||
|
mDeviceProfile.updateIconSize(1, getResources());
|
||||||
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
|
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
|
||||||
mDeviceProfile.updateIconSize(iconScale, getResources());
|
mDeviceProfile.updateIconSize(iconScale, getResources());
|
||||||
|
|
||||||
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
|
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
|
||||||
mDragLayer = (TaskbarDragLayer) mLayoutInflater
|
mDragLayer = (TaskbarDragLayer) mLayoutInflater
|
||||||
.inflate(R.layout.taskbar, null, false);
|
.inflate(R.layout.taskbar, null, false);
|
||||||
|
|
||||||
mRotationButtonController = new RotationButtonController(this,
|
mRotationButtonController = new RotationButtonController(this,
|
||||||
R.color.popup_color_primary_light, R.color.popup_color_primary_light);
|
R.color.popup_color_primary_light, R.color.popup_color_primary_light);
|
||||||
mIconController = new TaskbarIconController(this, mDragLayer,
|
mNavbarButtonUIController = new NavbarButtonUIController(this);
|
||||||
mRotationButtonController);
|
mIconController = new TaskbarIconController(this, mDragLayer, mNavbarButtonUIController);
|
||||||
|
|
||||||
Display display = windowContext.getDisplay();
|
Display display = windowContext.getDisplay();
|
||||||
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
|
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
|
||||||
? windowContext.getApplicationContext()
|
? windowContext.getApplicationContext()
|
||||||
: windowContext.getApplicationContext().createDisplayContext(display);
|
: windowContext.getApplicationContext().createDisplayContext(display);
|
||||||
mWindowManager = c.getSystemService(WindowManager.class);
|
mWindowManager = c.getSystemService(WindowManager.class);
|
||||||
|
|
||||||
|
mTaskbarIconAlpha = new MultiValueAlpha(mDragLayer.findViewById(R.id.taskbar_view), 3);
|
||||||
|
mTaskbarIconAlpha.setUpdateVisibility(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
@@ -187,12 +172,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
|
new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
|
||||||
);
|
);
|
||||||
|
|
||||||
mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener,
|
mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener);
|
||||||
mNavMode);
|
mNavbarButtonUIController.init(mDragLayer, mNavButtonController, mRotationButtonController,
|
||||||
|
mBgNavbar, mTaskbarIconAlpha.getProperty(ALPHA_INDEX_IME));
|
||||||
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
|
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
|
||||||
if (mNavMode == Mode.THREE_BUTTONS) {
|
if (canShowNavButtons()) {
|
||||||
mSystemTaskbarNotificationManager
|
mRotationButtonController.init();
|
||||||
.registerSystemTaskbarNotifications(mSystemTaskbarNotifier);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,10 +217,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
mUIController.onDestroy();
|
mUIController.onDestroy();
|
||||||
mUIController = uiController;
|
mUIController = uiController;
|
||||||
mIconController.setUIController(mUIController);
|
mIconController.setUIController(mUIController);
|
||||||
mUIController.onCreate(mRotationButtonController::onTaskBarVisibilityChange);
|
mUIController.init(mBgTaskbar, mTaskbarIconAlpha.getProperty(ALPHA_INDEX_LAUNCHER_STATE),
|
||||||
if (mNavMode == Mode.THREE_BUTTONS) {
|
mTaskbarIconAlpha.getProperty(ALPHA_INDEX_HOME));
|
||||||
mRotationButtonController.init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,12 +227,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
setUIController(TaskbarUIController.DEFAULT);
|
setUIController(TaskbarUIController.DEFAULT);
|
||||||
mIconController.onDestroy();
|
mIconController.onDestroy();
|
||||||
|
mRotationButtonController.onDestroy();
|
||||||
mWindowManager.removeViewImmediate(mDragLayer);
|
mWindowManager.removeViewImmediate(mDragLayer);
|
||||||
if (mNavMode == Mode.THREE_BUTTONS) {
|
|
||||||
mSystemTaskbarNotificationManager.removeSystemTaskbarNotifications(
|
|
||||||
mSystemTaskbarNotifier);
|
|
||||||
mRotationButtonController.cleanup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onNavigationButtonClick(@TaskbarButton int buttonType) {
|
void onNavigationButtonClick(@TaskbarButton int buttonType) {
|
||||||
@@ -261,6 +240,36 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
*/
|
*/
|
||||||
public void setImeIsVisible(boolean isImeVisible) {
|
public void setImeIsVisible(boolean isImeVisible) {
|
||||||
mIconController.setImeIsVisible(isImeVisible);
|
mIconController.setImeIsVisible(isImeVisible);
|
||||||
|
mNavbarButtonUIController.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
|
||||||
|
*/
|
||||||
|
public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
|
||||||
|
if (displayId != getDisplayId() || !canShowNavButtons()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mNavbarButtonUIController.setImeSwitcherVisible(showImeSwitcher);
|
||||||
|
setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRotationProposal(int rotation, boolean isValid) {
|
||||||
|
mRotationButtonController.onRotationProposal(rotation, isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable(int displayId, int state1, int state2, boolean animate) {
|
||||||
|
if (displayId != getDisplayId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mRotationButtonController.onDisable2FlagChanged(state2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSystemBarAttributesChanged(int displayId, int behavior) {
|
||||||
|
mRotationButtonController.onBehaviorChanged(displayId, behavior);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,7 +325,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
});
|
});
|
||||||
} else if (tag instanceof WorkspaceItemInfo) {
|
} else if (tag instanceof WorkspaceItemInfo) {
|
||||||
WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
|
WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
|
||||||
if (!(info.isDisabled() && ItemClickHandler.handleDisabledItemClicked(info, this))) {
|
if (info.isDisabled()) {
|
||||||
|
ItemClickHandler.handleDisabledItemClicked(info, this);
|
||||||
|
} else {
|
||||||
Intent intent = new Intent(info.getIntent())
|
Intent intent = new Intent(info.getIntent())
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
try {
|
try {
|
||||||
@@ -352,4 +363,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||||||
|
|
||||||
AbstractFloatingView.closeAllOpenViews(this);
|
AbstractFloatingView.closeAllOpenViews(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBackgroundAlpha() {
|
||||||
|
mDragLayer.setTaskbarBackgroundAlpha(Math.max(mBgNavbar.value, mBgTaskbar.value));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 com.android.launcher3.LauncherState.TASKBAR;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
|
|
||||||
import com.android.launcher3.BaseQuickstepLauncher;
|
|
||||||
import com.android.launcher3.Utilities;
|
|
||||||
import com.android.launcher3.taskbar.LauncherTaskbarUIController.TaskbarAnimationControllerCallbacks;
|
|
||||||
import com.android.quickstep.AnimatedFloat;
|
|
||||||
import com.android.quickstep.SystemUiProxy;
|
|
||||||
import com.android.systemui.shared.system.QuickStepContract;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Works with TaskbarController to update the TaskbarView's visual properties based on factors such
|
|
||||||
* as LauncherState, whether Launcher is in the foreground, etc.
|
|
||||||
*/
|
|
||||||
public class TaskbarAnimationController {
|
|
||||||
|
|
||||||
private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
|
|
||||||
|
|
||||||
private final BaseQuickstepLauncher mLauncher;
|
|
||||||
private final TaskbarAnimationControllerCallbacks mTaskbarCallbacks;
|
|
||||||
|
|
||||||
// Background alpha.
|
|
||||||
private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
|
|
||||||
this::onTaskbarBackgroundAlphaChanged);
|
|
||||||
|
|
||||||
// Overall visibility.
|
|
||||||
private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
|
|
||||||
this::updateVisibilityAlpha);
|
|
||||||
private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
|
|
||||||
this::updateVisibilityAlphaForIme);
|
|
||||||
|
|
||||||
// Scale.
|
|
||||||
private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat(
|
|
||||||
this::updateScale);
|
|
||||||
|
|
||||||
// TranslationY.
|
|
||||||
private final AnimatedFloat mTaskbarTranslationYForLauncherState = new AnimatedFloat(
|
|
||||||
this::updateTranslationY);
|
|
||||||
|
|
||||||
public TaskbarAnimationController(BaseQuickstepLauncher launcher,
|
|
||||||
TaskbarAnimationControllerCallbacks taskbarCallbacks) {
|
|
||||||
mLauncher = launcher;
|
|
||||||
mTaskbarCallbacks = taskbarCallbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init() {
|
|
||||||
mTaskbarBackgroundAlpha.updateValue(mLauncher.hasBeenResumed() ? 0f : 1f);
|
|
||||||
boolean isVisibleForLauncherState = (mLauncher.getStateManager().getState()
|
|
||||||
.getVisibleElements(mLauncher) & TASKBAR) != 0;
|
|
||||||
mTaskbarVisibilityAlphaForLauncherState.updateValue(isVisibleForLauncherState ? 1f : 0f);
|
|
||||||
boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
|
|
||||||
& QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
|
|
||||||
mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
|
|
||||||
|
|
||||||
onTaskbarBackgroundAlphaChanged();
|
|
||||||
updateVisibilityAlpha();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void cleanup() {
|
|
||||||
setNavBarButtonAlpha(1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AnimatedFloat getTaskbarVisibilityForLauncherState() {
|
|
||||||
return mTaskbarVisibilityAlphaForLauncherState;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AnimatedFloat getTaskbarScaleForLauncherState() {
|
|
||||||
return mTaskbarScaleForLauncherState;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AnimatedFloat getTaskbarTranslationYForLauncherState() {
|
|
||||||
return mTaskbarTranslationYForLauncherState;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
|
|
||||||
return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
|
|
||||||
.setDuration(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void animateToVisibilityForIme(float toAlpha) {
|
|
||||||
mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForIme.value, toAlpha)
|
|
||||||
.setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onTaskbarBackgroundAlphaChanged() {
|
|
||||||
mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
|
|
||||||
updateVisibilityAlpha();
|
|
||||||
updateScale();
|
|
||||||
updateTranslationY();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateVisibilityAlpha() {
|
|
||||||
// We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
|
|
||||||
// assumption being that Taskbar should always be visible regardless of the current
|
|
||||||
// LauncherState if Launcher is paused.
|
|
||||||
float alphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
|
|
||||||
float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
|
|
||||||
mTaskbarVisibilityAlphaForLauncherState.value);
|
|
||||||
float taskbarAlpha = alphaDueToLauncher * alphaDueToIme;
|
|
||||||
mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha);
|
|
||||||
|
|
||||||
// Make the nav bar invisible if taskbar is visible.
|
|
||||||
setNavBarButtonAlpha(1f - taskbarAlpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateVisibilityAlphaForIme() {
|
|
||||||
updateVisibilityAlpha();
|
|
||||||
float taskbarAlphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
|
|
||||||
mTaskbarCallbacks.updateImeBarVisibilityAlpha(1f - taskbarAlphaDueToIme);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateScale() {
|
|
||||||
// We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
|
|
||||||
// assumption being that Taskbar should always be at scale 1f regardless of the current
|
|
||||||
// LauncherState if Launcher is paused.
|
|
||||||
float scale = mTaskbarScaleForLauncherState.value;
|
|
||||||
scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f);
|
|
||||||
mTaskbarCallbacks.updateTaskbarScale(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTranslationY() {
|
|
||||||
// We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
|
|
||||||
// assumption being that Taskbar should always be at translationY 0f regardless of the
|
|
||||||
// current LauncherState if Launcher is paused.
|
|
||||||
float translationY = mTaskbarTranslationYForLauncherState.value;
|
|
||||||
translationY = Utilities.mapRange(mTaskbarBackgroundAlpha.value, translationY, 0f);
|
|
||||||
mTaskbarCallbacks.updateTaskbarTranslationY(translationY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setNavBarButtonAlpha(float navBarAlpha) {
|
|
||||||
SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,9 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
|
||||||
import static android.view.View.VISIBLE;
|
|
||||||
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -89,7 +86,7 @@ public class TaskbarDragController extends DragController<TaskbarActivityContext
|
|||||||
mActivity.setTaskbarWindowFullscreen(true);
|
mActivity.setTaskbarWindowFullscreen(true);
|
||||||
view.post(() -> {
|
view.post(() -> {
|
||||||
startInternalDrag(btv);
|
startInternalDrag(btv);
|
||||||
btv.setVisibility(INVISIBLE);
|
btv.setAlpha(0);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -294,16 +291,9 @@ public class TaskbarDragController extends DragController<TaskbarActivityContext
|
|||||||
return super.isDragging() || mIsSystemDragInProgress;
|
return super.isDragging() || mIsSystemDragInProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether we started dragging the given view and the drag is still in progress.
|
|
||||||
*/
|
|
||||||
public boolean isDraggingView(View child) {
|
|
||||||
return isDragging() && mDragObject != null && mDragObject.originalView == child;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeOnDragEnd() {
|
private void maybeOnDragEnd() {
|
||||||
if (!isDragging()) {
|
if (!isDragging()) {
|
||||||
((View) mDragObject.originalView).setVisibility(VISIBLE);
|
((View) mDragObject.originalView).setAlpha(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
|
|||||||
mFolderMargin = getResources().getDimensionPixelSize(R.dimen.taskbar_folder_margin);
|
mFolderMargin = getResources().getDimensionPixelSize(R.dimen.taskbar_folder_margin);
|
||||||
mTaskbarBackgroundPaint = new Paint();
|
mTaskbarBackgroundPaint = new Paint();
|
||||||
mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
|
mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
|
||||||
|
mTaskbarBackgroundPaint.setAlpha(0);
|
||||||
recreateControllers();
|
recreateControllers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,12 +110,6 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateImeBarVisibilityAlpha(float alpha) {
|
|
||||||
if (mControllerCallbacks != null) {
|
|
||||||
mControllerCallbacks.updateImeBarVisibilityAlpha(alpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewRemoved(View child) {
|
public void onViewRemoved(View child) {
|
||||||
super.onViewRemoved(child);
|
super.onViewRemoved(child);
|
||||||
@@ -139,7 +134,6 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
|
|||||||
return boundingBox;
|
return boundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the alpha of the background color behind all the Taskbar contents.
|
* Sets the alpha of the background color behind all the Taskbar contents.
|
||||||
* @param alpha 0 is fully transparent, 1 is fully opaque.
|
* @param alpha 0 is fully transparent, 1 is fully opaque.
|
||||||
|
|||||||
@@ -15,14 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
import static android.view.View.GONE;
|
|
||||||
import static android.view.View.VISIBLE;
|
|
||||||
|
|
||||||
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
|
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
|
||||||
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
|
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.inputmethodservice.InputMethodService;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.View.OnLongClickListener;
|
import android.view.View.OnLongClickListener;
|
||||||
@@ -31,8 +26,6 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||||
import com.android.launcher3.taskbar.contextual.RotationButtonController;
|
|
||||||
import com.android.quickstep.SysUINavigationMode;
|
|
||||||
import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
|
import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,42 +33,28 @@ import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
|
|||||||
*/
|
*/
|
||||||
public class TaskbarIconController {
|
public class TaskbarIconController {
|
||||||
|
|
||||||
private final Rect mTempRect = new Rect();
|
|
||||||
|
|
||||||
private final TaskbarActivityContext mActivity;
|
private final TaskbarActivityContext mActivity;
|
||||||
private final TaskbarDragLayer mDragLayer;
|
private final TaskbarDragLayer mDragLayer;
|
||||||
|
private final NavbarButtonUIController mNavbarButtonUIController;
|
||||||
|
|
||||||
private final TaskbarView mTaskbarView;
|
private final TaskbarView mTaskbarView;
|
||||||
private final ImeBarView mImeBarView;
|
|
||||||
private final RotationButtonController mRotationButtonController;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private TaskbarUIController mUIController = TaskbarUIController.DEFAULT;
|
private TaskbarUIController mUIController = TaskbarUIController.DEFAULT;
|
||||||
|
|
||||||
TaskbarIconController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer,
|
TaskbarIconController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer,
|
||||||
RotationButtonController rotationButtonController) {
|
NavbarButtonUIController navbarButtonUIController) {
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
mDragLayer = dragLayer;
|
mDragLayer = dragLayer;
|
||||||
|
mNavbarButtonUIController = navbarButtonUIController;
|
||||||
mTaskbarView = mDragLayer.findViewById(R.id.taskbar_view);
|
mTaskbarView = mDragLayer.findViewById(R.id.taskbar_view);
|
||||||
mImeBarView = mDragLayer.findViewById(R.id.ime_bar_view);
|
|
||||||
mRotationButtonController = rotationButtonController;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(OnClickListener clickListener, OnLongClickListener longClickListener,
|
public void init(OnClickListener clickListener, OnLongClickListener longClickListener) {
|
||||||
SysUINavigationMode.Mode navMode) {
|
mTaskbarView.init(clickListener, longClickListener);
|
||||||
mDragLayer.addOnLayoutChangeListener((v, a, b, c, d, e, f, g, h) ->
|
|
||||||
mUIController.alignRealHotseatWithTaskbar());
|
|
||||||
|
|
||||||
ButtonProvider buttonProvider = new ButtonProvider(mActivity);
|
|
||||||
mImeBarView.init(buttonProvider);
|
|
||||||
mTaskbarView.init(new TaskbarViewCallbacks(), clickListener, longClickListener,
|
|
||||||
buttonProvider);
|
|
||||||
mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
|
mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
|
||||||
|
|
||||||
mDragLayer.init(new TaskbarDragLayerCallbacks(), mTaskbarView);
|
mDragLayer.init(new TaskbarDragLayerCallbacks(), mTaskbarView);
|
||||||
if (mActivity.canShowNavButtons()) {
|
|
||||||
mRotationButtonController.setRotationButton(mTaskbarView.getContextualRotationButton());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
@@ -86,27 +65,11 @@ public class TaskbarIconController {
|
|||||||
mUIController = uiController;
|
mUIController = uiController;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
|
|
||||||
if (displayId != mActivity.getDisplayId() || !mActivity.canShowNavButtons()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mImeBarView.setImeSwitcherVisibility(showImeSwitcher);
|
|
||||||
setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
|
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
|
||||||
*/
|
*/
|
||||||
public void setImeIsVisible(boolean isImeVisible) {
|
public void setImeIsVisible(boolean isImeVisible) {
|
||||||
mTaskbarView.setTouchesEnabled(!isImeVisible);
|
mTaskbarView.setTouchesEnabled(!isImeVisible);
|
||||||
mUIController.onImeVisible(mDragLayer, isImeVisible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +85,7 @@ public class TaskbarIconController {
|
|||||||
if (mDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
|
if (mDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
|
||||||
// Let touches pass through us.
|
// Let touches pass through us.
|
||||||
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
|
||||||
} else if (mImeBarView.getVisibility() == VISIBLE) {
|
} else if (mNavbarButtonUIController.isImeVisible()) {
|
||||||
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
|
||||||
} else if (!mUIController.isTaskbarTouchable()) {
|
} else if (!mUIController.isTaskbarTouchable()) {
|
||||||
// Let touches pass through us.
|
// Let touches pass through us.
|
||||||
@@ -131,17 +94,8 @@ public class TaskbarIconController {
|
|||||||
// Buttons are visible, take over the full taskbar area
|
// Buttons are visible, take over the full taskbar area
|
||||||
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
|
||||||
} else {
|
} else {
|
||||||
if (mTaskbarView.mSystemButtonContainer.getVisibility() == VISIBLE) {
|
mNavbarButtonUIController.addVisibleButtonsRegion(
|
||||||
mDragLayer.getDescendantRectRelativeToSelf(
|
mDragLayer, insetsInfo.touchableRegion);
|
||||||
mTaskbarView.mSystemButtonContainer, mTempRect);
|
|
||||||
insetsInfo.touchableRegion.set(mTempRect);
|
|
||||||
}
|
|
||||||
if (mTaskbarView.mContextualButtonContainer.getVisibility() == VISIBLE) {
|
|
||||||
mDragLayer.getDescendantRectRelativeToSelf(
|
|
||||||
mTaskbarView.mContextualButtonContainer, mTempRect);
|
|
||||||
insetsInfo.touchableRegion.union(mTempRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
|
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,32 +114,11 @@ public class TaskbarIconController {
|
|||||||
// Ensure no other children present (like Folders, etc)
|
// Ensure no other children present (like Folders, etc)
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
View v = mDragLayer.getChildAt(i);
|
View v = mDragLayer.getChildAt(i);
|
||||||
if (!((v instanceof TaskbarView) || (v instanceof ImeBarView))) {
|
if (!(v instanceof TaskbarView)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mActivity.setTaskbarWindowFullscreen(false);
|
mActivity.setTaskbarWindowFullscreen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateImeBarVisibilityAlpha(float alpha) {
|
|
||||||
if (!mActivity.canShowNavButtons()) {
|
|
||||||
// TODO Remove sysui IME bar for gesture nav as well
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mImeBarView.setAlpha(alpha);
|
|
||||||
mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callbacks for {@link TaskbarView} to interact with the icon controller
|
|
||||||
*/
|
|
||||||
public class TaskbarViewCallbacks {
|
|
||||||
/**
|
|
||||||
* Returns whether no other controller is currently handling the given View's visibility.
|
|
||||||
*/
|
|
||||||
public boolean canUpdateViewVisibility(View child) {
|
|
||||||
return !mActivity.getDragController().isDraggingView(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,14 +40,11 @@ import com.android.quickstep.SysUINavigationMode;
|
|||||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||||
import com.android.quickstep.TouchInteractionService;
|
import com.android.quickstep.TouchInteractionService;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage taskbar lifecycle
|
* Class to manage taskbar lifecycle
|
||||||
*/
|
*/
|
||||||
public class TaskbarManager implements DisplayController.DisplayInfoChangeListener,
|
public class TaskbarManager implements DisplayController.DisplayInfoChangeListener,
|
||||||
SysUINavigationMode.NavigationModeChangeListener, SystemTaskbarNotificationManager {
|
SysUINavigationMode.NavigationModeChangeListener {
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final DisplayController mDisplayController;
|
private final DisplayController mDisplayController;
|
||||||
@@ -62,8 +59,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
|
|
||||||
private boolean mUserUnlocked = false;
|
private boolean mUserUnlocked = false;
|
||||||
|
|
||||||
private List<SystemTaskbarNotifier> mSystemTaskbarNotifiers = new ArrayList<>();
|
|
||||||
|
|
||||||
public TaskbarManager(TouchInteractionService service) {
|
public TaskbarManager(TouchInteractionService service) {
|
||||||
mDisplayController = DisplayController.INSTANCE.get(service);
|
mDisplayController = DisplayController.INSTANCE.get(service);
|
||||||
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
|
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
|
||||||
@@ -129,7 +124,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mTaskbarActivityContext = new TaskbarActivityContext(
|
mTaskbarActivityContext = new TaskbarActivityContext(
|
||||||
mContext, dp.copy(mContext), mNavButtonController, this);
|
mContext, dp.copy(mContext), mNavButtonController);
|
||||||
mTaskbarActivityContext.init();
|
mTaskbarActivityContext.init();
|
||||||
if (mLauncher != null) {
|
if (mLauncher != null) {
|
||||||
mTaskbarActivityContext.setUIController(
|
mTaskbarActivityContext.setUIController(
|
||||||
@@ -137,9 +132,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - I don't think this is the best place for these pass through methods,
|
|
||||||
// maybe directly in TaskbarIconController?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
|
* See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
|
||||||
* @param systemUiStateFlags The latest SystemUiStateFlags
|
* @param systemUiStateFlags The latest SystemUiStateFlags
|
||||||
@@ -151,16 +143,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerSystemTaskbarNotifications(SystemTaskbarNotifier notifier) {
|
|
||||||
if (!mSystemTaskbarNotifiers.contains(notifier)) {
|
|
||||||
mSystemTaskbarNotifiers.add(notifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeSystemTaskbarNotifications(SystemTaskbarNotifier notifier) {
|
|
||||||
mSystemTaskbarNotifiers.remove(notifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
|
* 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.
|
* instantiating at all, which is what's responsible for sending sysui state flags over.
|
||||||
@@ -171,26 +153,26 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
*/
|
*/
|
||||||
public void updateImeStatus(int displayId, int vis, int backDisposition,
|
public void updateImeStatus(int displayId, int vis, int backDisposition,
|
||||||
boolean showImeSwitcher) {
|
boolean showImeSwitcher) {
|
||||||
for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
|
if (mTaskbarActivityContext != null) {
|
||||||
notifier.updateImeStatus(displayId, vis, backDisposition, showImeSwitcher);
|
mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRotationProposal(int rotation, boolean isValid) {
|
public void onRotationProposal(int rotation, boolean isValid) {
|
||||||
for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
|
if (mTaskbarActivityContext != null) {
|
||||||
notifier.onRotationProposal(rotation, isValid);
|
mTaskbarActivityContext.onRotationProposal(rotation, isValid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disable(int displayId, int state1, int state2, boolean animate) {
|
public void disable(int displayId, int state1, int state2, boolean animate) {
|
||||||
for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
|
if (mTaskbarActivityContext != null) {
|
||||||
notifier.disable(displayId, state1, state2, animate);
|
mTaskbarActivityContext.disable(displayId, state1, state2, animate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSystemBarAttributesChanged(int displayId, int behavior) {
|
public void onSystemBarAttributesChanged(int displayId, int behavior) {
|
||||||
for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
|
if (mTaskbarActivityContext != null) {
|
||||||
notifier.onSystemBarAttributesChanged(displayId, behavior);
|
mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,18 +184,4 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||||||
mDisplayController.removeChangeListener(this);
|
mDisplayController.removeChangeListener(this);
|
||||||
mSysUINavigationMode.removeModeChangeListener(this);
|
mSysUINavigationMode.removeModeChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface SystemTaskbarNotifier {
|
|
||||||
void updateImeStatus(int displayId, int vis, int backDisposition,
|
|
||||||
boolean showImeSwitcher);
|
|
||||||
void onRotationProposal(int rotation, boolean isValid);
|
|
||||||
void disable(int displayId, int state1, int state2, boolean animate);
|
|
||||||
void onSystemBarAttributesChanged(int displayId, int behavior);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SystemTaskbarNotificationManager {
|
|
||||||
void registerSystemTaskbarNotifications(TaskbarManager.SystemTaskbarNotifier notifier);
|
|
||||||
void removeSystemTaskbarNotifications(TaskbarManager.SystemTaskbarNotifier notifier);
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherState.TASKBAR;
|
import static com.android.launcher3.LauncherState.TASKBAR;
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -27,7 +26,7 @@ import com.android.launcher3.anim.PendingAnimation;
|
|||||||
import com.android.launcher3.anim.PropertySetter;
|
import com.android.launcher3.anim.PropertySetter;
|
||||||
import com.android.launcher3.statemanager.StateManager;
|
import com.android.launcher3.statemanager.StateManager;
|
||||||
import com.android.launcher3.states.StateAnimationConfig;
|
import com.android.launcher3.states.StateAnimationConfig;
|
||||||
import com.android.quickstep.AnimatedFloat;
|
import com.android.launcher3.util.MultiValueAlpha;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
|
* StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
|
||||||
@@ -37,15 +36,15 @@ public class TaskbarStateHandler implements StateManager.StateHandler<LauncherSt
|
|||||||
|
|
||||||
private final BaseQuickstepLauncher mLauncher;
|
private final BaseQuickstepLauncher mLauncher;
|
||||||
|
|
||||||
// Contains Taskbar-related methods and fields we should aniamte. If null, don't do anything.
|
// Contains Taskbar-related properties we should aniamte. If null, don't do anything.
|
||||||
private @Nullable TaskbarAnimationController mAnimationController = null;
|
private @Nullable MultiValueAlpha.AlphaProperty mTaskbarAlpha = null;
|
||||||
|
|
||||||
public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
|
public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
|
||||||
mLauncher = launcher;
|
mLauncher = launcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAnimationController(TaskbarAnimationController callbacks) {
|
public void setAnimationController(MultiValueAlpha.AlphaProperty taskbarAlpha) {
|
||||||
mAnimationController = callbacks;
|
mTaskbarAlpha = taskbarAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,17 +58,15 @@ public class TaskbarStateHandler implements StateManager.StateHandler<LauncherSt
|
|||||||
setState(toState, animation);
|
setState(toState, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setState(LauncherState toState, PropertySetter setter) {
|
/**
|
||||||
if (mAnimationController == null) {
|
* Sets the provided state
|
||||||
|
*/
|
||||||
|
public void setState(LauncherState toState, PropertySetter setter) {
|
||||||
|
if (mTaskbarAlpha == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
|
boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
|
||||||
setter.setFloat(mAnimationController.getTaskbarVisibilityForLauncherState(),
|
setter.setFloat(mTaskbarAlpha, MultiValueAlpha.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
|
||||||
AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
|
|
||||||
setter.setFloat(mAnimationController.getTaskbarScaleForLauncherState(),
|
|
||||||
AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher), LINEAR);
|
|
||||||
setter.setFloat(mAnimationController.getTaskbarTranslationYForLauncherState(),
|
|
||||||
AnimatedFloat.VALUE, toState.getTaskbarTranslationY(mLauncher), ACCEL_DEACCEL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
|
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||||
|
import com.android.quickstep.AnimatedFloat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for providing different taskbar UI
|
* Base class for providing different taskbar UI
|
||||||
*/
|
*/
|
||||||
@@ -22,20 +25,12 @@ public class TaskbarUIController {
|
|||||||
|
|
||||||
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
|
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
|
||||||
|
|
||||||
/**
|
protected void init(AnimatedFloat taskBarAlpha, AlphaProperty iconAlphaForLauncherState,
|
||||||
* Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
|
AlphaProperty iconAlphaForHome) { }
|
||||||
*/
|
|
||||||
public void alignRealHotseatWithTaskbar() { }
|
|
||||||
|
|
||||||
protected void onCreate(LauncherTaskbarUIController.ContextualRotationNotifier notifier) { }
|
|
||||||
|
|
||||||
protected void onDestroy() { }
|
protected void onDestroy() { }
|
||||||
|
|
||||||
protected boolean isTaskbarTouchable() {
|
protected boolean isTaskbarTouchable() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onImeVisible(TaskbarDragLayer container, boolean isVisible) {
|
|
||||||
container.updateImeBarVisibilityAlpha(isVisible ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,77 +15,60 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.taskbar;
|
package com.android.launcher3.taskbar;
|
||||||
|
|
||||||
import static android.view.View.MeasureSpec.EXACTLY;
|
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||||
|
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||||
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.LayoutRes;
|
import androidx.annotation.LayoutRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.BubbleTextView;
|
import com.android.launcher3.BubbleTextView;
|
||||||
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Insettable;
|
import com.android.launcher3.Insettable;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.anim.PropertySetter;
|
||||||
import com.android.launcher3.folder.FolderIcon;
|
import com.android.launcher3.folder.FolderIcon;
|
||||||
import com.android.launcher3.model.data.FolderInfo;
|
import com.android.launcher3.model.data.FolderInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.taskbar.contextual.RotationContextButton;
|
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||||
import com.android.launcher3.views.ActivityContext;
|
import com.android.launcher3.views.ActivityContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
|
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
|
||||||
*/
|
*/
|
||||||
public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable {
|
public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable {
|
||||||
|
|
||||||
private final int mIconTouchSize;
|
|
||||||
private final boolean mIsRtl;
|
|
||||||
private final int mTouchSlop;
|
|
||||||
private final RectF mTempDelegateBounds = new RectF();
|
|
||||||
private final RectF mDelegateSlopBounds = new RectF();
|
|
||||||
private final int[] mTempOutLocation = new int[2];
|
private final int[] mTempOutLocation = new int[2];
|
||||||
|
|
||||||
|
private final Rect mIconLayoutBounds = new Rect();
|
||||||
|
private final int mIconTouchSize;
|
||||||
private final int mItemMarginLeftRight;
|
private final int mItemMarginLeftRight;
|
||||||
|
private final int mItemPadding;
|
||||||
|
|
||||||
private final TaskbarActivityContext mActivityContext;
|
private final TaskbarActivityContext mActivityContext;
|
||||||
|
|
||||||
// Initialized in init.
|
// Initialized in init.
|
||||||
private TaskbarIconController.TaskbarViewCallbacks mControllerCallbacks;
|
|
||||||
private View.OnClickListener mIconClickListener;
|
private View.OnClickListener mIconClickListener;
|
||||||
private View.OnLongClickListener mIconLongClickListener;
|
private View.OnLongClickListener mIconLongClickListener;
|
||||||
|
|
||||||
LinearLayout mSystemButtonContainer;
|
|
||||||
LinearLayout mHotseatIconsContainer;
|
|
||||||
LinearLayout mContextualButtonContainer;
|
|
||||||
|
|
||||||
// Delegate touches to the closest view if within mIconTouchSize.
|
|
||||||
private boolean mDelegateTargeted;
|
|
||||||
private View mDelegateView;
|
|
||||||
// Prevents dispatching touches to children if true
|
// Prevents dispatching touches to children if true
|
||||||
private boolean mTouchEnabled = true;
|
private boolean mTouchEnabled = true;
|
||||||
|
|
||||||
// Only non-null when the corresponding Folder is open.
|
// Only non-null when the corresponding Folder is open.
|
||||||
private @Nullable FolderIcon mLeaveBehindFolderIcon;
|
private @Nullable FolderIcon mLeaveBehindFolderIcon;
|
||||||
|
|
||||||
/** Provider of buttons added to taskbar in 3 button nav */
|
|
||||||
private ButtonProvider mButtonProvider;
|
|
||||||
private RotationContextButton mContextualRotationButton;
|
|
||||||
|
|
||||||
private boolean mDisableRelayout;
|
|
||||||
private boolean mAreHolesAllowed;
|
|
||||||
|
|
||||||
public TaskbarView(@NonNull Context context) {
|
public TaskbarView(@NonNull Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -106,61 +89,68 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
|
|
||||||
Resources resources = getResources();
|
Resources resources = getResources();
|
||||||
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
|
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
|
||||||
mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
|
|
||||||
|
|
||||||
mIsRtl = Utilities.isRtl(resources);
|
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
|
||||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
|
||||||
|
|
||||||
|
// We layout the icons to be of mIconTouchSize in width and height
|
||||||
|
mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2;
|
||||||
|
mItemPadding = (mIconTouchSize - actualIconSize) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void init(OnClickListener clickListener, OnLongClickListener longClickListener) {
|
||||||
protected void onFinishInflate() {
|
|
||||||
super.onFinishInflate();
|
|
||||||
mSystemButtonContainer = findViewById(R.id.nav_button_layout);
|
|
||||||
mHotseatIconsContainer = findViewById(R.id.hotseat_icons_layout);
|
|
||||||
mContextualButtonContainer = findViewById(R.id.contextual_button_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init(TaskbarIconController.TaskbarViewCallbacks callbacks,
|
|
||||||
OnClickListener clickListener, OnLongClickListener longClickListener,
|
|
||||||
ButtonProvider buttonProvider) {
|
|
||||||
mControllerCallbacks = callbacks;
|
|
||||||
mIconClickListener = clickListener;
|
mIconClickListener = clickListener;
|
||||||
mIconLongClickListener = longClickListener;
|
mIconLongClickListener = longClickListener;
|
||||||
mButtonProvider = buttonProvider;
|
|
||||||
|
|
||||||
if (mActivityContext.canShowNavButtons()) {
|
|
||||||
createNavButtons();
|
|
||||||
} else {
|
|
||||||
mSystemButtonContainer.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int numHotseatIcons = mActivityContext.getDeviceProfile().numShownHotseatIcons;
|
int numHotseatIcons = mActivityContext.getDeviceProfile().numShownHotseatIcons;
|
||||||
updateHotseatItems(new ItemInfo[numHotseatIcons]);
|
updateHotseatItems(new ItemInfo[numHotseatIcons]);
|
||||||
|
}
|
||||||
|
|
||||||
if (mActivityContext.canShowNavButtons()) {
|
/**
|
||||||
createContextualRegion();
|
* Aligns the icons in the taskbar to that of Launcher.
|
||||||
|
*/
|
||||||
|
public void alignIconsWithLauncher(DeviceProfile launcherDp, PropertySetter setter) {
|
||||||
|
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(getContext());
|
||||||
|
float scaleUp = ((float) launcherDp.iconSizePx)
|
||||||
|
/ mActivityContext.getDeviceProfile().iconSizePx;
|
||||||
|
int hotseatCellSize =
|
||||||
|
(launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
|
||||||
|
/ launcherDp.numShownHotseatIcons;
|
||||||
|
|
||||||
|
int offsetY = launcherDp.getTaskbarOffsetY();
|
||||||
|
setter.setFloat(this, VIEW_TRANSLATE_Y, -offsetY, LINEAR);
|
||||||
|
mActivityContext.setTaskbarWindowHeight(
|
||||||
|
mActivityContext.getDeviceProfile().taskbarSize + offsetY);
|
||||||
|
|
||||||
|
int count = getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
if (child.getVisibility() != VISIBLE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
|
||||||
|
|
||||||
|
float childCenter = (child.getLeft() + child.getRight()) / 2;
|
||||||
|
float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * (i)
|
||||||
|
+ hotseatCellSize / 2;
|
||||||
|
setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables/disables empty icons in taskbar so that the layout matches with Launcher
|
* Aligns the icons in the taskbar to that of Launcher.
|
||||||
|
* @return a callback to be executed at the end of the setter
|
||||||
*/
|
*/
|
||||||
public void setHolesAllowedInLayout(boolean areHolesAllowed) {
|
public Runnable resetIconPosition(PropertySetter setter) {
|
||||||
if (mAreHolesAllowed != areHolesAllowed) {
|
int count = getChildCount();
|
||||||
mAreHolesAllowed = areHolesAllowed;
|
for (int i = 0; i < count; i++) {
|
||||||
updateHotseatItemsVisibility();
|
View child = getChildAt(i);
|
||||||
// TODO: Add animation
|
setter.setFloat(child, SCALE_PROPERTY, 1, LINEAR);
|
||||||
}
|
setter.setFloat(child, VIEW_TRANSLATE_X, 0, LINEAR);
|
||||||
}
|
|
||||||
|
|
||||||
private void setHolesAllowedInLayoutNoAnimation(boolean areHolesAllowed) {
|
|
||||||
if (mAreHolesAllowed != areHolesAllowed) {
|
|
||||||
mAreHolesAllowed = areHolesAllowed;
|
|
||||||
updateHotseatItemsVisibility();
|
|
||||||
onMeasure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
|
|
||||||
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
|
|
||||||
onLayout(false, getLeft(), getTop(), getRight(), getBottom());
|
|
||||||
}
|
}
|
||||||
|
setter.setFloat(this, VIEW_TRANSLATE_Y, 0, LINEAR);
|
||||||
|
return () -> mActivityContext.setTaskbarWindowHeight(
|
||||||
|
mActivityContext.getDeviceProfile().taskbarSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,9 +158,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
*/
|
*/
|
||||||
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
|
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
|
||||||
for (int i = 0; i < hotseatItemInfos.length; i++) {
|
for (int i = 0; i < hotseatItemInfos.length; i++) {
|
||||||
ItemInfo hotseatItemInfo = hotseatItemInfos[
|
ItemInfo hotseatItemInfo = hotseatItemInfos[i];
|
||||||
!mIsRtl ? i : hotseatItemInfos.length - i - 1];
|
View hotseatView = getChildAt(i);
|
||||||
View hotseatView = mHotseatIconsContainer.getChildAt(i);
|
|
||||||
|
|
||||||
// Replace any Hotseat views with the appropriate type if it's not already that type.
|
// Replace any Hotseat views with the appropriate type if it's not already that type.
|
||||||
final int expectedLayoutResId;
|
final int expectedLayoutResId;
|
||||||
@@ -191,7 +180,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
if (hotseatView == null
|
if (hotseatView == null
|
||||||
|| hotseatView.getSourceLayoutResId() != expectedLayoutResId
|
|| hotseatView.getSourceLayoutResId() != expectedLayoutResId
|
||||||
|| needsReinflate) {
|
|| needsReinflate) {
|
||||||
mHotseatIconsContainer.removeView(hotseatView);
|
removeView(hotseatView);
|
||||||
if (isFolder) {
|
if (isFolder) {
|
||||||
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
|
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
|
||||||
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
|
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
|
||||||
@@ -201,10 +190,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
} else {
|
} else {
|
||||||
hotseatView = inflate(expectedLayoutResId);
|
hotseatView = inflate(expectedLayoutResId);
|
||||||
}
|
}
|
||||||
int iconSize = mActivityContext.getDeviceProfile().iconSizePx;
|
LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
|
||||||
LayoutParams lp = new LayoutParams(iconSize, iconSize);
|
hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
|
||||||
lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
|
addView(hotseatView, i, lp);
|
||||||
mHotseatIconsContainer.addView(hotseatView, i, lp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
|
// Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
|
||||||
@@ -222,22 +210,42 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
hotseatView.setOnLongClickListener(null);
|
hotseatView.setOnLongClickListener(null);
|
||||||
hotseatView.setTag(null);
|
hotseatView.setTag(null);
|
||||||
}
|
}
|
||||||
updateHotseatItemVisibility(hotseatView);
|
hotseatView.setVisibility(hotseatView.getTag() != null ? VISIBLE : INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateHotseatItemsVisibility() {
|
@Override
|
||||||
for (int i = mHotseatIconsContainer.getChildCount() - 1; i >= 0; i--) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
updateHotseatItemVisibility(mHotseatIconsContainer.getChildAt(i));
|
int count = getChildCount();
|
||||||
|
// Find total visible children
|
||||||
|
int visibleChildren = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (getChildAt(i).getVisibility() == VISIBLE) {
|
||||||
|
visibleChildren++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void updateHotseatItemVisibility(View hotseatView) {
|
int spaceNeeded = visibleChildren * (mItemMarginLeftRight * 2 + mIconTouchSize);
|
||||||
if (!mControllerCallbacks.canUpdateViewVisibility(hotseatView)) {
|
int iconStart = (right - left - spaceNeeded) / 2;
|
||||||
return;
|
int startOffset = ApiWrapper.getHotseatStartOffset(getContext());
|
||||||
|
if (startOffset > iconStart) {
|
||||||
|
int diff = startOffset - iconStart;
|
||||||
|
iconStart = isLayoutRtl() ? (iconStart - diff) : iconStart + diff;
|
||||||
}
|
}
|
||||||
hotseatView.setVisibility(
|
// Layout the children
|
||||||
hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE));
|
mIconLayoutBounds.left = iconStart;
|
||||||
|
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
|
||||||
|
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
if (child.getVisibility() == VISIBLE) {
|
||||||
|
iconStart += mItemMarginLeftRight;
|
||||||
|
int iconEnd = iconStart + mIconTouchSize;
|
||||||
|
child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
|
||||||
|
iconStart = iconEnd + mItemMarginLeftRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIconLayoutBounds.right = iconStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -248,154 +256,21 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
return super.dispatchTouchEvent(ev);
|
return super.dispatchTouchEvent(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
|
||||||
boolean handled = delegateTouchIfNecessary(event);
|
|
||||||
return super.onTouchEvent(event) || handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTouchesEnabled(boolean touchEnabled) {
|
public void setTouchesEnabled(boolean touchEnabled) {
|
||||||
this.mTouchEnabled = touchEnabled;
|
this.mTouchEnabled = touchEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* User touched the Taskbar background. Determine whether the touch is close enough to a view
|
|
||||||
* that we should forward the touches to it.
|
|
||||||
* @return Whether a delegate view was chosen and it handled the touch event.
|
|
||||||
*/
|
|
||||||
private boolean delegateTouchIfNecessary(MotionEvent event) {
|
|
||||||
final float x = event.getX();
|
|
||||||
final float y = event.getY();
|
|
||||||
if (mDelegateView == null && event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
||||||
View delegateView = findDelegateView(x, y);
|
|
||||||
if (delegateView != null) {
|
|
||||||
mDelegateTargeted = true;
|
|
||||||
mDelegateView = delegateView;
|
|
||||||
mDelegateSlopBounds.set(mTempDelegateBounds);
|
|
||||||
mDelegateSlopBounds.inset(-mTouchSlop, -mTouchSlop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean sendToDelegate = mDelegateTargeted;
|
|
||||||
boolean inBounds = true;
|
|
||||||
switch (event.getAction()) {
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
inBounds = mDelegateSlopBounds.contains(x, y);
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
case MotionEvent.ACTION_CANCEL:
|
|
||||||
mDelegateTargeted = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean handled = false;
|
|
||||||
if (sendToDelegate) {
|
|
||||||
if (inBounds) {
|
|
||||||
// Offset event coordinates to be inside the target view
|
|
||||||
event.setLocation(mDelegateView.getWidth() / 2f, mDelegateView.getHeight() / 2f);
|
|
||||||
} else {
|
|
||||||
// Offset event coordinates to be outside the target view (in case it does
|
|
||||||
// something like tracking pressed state)
|
|
||||||
event.setLocation(-mTouchSlop * 2, -mTouchSlop * 2);
|
|
||||||
}
|
|
||||||
handled = mDelegateView.dispatchTouchEvent(event);
|
|
||||||
// Cleanup if this was the last event to send to the delegate.
|
|
||||||
if (!mDelegateTargeted) {
|
|
||||||
mDelegateView = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an item whose touch bounds contain the given coordinates,
|
|
||||||
* or null if no such item exists.
|
|
||||||
*
|
|
||||||
* Also sets {@link #mTempDelegateBounds} to be the touch bounds of the chosen delegate view.
|
|
||||||
*/
|
|
||||||
private @Nullable View findDelegateView(float x, float y) {
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View child = getChildAt(i);
|
|
||||||
if (!child.isShown() || !child.isClickable()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int childCenterX = child.getLeft() + child.getWidth() / 2;
|
|
||||||
int childCenterY = child.getTop() + child.getHeight() / 2;
|
|
||||||
mTempDelegateBounds.set(
|
|
||||||
childCenterX - mIconTouchSize / 2f,
|
|
||||||
childCenterY - mIconTouchSize / 2f,
|
|
||||||
childCenterX + mIconTouchSize / 2f,
|
|
||||||
childCenterY + mIconTouchSize / 2f);
|
|
||||||
if (mTempDelegateBounds.contains(x, y)) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
|
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
|
||||||
* touch bounds.
|
* touch bounds.
|
||||||
*/
|
*/
|
||||||
public boolean isEventOverAnyItem(MotionEvent ev) {
|
public boolean isEventOverAnyItem(MotionEvent ev) {
|
||||||
getLocationOnScreen(mTempOutLocation);
|
getLocationOnScreen(mTempOutLocation);
|
||||||
float xInOurCoordinates = ev.getX() - mTempOutLocation[0];
|
int xInOurCoordinates = (int) ev.getX() - mTempOutLocation[0];
|
||||||
float yInOurCoorindates = ev.getY() - mTempOutLocation[1];
|
int yInOurCoorindates = (int) ev.getY() - mTempOutLocation[1];
|
||||||
return findDelegateView(xInOurCoordinates, yInOurCoorindates) != null;
|
return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add back/home/recents buttons into a single ViewGroup that will be inserted at
|
|
||||||
* {@param navButtonStartIndex}
|
|
||||||
*/
|
|
||||||
private void createNavButtons() {
|
|
||||||
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
|
|
||||||
mActivityContext.getDeviceProfile().iconSizePx,
|
|
||||||
mActivityContext.getDeviceProfile().iconSizePx
|
|
||||||
);
|
|
||||||
buttonParams.gravity = Gravity.CENTER;
|
|
||||||
|
|
||||||
mSystemButtonContainer.addView(mButtonProvider.getBack(), buttonParams);
|
|
||||||
mSystemButtonContainer.addView(mButtonProvider.getHome(), buttonParams);
|
|
||||||
mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The bounding box of where the hotseat elements are relative to this TaskbarView.
|
|
||||||
*/
|
|
||||||
protected RectF getHotseatBounds() {
|
|
||||||
RectF result;
|
|
||||||
mDisableRelayout = true;
|
|
||||||
boolean wereHolesAllowed = mAreHolesAllowed;
|
|
||||||
setHolesAllowedInLayoutNoAnimation(true);
|
|
||||||
result = new RectF(
|
|
||||||
mHotseatIconsContainer.getLeft(),
|
|
||||||
mHotseatIconsContainer.getTop(),
|
|
||||||
mHotseatIconsContainer.getRight(),
|
|
||||||
mHotseatIconsContainer.getBottom());
|
|
||||||
setHolesAllowedInLayoutNoAnimation(wereHolesAllowed);
|
|
||||||
mDisableRelayout = false;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void requestLayout() {
|
|
||||||
if (!mDisableRelayout) {
|
|
||||||
super.requestLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createContextualRegion() {
|
|
||||||
mContextualRotationButton = mButtonProvider.getContextualRotation();
|
|
||||||
mContextualRotationButton.setVisibility(GONE);
|
|
||||||
mContextualButtonContainer.addView(mContextualRotationButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public RotationContextButton getContextualRotationButton() {
|
|
||||||
return mContextualRotationButton;
|
|
||||||
}
|
|
||||||
// FolderIconParent implemented methods.
|
// FolderIconParent implemented methods.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -432,11 +307,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
|||||||
// Ignore, we just implement Insettable to draw behind system insets.
|
// Ignore, we just implement Insettable to draw behind system insets.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconsVisibility(boolean isVisible) {
|
|
||||||
mHotseatIconsContainer.setVisibility(isVisible ? VISIBLE : INVISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areIconsVisible() {
|
public boolean areIconsVisible() {
|
||||||
return mHotseatIconsContainer.getVisibility() == VISIBLE;
|
// Consider the overall visibility
|
||||||
|
return getVisibility() == VISIBLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,16 +30,24 @@ import android.view.View;
|
|||||||
* * Directly use AnimatedVectorDrawable instead of KeyButtonDrawable
|
* * Directly use AnimatedVectorDrawable instead of KeyButtonDrawable
|
||||||
*/
|
*/
|
||||||
public interface RotationButton {
|
public interface RotationButton {
|
||||||
void setRotationButtonController(RotationButtonController rotationButtonController);
|
default void setRotationButtonController(RotationButtonController rotationButtonController) { }
|
||||||
View getCurrentView();
|
|
||||||
boolean show();
|
default View getCurrentView() {
|
||||||
boolean hide();
|
return null;
|
||||||
boolean isVisible();
|
}
|
||||||
void updateIcon(int lightIconColor, int darkIconColor);
|
default void show() { }
|
||||||
void setOnClickListener(View.OnClickListener onClickListener);
|
default void hide() { }
|
||||||
void setOnHoverListener(View.OnHoverListener onHoverListener);
|
default boolean isVisible() {
|
||||||
AnimatedVectorDrawable getImageDrawable();
|
return false;
|
||||||
void setDarkIntensity(float darkIntensity);
|
}
|
||||||
|
|
||||||
|
default void updateIcon(int lightIconColor, int darkIconColor) { }
|
||||||
|
default void setOnClickListener(View.OnClickListener onClickListener) { }
|
||||||
|
default void setOnHoverListener(View.OnHoverListener onHoverListener) { }
|
||||||
|
default AnimatedVectorDrawable getImageDrawable() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
default void setDarkIntensity(float darkIntensity) { }
|
||||||
default boolean acceptRotationProposal() {
|
default boolean acceptRotationProposal() {
|
||||||
return getCurrentView() != null;
|
return getCurrentView() != null;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -104,7 +104,7 @@ public class RotationButtonController {
|
|||||||
|
|
||||||
private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
|
private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onRotationChanged(final int rotation) throws RemoteException {
|
public void onRotationChanged(final int rotation) {
|
||||||
// We need this to be scheduled as early as possible to beat the redrawing of
|
// We need this to be scheduled as early as possible to beat the redrawing of
|
||||||
// window in response to the orientation change.
|
// window in response to the orientation change.
|
||||||
mMainThreadHandler.postAtFrontOfQueue(() -> {
|
mMainThreadHandler.postAtFrontOfQueue(() -> {
|
||||||
@@ -137,7 +137,7 @@ public class RotationButtonController {
|
|||||||
|
|
||||||
mAccessibilityManager = AccessibilityManager.getInstance(context);
|
mAccessibilityManager = AccessibilityManager.getInstance(context);
|
||||||
mTaskStackListener = new TaskStackListenerImpl();
|
mTaskStackListener = new TaskStackListenerImpl();
|
||||||
mDisplayController = DisplayController.INSTANCE.getNoCreate();
|
mDisplayController = DisplayController.INSTANCE.get(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRotationButton(RotationButton rotationButton) {
|
public void setRotationButton(RotationButton rotationButton) {
|
||||||
@@ -156,7 +156,7 @@ public class RotationButtonController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
public void onDestroy() {
|
||||||
unregisterListeners();
|
unregisterListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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.contextual;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
|
||||||
|
|
||||||
/** Containing logic for the rotation button in nav bar. */
|
|
||||||
public class RotationContextButton extends ImageView implements RotationButton {
|
|
||||||
|
|
||||||
private AnimatedVectorDrawable mImageDrawable;
|
|
||||||
|
|
||||||
public RotationContextButton(Context context) {
|
|
||||||
super(context);
|
|
||||||
setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRotationButtonController(RotationButtonController rotationButtonController) {
|
|
||||||
// TODO(b/187754252) UI polish, different icons based on light/dark context, etc
|
|
||||||
mImageDrawable = (AnimatedVectorDrawable) getContext()
|
|
||||||
.getDrawable(rotationButtonController.getIconResId());
|
|
||||||
setImageDrawable(mImageDrawable);
|
|
||||||
mImageDrawable.setCallback(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getCurrentView() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean show() {
|
|
||||||
setVisibility(VISIBLE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hide() {
|
|
||||||
setVisibility(GONE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isVisible() {
|
|
||||||
return getVisibility() == VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateIcon(int lightIconColor, int darkIconColor) {
|
|
||||||
// TODO(b/187754252): UI Polish
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOnClickListener(View.OnClickListener onClickListener) {
|
|
||||||
super.setOnClickListener(onClickListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOnHoverListener(View.OnHoverListener onHoverListener) {
|
|
||||||
super.setOnHoverListener(onHoverListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnimatedVectorDrawable getImageDrawable() {
|
|
||||||
return mImageDrawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDarkIntensity(float darkIntensity) {
|
|
||||||
// TODO(b/187754252) UI polish
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVisibility(int visibility) {
|
|
||||||
super.setVisibility(visibility);
|
|
||||||
|
|
||||||
if (visibility != View.VISIBLE && mImageDrawable != null) {
|
|
||||||
mImageDrawable.clearAnimationCallbacks();
|
|
||||||
mImageDrawable.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the rotation animation once it becomes visible
|
|
||||||
if (visibility == View.VISIBLE && mImageDrawable != null) {
|
|
||||||
mImageDrawable.reset();
|
|
||||||
mImageDrawable.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptRotationProposal() {
|
|
||||||
return isAttachedToWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,10 +17,15 @@
|
|||||||
package com.android.launcher3.uioverrides;
|
package com.android.launcher3.uioverrides;
|
||||||
|
|
||||||
import android.app.Person;
|
import android.app.Person;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
|
||||||
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.quickstep.SysUINavigationMode;
|
||||||
|
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||||
|
|
||||||
public class ApiWrapper {
|
public class ApiWrapper {
|
||||||
|
|
||||||
@@ -37,4 +42,18 @@ public class ApiWrapper {
|
|||||||
public static boolean isInternalDisplay(Display display) {
|
public static boolean isInternalDisplay(Display display) {
|
||||||
return display.getType() == Display.TYPE_INTERNAL;
|
return display.getType() == Display.TYPE_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum space that should be left empty at the start of hotseat
|
||||||
|
*/
|
||||||
|
public static int getHotseatStartOffset(Context context) {
|
||||||
|
if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) {
|
||||||
|
Resources res = context.getResources();
|
||||||
|
return 2 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_spacing)
|
||||||
|
+ 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,16 +82,6 @@ public class OverviewState extends LauncherState {
|
|||||||
return new float[] {NO_SCALE, NO_OFFSET};
|
return new float[] {NO_SCALE, NO_OFFSET};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getTaskbarScale(Launcher launcher) {
|
|
||||||
return 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getTaskbarTranslationY(Launcher launcher) {
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
||||||
return new PageAlphaProvider(DEACCEL_2) {
|
return new PageAlphaProvider(DEACCEL_2) {
|
||||||
|
|||||||
@@ -295,6 +295,10 @@
|
|||||||
|
|
||||||
<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
|
<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
|
||||||
<dimen name="taskbar_size">0dp</dimen>
|
<dimen name="taskbar_size">0dp</dimen>
|
||||||
|
<dimen name="qsb_widget_height">0dp</dimen>
|
||||||
|
<dimen name="taskbar_icon_size">44dp</dimen>
|
||||||
|
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
||||||
|
<dimen name="taskbar_icon_spacing">8dp</dimen>
|
||||||
|
|
||||||
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
|
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
|
||||||
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
|
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import com.android.launcher3.config.FeatureFlags;
|
|||||||
import com.android.launcher3.icons.DotRenderer;
|
import com.android.launcher3.icons.DotRenderer;
|
||||||
import com.android.launcher3.icons.GraphicsUtils;
|
import com.android.launcher3.icons.GraphicsUtils;
|
||||||
import com.android.launcher3.icons.IconNormalizer;
|
import com.android.launcher3.icons.IconNormalizer;
|
||||||
|
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||||
import com.android.launcher3.util.DisplayController;
|
import com.android.launcher3.util.DisplayController;
|
||||||
import com.android.launcher3.util.DisplayController.Info;
|
import com.android.launcher3.util.DisplayController.Info;
|
||||||
import com.android.launcher3.util.WindowBounds;
|
import com.android.launcher3.util.WindowBounds;
|
||||||
@@ -54,6 +55,8 @@ import java.io.PrintWriter;
|
|||||||
public class DeviceProfile {
|
public class DeviceProfile {
|
||||||
|
|
||||||
private static final int DEFAULT_DOT_SIZE = 100;
|
private static final int DEFAULT_DOT_SIZE = 100;
|
||||||
|
// Ratio of empty space, qsb should take up to appear visually centered.
|
||||||
|
private static final float QSB_CENTER_FACTOR = .325f;
|
||||||
|
|
||||||
public final InvariantDeviceProfile inv;
|
public final InvariantDeviceProfile inv;
|
||||||
private final Info mInfo;
|
private final Info mInfo;
|
||||||
@@ -156,6 +159,7 @@ public class DeviceProfile {
|
|||||||
// Start is the side next to the nav bar, end is the side next to the workspace
|
// Start is the side next to the nav bar, end is the side next to the workspace
|
||||||
public final int hotseatBarSidePaddingStartPx;
|
public final int hotseatBarSidePaddingStartPx;
|
||||||
public final int hotseatBarSidePaddingEndPx;
|
public final int hotseatBarSidePaddingEndPx;
|
||||||
|
public final int hotseatQsbHeight;
|
||||||
|
|
||||||
// All apps
|
// All apps
|
||||||
public int allAppsOpenVerticalTranslate;
|
public int allAppsOpenVerticalTranslate;
|
||||||
@@ -240,6 +244,7 @@ public class DeviceProfile {
|
|||||||
mMetrics = context.getResources().getDisplayMetrics();
|
mMetrics = context.getResources().getDisplayMetrics();
|
||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
|
|
||||||
|
hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
|
||||||
isTaskbarPresent = isTablet && FeatureFlags.ENABLE_TASKBAR.get();
|
isTaskbarPresent = isTablet && FeatureFlags.ENABLE_TASKBAR.get();
|
||||||
if (isTaskbarPresent) {
|
if (isTaskbarPresent) {
|
||||||
// Taskbar will be added later, but provides bottom insets that we should subtract
|
// Taskbar will be added later, but provides bottom insets that we should subtract
|
||||||
@@ -740,7 +745,10 @@ public class DeviceProfile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getHotseatLayoutPadding() {
|
/**
|
||||||
|
* Returns the padding for hotseat view
|
||||||
|
*/
|
||||||
|
public Rect getHotseatLayoutPadding(Context context) {
|
||||||
if (isVerticalBarLayout()) {
|
if (isVerticalBarLayout()) {
|
||||||
if (isSeascape()) {
|
if (isSeascape()) {
|
||||||
mHotseatPadding.set(mInsets.left + hotseatBarSidePaddingStartPx,
|
mHotseatPadding.set(mInsets.left + hotseatBarSidePaddingStartPx,
|
||||||
@@ -749,6 +757,30 @@ public class DeviceProfile {
|
|||||||
mHotseatPadding.set(hotseatBarSidePaddingEndPx, mInsets.top,
|
mHotseatPadding.set(hotseatBarSidePaddingEndPx, mInsets.top,
|
||||||
mInsets.right + hotseatBarSidePaddingStartPx, mInsets.bottom);
|
mInsets.right + hotseatBarSidePaddingStartPx, mInsets.bottom);
|
||||||
}
|
}
|
||||||
|
} else if (isTaskbarPresent) {
|
||||||
|
int hotseatHeight = workspacePadding.bottom + taskbarSize;
|
||||||
|
int taskbarOffset = getTaskbarOffsetY();
|
||||||
|
int hotseatTopDiff = hotseatHeight - taskbarSize - taskbarOffset;
|
||||||
|
|
||||||
|
int startOffset = ApiWrapper.getHotseatStartOffset(context);
|
||||||
|
int requiredWidth = iconSizePx * numShownHotseatIcons;
|
||||||
|
|
||||||
|
Resources res = context.getResources();
|
||||||
|
float taskbarIconSize = res.getDimension(R.dimen.taskbar_icon_size);
|
||||||
|
float taskbarIconSpacing = 2 * res.getDimension(R.dimen.taskbar_icon_spacing);
|
||||||
|
int maxSize = (int) (requiredWidth
|
||||||
|
* (taskbarIconSize + taskbarIconSpacing) / taskbarIconSize);
|
||||||
|
int hotseatSize = Math.min(maxSize, availableWidthPx - startOffset);
|
||||||
|
int sideSpacing = (availableWidthPx - hotseatSize) / 2;
|
||||||
|
mHotseatPadding.set(sideSpacing, hotseatTopDiff, sideSpacing, taskbarOffset);
|
||||||
|
|
||||||
|
if (startOffset > sideSpacing) {
|
||||||
|
int diff = Utilities.isRtl(context.getResources())
|
||||||
|
? sideSpacing - startOffset
|
||||||
|
: startOffset - sideSpacing;
|
||||||
|
mHotseatPadding.left += diff;
|
||||||
|
mHotseatPadding.right -= diff;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// We want the edges of the hotseat to line up with the edges of the workspace, but the
|
// We want the edges of the hotseat to line up with the edges of the workspace, but the
|
||||||
// icons in the hotseat are a different size, and so don't line up perfectly. To account
|
// icons in the hotseat are a different size, and so don't line up perfectly. To account
|
||||||
@@ -768,6 +800,24 @@ public class DeviceProfile {
|
|||||||
return mHotseatPadding;
|
return mHotseatPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of pixels the QSB is translated from the bottom of the screen.
|
||||||
|
*/
|
||||||
|
public int getQsbOffsetY() {
|
||||||
|
int freeSpace = isTaskbarPresent
|
||||||
|
? workspacePadding.bottom
|
||||||
|
: hotseatBarSizePx - hotseatCellHeightPx - hotseatQsbHeight;
|
||||||
|
return (int) (freeSpace * QSB_CENTER_FACTOR)
|
||||||
|
+ (isTaskbarPresent ? taskbarSize : getInsets().bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of pixels the taskbar is translated from the bottom of the screen.
|
||||||
|
*/
|
||||||
|
public int getTaskbarOffsetY() {
|
||||||
|
return (getQsbOffsetY() - taskbarSize) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the bounds for which the open folders should be contained within
|
* @return the bounds for which the open folders should be contained within
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ public class Hotseat extends CellLayout implements Insettable {
|
|||||||
private final View mQsb;
|
private final View mQsb;
|
||||||
private final int mQsbHeight;
|
private final int mQsbHeight;
|
||||||
|
|
||||||
private final int mTaskbarViewHeight;
|
|
||||||
|
|
||||||
public Hotseat(Context context) {
|
public Hotseat(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -63,10 +61,9 @@ public class Hotseat extends CellLayout implements Insettable {
|
|||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
|
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
|
||||||
mQsbHeight = mQsb.getLayoutParams().height;
|
|
||||||
addView(mQsb);
|
addView(mQsb);
|
||||||
|
|
||||||
mTaskbarViewHeight = context.getResources().getDimensionPixelSize(R.dimen.taskbar_size);
|
mQsbHeight = getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,18 +111,13 @@ public class Hotseat extends CellLayout implements Insettable {
|
|||||||
lp.gravity = Gravity.BOTTOM;
|
lp.gravity = Gravity.BOTTOM;
|
||||||
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
lp.height = (grid.isTaskbarPresent
|
lp.height = (grid.isTaskbarPresent
|
||||||
? grid.workspacePadding.bottom
|
? grid.workspacePadding.bottom
|
||||||
: grid.hotseatBarSizePx)
|
: grid.hotseatBarSizePx)
|
||||||
+ (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom);
|
+ (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!grid.isTaskbarPresent) {
|
Rect padding = grid.getHotseatLayoutPadding(getContext());
|
||||||
// When taskbar is present, we set the padding separately to ensure a seamless visual
|
setPadding(padding.left, padding.top, padding.right, padding.bottom);
|
||||||
// handoff between taskbar and hotseat during drag and drop.
|
|
||||||
Rect padding = grid.getHotseatLayoutPadding();
|
|
||||||
setPadding(padding.left, padding.top, padding.right, padding.bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
setLayoutParams(lp);
|
setLayoutParams(lp);
|
||||||
InsettableFrameLayout.dispatchInsets(this, insets);
|
InsettableFrameLayout.dispatchInsets(this, insets);
|
||||||
}
|
}
|
||||||
@@ -193,30 +185,11 @@ public class Hotseat extends CellLayout implements Insettable {
|
|||||||
int left = (r - l - qsbWidth) / 2;
|
int left = (r - l - qsbWidth) / 2;
|
||||||
int right = left + qsbWidth;
|
int right = left + qsbWidth;
|
||||||
|
|
||||||
int bottom = b - t - getQsbOffsetY();
|
int bottom = b - t - mActivity.getDeviceProfile().getQsbOffsetY();
|
||||||
int top = bottom - mQsbHeight;
|
int top = bottom - mQsbHeight;
|
||||||
mQsb.layout(left, top, right, bottom);
|
mQsb.layout(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of pixels the QSB is translated from the bottom of the screen.
|
|
||||||
*/
|
|
||||||
private int getQsbOffsetY() {
|
|
||||||
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
||||||
int freeSpace = dp.isTaskbarPresent
|
|
||||||
? dp.workspacePadding.bottom
|
|
||||||
: dp.hotseatBarSizePx - dp.hotseatCellHeightPx - mQsbHeight;
|
|
||||||
return (int) (freeSpace * QSB_CENTER_FACTOR)
|
|
||||||
+ (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of pixels the taskbar is translated from the bottom of the screen.
|
|
||||||
*/
|
|
||||||
public int getTaskbarOffsetY() {
|
|
||||||
return (getQsbOffsetY() - mTaskbarViewHeight) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the alpha value of just our ShortcutAndWidgetContainer.
|
* Sets the alpha value of just our ShortcutAndWidgetContainer.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2811,13 +2811,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
|||||||
return new float[] {NO_SCALE, NO_OFFSET};
|
return new float[] {NO_SCALE, NO_OFFSET};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see LauncherState#getTaskbarScale(Launcher)
|
|
||||||
*/
|
|
||||||
public float getNormalTaskbarScale() {
|
|
||||||
return 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Launcher getLauncher(Context context) {
|
public static Launcher getLauncher(Context context) {
|
||||||
return fromContext(context);
|
return fromContext(context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,14 +181,6 @@ public abstract class LauncherState implements BaseState<LauncherState> {
|
|||||||
return launcher.getNormalOverviewScaleAndOffset();
|
return launcher.getNormalOverviewScaleAndOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getTaskbarScale(Launcher launcher) {
|
|
||||||
return launcher.getNormalTaskbarScale();
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getTaskbarTranslationY(Launcher launcher) {
|
|
||||||
return -launcher.getHotseat().getTaskbarOffsetY();
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getOverviewFullscreenProgress() {
|
public float getOverviewFullscreenProgress() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.launcher3.uioverrides;
|
package com.android.launcher3.uioverrides;
|
||||||
|
|
||||||
import android.app.Person;
|
import android.app.Person;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
|
||||||
@@ -36,4 +37,11 @@ public class ApiWrapper {
|
|||||||
public static boolean isInternalDisplay(Display display) {
|
public static boolean isInternalDisplay(Display display) {
|
||||||
return display.getDisplayId() == Display.DEFAULT_DISPLAY;
|
return display.getDisplayId() == Display.DEFAULT_DISPLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum space that should be left empty at the start of hotseat
|
||||||
|
*/
|
||||||
|
public static int getHotseatStartOffset(Context context) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user