Merge "First pass of the Launcher Overlay interface / impl" into ub-now-queens

This commit is contained in:
Adam Cohen 2014-10-23 00:41:58 +00:00 committed by Android (Google) Code Review
commit 24e18aea81
13 changed files with 693 additions and 39 deletions

View File

@ -88,7 +88,25 @@
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="nosensor">
android:screenOrientation="nosensor"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
</activity>
<activity
android:name="com.android.launcher3.LauncherExtension"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="nosensor"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />

View File

@ -63,4 +63,11 @@
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
android:id="@+id/launcher_overlay_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/launcher_overlay"
android:layout="@layout/launcher_overlay" />
</FrameLayout>

View File

@ -83,4 +83,11 @@
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
android:id="@+id/launcher_overlay_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/launcher_overlay"
android:layout="@layout/launcher_overlay" />
</FrameLayout>

View File

@ -82,4 +82,12 @@
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
android:id="@+id/launcher_overlay_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inflatedId="@+id/launcher_overlay"
android:layout="@layout/launcher_overlay" />
</FrameLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/search_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff00ff00"
android:visibility="invisible" />
<FrameLayout
android:id="@+id/search_box"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="36dp"
android:background="#ffff0000" />
</FrameLayout>

View File

@ -89,6 +89,8 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
private Drawable mLeftHoverDrawableActive;
private Drawable mRightHoverDrawableActive;
private boolean mBlockTouches = false;
/**
* Used to create a new DragLayer from XML.
*
@ -185,11 +187,19 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
return false;
}
public void setBlockTouch(boolean block) {
mBlockTouches = block;
}
private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
Rect hitRect = new Rect();
int x = (int) ev.getX();
int y = (int) ev.getY();
if (mBlockTouches) {
return true;
}
for (AppWidgetResizeFrame child: mResizeFrames) {
child.getHitRect(hitRect);
if (hitRect.contains(x, y)) {
@ -332,6 +342,10 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
int x = (int) ev.getX();
int y = (int) ev.getY();
if (mBlockTouches) {
return true;
}
if (action == MotionEvent.ACTION_DOWN) {
if (handleTouchDown(ev, false)) {
return true;

View File

@ -86,6 +86,7 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
@ -228,6 +229,10 @@ public class Launcher extends Activity
private boolean mIsSafeModeEnabled;
LauncherOverlayCallbacks mLauncherOverlayCallbacks = new LauncherOverlayCallbacksImpl();
LauncherOverlay mLauncherOverlay;
ViewGroup mLauncherOverlayView;
static final int APPWIDGET_HOST_ID = 1024;
public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@ -507,6 +512,13 @@ public class Launcher extends Activity
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
if (mLauncherCallbacks.hasLauncherOverlay()) {
ViewStub stub = (ViewStub) findViewById(R.id.launcher_overlay_stub);
mLauncherOverlayView = (ViewGroup) stub.inflate();
mLauncherOverlay = mLauncherCallbacks.setLauncherOverlayView(mLauncherOverlayView,
mLauncherOverlayCallbacks);
mWorkspace.setLauncherOverlay(mLauncherOverlay);
}
}
}
@ -1145,6 +1157,84 @@ public class Launcher extends Activity
boolean isScrollingAllowed();
}
public interface LauncherOverlay {
/**
* Touch interaction leading to overscroll has begun
*/
public void onScrollInteractionBegin();
/**
* Touch interaction related to overscroll has ended
*/
public void onScrollInteractionEnd();
/**
* Scroll progress, between 0 and 100, when the user scrolls beyond the leftmost
* screen (or in the case of RTL, the rightmost screen).
*/
public void onScrollChange(int progress, boolean rtl);
/**
* Screen has stopped scrolling
*/
public void onScrollSettled();
/**
* This method can be called by the Launcher in order to force the LauncherOverlay
* to exit fully immersive mode.
*/
public void forceExitFullImmersion();
}
public interface LauncherOverlayCallbacks {
/**
* This method indicates whether a call to {@link #enterFullImmersion()} will succeed,
* however it doesn't modify any state within the launcher.
*/
public boolean canEnterFullImmersion();
/**
* Should be called to tell Launcher that the LauncherOverlay will take over interaction,
* eg. by occupying the full screen and handling all touch events.
*
* @return true if Launcher allows the LauncherOverlay to become fully immersive. In this
* case, Launcher will modify any necessary state and assumes the overlay is
* handling all interaction. If false, the LauncherOverlay should cancel any
*
*/
public boolean enterFullImmersion();
/**
* Must be called when exiting fully immersive mode. Indicates to Launcher that it has
* full control over UI and state.
*/
public void exitFullImmersion();
}
class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
@Override
public boolean canEnterFullImmersion() {
return mState == State.WORKSPACE;
}
@Override
public boolean enterFullImmersion() {
if (mState == State.WORKSPACE) {
// When fully immersed, disregard any touches which fall through.
mDragLayer.setBlockTouch(true);
return true;
}
return false;
}
@Override
public void exitFullImmersion() {
mDragLayer.setBlockTouch(false);
}
}
protected boolean hasSettings() {
if (mLauncherCallbacks != null) {
return mLauncherCallbacks.hasSettings();
@ -4084,11 +4174,8 @@ public class Launcher extends Activity
}
public View getQsbBar() {
if (mLauncherCallbacks != null) {
View qsb = mLauncherCallbacks.getQsbBar();
if (qsb != null) {
return qsb;
}
if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
return mLauncherCallbacks.getQsbBar();
}
if (mQsb == null) {

View File

@ -6,6 +6,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@ -86,4 +87,22 @@ public interface LauncherCallbacks {
public boolean overrideWallpaperDimensions();
public boolean isLauncherPreinstalled();
/**
* Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
* com.android.launcher3.Launcher.LauncherOverlayCallbacks)}.
*
* @return true if this launcher extension will provide an overlay
*/
public boolean hasLauncherOverlay();
/**
* Handshake to establish an overlay relationship
*
* @param overlayView Full screen overlay ViewGroup into which custom views can be placed.
* @param callbacks A set of callbacks provided by Launcher in relation to the overlay
* @return an interface used to make requests and notify the Launcher in relation to the overlay
*/
public Launcher.LauncherOverlay setLauncherOverlayView(ViewGroup overlayView,
Launcher.LauncherOverlayCallbacks callbacks);
}

View File

@ -0,0 +1,354 @@
package com.android.launcher3;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
* This class represents a very trivial LauncherExtension. It primarily serves as a simple
* class to exercise the LauncherOverlay interface.
*/
public class LauncherExtension extends Launcher {
//------ Activity methods -------//
@Override
public void onCreate(Bundle savedInstanceState) {
setLauncherCallbacks(new LauncherExtensionCallbacks());
super.onCreate(savedInstanceState);
}
public class LauncherExtensionCallbacks implements LauncherCallbacks {
LauncherExtensionOverlay mLauncherOverlay = new LauncherExtensionOverlay();
@Override
public void preOnCreate() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
}
@Override
public void preOnResume() {
}
@Override
public void onResume() {
}
@Override
public void onStart() {
}
@Override
public void onStop() {
}
@Override
public void onPause() {
}
@Override
public void onDestroy() {
}
@Override
public void onSaveInstanceState(Bundle outState) {
}
@Override
public void onPostCreate(Bundle savedInstanceState) {
}
@Override
public void onNewIntent(Intent intent) {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
return false;
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args) {
}
@Override
public void onHomeIntent() {
}
@Override
public boolean handleBackPressed() {
if (mLauncherOverlay.isOverlayPanelShowing()) {
mLauncherOverlay.hideOverlayPanel();
return true;
}
return false;
}
@Override
public void onLauncherProviderChange() {
}
@Override
public void finishBindingItems(boolean upgradePath) {
}
@Override
public void onClickAllAppsButton(View v) {
}
@Override
public void bindAllApplications(ArrayList<AppInfo> apps) {
}
@Override
public void onClickFolderIcon(View v) {
}
@Override
public void onClickAppShortcut(View v) {
}
@Override
public void onClickPagedViewIcon(View v) {
}
@Override
public void onClickWallpaperPicker(View v) {
}
@Override
public void onClickSettingsButton(View v) {
}
@Override
public void onClickAddWidgetButton(View v) {
}
@Override
public void onPageSwitch(View newPage, int newPageIndex) {
}
@Override
public void onWorkspaceLockedChanged() {
}
@Override
public void onDragStarted(View view) {
}
@Override
public void onInteractionBegin() {
}
@Override
public void onInteractionEnd() {
}
@Override
public boolean forceDisableVoiceButtonProxy() {
return false;
}
@Override
public boolean providesSearch() {
return true;
}
@Override
public boolean startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, Rect sourceBounds) {
return false;
}
@Override
public void startVoice() {
}
@Override
public boolean hasCustomContentToLeft() {
return false;
}
@Override
public void populateCustomContentContainer() {
}
@Override
public View getQsbBar() {
return mLauncherOverlay.getSearchBox();
}
@Override
public Intent getFirstRunActivity() {
return null;
}
@Override
public boolean hasFirstRunActivity() {
return false;
}
@Override
public boolean hasDismissableIntroScreen() {
return false;
}
@Override
public View getIntroScreen() {
return null;
}
@Override
public boolean shouldMoveToDefaultScreenOnHomeIntent() {
return true;
}
@Override
public boolean hasSettings() {
return false;
}
@Override
public ComponentName getWallpaperPickerComponent() {
return null;
}
@Override
public boolean overrideWallpaperDimensions() {
return false;
}
@Override
public boolean isLauncherPreinstalled() {
return false;
}
@Override
public boolean hasLauncherOverlay() {
return true;
}
@Override
public LauncherOverlay setLauncherOverlayView(ViewGroup overlayView,
LauncherOverlayCallbacks callbacks) {
mLauncherOverlay.setOverlayCallbacks(callbacks);
mLauncherOverlay.setOverlayView(overlayView);
return mLauncherOverlay;
}
class LauncherExtensionOverlay implements LauncherOverlay {
LauncherOverlayCallbacks mLauncherOverlayCallbacks;
ViewGroup mOverlayView;
View mSearchBox;
View mSearchOverlay;
boolean mShowOverlayFeedback;
int mProgress;
boolean mOverlayPanelShowing;
@Override
public void onScrollInteractionBegin() {
if (mLauncherOverlayCallbacks.canEnterFullImmersion()) {
mShowOverlayFeedback = true;
updatePanelOffset(0);
mSearchOverlay.setVisibility(View.VISIBLE);
mSearchOverlay.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
}
@Override
public void onScrollChange(int progress, boolean rtl) {
mProgress = progress;
if (mShowOverlayFeedback) {
updatePanelOffset(progress);
}
}
private void updatePanelOffset(int progress) {
int panelWidth = mSearchOverlay.getMeasuredWidth();
int offset = (int) ((progress / 100f) * panelWidth);
mSearchOverlay.setTranslationX(- panelWidth + offset);
}
@Override
public void onScrollInteractionEnd() {
if (mProgress > 25 && mLauncherOverlayCallbacks.enterFullImmersion()) {
ObjectAnimator oa = LauncherAnimUtils.ofFloat(mSearchOverlay, "translationX", 0);
oa.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator arg0) {
mSearchOverlay.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
oa.start();
mOverlayPanelShowing = true;
mShowOverlayFeedback = false;
}
}
@Override
public void onScrollSettled() {
if (mShowOverlayFeedback) {
mSearchOverlay.setVisibility(View.INVISIBLE);
mSearchOverlay.setLayerType(View.LAYER_TYPE_NONE, null);
}
mShowOverlayFeedback = false;
mProgress = 0;
}
public void hideOverlayPanel() {
mLauncherOverlayCallbacks.exitFullImmersion();
mSearchOverlay.setVisibility(View.INVISIBLE);
mOverlayPanelShowing = false;
}
public boolean isOverlayPanelShowing() {
return mOverlayPanelShowing;
}
@Override
public void forceExitFullImmersion() {
hideOverlayPanel();
}
public void setOverlayView(ViewGroup overlayView) {
mOverlayView = (ViewGroup) getLayoutInflater().inflate(
R.layout.launcher_overlay_example, overlayView);
mSearchOverlay = mOverlayView.findViewById(R.id.search_overlay);
mSearchBox = mOverlayView.findViewById(R.id.search_box);
}
public View getSearchBox() {
return mSearchBox;
}
public void setOverlayCallbacks(LauncherOverlayCallbacks callbacks) {
mLauncherOverlayCallbacks = callbacks;
}
};
}
}

View File

@ -204,6 +204,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
protected boolean mAllowLongPress = true;
private boolean mWasInOverscroll = false;
// Page Indicator
private int mPageIndicatorViewId;
private PageIndicator mPageIndicator;
@ -625,6 +627,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
// a method that subclasses can override to add behavior
protected void onPageEndMoving() {
mWasInOverscroll = false;
}
/**
@ -663,6 +666,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
if (isXBeforeFirstPage) {
super.scrollTo(0, y);
if (mAllowOverScroll) {
mWasInOverscroll = true;
if (isRtl) {
overScroll(x - mMaxScrollX);
} else {
@ -672,6 +676,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
} else if (isXAfterLastPage) {
super.scrollTo(mMaxScrollX, y);
if (mAllowOverScroll) {
mWasInOverscroll = true;
if (isRtl) {
overScroll(x);
} else {
@ -679,6 +684,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
}
} else {
if (mWasInOverscroll) {
overScroll(0);
mWasInOverscroll = false;
}
mOverScrollX = x;
super.scrollTo(x, y);
}
@ -1513,6 +1522,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mLastMotionXRemainder = 0;
mTouchX = getViewportOffsetX() + getScrollX();
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
onScrollInteractionBegin();
pageBeginMoving();
}
}
@ -1752,6 +1762,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mActivePointerId = ev.getPointerId(0);
if (mTouchState == TOUCH_STATE_SCROLLING) {
onScrollInteractionBegin();
pageBeginMoving();
}
break;
@ -1940,6 +1951,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
invalidate();
}
onScrollInteractionEnd();
} else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
@ -2025,6 +2037,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mActivePointerId = INVALID_POINTER;
}
/**
* Triggered by scrolling via touch
*/
protected void onScrollInteractionBegin() {
}
protected void onScrollInteractionEnd() {
}
protected void onUnhandledTap(MotionEvent ev) {
((Launcher) getContext()).onClick(this);
}

View File

@ -19,6 +19,7 @@ package com.android.launcher3;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@ -37,7 +38,7 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
private static final int sTransitionOutDuration = 175;
private ObjectAnimator mDropTargetBarAnim;
private ObjectAnimator mQSBSearchBarAnim;
private ValueAnimator mQSBSearchBarAnim;
private static final AccelerateInterpolator sAccelerateInterpolator =
new AccelerateInterpolator();
@ -70,28 +71,38 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
mInfoDropTarget.setLauncher(launcher);
mDeleteDropTarget.setLauncher(launcher);
mQSBSearchBar = launcher.getQsbBar();
if (mEnableDropDownDropTargets) {
mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0,
-mBarHeight);
if (mQSBSearchBar != null) {
if (mEnableDropDownDropTargets) {
mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0,
-mBarHeight);
} else {
mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
}
setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
} else {
mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
// Create a no-op animation of the search bar is null
mQSBSearchBarAnim = ValueAnimator.ofFloat(0, 0);
mQSBSearchBarAnim.setDuration(sTransitionInDuration);
}
setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
}
private void prepareStartAnimation(View v) {
// Enable the hw layers before the animation starts (will be disabled in the onAnimationEnd
// callback below)
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (v != null) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
}
private void setupAnimation(ObjectAnimator anim, final View v) {
private void setupAnimation(ValueAnimator anim, final View v) {
anim.setInterpolator(sAccelerateInterpolator);
anim.setDuration(sTransitionInDuration);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
if (v != null) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
});
}
@ -145,9 +156,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
mQSBSearchBarAnim.reverse();
} else {
mQSBSearchBarAnim.cancel();
if (mEnableDropDownDropTargets) {
if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
mQSBSearchBar.setTranslationY(0);
} else {
} else if (mQSBSearchBar != null) {
mQSBSearchBar.setAlpha(1f);
}
}
@ -161,9 +172,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
mQSBSearchBarAnim.start();
} else {
mQSBSearchBarAnim.cancel();
if (mEnableDropDownDropTargets) {
if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
mQSBSearchBar.setTranslationY(-mBarHeight);
} else {
} else if (mQSBSearchBar != null) {
mQSBSearchBar.setAlpha(0f);
}
}

View File

@ -67,6 +67,7 @@ import android.widget.TextView;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
@ -289,6 +290,12 @@ public class Workspace extends SmoothPagedView
private boolean mDeferDropAfterUninstall;
private boolean mUninstallSuccessful;
// State related to Launcher Overlay
LauncherOverlay mLauncherOverlay;
boolean mScrollInteractionBegan;
boolean mStartedSendingScrollEvents;
boolean mShouldSendPageSettled;
private final Runnable mBindPages = new Runnable() {
@Override
public void run() {
@ -1249,6 +1256,58 @@ public class Workspace extends SmoothPagedView
stripEmptyScreens();
mStripScreensOnPageStopMoving = false;
}
if (mShouldSendPageSettled) {
mLauncherOverlay.onScrollSettled();
mShouldSendPageSettled = false;
}
}
protected void onScrollInteractionBegin() {
super.onScrollInteractionEnd();
mScrollInteractionBegan = true;
}
protected void onScrollInteractionEnd() {
super.onScrollInteractionEnd();
mScrollInteractionBegan = false;
if (mStartedSendingScrollEvents) {
mStartedSendingScrollEvents = false;
mLauncherOverlay.onScrollInteractionEnd();
}
}
public void setLauncherOverlay(LauncherOverlay overlay) {
mLauncherOverlay = overlay;
}
@Override
protected void overScroll(float amount) {
boolean isRtl = isLayoutRtl();
boolean shouldOverScroll = (amount <= 0 && (!hasCustomContent() || isRtl)) ||
(amount >= 0 && (!hasCustomContent() || !isRtl));
boolean shouldScrollOverlay = (amount <= 0 && mLauncherOverlay != null && !isRtl) ||
(amount >= 0 && mLauncherOverlay != null && isRtl);
if (shouldScrollOverlay) {
if (!mStartedSendingScrollEvents && mScrollInteractionBegan) {
mStartedSendingScrollEvents = true;
mLauncherOverlay.onScrollInteractionBegin();
mShouldSendPageSettled = true;
}
int screenSize = getViewportWidth();
float f = (amount / screenSize);
int progress = (int) Math.abs((f * 100));
mLauncherOverlay.onScrollChange(progress, isRtl);
} else if (shouldOverScroll) {
dampedOverScroll(amount);
mOverScrollEffect = acceleratedOverFactor(amount);
} else {
mOverScrollEffect = 0;
}
}
@Override
@ -1710,18 +1769,6 @@ public class Workspace extends SmoothPagedView
}
}
@Override
protected void overScroll(float amount) {
boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) ||
(amount > 0 && (!hasCustomContent() || !isLayoutRtl()));
if (shouldOverScroll) {
dampedOverScroll(amount);
mOverScrollEffect = acceleratedOverFactor(amount);
} else {
mOverScrollEffect = 0;
}
}
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mWindowToken = getWindowToken();
@ -2353,10 +2400,6 @@ public class Workspace extends SmoothPagedView
.alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));
Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
.alpha(finalSearchBarAlpha).withLayer();
searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));
Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)
.alpha(finalOverviewPanelAlpha).withLayer();
overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));
@ -2364,11 +2407,9 @@ public class Workspace extends SmoothPagedView
// For animation optimations, we may need to provide the Launcher transition
// with a set of views on which to force build layers in certain scenarios.
hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (layerViews != null) {
layerViews.add(hotseat);
layerViews.add(searchBar);
layerViews.add(overviewPanel);
}
@ -2385,11 +2426,21 @@ public class Workspace extends SmoothPagedView
overviewPanelAlpha.setDuration(duration);
pageIndicatorAlpha.setDuration(duration);
hotseatAlpha.setDuration(duration);
searchBarAlpha.setDuration(duration);
if (searchBar != null) {
Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
.alpha(finalSearchBarAlpha).withLayer();
searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));
searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (layerViews != null) {
layerViews.add(searchBar);
}
searchBarAlpha.setDuration(duration);
anim.play(searchBarAlpha);
}
anim.play(overviewPanelAlpha);
anim.play(hotseatAlpha);
anim.play(searchBarAlpha);
anim.play(pageIndicatorAlpha);
anim.setStartDelay(delay);
} else {