summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml20
-rw-r--r--res/layout-land/launcher.xml7
-rw-r--r--res/layout-port/launcher.xml7
-rw-r--r--res/layout-sw720dp/launcher.xml8
-rw-r--r--res/layout/launcher_overlay.xml20
-rw-r--r--res/layout/launcher_overlay_example.xml37
-rw-r--r--src/com/android/launcher3/DragLayer.java14
-rw-r--r--src/com/android/launcher3/Launcher.java97
-rw-r--r--src/com/android/launcher3/LauncherCallbacks.java19
-rw-r--r--src/com/android/launcher3/LauncherExtension.java354
-rw-r--r--src/com/android/launcher3/PagedView.java21
-rw-r--r--src/com/android/launcher3/SearchDropTargetBar.java37
-rw-r--r--src/com/android/launcher3/Workspace.java97
13 files changed, 695 insertions, 43 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 246b4db2d..f3425fe44 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -95,7 +95,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" />
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index a865bc6ca..d2088d819 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -85,4 +85,11 @@
android:layout_height="match_parent"
android:visibility="gone" />
</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>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 09da8fcd7..a0570720d 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -105,4 +105,11 @@
android:layout_height="match_parent"
android:visibility="gone" />
</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>
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 3a7f8c05e..36e76dd88 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -104,4 +104,12 @@
android:layout_height="match_parent"
android:visibility="gone" />
</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>
diff --git a/res/layout/launcher_overlay.xml b/res/layout/launcher_overlay.xml
new file mode 100644
index 000000000..9ef0c9a97
--- /dev/null
+++ b/res/layout/launcher_overlay.xml
@@ -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" /> \ No newline at end of file
diff --git a/res/layout/launcher_overlay_example.xml b/res/layout/launcher_overlay_example.xml
new file mode 100644
index 000000000..422f2811a
--- /dev/null
+++ b/res/layout/launcher_overlay_example.xml
@@ -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>
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 328c31173..1ded03038 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -90,6 +90,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.
*
@@ -219,11 +221,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)) {
@@ -366,6 +376,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;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0d964e206..58a09a435 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -98,6 +98,7 @@ import android.view.View;
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;
@@ -263,6 +264,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;
@@ -582,6 +587,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);
+ }
}
IntentFilter protectedAppsFilter = new IntentFilter(
"cyanogenmod.intent.action.PROTECTED_COMPONENT_UPDATE");
@@ -1323,6 +1335,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();
@@ -4743,11 +4833,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) {
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index aef2adc7f..e0cfa27ba 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -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);
+
}
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java
new file mode 100644
index 000000000..10bbd357d
--- /dev/null
+++ b/src/com/android/launcher3/LauncherExtension.java
@@ -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;
+ }
+ };
+ }
+}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index c456f06d6..ec69b7f8f 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -207,6 +207,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;
@@ -645,6 +647,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mDelayedSnapToPageRunnable.run();
mDelayedSnapToPageRunnable = null;
}
+ mWasInOverscroll = false;
}
/**
@@ -683,6 +686,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 {
@@ -692,6 +696,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 {
@@ -699,6 +704,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
}
} else {
+ if (mWasInOverscroll) {
+ overScroll(0);
+ mWasInOverscroll = false;
+ }
mOverScrollX = x;
super.scrollTo(x, y);
}
@@ -1608,6 +1617,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mLastMotionXRemainder = 0;
mTouchX = getViewportOffsetX() + getScrollX();
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+ onScrollInteractionBegin();
pageBeginMoving();
}
}
@@ -1847,6 +1857,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
mActivePointerId = ev.getPointerId(0);
if (mTouchState == TOUCH_STATE_SCROLLING) {
+ onScrollInteractionBegin();
pageBeginMoving();
}
break;
@@ -2036,6 +2047,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
@@ -2121,6 +2133,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);
}
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index 611948d29..1d90a4178 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -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();
@@ -78,28 +79,38 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
public void setupQSB(Launcher launcher) {
mLauncher = 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);
+ }
}
});
}
@@ -153,9 +164,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);
}
}
@@ -169,9 +180,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);
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 60200177d..2cbbaa702 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -70,6 +70,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;
@@ -295,6 +296,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() {
@@ -1284,6 +1291,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
@@ -1769,18 +1828,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();
@@ -2493,12 +2540,6 @@ public class Workspace extends SmoothPagedView
hotseatAlpha.addListener(
new AlphaUpdateListener(hotseat, finalHotseatAndPageIndicatorAlpha));
- Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
- .alpha(finalSearchBarAlpha).withLayer();
- if (mShowSearchBar) {
- searchBarAlpha.addListener(new AlphaUpdateListener(searchBar, finalSearchBarAlpha));
- }
-
Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)
.alpha(finalOverviewPanelAlpha).withLayer();
overviewPanelAlpha.addListener(
@@ -2507,11 +2548,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);
}
@@ -2528,7 +2567,20 @@ 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, finalSearchBarAlpha));
+ searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (layerViews != null) {
+ layerViews.add(searchBar);
+ }
+ searchBarAlpha.setDuration(duration);
+ if (mShowSearchBar && !mLauncher.getDragController().isDragging()) {
+ anim.play(searchBarAlpha);
+ }
+ }
float mOverviewPanelSlideScale = 1.0f;
@@ -2576,9 +2628,6 @@ public class Workspace extends SmoothPagedView
// Animation animation = AnimationUtils.loadAnimation(mLauncher, R.anim.drop_down);
// overviewPanel.startAnimation(animation);
anim.play(hotseatAlpha);
- if (mShowSearchBar && !mLauncher.getDragController().isDragging()) {
- anim.play(searchBarAlpha);
- }
anim.play(pageIndicatorAlpha);
anim.setStartDelay(delay);
} else {