Merge "Adds Search Onboarding count and renames existing edu pref." into tm-dev
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 097609f..0f3474e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -42,7 +42,6 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
-import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
@@ -105,7 +104,6 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DynamicResource;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
@@ -195,9 +193,7 @@
private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125;
protected final BaseQuickstepLauncher mLauncher;
-
private final DragLayer mDragLayer;
- private final AlphaProperty mDragLayerAlpha;
final Handler mHandler;
@@ -241,7 +237,6 @@
public QuickstepTransitionManager(Context context) {
mLauncher = Launcher.cast(Launcher.getLauncher(context));
mDragLayer = mLauncher.getDragLayer();
- mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS);
mHandler = new Handler(Looper.getMainLooper());
mDeviceProfile = mLauncher.getDeviceProfile();
mBackAnimationController = new LauncherBackAnimationController(mLauncher, this);
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index a9ae7bd..b797807 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -176,7 +176,8 @@
return revealAnim;
}
- public void onIsStashed(boolean isStashed) {
+ /** Called when taskbar is stashed or unstashed. */
+ public void onIsStashedChanged(boolean isStashed) {
mRegionSamplingHelper.setWindowVisible(isStashed);
if (isStashed) {
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9561b74..b349637 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -559,7 +559,7 @@
}
}
mWindowLayoutParams.height = height;
- mControllers.taskbarInsetsController.onTaskbarWindowHeightChanged();
+ mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 5d3a152..ff08e3d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -160,6 +160,7 @@
taskbarForceVisibleImmersiveController.onDestroy();
taskbarAllAppsController.onDestroy();
navButtonController.onDestroy();
+ taskbarInsetsController.onDestroy();
mControllersToLog = null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 089c26d..c1a6185 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -83,7 +83,6 @@
private void onComputeTaskbarInsets(InsetsInfo insetsInfo) {
if (mControllerCallbacks != null) {
mControllerCallbacks.updateInsetsTouchability(insetsInfo);
- mControllerCallbacks.updateContentInsets(insetsInfo.contentInsets);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 307f674..3e2695c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -164,16 +164,6 @@
}
/**
- * Called to update the {@link InsetsInfo#contentInsets}. This is reported to apps but our
- * internal launcher will ignore these insets.
- */
- public void updateContentInsets(Rect outContentInsets) {
- int contentHeight = mControllers.taskbarStashController
- .getContentHeightToReportToApps();
- outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight;
- }
-
- /**
* Called when a child is removed from TaskbarDragLayer.
*/
public void onDragLayerViewRemoved() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index a2ff780..9870a2e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,6 +18,7 @@
import android.graphics.Insets
import android.view.WindowManager
import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
import com.android.launcher3.R
import com.android.launcher3.anim.AlphaUpdateListener
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
@@ -53,20 +54,40 @@
)
)
+ windowLayoutParams.providedInternalInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
windowLayoutParams.providedInternalImeInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
- onTaskbarWindowHeightChanged()
+ onTaskbarWindowHeightOrInsetsChanged()
windowLayoutParams.insetsRoundedCornerFrame = true
}
- fun onTaskbarWindowHeightChanged() {
- val reducingSize = Insets.of(0, windowLayoutParams.height - taskbarHeightForIme, 0, 0)
+ fun onDestroy() {}
+
+ fun onTaskbarWindowHeightOrInsetsChanged() {
+ var reducingSize = getReducingInsetsForTaskbarInsetsHeight(
+ controllers.taskbarStashController.contentHeightToReportToApps)
+ windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
+ reducingSize = getReducingInsetsForTaskbarInsetsHeight(
+ controllers.taskbarStashController.tappableHeightToReportToApps)
+ windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
+
+ reducingSize = getReducingInsetsForTaskbarInsetsHeight(taskbarHeightForIme)
windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
}
/**
+ * WindowLayoutParams.providedInternal*Insets expects Insets that subtract from the window frame
+ * height (i.e. WindowLayoutParams#height). So for Taskbar to report bottom insets to apps, it
+ * actually provides insets from the top of its window frame.
+ * @param height The number of pixels from the bottom of the screen that Taskbar insets.
+ */
+ private fun getReducingInsetsForTaskbarInsetsHeight(height: Int): Insets {
+ return Insets.of(0, windowLayoutParams.height - height, 0, 0)
+ }
+
+ /**
* Called to update the touchable insets.
* @see InsetsInfo.setTouchableInsets
*/
@@ -88,18 +109,11 @@
} else if (controllers.taskbarDragController.isSystemDragInProgress) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
- } else if (AbstractFloatingView.getOpenView<AbstractFloatingView?>(
- context,
- AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
- ) != null
- ) {
+ } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_ALL_APPS)) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
} else if (controllers.taskbarViewController.areIconsVisible()
- || AbstractFloatingView.getOpenView<AbstractFloatingView?>(
- context,
- AbstractFloatingView.TYPE_ALL
- ) != null
+ || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
|| context.isNavBarKidsModeActive
) {
// Taskbar has some touchable elements, take over the full taskbar area
@@ -120,6 +134,10 @@
override fun dumpLogs(prefix: String, pw: PrintWriter) {
pw.println(prefix + "TaskbarInsetsController:")
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
+ pw.println("$prefix\tprovidedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
+ "${windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
+ pw.println("$prefix\tprovidedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
+ "${windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}")
pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
"${windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index be67136..f34759d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -30,6 +30,7 @@
import android.content.SharedPreferences;
import android.util.Log;
import android.view.ViewConfiguration;
+import android.view.WindowInsets;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -280,6 +281,8 @@
/**
* Returns the height that taskbar will inset when inside apps.
+ * @see WindowInsets.Type#navigationBars()
+ * @see WindowInsets.Type#systemBars()
*/
public int getContentHeightToReportToApps() {
if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
@@ -304,6 +307,15 @@
return mUnstashedHeight;
}
+ /**
+ * Returns the height that taskbar will inset when inside apps.
+ * @see WindowInsets.Type#tappableElement()
+ */
+ public int getTappableHeightToReportToApps() {
+ int contentHeight = getContentHeightToReportToApps();
+ return contentHeight <= mStashedHeight ? 0 : contentHeight;
+ }
+
public int getStashedHeight() {
return mStashedHeight;
}
@@ -442,7 +454,7 @@
@Override
public void onAnimationStart(Animator animation) {
mIsStashed = isStashed;
- onIsStashed(mIsStashed);
+ onIsStashedChanged(mIsStashed);
}
@Override
@@ -489,8 +501,11 @@
.setDuration(TASKBAR_HINT_STASH_DURATION).start();
}
- private void onIsStashed(boolean isStashed) {
- mControllers.stashedHandleViewController.onIsStashed(isStashed);
+ private void onIsStashedChanged(boolean isStashed) {
+ mControllers.runAfterInit(() -> {
+ mControllers.stashedHandleViewController.onIsStashedChanged(isStashed);
+ mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
+ });
}
public void applyState() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 947d3e2..86f26c3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -107,7 +107,6 @@
*/
private void handleSplitSelectionState(@NonNull LauncherState toState,
@Nullable PendingAnimation builder) {
- LauncherState currentState = mLauncher.getStateManager().getState();
boolean animate = builder != null;
PagedOrientationHandler orientationHandler =
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
@@ -116,7 +115,7 @@
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mLauncher.getDeviceProfile());
- if (isSplitSelectionState(currentState, toState)) {
+ if (toState == OVERVIEW_SPLIT_SELECT) {
// Animation to "dismiss" selected taskView
PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
toState.getTransitionDuration(mLauncher));
@@ -125,30 +124,18 @@
toState.getSplitSelectTranslation(mLauncher), LINEAR);
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
- if (!animate && isSplitSelectionState(currentState, toState)) {
+ if (!animate) {
splitSelectInitAnimation.buildAnim().start();
- } else if (animate &&
- isSplitSelectionState(currentState, toState)) {
+ } else {
builder.add(splitSelectInitAnimation.buildAnim());
}
- }
- if (isSplitSelectionState(currentState, toState)) {
mRecentsView.applySplitPrimaryScrollOffset();
} else {
mRecentsView.resetSplitPrimaryScrollOffset();
}
}
- /**
- * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
- * and {@param fromState} is not {@link LauncherState#OVERVIEW_SPLIT_SELECT}
- */
- private boolean isSplitSelectionState(@NonNull LauncherState fromState,
- @NonNull LauncherState toState) {
- return fromState != OVERVIEW_SPLIT_SELECT && toState == OVERVIEW_SPLIT_SELECT;
- }
-
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
LauncherState state) {
float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 7bfb76a..34a6821 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -21,7 +21,8 @@
import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_PROGRESS;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_ALPHA;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_TRANSLATION;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
@@ -40,11 +41,9 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.TaskUtils;
@@ -148,16 +147,10 @@
AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_TASK_MENU);
} else if (mStartState == ALL_APPS) {
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
- builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_PROGRESS,
- -mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR);
-
- // Slightly fade out all apps content to further distinguish from scrolling.
- StateAnimationConfig config = new StateAnimationConfig();
- config.duration = accuracy;
- config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators
- .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
-
- allAppsController.setAlphas(mEndState, config, builder);
+ builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_TRANSLATION,
+ -mPullbackDistance, PULLBACK_INTERPOLATOR);
+ builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_ALPHA,
+ 0.5f, PULLBACK_INTERPOLATOR);
}
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b073b90..b90e820 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1013,19 +1013,19 @@
return RECENTS;
}
final GestureEndTarget endTarget;
- final boolean goingToNewTask;
+ final boolean canGoToNewTask;
if (mRecentsView != null) {
if (!hasTargets()) {
// If there are no running tasks, then we can assume that this is a continuation of
// the last gesture, but after the recents animation has finished
- goingToNewTask = true;
+ canGoToNewTask = true;
} else {
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
- goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
+ canGoToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
}
} else {
- goingToNewTask = false;
+ canGoToNewTask = false;
}
final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources()
@@ -1034,13 +1034,13 @@
if (isCancel) {
endTarget = LAST_TASK;
} else if (mDeviceState.isFullyGesturalNavMode()) {
- if (goingToNewTask && isFlingX) {
+ if (canGoToNewTask && isFlingX) {
// Flinging towards new task takes precedence over mIsMotionPaused (which only
// checks y-velocity).
endTarget = NEW_TASK;
} else if (mIsMotionPaused) {
endTarget = RECENTS;
- } else if (goingToNewTask) {
+ } else if (canGoToNewTask) {
endTarget = NEW_TASK;
} else {
endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME;
@@ -1048,26 +1048,22 @@
} else {
endTarget = reachedOverviewThreshold && mGestureStarted
? RECENTS
- : goingToNewTask
+ : canGoToNewTask
? NEW_TASK
: LAST_TASK;
}
} else {
// If swiping at a diagonal, base end target on the faster velocity.
boolean isSwipeUp = endVelocity < 0;
- boolean willGoToNewTaskOnSwipeUp =
- goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity);
+ boolean willGoToNewTask =
+ canGoToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity);
- if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) {
- endTarget = HOME;
- } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) {
- // If swiping at a diagonal, base end target on the faster velocity.
- endTarget = NEW_TASK;
+ if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) {
+ endTarget = willGoToNewTask ? NEW_TASK : HOME;
} else if (isSwipeUp) {
- endTarget = !reachedOverviewThreshold && willGoToNewTaskOnSwipeUp
- ? NEW_TASK : RECENTS;
+ endTarget = (!reachedOverviewThreshold && willGoToNewTask) ? NEW_TASK : RECENTS;
} else {
- endTarget = goingToNewTask ? NEW_TASK : LAST_TASK;
+ endTarget = willGoToNewTask ? NEW_TASK : LAST_TASK; // Swipe is downward.
}
}
@@ -1145,6 +1141,8 @@
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
}
+ } else if (endTarget == LAST_TASK && mRecentsView != null) {
+ mRecentsView.snapToPage(mRecentsView.getCurrentPage(), Math.toIntExact(duration));
}
// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index b686505..9ba5577 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -117,7 +117,22 @@
mTutorialFragment.closeTutorial();
}
} else if (mTutorialType == BACK_NAVIGATION) {
- showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
+ switch (result) {
+ case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ showFeedback(R.string.back_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ case HOME_GESTURE_COMPLETED:
+ case OVERVIEW_GESTURE_COMPLETED:
+ case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case ASSISTANT_COMPLETED:
+ case ASSISTANT_NOT_STARTED_BAD_ANGLE:
+ case ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT:
+ default:
+ showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
+
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5f715f8..49bf827 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1396,6 +1396,9 @@
if (taskGroups == null || taskGroups.isEmpty()) {
removeTasksViewsAndClearAllButton();
onTaskStackUpdated();
+ // With all tasks removed, touch handling in PagedView is disabled and we need to reset
+ // touch state or otherwise values will be obsolete.
+ resetTouchState();
return;
}
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 4386f41..90869c2 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -208,6 +208,13 @@
}
/**
+ * Returns whether there is at least one view of the given type where {@link #isOpen()} == true.
+ */
+ public static boolean hasOpenView(ActivityContext activity, @FloatingViewType int type) {
+ return getOpenView(activity, type) != null;
+ }
+
+ /**
* Returns a view matching FloatingViewType, and {@link #isOpen()} may be false (if animating
* closed).
*/
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b6a05b0..4b42ecb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -42,7 +42,6 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
-import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -65,7 +64,6 @@
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.Notification;
@@ -109,7 +107,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
@@ -130,7 +128,6 @@
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -186,8 +183,6 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -341,6 +336,7 @@
private Runnable mOnDeferredActivityLaunchCallback;
private ViewOnDrawExecutor mPendingExecutor;
+ private OnPreDrawListener mOnInitialBindListener;
private LauncherModel mModel;
private ModelWriter mModelWriter;
@@ -503,11 +499,10 @@
if (!mModel.addCallbacksAndLoad(this)) {
if (!internalStateHandled) {
- Log.d(BAD_STATE, "Launcher onCreate not binding sync, setting DragLayer alpha "
- + "ALPHA_INDEX_LAUNCHER_LOAD to 0");
- // If we are not binding synchronously, show a fade in animation when
- // the first page bind completes.
- mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
+ Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing");
+ // If we are not binding synchronously, pause drawing until initial bind complete,
+ // so that the system could continue to show the device loading prompt
+ mOnInitialBindListener = Boolean.FALSE::booleanValue;
}
}
@@ -515,25 +510,9 @@
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
setContentView(getRootView());
- getRootView().getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- // Checks the status of fade in animation.
- final AlphaProperty property =
- mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
- if (property.getValue() == 0) {
- Log.d(BAD_STATE, "Launcher onPreDraw ALPHA_INDEX_LAUNCHER_LOAD not"
- + " started yet, cancelling draw.");
- // Animation haven't started yet; suspend.
- return false;
- } else {
- // The animation is started; start drawing.
- getRootView().getViewTreeObserver().removeOnPreDrawListener(this);
- return true;
- }
- }
- });
+ if (mOnInitialBindListener != null) {
+ getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener);
+ }
getRootView().dispatchInsets();
// Listen for broadcasts
@@ -2692,36 +2671,12 @@
AllAppsStore.DEFER_UPDATES_NEXT_DRAW));
}
- AlphaProperty property = mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
- if (property.getValue() < 1) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(property, MultiValueAlpha.VALUE, 1);
-
- Log.d(BAD_STATE, "Launcher onInitialBindComplete toAlpha=" + 1);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onStart");
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- float alpha = mDragLayer == null
- ? -1
- : mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).getValue();
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onCancel, alpha=" + alpha);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onEnd");
- }
- });
-
- anim.addListener(AnimatorListeners.forEndCallback(executor::onLoadAnimationCompleted));
- anim.start();
- } else {
- executor.onLoadAnimationCompleted();
+ if (mOnInitialBindListener != null) {
+ getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener);
+ mOnInitialBindListener = null;
}
+
+ executor.onLoadAnimationCompleted();
executor.attachTo(this);
if (Utilities.ATLEAST_S) {
Trace.endAsyncSection(DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index f5ac359..0a1d25c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1440,7 +1440,7 @@
return Math.abs(velocity) > threshold;
}
- private void resetTouchState() {
+ protected void resetTouchState() {
releaseVelocityTracker();
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 8662d00..637a418 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -44,6 +44,8 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.MultiAdditivePropertyFactory;
+import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.views.ScrimView;
@@ -76,20 +78,56 @@
}
};
- public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_PROGRESS =
- new FloatProperty<AllAppsTransitionController>("allAppsPullBackProgress") {
+ public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_TRANSLATION =
+ new FloatProperty<AllAppsTransitionController>("allAppsPullBackTranslation") {
@Override
public Float get(AllAppsTransitionController controller) {
- return controller.mPullBackProgress;
+ if (controller.mIsTablet) {
+ return controller.mAppsView.getRecyclerViewContainer().getTranslationY();
+ } else {
+ return controller.getAppsViewPullbackTranslationY().get(
+ controller.mAppsView);
+ }
}
@Override
- public void setValue(AllAppsTransitionController controller, float progress) {
- controller.setPullBackProgress(progress);
+ public void setValue(AllAppsTransitionController controller, float translation) {
+ if (controller.mIsTablet) {
+ controller.mAppsView.getRecyclerViewContainer().setTranslationY(
+ translation);
+ } else {
+ controller.getAppsViewPullbackTranslationY().set(controller.mAppsView,
+ translation);
+ }
}
};
+ public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_ALPHA =
+ new FloatProperty<AllAppsTransitionController>("allAppsPullBackAlpha") {
+
+ @Override
+ public Float get(AllAppsTransitionController controller) {
+ if (controller.mIsTablet) {
+ return controller.mAppsView.getRecyclerViewContainer().getAlpha();
+ } else {
+ return controller.getAppsViewPullbackAlpha().getValue();
+ }
+ }
+
+ @Override
+ public void setValue(AllAppsTransitionController controller, float alpha) {
+ if (controller.mIsTablet) {
+ controller.mAppsView.getRecyclerViewContainer().setAlpha(alpha);
+ } else {
+ controller.getAppsViewPullbackAlpha().setValue(alpha);
+ }
+ }
+ };
+
+ private static final int INDEX_APPS_VIEW_PROGRESS = 0;
+ private static final int INDEX_APPS_VIEW_PULLBACK = 1;
+ private static final int APPS_VIEW_INDEX_COUNT = 2;
private ActivityAllAppsContainerView<Launcher> mAppsView;
@@ -104,18 +142,23 @@
// When {@link mProgress} is 1, all apps container is pulled down.
private float mShiftRange; // changes depending on the orientation
private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent
- private float mPullBackProgress; // [0, 1], mShiftRange * mPullBackProgress = shiftCurrent
private ScrimView mScrimView;
- private View mPullBackView;
+
+ private final MultiAdditivePropertyFactory<View>
+ mAppsViewTranslationYPropertyFactory = new MultiAdditivePropertyFactory<>(
+ "appsViewTranslationY", View.TRANSLATION_Y);
+ private MultiValueAlpha mAppsViewAlpha;
+
+ private boolean mIsTablet;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
DeviceProfile dp = mLauncher.getDeviceProfile();
setShiftRange(dp.allAppsShiftRange);
mProgress = 1f;
- mPullBackProgress = 1f;
mIsVerticalLayout = dp.isVerticalBarLayout();
+ mIsTablet = dp.isTablet;
mLauncher.addOnDeviceProfileChangeListener(this);
}
@@ -133,7 +176,7 @@
mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
}
- mPullBackView = dp.isTablet ? mAppsView.getRecyclerViewContainer() : mAppsView;
+ mIsTablet = dp.isTablet;
}
/**
@@ -146,16 +189,27 @@
*/
public void setProgress(float progress) {
mProgress = progress;
- mAppsView.setTranslationY(mProgress * mShiftRange);
+ getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange);
}
public float getProgress() {
return mProgress;
}
- private void setPullBackProgress(float progress) {
- mPullBackProgress = progress;
- mPullBackView.setTranslationY(mPullBackProgress * mShiftRange);
+ private FloatProperty<View> getAppsViewProgressTranslationY() {
+ return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PROGRESS);
+ }
+
+ private FloatProperty<View> getAppsViewPullbackTranslationY() {
+ return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PULLBACK);
+ }
+
+ private MultiValueAlpha.AlphaProperty getAppsViewProgressAlpha() {
+ return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PROGRESS);
+ }
+
+ private MultiValueAlpha.AlphaProperty getAppsViewPullbackAlpha() {
+ return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PULLBACK);
}
/**
@@ -164,8 +218,6 @@
*/
@Override
public void setState(LauncherState state) {
- // Always reset pull back progress when switching states.
- setPullBackProgress(0f);
setProgress(state.getVerticalProgress(mLauncher));
setAlphas(state, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
@@ -180,10 +232,13 @@
StateAnimationConfig config, PendingAnimation builder) {
if (NORMAL.equals(toState) && mLauncher.isInState(ALL_APPS)) {
UiThreadHelper.hideKeyboardAsync(mLauncher, mLauncher.getAppsView().getWindowToken());
+ builder.addEndListener(success -> {
+ // Reset pull back progress and alpha after switching states.
+ ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f);
+ ALL_APPS_PULL_BACK_ALPHA.set(this, 1f);
+ });
}
- // Always reset pull back progress when switching states.
- setPullBackProgress(0f);
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -222,7 +277,8 @@
boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
- setter.setViewAlpha(mAppsView, hasAllAppsContent ? 1 : 0, allAppsFade);
+ setter.setFloat(getAppsViewProgressAlpha(), MultiValueAlpha.VALUE,
+ hasAllAppsContent ? 1 : 0, allAppsFade);
boolean shouldProtectHeader =
ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS;
@@ -245,8 +301,8 @@
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
mAppsView.setScrimView(scrimView);
- mPullBackView = mLauncher.getDeviceProfile().isTablet
- ? mAppsView.getRecyclerViewContainer() : mAppsView;
+ mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT);
+ mAppsViewAlpha.setUpdateVisibility(true);
}
/**
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 14e10918..8eeca7d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -65,9 +65,7 @@
public class DragLayer extends BaseDragLayer<Launcher> {
public static final int ALPHA_INDEX_OVERLAY = 0;
- public static final int ALPHA_INDEX_LAUNCHER_LOAD = 1;
- public static final int ALPHA_INDEX_TRANSITIONS = 2;
- private static final int ALPHA_CHANNEL_COUNT = 3;
+ private static final int ALPHA_CHANNEL_COUNT = 1;
public static final int ANIMATION_END_DISAPPEAR = 0;
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
diff --git a/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java
new file mode 100644
index 0000000..50f7027
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.util.ArrayMap;
+import android.util.FloatProperty;
+import android.util.Log;
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Allows to combine multiple values set by several sources.
+ *
+ * The various sources are meant to use [set], providing different `setterIndex` params. When it is
+ * not set, 0 is used. This is meant to cover the case multiple animations are going on at the same
+ * time.
+ *
+ * This class behaves similarly to [MultiValueAlpha], but is meant to be more abstract and reusable.
+ * It sets the addition of all values.
+ *
+ * @param <T> Type where to apply the property.
+ */
+public class MultiAdditivePropertyFactory<T extends View> {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "MultiAdditivePropertyFactory";
+ private final String mName;
+ private final ArrayMap<Integer, MultiAdditiveProperty> mProperties =
+ new ArrayMap<>();
+
+ // This is an optimization for cases when set is called repeatedly with the same setterIndex.
+ private float mAggregationOfOthers = 0f;
+ private Integer mLastIndexSet = -1;
+ private final Property<View, Float> mProperty;
+
+ public MultiAdditivePropertyFactory(String name, Property<View, Float> property) {
+ mName = name;
+ mProperty = property;
+ }
+
+ /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
+ public MultiAdditiveProperty get(Integer index) {
+ return mProperties.computeIfAbsent(index,
+ (k) -> new MultiAdditiveProperty(index, mName + "_" + index));
+ }
+
+ /**
+ * Each [setValue] will be aggregated with the other properties values created by the
+ * corresponding factory.
+ */
+ class MultiAdditiveProperty extends FloatProperty<T> {
+ private final int mInx;
+ private float mValue = 0f;
+
+ MultiAdditiveProperty(int inx, String name) {
+ super(name);
+ mInx = inx;
+ }
+
+ @Override
+ public void setValue(T obj, float newValue) {
+ if (mLastIndexSet != mInx) {
+ mAggregationOfOthers = 0f;
+ mProperties.forEach((key, property) -> {
+ if (key != mInx) {
+ mAggregationOfOthers += property.mValue;
+ }
+ });
+ mLastIndexSet = mInx;
+ }
+ float lastAggregatedValue = mAggregationOfOthers + newValue;
+ mValue = newValue;
+ apply(obj, lastAggregatedValue);
+
+ if (DEBUG) {
+ Log.d(TAG, "name=" + mName
+ + " newValue=" + newValue + " mInx=" + mInx
+ + " aggregated=" + lastAggregatedValue + " others= " + mProperties);
+ }
+ }
+
+ @Override
+ public Float get(T view) {
+ // The scale of the view should match mLastAggregatedValue. Still, if it has been
+ // changed without using this property, it can differ. As this get method is usually
+ // used to set the starting point on an animation, this would result in some jumps
+ // when the view scale is different than the last aggregated value. To stay on the
+ // safe side, let's return the real view scale.
+ return mProperty.get(view);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(mValue);
+ }
+ }
+
+ protected void apply(View view, float value) {
+ mProperty.set(view, value);
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt
new file mode 100644
index 0000000..309d055
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit tests for [MultiAdditivePropertyFactory] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MultiAdditivePropertyTest {
+
+ private val received = mutableListOf<Float>()
+
+ private val factory =
+ object : MultiAdditivePropertyFactory<View?>("Test", View.TRANSLATION_X) {
+ override fun apply(obj: View?, value: Float) {
+ received.add(value)
+ }
+ }
+
+ private val p1 = factory.get(1)
+ private val p2 = factory.get(2)
+ private val p3 = factory.get(3)
+
+ @Test
+ fun set_sameIndexes_allApplied() {
+ val v1 = 50f
+ val v2 = 100f
+ p1.set(null, v1)
+ p1.set(null, v1)
+ p1.set(null, v2)
+
+ assertThat(received).containsExactly(v1, v1, v2)
+ }
+
+ @Test
+ fun set_differentIndexes_aggregationApplied() {
+ val v1 = 50f
+ val v2 = 100f
+ val v3 = 150f
+ p1.set(null, v1)
+ p2.set(null, v2)
+ p3.set(null, v3)
+
+ assertThat(received).containsExactly(v1, v1 + v2, v1 + v2 + v3)
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
index 6099987..7d92214 100644
--- a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
+++ b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.launcher3.util
import android.view.View