Snap for 7339742 from 7ef5456182 to sc-v2-release

Change-Id: Ibb4e00821b01b0cb46d14b2bb2828115aa4f4154
This commit is contained in:
android-build-team Robot
2021-05-06 01:09:33 +00:00
45 changed files with 1147 additions and 215 deletions
+28 -4
View File
@@ -103,16 +103,40 @@
android:clearTaskOnLaunch="true"
android:exported="false"/>
<!--
Activity for gesture nav onboarding.
It's protected by android.permission.REBOOT to ensure that only system apps can start it
(setup wizard already has this permission)
-->
<activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:exported="true">
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:permission="android.permission.REBOOT"
android:exported="true">
<intent-filter>
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<!--
Activity following gesture nav onboarding.
It's protected by android.permission.REBOOT to ensure that only system apps can start it
(setup wizard already has this permission)
-->
<activity android:name="com.android.quickstep.interaction.AllSetActivity"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:permission="android.permission.REBOOT"
android:exported="true">
<intent-filter>
<action android:name="com.android.quickstep.action.GESTURE_ONBOARDING_ALL_SET"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".hybridhotseat.HotseatEduActivity"
android:theme="@android:style/Theme.NoDisplay"
+24
View File
@@ -0,0 +1,24 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="42dp"
android:height="40dp"
android:viewportWidth="42"
android:viewportHeight="40">
<path
android:pathData="M38,14H25.38L27.28,4.86L27.34,4.22C27.34,3.4 27,2.64 26.46,2.1L24.34,0C24.34,0 10.16,13.7 10,14H0V40H32C33.66,40 35.08,39 35.68,37.56L41.72,23.46C41.9,23 42,22.52 42,22V18C42,15.8 40.2,14 38,14ZM10,36H4V18H10V36ZM38,22L32,36H14V16L22.68,7.32L20,18H38V22Z"
android:fillColor="#FFFFFF"/>
</vector>
+80
View File
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/allset_page_margin_horizontal"
android:paddingEnd="@dimen/allset_page_margin_horizontal"
android:layoutDirection="locale"
android:textDirection="locale"
android:background="?android:attr/colorBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_gravity="start"
android:gravity="start"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/allset_title_icon_margin_top"
android:src="@drawable/ic_all_set"/>
<TextView
android:id="@+id/title"
style="@style/TextAppearance.GestureTutorial.Feedback.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/allset_title_margin_top"
android:gravity="start"
android:text="@string/allset_title"/>
<TextView
android:id="@+id/subtitle"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/allset_subtitle_margin_top"
android:gravity="start"
android:text="@string/allset_description"/>
</LinearLayout>
<TextView
android:id="@+id/navigation_settings"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/hint"
android:gravity="center_horizontal"
android:layout_marginBottom="72dp"/>
<TextView
android:id="@id/hint"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/allset_hint_margin_bottom"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/allset_hint"/>
</RelativeLayout>
+7 -6
View File
@@ -15,12 +15,6 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.quickstep.views.SplitPlaceholderView
android:id="@+id/split_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/split_placeholder_size"
android:background="@android:color/darker_gray"
android:visibility="gone" />
<com.android.quickstep.views.LauncherRecentsView
android:id="@+id/overview_panel"
@@ -31,6 +25,13 @@
android:clipToPadding="false"
android:visibility="invisible" />
<com.android.quickstep.views.SplitPlaceholderView
android:id="@+id/split_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/split_placeholder_size"
android:background="@android:color/darker_gray"
android:visibility="gone" />
<include
android:id="@+id/overview_actions_view"
layout="@layout/overview_actions_container" />
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<declare-styleable name="AllSetLinkSpan">
<attr name="android:textSize"/>
<attr name="android:fontFamily"/>
</declare-styleable>
</resources>
+7
View File
@@ -99,6 +99,13 @@
<dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
<dimen name="gesture_tutorial_button_margin_start_end">18dp</dimen>
<!-- All Set page -->
<dimen name="allset_page_margin_horizontal">40dp</dimen>
<dimen name="allset_title_margin_top">28dp</dimen>
<dimen name="allset_title_icon_margin_top">80dp</dimen>
<dimen name="allset_hint_margin_bottom">52dp</dimen>
<dimen name="allset_subtitle_margin_top">24dp</dimen>
<!-- All Apps Education tutorial -->
<dimen name="swipe_edu_padding">8dp</dimen>
<dimen name="swipe_edu_circle_size">64dp</dimen>
+9
View File
@@ -177,6 +177,15 @@
<!-- Feedback subtext displaying the current step and the total number of steps for the tutorial. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_step">Tutorial <xliff:g id="current">%1$d</xliff:g>/<xliff:g id="total">%2$d</xliff:g></string>
<!-- Title of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_title">All set!</string>
<!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_hint">Swipe up to go home</string>
<!-- Description of "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_description">You\u2019re ready to start using your phone</string>
<!-- String linking to navigation settings on "All Set" page [CHAR LIMIT=NONE] -->
<string name="allset_navigation_settings"><annotation id="link">Navigation settings for accessibility</annotation></string>
<!-- ******* Overview ******* -->
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
<string name="action_share">Share</string>
+6 -1
View File
@@ -59,7 +59,7 @@
parent="TextAppearance.GestureTutorial">
<item name="android:gravity">start</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">google-sans</item>
<item name="android:fontFamily">google-sans-text</item>
<item name="android:letterSpacing">0.03</item>
<item name="android:textSize">18sp</item>
<item name="android:lineHeight">24sp</item>
@@ -99,6 +99,11 @@
<item name="android:textColor">@color/gesture_tutorial_primary_color</item>
</style>
<style name="TextAppearance.GestureTutorial.LinkText"
parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
<item name="android:textSize">14sp</item>
</style>
<!--
Can be applied to views to color things like ripples and list highlights the workspace text
color.
@@ -22,12 +22,12 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
@@ -97,10 +97,10 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
PagedOrientationHandler orientationHandler =
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
TASK_PRIMARY_TRANSLATION, TASK_SECONDARY_TRANSLATION, mLauncher.getDeviceProfile());
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mLauncher.getDeviceProfile());
setter.setFloat(mRecentsView, taskViewsFloat,
toState.getOverviewSecondaryTranslation(mLauncher),
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
toState.getOverviewSecondaryTranslation(mLauncher), LINEAR);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -36,11 +36,13 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_F
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -207,7 +209,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
/** Create state animation to control non-overview components. */
private void updateNonOverviewAnim(LauncherState toState, StateAnimationConfig config) {
config.duration = (long) (Math.max(mXRange, mYRange) * 2);
config.animFlags |= SKIP_OVERVIEW;
config.animFlags |= SKIP_OVERVIEW | SKIP_SCRIM;
mNonOverviewAnim = mLauncher.getStateManager()
.createAnimationToNewWorkspace(toState, config);
mNonOverviewAnim.getTarget().addListener(mClearStateOnCancelListener);
@@ -229,10 +231,14 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
// As we drag right, animate the following properties:
// - RecentsView translationX
// - OverviewScrim
// - RecentsView fade (if it's empty)
PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR);
xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
toState.getWorkspaceScrimColor(mLauncher), LINEAR);
if (mRecentsView.getTaskViewCount() == 0) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
}
mXOverviewAnim = xAnim.createPlaybackController();
mXOverviewAnim.dispatchOnStart();
@@ -47,7 +47,6 @@ import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -55,7 +54,6 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACT
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -464,8 +462,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mDeviceState.getRotationTouchHelper()
.onEndTargetCalculated(mGestureState.getEndTarget(),
mActivityInterface);
mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget());
});
notifyGestureStartedAsync();
@@ -1133,6 +1129,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
mLauncherTransitionController = null;
if (mRecentsView != null) {
mRecentsView.onPrepareGestureEndAnimation(null, mGestureState.getEndTarget());
}
} else {
AnimatorSet animatorSet = new AnimatorSet();
ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
@@ -1171,9 +1171,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
});
animatorSet.play(windowAnim);
S state = mActivityInterface.stateFromGestureEndTarget(mGestureState.getEndTarget());
if (mRecentsView != null && state.displayOverviewTasksAsGrid(mDp)) {
animatorSet.play(ObjectAnimator.ofFloat(mRecentsView, RECENTS_GRID_PROGRESS, 1));
if (mRecentsView != null) {
mRecentsView.onPrepareGestureEndAnimation(
animatorSet, mGestureState.getEndTarget());
}
animatorSet.setDuration(duration).setInterpolator(interpolator);
animatorSet.start();
@@ -1701,7 +1701,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
// No need to apply any transform if there is ongoing swipe-pip-to-home animator since
// that animator handles the leash solely.
if (mRecentsAnimationTargets != null && !mIsSwipingPipToHome) {
if (mRecentsViewScrollLinked) {
if (mRecentsViewScrollLinked && mRecentsView != null) {
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
}
mTaskViewSimulator.apply(mTransformParams);
@@ -163,7 +163,9 @@ public final class FallbackActivityInterface extends
@Override
public boolean isInLiveTileMode() {
return false;
RecentsActivity activity = getCreatedActivity();
return activity != null && activity.getStateManager().getState() == DEFAULT &&
activity.isStarted();
}
@Override
@@ -260,6 +260,7 @@ public class LauncherSwipeHandlerV2 extends
@Override
public void setAnimation(RectFSpringAnim anim) {
anim.addAnimatorListener(floatingWidgetView);
floatingWidgetView.setOnTargetChangeListener(anim::onTargetPositionChanged);
floatingWidgetView.setFastFinishRunnable(anim::end);
}
@@ -22,10 +22,13 @@ import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DU
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
import static com.android.launcher3.Utilities.createHomeIntent;
import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -35,6 +38,7 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import androidx.annotation.Nullable;
@@ -47,6 +51,7 @@ import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.R;
import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -69,6 +74,7 @@ import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.SplitPlaceholderView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -90,6 +96,8 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private static final long HOME_APPEAR_DURATION = 250;
private RecentsDragLayer mDragLayer;
private ScrimView mScrimView;
private FallbackRecentsView mFallbackRecentsView;
@@ -112,6 +120,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
mScrimView = findViewById(R.id.scrim_view);
mFallbackRecentsView = findViewById(R.id.overview_panel);
mActionsView = findViewById(R.id.overview_actions_view);
SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
splitPlaceholderView.init(
@@ -291,6 +300,16 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
super.onConfigurationChanged(newConfig);
}
@Override
public void onStateSetEnd(RecentsState state) {
super.onStateSetEnd(state);
if (state == RecentsState.DEFAULT) {
AccessibilityManagerCompat.sendStateEventToTest(getBaseContext(),
OVERVIEW_STATE_ORDINAL);
}
}
/**
* Initialize/update the device profile.
*/
@@ -329,7 +348,42 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
}
public void startHome() {
startActivity(createHomeIntent());
if (LIVE_TILE.get()) {
RecentsView recentsView = getOverviewPanel();
recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
this::startHomeInternal));
} else {
startHomeInternal();
}
}
private void startHomeInternal() {
WrappedLauncherAnimationRunner runner = new WrappedLauncherAnimationRunner(
getMainThreadHandler(), this::onCreateAnimationToHome, true);
RemoteAnimationAdapterCompat adapterCompat =
new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
startActivity(createHomeIntent(),
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
}
private void onCreateAnimationToHome(
int transit, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
AnimatorPlaybackController controller = getStateManager()
.createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
controller.dispatchOnStart();
RemoteAnimationTargets targets = new RemoteAnimationTargets(
appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
for (RemoteAnimationTargetCompat app : targets.apps) {
new Transaction().setAlpha(app.leash.getSurfaceControl(), 1).apply();
}
AnimatorSet anim = new AnimatorSet();
anim.play(controller.getAnimationPlayer());
anim.setDuration(HOME_APPEAR_DURATION);
result.setAnimation(anim, this,
() -> getStateManager().goToState(RecentsState.HOME, false));
}
@Override
@@ -20,6 +20,7 @@ import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
@@ -27,6 +28,9 @@ import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.testing.TestProtocol;
@@ -67,7 +71,6 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
@Override
public void startHome() {
mActivity.startHome();
mActivity.getStateManager().goToState(RecentsState.HOME);
}
/**
@@ -86,14 +89,17 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
* to the center.
*/
@Override
public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
super.onGestureEndTargetCalculated(endTarget);
if (mHomeTaskInfo != null && endTarget == RECENTS) {
public void onPrepareGestureEndAnimation(
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget) {
super.onPrepareGestureEndAnimation(animatorSet, endTarget);
if (mHomeTaskInfo != null && endTarget == RECENTS && animatorSet != null) {
TaskView tv = getTaskView(mHomeTaskInfo.taskId);
if (tv != null) {
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
pa.addEndListener(e -> setCurrentTask(-1));
runDismissAnimation(pa);
AnimatorPlaybackController controller = pa.createPlaybackController();
controller.dispatchOnStart();
animatorSet.play(controller.getAnimationPlayer());
}
}
}
@@ -39,15 +39,18 @@ public class RecentsState implements BaseState<RecentsState> {
private static final int FLAG_OVERVIEW_ACTIONS = BaseState.getFlag(3);
private static final int FLAG_SHOW_AS_GRID = BaseState.getFlag(4);
private static final int FLAG_SCRIM = BaseState.getFlag(5);
private static final int FLAG_LIVE_TILE = BaseState.getFlag(6);
public static final RecentsState DEFAULT = new RecentsState(0,
FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM);
FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM
| FLAG_LIVE_TILE);
public static final RecentsState MODAL_TASK = new ModalState(1,
FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_MODAL
| FLAG_SHOW_AS_GRID | FLAG_SCRIM);
| FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_LIVE_TILE);
public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
public static final RecentsState HOME = new RecentsState(3, 0);
public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0);
public final int ordinal;
private final int mFlags;
@@ -107,6 +110,13 @@ public class RecentsState implements BaseState<RecentsState> {
return hasFlag(FLAG_OVERVIEW_ACTIONS);
}
/**
* For this state, whether live tile should be shown.
*/
public boolean hasLiveTile() {
return hasFlag(FLAG_LIVE_TILE);
}
/**
* For this state, what color scrim should be drawn behind overview.
*/
@@ -152,4 +162,15 @@ public class RecentsState implements BaseState<RecentsState> {
return getOverviewScaleAndOffsetForBackgroundState(activity);
}
}
private static class LauncherState extends RecentsState {
LauncherState(int id, int flags) {
super(id, flags);
}
@Override
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return new float[] { NO_SCALE, 1 };
}
}
}
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.fallback;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.quickstep.RecentsActivity;
@@ -26,7 +28,8 @@ public class RecentsTaskController extends TaskViewTouchController<RecentsActivi
@Override
protected boolean isRecentsInteractive() {
return mActivity.hasWindowFocus();
return mActivity.hasWindowFocus() || (LIVE_TILE.get()
&& mActivity.getStateManager().getState().hasLiveTile());
}
@Override
@@ -0,0 +1,133 @@
/*
* 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.quickstep.interaction;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
import java.net.URISyntaxException;
/**
* A page shows after SUW flow to hint users to swipe up from the bottom of the screen to go home
* for the gestural system navigation.
*/
public class AllSetActivity extends Activity {
private static final String LOG_TAG = "AllSetActivity";
private static final String URI_SYSTEM_NAVIGATION_SETTING =
"#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S.:settings:fragment_args_key=gesture_system_navigation_input_summary;S.:settings:show_fragment=com.android.settings.gestures.SystemNavigationGestureSettings;end";
private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "accent_color_dark_mode";
private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "accent_color_light_mode";
private int mAccentColor;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_allset);
setTitle(R.string.allset_title);
final int mode =
getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
mAccentColor = getIntent().getIntExtra(
mode == Configuration.UI_MODE_NIGHT_YES
? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE,
/* defValue= */ Color.BLACK);
((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(mAccentColor);
TextView navigationSettings = findViewById(R.id.navigation_settings);
navigationSettings.setMovementMethod(LinkMovementMethod.getInstance());
AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION,
new AllSetLinkSpan(
/* context= */ this,
view -> {
try {
startActivityForResult(
Intent.parseUri(URI_SYSTEM_NAVIGATION_SETTING, 0), 0);
} catch (URISyntaxException e) {
Log.e(LOG_TAG, "Failed to parse system nav settings intent", e);
}
finish();
}));
navigationSettings.setText(
AnnotationSpan.linkify(getText(R.string.allset_navigation_settings), linkInfo));
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
hideSystemUI();
}
}
private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
}
private final class AllSetLinkSpan extends AnnotationSpan {
private final String mFontFamily;
private final int mTextSize;
AllSetLinkSpan(Context context, View.OnClickListener listener) {
super(listener);
TypedArray typedArray =
context.obtainStyledAttributes(R.style.TextAppearance_GestureTutorial_LinkText,
R.styleable.AllSetLinkSpan);
mFontFamily = typedArray.getString(R.styleable.AllSetLinkSpan_android_fontFamily);
mTextSize =
typedArray.getDimensionPixelSize(
R.styleable.AllSetLinkSpan_android_textSize, /* defValue= */ -1);
typedArray.recycle();
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(mAccentColor);
ds.setTypeface(Typeface.create(mFontFamily, Typeface.NORMAL));
ds.setUnderlineText(false);
if (mTextSize != -1) {
ds.setTextSize(mTextSize);
}
}
}
}
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2018 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.quickstep.interaction;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.text.Annotation;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.URLSpan;
import android.util.Log;
import android.view.View;
import java.util.Arrays;
import java.util.Comparator;
/**
* This class is used to add {@link View.OnClickListener} for the text been wrapped by
* annotation.
*
* Copied from packages/apps/Settings/src/com/android/settings/utils/AnnotationSpan.java.
*/
public class AnnotationSpan extends URLSpan {
private final View.OnClickListener mClickListener;
AnnotationSpan(View.OnClickListener lsn) {
super((String) null);
mClickListener = lsn;
}
@Override
public void onClick(View widget) {
if (mClickListener != null) {
mClickListener.onClick(widget);
}
}
public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) {
SpannableString msg = new SpannableString(rawText);
Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
SpannableStringBuilder builder = new SpannableStringBuilder(msg);
for (Annotation annotation : spans) {
final String key = annotation.getValue();
int start = msg.getSpanStart(annotation);
int end = msg.getSpanEnd(annotation);
AnnotationSpan link = null;
for (LinkInfo linkInfo : linkInfos) {
if (linkInfo.mAnnotation.equals(key)) {
link = linkInfo.mCustomizedSpan != null ? linkInfo.mCustomizedSpan
: new AnnotationSpan(linkInfo.mClickListener);
break;
}
}
if (link != null) {
builder.setSpan(link, start, end, msg.getSpanFlags(link));
}
}
return builder;
}
/**
* get the text part without having text for link part
*/
public static CharSequence textWithoutLink(CharSequence encodedText) {
SpannableString msg = new SpannableString(encodedText);
Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
if (spans == null) {
return encodedText;
}
Arrays.sort(spans, Comparator.comparingInt(span -> -msg.getSpanStart(span)));
StringBuilder msgWithoutLink = new StringBuilder(msg.toString());
for (Annotation span : spans) {
msgWithoutLink.delete(msg.getSpanStart(span), msg.getSpanEnd(span));
}
return msgWithoutLink.toString();
}
/** Data class to store the annotation and the click action. */
public static class LinkInfo {
public static final String DEFAULT_ANNOTATION = "link";
private static final String TAG = "AnnotationSpan.LinkInfo";
private final String mAnnotation;
private final Boolean mActionable;
private final View.OnClickListener mClickListener;
private final AnnotationSpan mCustomizedSpan;
public LinkInfo(String annotation, View.OnClickListener listener) {
mAnnotation = annotation;
mClickListener = listener;
mActionable = true; // assume actionable
mCustomizedSpan = null;
}
public LinkInfo(String annotation, AnnotationSpan customizedSpan) {
mAnnotation = annotation;
mClickListener = null;
mActionable = customizedSpan != null;
mCustomizedSpan = customizedSpan;
}
public LinkInfo(Context context, String annotation, Intent intent) {
mAnnotation = annotation;
mCustomizedSpan = null;
if (intent != null) {
mActionable = context.getPackageManager().resolveActivity(intent, 0) != null;
} else {
mActionable = false;
}
if (mActionable) {
mClickListener =
view -> {
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(TAG, "Activity was not found for intent, " + intent);
}
};
} else {
mClickListener = null;
}
}
public boolean isActionable() {
return mActionable;
}
}
}
@@ -20,8 +20,6 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI
import android.content.Context;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.SysUINavigationMode;
import java.util.function.Predicate;
@@ -37,7 +35,6 @@ public class NavigationModeFeatureFlag implements
private final Supplier<Boolean> mBasePredicate;
private final Predicate<SysUINavigationMode.Mode> mModePredicate;
private boolean mSupported;
private OverviewComponentObserver mObserver;
private NavigationModeFeatureFlag(Supplier<Boolean> basePredicate,
Predicate<SysUINavigationMode.Mode> modePredicate) {
@@ -46,17 +43,12 @@ public class NavigationModeFeatureFlag implements
}
public boolean get() {
return mBasePredicate.get() && mSupported && mObserver != null
&& mObserver.isHomeAndOverviewSame();
return mBasePredicate.get() && mSupported;
}
public void initialize(Context context) {
onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context).getMode());
SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
// Temporary solution to disable live tile for the fallback launcher
RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(context);
mObserver = new OverviewComponentObserver(context, rads);
}
@Override
@@ -25,6 +25,7 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -64,6 +65,7 @@ public class SplitSelectStateController {
private final SystemUiProxy mSystemUiProxy;
private TaskView mInitialTaskView;
private SplitPositionOption mInitialPosition;
private Rect mInitialBounds;
private final Handler mHandler;
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
@@ -74,9 +76,11 @@ public class SplitSelectStateController {
/**
* To be called after first task selected
*/
public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption) {
public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption,
Rect initialBounds) {
mInitialTaskView = taskView;
mInitialPosition = positionOption;
mInitialBounds = initialBounds;
}
/**
@@ -220,9 +224,14 @@ public class SplitSelectStateController {
public void resetState() {
mInitialTaskView = null;
mInitialPosition = null;
mInitialBounds = null;
}
public boolean isSplitSelectActive() {
return mInitialTaskView != null;
}
public Rect getInitialBounds() {
return mInitialBounds;
}
}
@@ -36,6 +36,7 @@ import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
@@ -95,7 +96,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
mContext = context;
mSizeStrategy = sizeStrategy;
mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
// TODO(b/187074722): Don't create this per-TaskViewSimulator
mOrientationState = TraceHelper.allowIpcs("",
() -> new RecentsOrientedState(context, sizeStrategy, i -> { }));
mOrientationState.setGestureActive(true);
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mOrientationStateId = mOrientationState.getStateId();
@@ -100,8 +100,8 @@ final class FloatingWidgetBackgroundView extends View {
/** Restores the drawables to the source view. */
void finish() {
if (isUninitialized()) return;
mSourceView.setForeground(mOriginalForeground);
mSourceView.setBackground(mOriginalBackground);
if (mOriginalForeground != null) mSourceView.setForeground(mOriginalForeground);
if (mOriginalBackground != null) mSourceView.setBackground(mOriginalBackground);
}
void recycle() {
@@ -27,6 +27,7 @@ import android.util.Size;
import android.view.GhostView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import com.android.launcher3.Launcher;
@@ -39,7 +40,8 @@ import com.android.launcher3.widget.RoundedCornerEnforcement;
/** A view that mimics an App Widget through a launch animation. */
@TargetApi(Build.VERSION_CODES.S)
public class FloatingWidgetView extends FrameLayout implements AnimatorListener {
public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
OnGlobalLayoutListener {
private static final Matrix sTmpMatrix = new Matrix();
private final Launcher mLauncher;
@@ -54,6 +56,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener
private Runnable mEndRunnable;
private Runnable mFastFinishRunnable;
private Runnable mOnTargetChangeRunnable;
public FloatingWidgetView(Context context) {
this(context, null);
@@ -93,6 +96,32 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener
public void onAnimationRepeat(Animator animator) {
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
super.onDetachedFromWindow();
}
@Override
public void onGlobalLayout() {
if (isUninitialized()) return;
positionViews();
if (mOnTargetChangeRunnable != null) {
mOnTargetChangeRunnable.run();
}
}
/** Sets a runnable that is called on global layout change. */
public void setOnTargetChangeListener(Runnable onTargetChangeListener) {
mOnTargetChangeRunnable = onTargetChangeListener;
}
/** Sets a runnable that is called after a call to {@link #fastFinish()}. */
public void setFastFinishRunnable(Runnable runnable) {
mFastFinishRunnable = runnable;
@@ -205,6 +234,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener
private void recycle() {
mEndRunnable = null;
mFastFinishRunnable = null;
mOnTargetChangeRunnable = null;
mBackgroundPosition = null;
mListenerView.setListener(null);
mAppWidgetView = null;
@@ -245,8 +245,8 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher, Laun
if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
// We want to keep the tasks translations in this temporary state
// after resetting the rest above
setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
setTaskViewsPrimarySplitTranslation(mTaskViewsPrimarySplitTranslation);
setTaskViewsSecondarySplitTranslation(mTaskViewsSecondarySplitTranslation);
}
}
@@ -254,16 +254,29 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
* more specific, we'd want to create a similar FloatProperty just for a TaskView's
* offsetX/Y property
*/
public static final FloatProperty<RecentsView> TASK_PRIMARY_TRANSLATION =
new FloatProperty<RecentsView>("taskPrimaryTranslation") {
public static final FloatProperty<RecentsView> TASK_PRIMARY_SPLIT_TRANSLATION =
new FloatProperty<RecentsView>("taskPrimarySplitTranslation") {
@Override
public void setValue(RecentsView recentsView, float v) {
recentsView.setTaskViewsPrimaryTranslation(v);
recentsView.setTaskViewsPrimarySplitTranslation(v);
}
@Override
public Float get(RecentsView recentsView) {
return recentsView.mTaskViewsPrimaryTranslation;
return recentsView.mTaskViewsPrimarySplitTranslation;
}
};
public static final FloatProperty<RecentsView> TASK_SECONDARY_SPLIT_TRANSLATION =
new FloatProperty<RecentsView>("taskSecondarySplitTranslation") {
@Override
public void setValue(RecentsView recentsView, float v) {
recentsView.setTaskViewsSecondarySplitTranslation(v);
}
@Override
public Float get(RecentsView recentsView) {
return recentsView.mTaskViewsSecondarySplitTranslation;
}
};
@@ -279,7 +292,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
view.mLiveTileTaskViewSimulator.recentsViewScale.value = scale;
view.updatePageOffsets();
view.setTaskViewsResistanceTranslation(view.mTaskViewsSecondaryTranslation);
view.setTaskViewsPrimaryTranslation(view.mTaskViewsPrimaryTranslation);
}
@Override
@@ -363,7 +375,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private float mAdjacentPageOffset = 0;
protected float mTaskViewsSecondaryTranslation = 0;
protected float mTaskViewsPrimaryTranslation = 0;
protected float mTaskViewsPrimarySplitTranslation = 0;
protected float mTaskViewsSecondarySplitTranslation = 0;
// Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
private float mGridProgress = 0;
private final IntSet mTopRowIdSet = new IntSet();
@@ -1631,7 +1644,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
/**
* Called when a gesture from an app has finished, and an end target has been determined.
*/
public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
public void onPrepareGestureEndAnimation(
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget) {
if (mSizeStrategy.stateFromGestureEndTarget(endTarget)
.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
if (animatorSet == null) {
setGridProgress(1);
} else {
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
}
}
mCurrentGestureEndTarget = endTarget;
if (endTarget == GestureState.GestureEndTarget.NEW_TASK
|| endTarget == GestureState.GestureEndTarget.LAST_TASK) {
@@ -1839,15 +1861,28 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
mLastComputedGridTaskSize.height());
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
/*
* taskGridVerticalDiff is used to position the top of a task in the top row of the grid
* heightOffset is the vertical space one grid task takes + space between top and
* bottom row
* Summed together they provide the top position for bottom row of grid tasks
*/
final float taskGridVerticalDiff =
mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
final float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
int topRowWidth = 0;
int bottomRowWidth = 0;
float topAccumulatedTranslationX = 0;
float bottomAccumulatedTranslationX = 0;
// Contains whether the child index is in top or bottom of grid (for non-focused task)
// Different from mTopRowIdSet, which contains the taskId of what task is in top row
IntSet topSet = new IntSet();
IntSet bottomSet = new IntSet();
// Horizontal grid translation for each task
float[] gridTranslations = new float[taskCount];
int focusedTaskIndex = Integer.MAX_VALUE;
@@ -1901,7 +1936,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId)
: topRowWidth <= bottomRowWidth;
if (isTopRow) {
gridTranslations[i] += topAccumulatedTranslationX;
topRowWidth += taskWidthAndSpacing;
topSet.add(i);
mTopRowIdSet.add(taskId);
@@ -1917,11 +1951,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += gridTranslationX;
topAccumulatedTranslationX += gridTranslationX;
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
topAccumulatedTranslationX += currentTaskTranslationX;
} else {
gridTranslations[i] += bottomAccumulatedTranslationX;
bottomRowWidth += taskWidthAndSpacing;
bottomSet.add(i);
@@ -1937,9 +1970,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += gridTranslationX;
bottomAccumulatedTranslationX += gridTranslationX;
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
bottomAccumulatedTranslationX += currentTaskTranslationX;
}
if (taskView == snappedTaskView) {
snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
@@ -2130,18 +2163,43 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
// alpha is set to 0 so that it can be recycled in the view pool properly
anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
FloatProperty<TaskView> secondaryViewTranslate =
taskView.getSecondaryDissmissTranslationProperty();
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
ResourceProvider rp = DynamicResource.provider(mActivity);
SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
.setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio))
.setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness));
FloatProperty<TaskView> dismissingTaskViewTranslate =
taskView.getSecondaryDissmissTranslationProperty();;
// TODO(b/186800707) translate entire grid size distance
int translateDistance = mOrientationHandler.getSecondaryDimension(taskView);
int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
if (splitController.isSplitSelectActive()) {
// Have the task translate towards whatever side was just pinned
int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController
.getActiveSplitPositionOption(), mActivity.getDeviceProfile());
switch (dir) {
case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE:
dismissingTaskViewTranslate = taskView
.getSecondaryDissmissTranslationProperty();
positiveNegativeFactor = -1;
break;
anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE:
dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
positiveNegativeFactor = 1;
break;
case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE:
dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
positiveNegativeFactor = -1;
break;
default:
throw new IllegalStateException("Invalid split task translation: " + dir);
}
}
anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp);
if (LIVE_TILE.get() && taskView.isRunningTask()) {
anim.addOnFrameCallback(() -> {
@@ -2206,18 +2264,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
}
// Additional offset for fake landscape, if the pinning happens to the right or
// left, we need to scroll all the tasks away from the direction of the splaceholder
// view
if (isSplitSelectionActive()) {
int splitPosition = getSplitPlaceholder().getSplitController()
.getActiveSplitPositionOption().mStagePosition;
int direction = mOrientationHandler
.getSplitTranslationDirectionFactor(splitPosition);
int splitOffset = mOrientationHandler.getSplitAnimationTranslation(
mSplitPlaceholderView.getHeight(), mActivity.getDeviceProfile());
offset += direction * splitOffset;
}
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView
@@ -2249,7 +2295,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (LIVE_TILE.get() && taskView.isRunningTask() && success) {
if (LIVE_TILE.get() && mEnableDrawingLiveTile && taskView.isRunningTask()
&& success) {
finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
} else {
onEnd(success);
@@ -2347,7 +2394,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return true;
}
protected void runDismissAnimation(PendingAnimation pendingAnim) {
private void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
@@ -2759,13 +2806,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
}
protected void setTaskViewsPrimaryTranslation(float translation) {
mTaskViewsPrimaryTranslation = translation;
protected void setTaskViewsPrimarySplitTranslation(float translation) {
mTaskViewsPrimarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView task = getTaskViewAt(i);
task.getPrimaryDismissTranslationProperty().set(task, translation / getScaleY());
task.getPrimarySplitTranslationProperty().set(task, translation);
}
}
protected void setTaskViewsSecondarySplitTranslation(float translation) {
mTaskViewsSecondarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView task = getTaskViewAt(i);
task.getSecondarySplitTranslationProperty().set(task, translation);
}
mLiveTileTaskViewSimulator.recentsViewPrimaryTranslation.value = translation;
}
/**
@@ -2788,8 +2842,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
mSplitHiddenTaskView = taskView;
SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
splitController.setInitialTaskSelect(taskView,
splitPositionOption);
Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
taskView.getBottom());
splitController.setInitialTaskSelect(taskView, splitPositionOption, initialBounds);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
mSplitPlaceholderView.setLayoutParams(
splitController.getLayoutParamsForActivePosition(getResources(),
@@ -2809,7 +2864,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
public PendingAnimation cancelSplitSelect(boolean animate) {
mSplitPlaceholderView.getSplitController().resetState();
SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
SplitPositionOption splitOption = splitController.getActiveSplitPositionOption();
Rect initialBounds = splitController.getInitialBounds();
splitController.resetState();
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
PendingAnimation pendingAnim = new PendingAnimation(duration);
if (!animate) {
@@ -2824,8 +2882,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
getPageScrolls(oldScroll, false,
view -> view.getVisibility() != GONE && view != mSplitHiddenTaskView);
// x is correct, y is before tasks move up
int[] locationOnScreen = mSplitHiddenTaskView.getLocationOnScreen();
int[] newScroll = new int[getChildCount()];
getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC);
@@ -2833,20 +2889,42 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) {
View child = getChildAt(i);
if (child == mSplitHiddenTaskView) {
TaskView taskView = (TaskView) child;
int left = newScroll[i] + getPaddingStart();
int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1];
mSplitHiddenTaskView.layout(left, top,
left + mSplitHiddenTaskView.getWidth(),
top + mSplitHiddenTaskView.getHeight());
pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, TRANSLATION_Y,
-top + mSplitPlaceholderView.getHeight() - topMargin));
int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitOption,
mActivity.getDeviceProfile());
FloatProperty<TaskView> dismissingTaskViewTranslate;
Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(),
taskView.getRight(), taskView.getBottom());
int distanceDelta = 0;
if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) {
dismissingTaskViewTranslate = taskView
.getSecondaryDissmissTranslationProperty();
distanceDelta = initialBounds.top - hiddenBounds.top;
taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right,
hiddenBounds.bottom);
} else {
dismissingTaskViewTranslate = taskView
.getPrimaryDismissTranslationProperty();
distanceDelta = initialBounds.left - hiddenBounds.left;
taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right,
initialBounds.bottom);
if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) {
distanceDelta *= -1;
}
}
pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView,
dismissingTaskViewTranslate,
distanceDelta));
pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1));
} else {
// If insertion is on last index (furthest from clear all), we directly add the view
// else we translate all views to the right of insertion index further right,
// ignore views to left
if (showAsGrid()) {
// TODO(b/186800707) handle more elegantly for grid
continue;
}
int scrollDiff = newScroll[i] - oldScroll[i];
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView
@@ -2872,6 +2950,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
pendingAnim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
// TODO(b/186800707) Figure out how to undo for grid view
// Need to handle cases where dismissed task is
// * Top Row
// * Bottom Row
// * Focused Task
updateGridProperties();
resetFromSplitSelectionState();
}
});
@@ -2881,13 +2965,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private void resetFromSplitSelectionState() {
mSplitHiddenTaskView.setTranslationY(0);
int pageToSnapTo = mCurrentPage;
if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
pageToSnapTo += 1;
} else {
pageToSnapTo = mSplitHiddenTaskViewIndex;
if (!showAsGrid()) {
// TODO(b/186800707)
int pageToSnapTo = mCurrentPage;
if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
pageToSnapTo += 1;
} else {
pageToSnapTo = mSplitHiddenTaskViewIndex;
}
snapToPageImmediately(pageToSnapTo);
}
snapToPageImmediately(pageToSnapTo);
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
resetTaskVisuals();
mSplitHiddenTaskView = null;
@@ -172,6 +172,32 @@ public class TaskView extends FrameLayout implements Reusable {
}
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_X =
new FloatProperty<TaskView>("splitSelectTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationX(v);
}
@Override
public Float get(TaskView taskView) {
return taskView.mSplitSelectTranslationX;
}
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_Y =
new FloatProperty<TaskView>("splitSelectTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationY(v);
}
@Override
public Float get(TaskView taskView) {
return taskView.mSplitSelectTranslationY;
}
};
private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
new FloatProperty<TaskView>("dismissTranslationX") {
@Override
@@ -345,6 +371,9 @@ public class TaskView extends FrameLayout implements Reusable {
// The following grid translations scales with mGridProgress.
private float mGridTranslationX;
private float mGridTranslationY;
// Used when in SplitScreenSelectState
private float mSplitSelectTranslationY;
private float mSplitSelectTranslationX;
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
@@ -553,6 +582,7 @@ public class TaskView extends FrameLayout implements Reusable {
@Override
public void onAnimationEnd(Animator animator) {
recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(true);
mIsClickableAsLiveTile = true;
}
});
@@ -825,8 +855,10 @@ public class TaskView extends FrameLayout implements Reusable {
protected void resetViewTransforms() {
// fullscreenTranslation and accumulatedTranslation should not be reset, as
// resetViewTransforms is called during Quickswitch scrolling.
mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = 0f;
mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f;
mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX =
mSplitSelectTranslationX = 0f;
mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY =
mSplitSelectTranslationY = 0f;
applyTranslationX();
applyTranslationY();
setTranslationZ(0);
@@ -956,6 +988,15 @@ public class TaskView extends FrameLayout implements Reusable {
setScaleY(scale);
}
private void setSplitSelectTranslationX(float x) {
mSplitSelectTranslationX = x;
applyTranslationX();
}
private void setSplitSelectTranslationY(float y) {
mSplitSelectTranslationY = y;
applyTranslationY();
}
private void setDismissTranslationX(float x) {
mDismissTranslationX = x;
applyTranslationX();
@@ -1056,12 +1097,12 @@ public class TaskView extends FrameLayout implements Reusable {
private void applyTranslationX() {
setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
+ getPersistentTranslationX());
+ mSplitSelectTranslationX + getPersistentTranslationX());
}
private void applyTranslationY() {
setTranslationY(mDismissTranslationY + mTaskOffsetTranslationY + mTaskResistanceTranslationY
+ getPersistentTranslationY());
+ mSplitSelectTranslationY + getPersistentTranslationY());
}
/**
@@ -1085,6 +1126,16 @@ public class TaskView extends FrameLayout implements Reusable {
+ getGridTrans(mGridTranslationY);
}
public FloatProperty<TaskView> getPrimarySplitTranslationProperty() {
return getPagedOrientationHandler().getPrimaryValue(
SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y);
}
public FloatProperty<TaskView> getSecondarySplitTranslationProperty() {
return getPagedOrientationHandler().getSecondaryValue(
SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y);
}
public FloatProperty<TaskView> getPrimaryDismissTranslationProperty() {
return getPagedOrientationHandler().getPrimaryValue(
DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y);
@@ -1417,9 +1468,10 @@ public class TaskView extends FrameLayout implements Reusable {
}
private void setColorTint(float amount) {
mSnapshotView.setDimAlpha(amount);
mIconView.setIconColorTint(mTintingColor, amount);
mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount);
mTintAmount = amount;
mSnapshotView.setDimAlpha(mTintAmount);
mIconView.setIconColorTint(mTintingColor, mTintAmount);
mDigitalWellBeingToast.setBannerColorTint(mTintingColor, mTintAmount);
}
private float getColorTint() {
+1 -1
View File
@@ -221,7 +221,7 @@
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="styles_wallpaper_button_text">Styles &amp; wallpapers</string>
<string name="styles_wallpaper_button_text">Wallpaper &amp; style</string>
<!-- Text for settings button [CHAR LIMIT=30]-->
<string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
@@ -57,6 +57,22 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private final View[] mDragHandles = new View[HANDLE_COUNT];
private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
private final OnAttachStateChangeListener mWidgetViewAttachStateChangeListener =
new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
// Do nothing
}
@Override
public void onViewDetachedFromWindow(View view) {
// When the app widget view is detached, we should close the resize frame.
// An example is when the dragging starts, the widget view is detached from
// CellLayout and then reattached to DragLayout.
close(false);
}
};
private LauncherAppWidgetHostView mWidgetView;
private CellLayout mCellLayout;
@@ -177,7 +193,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
DragLayer dragLayer) {
mCellLayout = cellLayout;
if (mWidgetView != null) {
mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
}
mWidgetView = widgetView;
mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
widgetView.getAppWidgetInfo();
mResizeMode = info.resizeMode;
@@ -628,6 +648,9 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
@Override
protected void handleClose(boolean animate) {
mDragLayer.removeView(this);
if (mWidgetView != null) {
mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
}
}
@Override
+10 -2
View File
@@ -18,6 +18,7 @@ package com.android.launcher3;
import static android.animation.ValueAnimator.areAnimatorsEnabled;
import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import android.animation.Animator;
@@ -193,6 +194,8 @@ public class CellLayout extends ViewGroup {
private static final int INVALID_DIRECTION = -100;
private final Rect mTempRect = new Rect();
private final RectF mTempRectF = new RectF();
private final float[] mTmpFloatArray = new float[4];
private static final Paint sPaint = new Paint();
@@ -1070,11 +1073,16 @@ public class CellLayout extends ViewGroup {
// Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
View view = dragObject.dragView.getContentView();
if (view instanceof LauncherAppWidgetHostView) {
Workspace workspace =
Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace();
Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext());
Workspace workspace = launcher.getWorkspace();
int screenId = workspace.getIdForScreen(this);
int pageId = workspace.getPageIndexForScreenId(screenId);
cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
// Now get the rect in drag layer coordinates.
getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false,
mTmpFloatArray, mTempRectF);
Utilities.setRect(mTempRectF, mTempRect);
((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId);
}
}
+50
View File
@@ -33,6 +33,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -84,6 +85,7 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.lang.reflect.Method;
@@ -104,6 +106,8 @@ public final class Utilities {
private static final Pattern sTrimPattern =
Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$");
private static final float[] sTmpFloatArray = new float[4];
private static final int[] sLoc0 = new int[2];
private static final int[] sLoc1 = new int[2];
private static final Matrix sMatrix = new Matrix();
@@ -133,6 +137,15 @@ public final class Utilities {
Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
/**
* Returns true if theme is dark.
*/
public static boolean isDarkTheme(Context context) {
Configuration configuration = context.getResources().getConfiguration();
int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
return nightMode == Configuration.UI_MODE_NIGHT_YES;
}
public static boolean isDevelopersOptionsEnabled(Context context) {
return Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
@@ -218,6 +231,33 @@ public final class Utilities {
return scale;
}
/**
* Returns bounds for a child view of DragLayer, in drag layer coordinates.
*
* see {@link com.android.launcher3.dragndrop.DragLayer}.
*
* @param viewBounds Bounds of the view wanted in drag layer coordinates, relative to the view
* itself. eg. (0, 0, view.getWidth, view.getHeight)
* @param ignoreTransform If true, view transform is ignored
* @param outRect The out rect where we return the bounds of {@param view} in drag layer coords.
*/
public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view,
Rect viewBounds, boolean ignoreTransform, float[] recycle, RectF outRect) {
float[] points = recycle == null ? new float[4] : recycle;
points[0] = viewBounds.left;
points[1] = viewBounds.top;
points[2] = viewBounds.right;
points[3] = viewBounds.bottom;
Utilities.getDescendantCoordRelativeToAncestor(view, dragLayer, points,
false, ignoreTransform);
outRect.set(
Math.min(points[0], points[2]),
Math.min(points[1], points[3]),
Math.max(points[0], points[2]),
Math.max(points[1], points[3]));
}
/**
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
*/
@@ -273,6 +313,16 @@ public final class Utilities {
return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]};
}
/**
* Helper method to set rectOut with rectFSrc.
*/
public static void setRect(RectF rectFSrc, Rect rectOut) {
rectOut.left = (int) rectFSrc.left;
rectOut.top = (int) rectFSrc.top;
rectOut.right = (int) rectFSrc.right;
rectOut.bottom = (int) rectFSrc.bottom;
}
public static void scaleRectFAboutCenter(RectF r, float scale) {
if (scale != 1.0f) {
float cx = r.centerX();
@@ -32,6 +32,7 @@ import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.keyboard.KeyboardDragAndDropView;
import com.android.launcher3.model.data.AppInfo;
@@ -290,7 +291,12 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
return actions;
}
CellLayout layout = (CellLayout) host.getParent().getParent();
CellLayout layout;
if (host.getParent() instanceof DragView) {
layout = (CellLayout) ((DragView) host.getParent()).getContentViewParent().getParent();
} else {
layout = (CellLayout) host.getParent().getParent();
}
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
@@ -75,7 +75,7 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag
public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener {
private static final float FLING_VELOCITY_MULTIPLIER = 1800f;
private static final float FLING_VELOCITY_MULTIPLIER = 1000f;
// Starts the springs after at least 25% of the animation has passed.
private static final float FLING_ANIMATION_THRESHOLD = 0.25f;
@@ -611,7 +611,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (shouldSpring
&& valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
absorbSwipeUpVelocity(-Math.abs(
absorbSwipeUpVelocity(Math.abs(
Math.round(velocity * FLING_VELOCITY_MULTIPLIER)));
shouldSpring = false;
}
@@ -15,13 +15,15 @@
*/
package com.android.launcher3.allapps;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALLAPPS;
@@ -154,9 +156,9 @@ public class AllAppsTransitionController
return;
}
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
Interpolator interpolator = toState.equals(ALL_APPS)
? (config.userControlled ? ACCEL_2 : ACCEL_0_75) :
(config.userControlled ? DEACCEL_2 : DEACCEL);
Animator anim = createSpringAnimation(mProgress, targetProgress);
anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
@@ -21,7 +21,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
@@ -34,6 +33,7 @@ import android.util.Property;
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.GraphicsUtils;
@@ -119,9 +119,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
info,
IconPalette.getPreloadProgressColor(context, info.bitmap.color),
getPreloadColors(context),
(context.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK
& Configuration.UI_MODE_NIGHT_YES) != 0) /* isDarkMode */;
Utilities.isDarkTheme(context));
}
public PreloadIconDrawable(
@@ -94,6 +94,11 @@ public class SearchActionItemInfo extends ItemInfoWithIcon {
"SearchActionItemInfo can only have either an Intent or a PendingIntent");
}
mIntent = intent;
// bandage fix for just one week
if (intent != null && "com.android.server.telecom".equals(intent.getPackage())) {
intent.setAction(Intent.ACTION_DIAL);
intent.setPackage(null);
}
}
public PendingIntent getPendingIntent() {
+100 -5
View File
@@ -16,7 +16,6 @@
package com.android.launcher3.popup;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
@@ -31,6 +30,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@@ -41,17 +41,21 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
@@ -59,9 +63,11 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.LocalColorExtractor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
/**
* A container for shortcuts to deep links and notifications associated with an app.
@@ -73,6 +79,9 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
// +1 for system shortcut view
private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
// Index used to get background color when using local wallpaper color extraction,
private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50;
private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800;
private final Rect mTempRect = new Rect();
@@ -104,8 +113,14 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
private Runnable mOnCloseCallback = () -> { };
// The rect string of the view that the arrow is attached to, in screen reference frame.
private String mArrowColorRectString;
private int mArrowColor;
private final int[] mColors;
private final HashMap<String, View> mViewForRect = new HashMap<>();
private final int mColorExtractionIndex;
@Nullable private LocalColorExtractor mColorExtractor;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -113,7 +128,9 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
mOutlineRadius = Themes.getDialogCornerRadius(context);
mLauncher = BaseDraggingActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
mColorExtractionIndex = Utilities.isDarkTheme(context)
? DARK_COLOR_EXTRACTION_INDEX
: LIGHT_COLOR_EXTRACTION_INDEX;
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -158,6 +175,10 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
mColors[i] =
(int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
}
if (Utilities.ATLEAST_S) {
setupColorExtraction();
}
}
}
@@ -342,6 +363,15 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
// so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
mArrow.setVisibility(INVISIBLE);
} else {
updateArrowColor();
}
mArrow.setPivotX(mArrowWidth / 2.0f);
mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0);
}
private void updateArrowColor() {
if (!Gravity.isVertical(mGravity)) {
mArrow.setBackground(new RoundedArrowDrawable(
mArrowWidth, mArrowHeight, mArrowPointRadius,
mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(),
@@ -350,9 +380,6 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
mArrowColor));
mArrow.setElevation(getElevation());
}
mArrow.setPivotX(mArrowWidth / 2.0f);
mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0);
}
/**
@@ -671,6 +698,12 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
getPopupContainer().removeView(this);
getPopupContainer().removeView(mArrow);
mOnCloseCallback.run();
mArrowColorRectString = null;
mViewForRect.clear();
if (mColorExtractor != null) {
mColorExtractor.removeLocations();
mColorExtractor.setListener(null);
}
}
/**
@@ -680,6 +713,68 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
mOnCloseCallback = callback;
}
private void setupColorExtraction() {
Workspace workspace = mLauncher.findViewById(R.id.workspace);
if (workspace == null) {
return;
}
mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
mColorExtractor.setListener((rect, extractedColors) -> {
String rectString = rect.toShortString();
View v = mViewForRect.get(rectString);
if (v != null) {
int newColor = extractedColors.get(mColorExtractionIndex);
setChildColor(v, newColor);
if (rectString.equals(mArrowColorRectString)) {
mArrowColor = newColor;
updateArrowColor();
}
}
});
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
ArrayList<RectF> locations = new ArrayList<>();
Rect r = new Rect();
int count = getChildCount();
int numVisibleChild = 0;
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
if (view.getVisibility() == VISIBLE) {
RectF rf = new RectF();
mColorExtractor.getExtractedRectForView(Launcher.getLauncher(getContext()),
workspace.getCurrentPage(), view, rf);
if (rf.isEmpty()) {
numVisibleChild++;
continue;
}
locations.add(rf);
String rectString = rf.toShortString();
mViewForRect.put(rectString, view);
// Arrow color matches the first child or the last child.
if (!mIsAboveIcon && numVisibleChild == 0) {
mArrowColorRectString = rectString;
} else if (mIsAboveIcon) {
mArrowColorRectString = rectString;
}
numVisibleChild++;
}
}
mColorExtractor.addLocation(locations);
return false;
}
});
}
protected BaseDragLayer getPopupContainer() {
return mLauncher.getDragLayer();
}
@@ -159,6 +159,19 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
return VIEW_TRANSLATE_X;
}
@Override
public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition,
DeviceProfile dp) {
// Don't use device profile here because we know we're in fake landscape, only split option
// available is top/left
if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
// Top (visually left) side
return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
}
throw new IllegalStateException("Invalid split stage position: " +
splitPosition.mStagePosition);
}
@Override
public int getPrimaryScroll(View view) {
return view.getScrollY();
@@ -42,6 +42,10 @@ import java.util.List;
*/
public interface PagedOrientationHandler {
int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0;
int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1;
int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2;
PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
@@ -71,6 +75,13 @@ public interface PagedOrientationHandler {
int getSecondaryDimension(View view);
FloatProperty<View> getPrimaryViewTranslate();
FloatProperty<View> getSecondaryViewTranslate();
/**
* @param splitPosition The position where the view to be split will go
* @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the
* dismissal should happen
*/
int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp);
int getPrimaryScroll(View view);
float getPrimaryScale(View view);
int getChildStart(View view);
@@ -155,6 +155,25 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
return VIEW_TRANSLATE_Y;
}
@Override
public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition,
DeviceProfile dp) {
if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
if (dp.isLandscape) {
// Left side
return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
} else {
// Top side
return SPLIT_TRANSLATE_SECONDARY_NEGATIVE;
}
} else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
// We don't have a bottom option, so should be right
return SPLIT_TRANSLATE_PRIMARY_POSITIVE;
}
throw new IllegalStateException("Invalid split stage position: " +
splitPosition.mStagePosition);
}
@Override
public int getPrimaryScroll(View view) {
return view.getScrollX();
@@ -277,7 +296,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
} else {
// Phone Portrait, LargeScreen Landscape/Portrait
viewGroup.setOrientation(LinearLayout.HORIZONTAL);
lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
lp.width = LinearLayout.LayoutParams.MATCH_PARENT;
}
lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
+1 -6
View File
@@ -22,7 +22,6 @@ import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.ColorMatrix;
@@ -54,16 +53,12 @@ public class Themes {
}
public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
Configuration configuration = context.getResources().getConfiguration();
int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
boolean supportsDarkText = Utilities.ATLEAST_S
&& (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
boolean isMainColorDark = Utilities.ATLEAST_S
&& (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
if (darkTheme) {
if (Utilities.isDarkTheme(context)) {
return supportsDarkText ? R.style.AppTheme_Dark_DarkText
: isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark;
} else {
@@ -48,7 +48,13 @@ public class UiThreadHelper {
WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets();
boolean isImeShown = rootInsets != null && rootInsets.isVisible(
WindowInsets.Type.ime());
if (!isImeShown) return;
if (isImeShown) {
// this call is already asynchronous
launcher.getAppsView().getWindowInsetsController().hide(
WindowInsets.Type.ime()
);
}
return;
}
Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget();
@@ -233,15 +233,8 @@ public class FloatingIconView extends FrameLayout implements
outViewBounds.set(0, 0, v.getWidth(), v.getHeight());
}
float[] points = new float[] {outViewBounds.left, outViewBounds.top, outViewBounds.right,
outViewBounds.bottom};
Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points,
false, ignoreTransform);
outRect.set(
Math.min(points[0], points[2]),
Math.min(points[1], points[3]),
Math.max(points[0], points[2]),
Math.max(points[1], points[3]));
Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds,
ignoreTransform, null /** recycle */, outRect);
}
/**
@@ -16,6 +16,9 @@
package com.android.launcher3.widget;
import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer;
import static com.android.launcher3.Utilities.setRect;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
@@ -25,7 +28,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
@@ -95,11 +97,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
private RectF mLastLocationRegistered = null;
@Nullable private AppWidgetHostViewDragListener mDragListener;
// Used to store the widget size during onLayout.
// Used to store the widget sizes in drag layer coordinates.
private final Rect mCurrentWidgetSize = new Rect();
private final Rect mWidgetSizeAtDrag = new Rect();
private final float[] mTmpFloatArray = new float[4];
private final RectF mTempRectF = new RectF();
private final boolean mIsRtl;
private final Rect mEnforcedRectangle = new Rect();
private final float mEnforcedCornerRadius;
private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
@@ -129,7 +132,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
setOnLightBackground(true);
}
mIsRtl = Utilities.isRtl(context.getResources());
mColorExtractor = LocalColorExtractor.newInstance(getContext());
mColorExtractor.setListener(this);
@@ -319,13 +321,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
mIsScrollable = checkScrollableRecursively(this);
if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
mCurrentWidgetSize.left = left;
mCurrentWidgetSize.top = top;
mCurrentWidgetSize.right = right;
mCurrentWidgetSize.bottom = bottom;
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
int pageId = mWorkspace.getPageIndexForScreenId(info.screenId);
updateColorExtraction(mCurrentWidgetSize, pageId);
getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true,
mTmpFloatArray, mTempRectF);
setRect(mTempRectF, mCurrentWidgetSize);
updateColorExtraction(mCurrentWidgetSize,
mWorkspace.getPageIndexForScreenId(info.screenId));
}
enforceRoundedCorners();
@@ -338,8 +339,8 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
}
/** Handles a drag event occurred on a workspace page, {@code pageId}. */
public void handleDrag(Rect rect, int pageId) {
mWidgetSizeAtDrag.set(rect);
public void handleDrag(Rect rectInDragLayer, int pageId) {
mWidgetSizeAtDrag.set(rectInDragLayer);
updateColorExtraction(mWidgetSizeAtDrag, pageId);
}
@@ -351,53 +352,14 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
requestLayout();
}
private void updateColorExtraction(Rect widgetLocation, int pageId) {
// If the widget hasn't been measured and laid out, we cannot do this.
if (widgetLocation.isEmpty()) {
return;
}
int screenWidth = mLauncher.getDeviceProfile().widthPx;
int screenHeight = mLauncher.getDeviceProfile().heightPx;
int numScreens = mWorkspace.getNumPagesForWallpaperParallax();
pageId = mIsRtl ? numScreens - pageId - 1 : pageId;
float relativeScreenWidth = 1f / numScreens;
float absoluteTop = widgetLocation.top;
float absoluteBottom = widgetLocation.bottom;
View v = this;
while (v.getParent() instanceof View) {
v = (View) v.getParent();
if (v.getId() != R.id.launcher) {
break;
}
absoluteBottom += v.getTop();
absoluteTop += v.getTop();
}
float xOffset = 0;
View parentView = (View) getParent();
// The layout depends on the orientation.
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
int parentViewWidth = parentView == null ? 0 : parentView.getWidth();
xOffset = screenWidth - mWorkspace.getPaddingRight() - parentViewWidth;
} else {
int parentViewPaddingLeft = parentView == null ? 0 : parentView.getPaddingLeft();
xOffset = mWorkspace.getPaddingLeft() + parentViewPaddingLeft;
}
// This is the position of the widget relative to the wallpaper, as expected by the
// local color extraction of the WallpaperManager.
// The coordinate system is such that, on the horizontal axis, each screen has a
// distinct range on the [0,1] segment. So if there are 3 screens, they will have the
// ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be
// the position of the widget relative to the screen. For the vertical axis, this is
// simply the location of the widget relative to the screen.
mTempRectF.left = ((widgetLocation.left + xOffset) / screenWidth + pageId)
* relativeScreenWidth;
mTempRectF.right = ((widgetLocation.right + xOffset) / screenWidth + pageId)
* relativeScreenWidth;
mTempRectF.top = absoluteTop / screenHeight;
mTempRectF.bottom = absoluteBottom / screenHeight;
if (mTempRectF.left < 0 || mTempRectF.right > 1 || mTempRectF.top < 0
|| mTempRectF.bottom > 1) {
Log.e(LOG_TAG, " Error, invalid relative position");
/**
* @param rectInDragLayer Rect of widget in drag layer coordinates.
* @param pageId The workspace page the widget is on.
*/
private void updateColorExtraction(Rect rectInDragLayer, int pageId) {
mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF);
if (mTempRectF.isEmpty()) {
return;
}
if (!mTempRectF.equals(mLastLocationRegistered)) {
@@ -19,11 +19,14 @@ package com.android.launcher3.widget;
import android.app.WallpaperColors;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.SparseIntArray;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -71,4 +74,33 @@ public class LocalColorExtractor implements ResourceBasedOverride {
* Updates the base context to contain the colors override
*/
public void applyColorsOverride(Context base, WallpaperColors colors) { }
/**
* Takes a view and returns its rect that can be used by the wallpaper local color extractor.
*
* @param launcher Launcher class class.
* @param pageId The page the workspace item is on.
* @param v The view.
* @param colorExtractionRectOut The location rect, but converted to a format expected by the
* wallpaper local color extractor.
*/
public void getExtractedRectForView(Launcher launcher, int pageId, View v,
RectF colorExtractionRectOut) {
// no-op
}
/**
* Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper
* local color extractor.
*
* @param launcher Launcher class.
* @param pageId The page the workspace item is on.
* @param rectInDragLayer The relevant bounds of the view in drag layer coordinates.
* @param colorExtractionRectOut The location rect, but converted to a format expected by the
* wallpaper local color extractor.
*/
public void getExtractedRectForViewRect(Launcher launcher, int pageId, Rect rectInDragLayer,
RectF colorExtractionRectOut) {
// no-op
}
}