Loading src/com/android/launcher3/Launcher.java +0 −1 Original line number Diff line number Diff line Loading @@ -917,7 +917,6 @@ public class Launcher extends BaseActivity } updateInteraction(Workspace.State.NORMAL, mWorkspace.getState()); mWorkspace.onResume(); // Process any items that were added while Launcher was away. InstallShortcutReceiver.disableAndFlushInstallQueue( Loading src/com/android/launcher3/Workspace.java +0 −4 Original line number Diff line number Diff line Loading @@ -1454,10 +1454,6 @@ public class Workspace extends PagedView mWallpaperOffset.setWindowToken(null); } protected void onResume() { mWallpaperOffset.onResume(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (mUnlockWallpaperFromDefaultPageOnLayout) { Loading src/com/android/launcher3/util/WallpaperOffsetInterpolator.java +164 −131 Original line number Diff line number Diff line package com.android.launcher3.util; import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; Loading @@ -13,60 +19,30 @@ import com.android.launcher3.Workspace; /** * Utility class to handle wallpaper scrolling along with workspace. */ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback { public class WallpaperOffsetInterpolator extends BroadcastReceiver { private static final int[] sTempInt = new int[2]; private static final String TAG = "WPOffsetInterpolator"; private static final int ANIMATION_DURATION = 250; // Don't use all the wallpaper for parallax until you have at least this many pages private static final int MIN_PARALLAX_PAGE_SPAN = 4; private final Choreographer mChoreographer; private final Interpolator mInterpolator; private final WallpaperManager mWallpaperManager; private final Workspace mWorkspace; private final boolean mIsRtl; private final Handler mHandler; private boolean mRegistered = false; private IBinder mWindowToken; private boolean mWallpaperIsLiveWallpaper; private float mLastSetWallpaperOffsetSteps = 0; private float mFinalOffset = 0.0f; private float mCurrentOffset = 0.5f; // to force an initial update private boolean mWaitingForUpdate; private boolean mLockedToDefaultPage; private boolean mAnimating; private long mAnimationStartTime; private float mAnimationStartOffset; int mNumScreens; int mNumPagesForWallpaperParallax; private int mNumScreens; public WallpaperOffsetInterpolator(Workspace workspace) { mChoreographer = Choreographer.getInstance(); mInterpolator = new DecelerateInterpolator(1.5f); mWorkspace = workspace; mWallpaperManager = WallpaperManager.getInstance(workspace.getContext()); mIsRtl = Utilities.isRtl(workspace.getResources()); } @Override public void doFrame(long frameTimeNanos) { updateOffset(false); } private void updateOffset(boolean force) { if (mWaitingForUpdate || force) { mWaitingForUpdate = false; if (computeScrollOffset() && mWindowToken != null) { try { mWallpaperManager.setWallpaperOffsets(mWindowToken, getCurrX(), 0.5f); setWallpaperOffsetSteps(); } catch (IllegalArgumentException e) { Log.e(TAG, "Error updating wallpaper offset: " + e); } } } mHandler = new OffsetHandler(workspace.getContext()); } /** Loading @@ -80,46 +56,25 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback return mLockedToDefaultPage; } public boolean computeScrollOffset() { final float oldOffset = mCurrentOffset; if (mAnimating) { long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime; float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; float t1 = mInterpolator.getInterpolation(t0); mCurrentOffset = mAnimationStartOffset + (mFinalOffset - mAnimationStartOffset) * t1; mAnimating = durationSinceAnimation < ANIMATION_DURATION; } else { mCurrentOffset = mFinalOffset; } if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) { scheduleUpdate(); } if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) { return true; } return false; } /** * Computes the wallpaper offset as an int ratio (out[0] / out[1]) * * TODO: do different behavior if it's a live wallpaper? */ public float wallpaperOffsetForScroll(int scroll) { private void wallpaperOffsetForScroll(int scroll, int numScrollingPages, final int[] out) { out[1] = 1; // To match the default wallpaper behavior in the system, we default to either the left // or right edge on initialization int numScrollingPages = getNumScreensExcludingEmpty(); if (mLockedToDefaultPage || numScrollingPages <= 1) { return mIsRtl ? 1f : 0f; out[0] = mIsRtl ? 1 : 0; return; } // Distribute the wallpaper parallax over a minimum of MIN_PARALLAX_PAGE_SPAN workspace // screens, not including the custom screen, and empty screens (if > MIN_PARALLAX_PAGE_SPAN) if (mWallpaperIsLiveWallpaper) { mNumPagesForWallpaperParallax = numScrollingPages; } else { mNumPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); } int numPagesForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollingPages : Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); // Offset by the custom screen int leftPageIndex; Loading @@ -136,106 +91,184 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback int leftPageScrollX = mWorkspace.getScrollForPage(leftPageIndex); int rightPageScrollX = mWorkspace.getScrollForPage(rightPageIndex); int scrollRange = rightPageScrollX - leftPageScrollX; if (scrollRange == 0) { return 0f; if (scrollRange <= 0) { out[0] = 0; return; } // Sometimes the left parameter of the pages is animated during a layout transition; // this parameter offsets it to keep the wallpaper from animating as well int adjustedScroll = scroll - leftPageScrollX - mWorkspace.getLayoutTransitionOffsetForPage(0); float offset = Utilities.boundToRange((float) adjustedScroll / scrollRange, 0f, 1f); adjustedScroll = Utilities.boundToRange(adjustedScroll, 0, scrollRange); out[1] = (numPagesForWallpaperParallax - 1) * scrollRange; // The offset is now distributed 0..1 between the left and right pages that we care about, // so we just map that between the pages that we are using for parallax float rtlOffset = 0; int rtlOffset = 0; if (mIsRtl) { // In RTL, the pages are right aligned, so adjust the offset from the end rtlOffset = (float) ((mNumPagesForWallpaperParallax - 1) - (numScrollingPages - 1)) / (mNumPagesForWallpaperParallax - 1); rtlOffset = out[1] - (numScrollingPages - 1) * scrollRange; } return rtlOffset + offset * ((float) (numScrollingPages - 1) / (mNumPagesForWallpaperParallax - 1)); out[0] = rtlOffset + adjustedScroll * (numScrollingPages - 1); } private float wallpaperOffsetForCurrentScroll() { return wallpaperOffsetForScroll(mWorkspace.getScrollX()); public float wallpaperOffsetForScroll(int scroll) { wallpaperOffsetForScroll(scroll, getNumScreensExcludingEmpty(), sTempInt); return ((float) sTempInt[0]) / sTempInt[1]; } private int numEmptyScreensToIgnore() { private int getNumScreensExcludingEmpty() { int numScrollingPages = mWorkspace.getChildCount(); if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) { return 1; return numScrollingPages - 1; } else { return 0; return numScrollingPages; } } private int getNumScreensExcludingEmpty() { return mWorkspace.getChildCount() - numEmptyScreensToIgnore(); public void syncWithScroll() { int numScreens = getNumScreensExcludingEmpty(); wallpaperOffsetForScroll(mWorkspace.getScrollX(), numScreens, sTempInt); Message msg = Message.obtain(mHandler, MSG_UPDATE_OFFSET, sTempInt[0], sTempInt[1], mWindowToken); if (numScreens != mNumScreens) { if (mNumScreens > 0) { // Don't animate if we're going from 0 screens msg.what = MSG_START_ANIMATION; } mNumScreens = numScreens; updateOffset(); } msg.sendToTarget(); } public void syncWithScroll() { float offset = wallpaperOffsetForCurrentScroll(); setFinalX(offset); updateOffset(true); private void updateOffset() { int numPagesForWallpaperParallax; if (mWallpaperIsLiveWallpaper) { numPagesForWallpaperParallax = mNumScreens; } else { numPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, mNumScreens); } Message.obtain(mHandler, MSG_SET_NUM_PARALLAX, numPagesForWallpaperParallax, 0, mWindowToken).sendToTarget(); } public float getCurrX() { return mCurrentOffset; public void jumpToFinal() { Message.obtain(mHandler, MSG_JUMP_TO_FINAL, mWindowToken).sendToTarget(); } public float getFinalX() { return mFinalOffset; public void setWindowToken(IBinder token) { mWindowToken = token; if (mWindowToken == null && mRegistered) { mWorkspace.getContext().unregisterReceiver(this); mRegistered = false; } else if (mWindowToken != null && !mRegistered) { mWorkspace.getContext() .registerReceiver(this, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED)); onReceive(mWorkspace.getContext(), null); mRegistered = true; } } private void animateToFinal() { mAnimating = true; mAnimationStartOffset = mCurrentOffset; mAnimationStartTime = System.currentTimeMillis(); @Override public void onReceive(Context context, Intent intent) { mWallpaperIsLiveWallpaper = WallpaperManager.getInstance(mWorkspace.getContext()).getWallpaperInfo() != null; updateOffset(); } private void setWallpaperOffsetSteps() { // Set wallpaper offset steps (1 / (number of screens - 1)) float xOffset = 1.0f / (mNumPagesForWallpaperParallax - 1); if (xOffset != mLastSetWallpaperOffsetSteps) { mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f); mLastSetWallpaperOffsetSteps = xOffset; private static final int MSG_START_ANIMATION = 1; private static final int MSG_UPDATE_OFFSET = 2; private static final int MSG_APPLY_OFFSET = 3; private static final int MSG_SET_NUM_PARALLAX = 4; private static final int MSG_JUMP_TO_FINAL = 5; private static class OffsetHandler extends Handler { private final Interpolator mInterpolator; private final WallpaperManager mWM; private float mCurrentOffset = 0.5f; // to force an initial update private boolean mAnimating; private long mAnimationStartTime; private float mAnimationStartOffset; private float mFinalOffset; private float mOffsetX; public OffsetHandler(Context context) { super(UiThreadHelper.getBackgroundLooper()); mInterpolator = new DecelerateInterpolator(1.5f); mWM = WallpaperManager.getInstance(context); } @Override public void handleMessage(Message msg) { final IBinder token = (IBinder) msg.obj; if (token == null) { return; } public void setFinalX(float x) { scheduleUpdate(); mFinalOffset = Math.max(0f, Math.min(x, 1f)); if (getNumScreensExcludingEmpty() != mNumScreens) { if (mNumScreens > 0 && Float.compare(mCurrentOffset, mFinalOffset) != 0) { // Don't animate if we're going from 0 screens, or if the final offset is the same // as the current offset animateToFinal(); switch (msg.what) { case MSG_START_ANIMATION: { mAnimating = true; mAnimationStartOffset = mCurrentOffset; mAnimationStartTime = msg.getWhen(); // Follow through } case MSG_UPDATE_OFFSET: mFinalOffset = ((float) msg.arg1) / msg.arg2; // Follow through case MSG_APPLY_OFFSET: { float oldOffset = mCurrentOffset; if (mAnimating) { long durationSinceAnimation = SystemClock.uptimeMillis() - mAnimationStartTime; float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; float t1 = mInterpolator.getInterpolation(t0); mCurrentOffset = mAnimationStartOffset + (mFinalOffset - mAnimationStartOffset) * t1; mAnimating = durationSinceAnimation < ANIMATION_DURATION; } else { mCurrentOffset = mFinalOffset; } mNumScreens = getNumScreensExcludingEmpty(); if (Float.compare(mCurrentOffset, oldOffset) != 0) { setOffsetSafely(token); // Force the wallpaper offset steps to be set again, because another app // might have changed them mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); } if (mAnimating) { // If we are animating, keep updating the offset Message.obtain(this, MSG_APPLY_OFFSET, token).sendToTarget(); } private void scheduleUpdate() { if (!mWaitingForUpdate) { mChoreographer.postFrameCallback(this); mWaitingForUpdate = true; return; } case MSG_SET_NUM_PARALLAX: { // Set wallpaper offset steps (1 / (number of screens - 1)) mOffsetX = 1.0f / (msg.arg1 - 1); mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); return; } public void jumpToFinal() { case MSG_JUMP_TO_FINAL: { if (Float.compare(mCurrentOffset, mFinalOffset) != 0) { mCurrentOffset = mFinalOffset; setOffsetSafely(token); } mAnimating = false; return; } } public void onResume() { mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null; // Force the wallpaper offset steps to be set again, because another app might have changed // them mLastSetWallpaperOffsetSteps = 0f; } public void setWindowToken(IBinder token) { mWindowToken = token; private void setOffsetSafely(IBinder token) { try { mWM.setWallpaperOffsets(token, mCurrentOffset, 0.5f); } catch (IllegalArgumentException e) { Log.e(TAG, "Error updating wallpaper offset: " + e); } } } } No newline at end of file Loading
src/com/android/launcher3/Launcher.java +0 −1 Original line number Diff line number Diff line Loading @@ -917,7 +917,6 @@ public class Launcher extends BaseActivity } updateInteraction(Workspace.State.NORMAL, mWorkspace.getState()); mWorkspace.onResume(); // Process any items that were added while Launcher was away. InstallShortcutReceiver.disableAndFlushInstallQueue( Loading
src/com/android/launcher3/Workspace.java +0 −4 Original line number Diff line number Diff line Loading @@ -1454,10 +1454,6 @@ public class Workspace extends PagedView mWallpaperOffset.setWindowToken(null); } protected void onResume() { mWallpaperOffset.onResume(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (mUnlockWallpaperFromDefaultPageOnLayout) { Loading
src/com/android/launcher3/util/WallpaperOffsetInterpolator.java +164 −131 Original line number Diff line number Diff line package com.android.launcher3.util; import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; Loading @@ -13,60 +19,30 @@ import com.android.launcher3.Workspace; /** * Utility class to handle wallpaper scrolling along with workspace. */ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback { public class WallpaperOffsetInterpolator extends BroadcastReceiver { private static final int[] sTempInt = new int[2]; private static final String TAG = "WPOffsetInterpolator"; private static final int ANIMATION_DURATION = 250; // Don't use all the wallpaper for parallax until you have at least this many pages private static final int MIN_PARALLAX_PAGE_SPAN = 4; private final Choreographer mChoreographer; private final Interpolator mInterpolator; private final WallpaperManager mWallpaperManager; private final Workspace mWorkspace; private final boolean mIsRtl; private final Handler mHandler; private boolean mRegistered = false; private IBinder mWindowToken; private boolean mWallpaperIsLiveWallpaper; private float mLastSetWallpaperOffsetSteps = 0; private float mFinalOffset = 0.0f; private float mCurrentOffset = 0.5f; // to force an initial update private boolean mWaitingForUpdate; private boolean mLockedToDefaultPage; private boolean mAnimating; private long mAnimationStartTime; private float mAnimationStartOffset; int mNumScreens; int mNumPagesForWallpaperParallax; private int mNumScreens; public WallpaperOffsetInterpolator(Workspace workspace) { mChoreographer = Choreographer.getInstance(); mInterpolator = new DecelerateInterpolator(1.5f); mWorkspace = workspace; mWallpaperManager = WallpaperManager.getInstance(workspace.getContext()); mIsRtl = Utilities.isRtl(workspace.getResources()); } @Override public void doFrame(long frameTimeNanos) { updateOffset(false); } private void updateOffset(boolean force) { if (mWaitingForUpdate || force) { mWaitingForUpdate = false; if (computeScrollOffset() && mWindowToken != null) { try { mWallpaperManager.setWallpaperOffsets(mWindowToken, getCurrX(), 0.5f); setWallpaperOffsetSteps(); } catch (IllegalArgumentException e) { Log.e(TAG, "Error updating wallpaper offset: " + e); } } } mHandler = new OffsetHandler(workspace.getContext()); } /** Loading @@ -80,46 +56,25 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback return mLockedToDefaultPage; } public boolean computeScrollOffset() { final float oldOffset = mCurrentOffset; if (mAnimating) { long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime; float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; float t1 = mInterpolator.getInterpolation(t0); mCurrentOffset = mAnimationStartOffset + (mFinalOffset - mAnimationStartOffset) * t1; mAnimating = durationSinceAnimation < ANIMATION_DURATION; } else { mCurrentOffset = mFinalOffset; } if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) { scheduleUpdate(); } if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) { return true; } return false; } /** * Computes the wallpaper offset as an int ratio (out[0] / out[1]) * * TODO: do different behavior if it's a live wallpaper? */ public float wallpaperOffsetForScroll(int scroll) { private void wallpaperOffsetForScroll(int scroll, int numScrollingPages, final int[] out) { out[1] = 1; // To match the default wallpaper behavior in the system, we default to either the left // or right edge on initialization int numScrollingPages = getNumScreensExcludingEmpty(); if (mLockedToDefaultPage || numScrollingPages <= 1) { return mIsRtl ? 1f : 0f; out[0] = mIsRtl ? 1 : 0; return; } // Distribute the wallpaper parallax over a minimum of MIN_PARALLAX_PAGE_SPAN workspace // screens, not including the custom screen, and empty screens (if > MIN_PARALLAX_PAGE_SPAN) if (mWallpaperIsLiveWallpaper) { mNumPagesForWallpaperParallax = numScrollingPages; } else { mNumPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); } int numPagesForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollingPages : Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); // Offset by the custom screen int leftPageIndex; Loading @@ -136,106 +91,184 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback int leftPageScrollX = mWorkspace.getScrollForPage(leftPageIndex); int rightPageScrollX = mWorkspace.getScrollForPage(rightPageIndex); int scrollRange = rightPageScrollX - leftPageScrollX; if (scrollRange == 0) { return 0f; if (scrollRange <= 0) { out[0] = 0; return; } // Sometimes the left parameter of the pages is animated during a layout transition; // this parameter offsets it to keep the wallpaper from animating as well int adjustedScroll = scroll - leftPageScrollX - mWorkspace.getLayoutTransitionOffsetForPage(0); float offset = Utilities.boundToRange((float) adjustedScroll / scrollRange, 0f, 1f); adjustedScroll = Utilities.boundToRange(adjustedScroll, 0, scrollRange); out[1] = (numPagesForWallpaperParallax - 1) * scrollRange; // The offset is now distributed 0..1 between the left and right pages that we care about, // so we just map that between the pages that we are using for parallax float rtlOffset = 0; int rtlOffset = 0; if (mIsRtl) { // In RTL, the pages are right aligned, so adjust the offset from the end rtlOffset = (float) ((mNumPagesForWallpaperParallax - 1) - (numScrollingPages - 1)) / (mNumPagesForWallpaperParallax - 1); rtlOffset = out[1] - (numScrollingPages - 1) * scrollRange; } return rtlOffset + offset * ((float) (numScrollingPages - 1) / (mNumPagesForWallpaperParallax - 1)); out[0] = rtlOffset + adjustedScroll * (numScrollingPages - 1); } private float wallpaperOffsetForCurrentScroll() { return wallpaperOffsetForScroll(mWorkspace.getScrollX()); public float wallpaperOffsetForScroll(int scroll) { wallpaperOffsetForScroll(scroll, getNumScreensExcludingEmpty(), sTempInt); return ((float) sTempInt[0]) / sTempInt[1]; } private int numEmptyScreensToIgnore() { private int getNumScreensExcludingEmpty() { int numScrollingPages = mWorkspace.getChildCount(); if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) { return 1; return numScrollingPages - 1; } else { return 0; return numScrollingPages; } } private int getNumScreensExcludingEmpty() { return mWorkspace.getChildCount() - numEmptyScreensToIgnore(); public void syncWithScroll() { int numScreens = getNumScreensExcludingEmpty(); wallpaperOffsetForScroll(mWorkspace.getScrollX(), numScreens, sTempInt); Message msg = Message.obtain(mHandler, MSG_UPDATE_OFFSET, sTempInt[0], sTempInt[1], mWindowToken); if (numScreens != mNumScreens) { if (mNumScreens > 0) { // Don't animate if we're going from 0 screens msg.what = MSG_START_ANIMATION; } mNumScreens = numScreens; updateOffset(); } msg.sendToTarget(); } public void syncWithScroll() { float offset = wallpaperOffsetForCurrentScroll(); setFinalX(offset); updateOffset(true); private void updateOffset() { int numPagesForWallpaperParallax; if (mWallpaperIsLiveWallpaper) { numPagesForWallpaperParallax = mNumScreens; } else { numPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, mNumScreens); } Message.obtain(mHandler, MSG_SET_NUM_PARALLAX, numPagesForWallpaperParallax, 0, mWindowToken).sendToTarget(); } public float getCurrX() { return mCurrentOffset; public void jumpToFinal() { Message.obtain(mHandler, MSG_JUMP_TO_FINAL, mWindowToken).sendToTarget(); } public float getFinalX() { return mFinalOffset; public void setWindowToken(IBinder token) { mWindowToken = token; if (mWindowToken == null && mRegistered) { mWorkspace.getContext().unregisterReceiver(this); mRegistered = false; } else if (mWindowToken != null && !mRegistered) { mWorkspace.getContext() .registerReceiver(this, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED)); onReceive(mWorkspace.getContext(), null); mRegistered = true; } } private void animateToFinal() { mAnimating = true; mAnimationStartOffset = mCurrentOffset; mAnimationStartTime = System.currentTimeMillis(); @Override public void onReceive(Context context, Intent intent) { mWallpaperIsLiveWallpaper = WallpaperManager.getInstance(mWorkspace.getContext()).getWallpaperInfo() != null; updateOffset(); } private void setWallpaperOffsetSteps() { // Set wallpaper offset steps (1 / (number of screens - 1)) float xOffset = 1.0f / (mNumPagesForWallpaperParallax - 1); if (xOffset != mLastSetWallpaperOffsetSteps) { mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f); mLastSetWallpaperOffsetSteps = xOffset; private static final int MSG_START_ANIMATION = 1; private static final int MSG_UPDATE_OFFSET = 2; private static final int MSG_APPLY_OFFSET = 3; private static final int MSG_SET_NUM_PARALLAX = 4; private static final int MSG_JUMP_TO_FINAL = 5; private static class OffsetHandler extends Handler { private final Interpolator mInterpolator; private final WallpaperManager mWM; private float mCurrentOffset = 0.5f; // to force an initial update private boolean mAnimating; private long mAnimationStartTime; private float mAnimationStartOffset; private float mFinalOffset; private float mOffsetX; public OffsetHandler(Context context) { super(UiThreadHelper.getBackgroundLooper()); mInterpolator = new DecelerateInterpolator(1.5f); mWM = WallpaperManager.getInstance(context); } @Override public void handleMessage(Message msg) { final IBinder token = (IBinder) msg.obj; if (token == null) { return; } public void setFinalX(float x) { scheduleUpdate(); mFinalOffset = Math.max(0f, Math.min(x, 1f)); if (getNumScreensExcludingEmpty() != mNumScreens) { if (mNumScreens > 0 && Float.compare(mCurrentOffset, mFinalOffset) != 0) { // Don't animate if we're going from 0 screens, or if the final offset is the same // as the current offset animateToFinal(); switch (msg.what) { case MSG_START_ANIMATION: { mAnimating = true; mAnimationStartOffset = mCurrentOffset; mAnimationStartTime = msg.getWhen(); // Follow through } case MSG_UPDATE_OFFSET: mFinalOffset = ((float) msg.arg1) / msg.arg2; // Follow through case MSG_APPLY_OFFSET: { float oldOffset = mCurrentOffset; if (mAnimating) { long durationSinceAnimation = SystemClock.uptimeMillis() - mAnimationStartTime; float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; float t1 = mInterpolator.getInterpolation(t0); mCurrentOffset = mAnimationStartOffset + (mFinalOffset - mAnimationStartOffset) * t1; mAnimating = durationSinceAnimation < ANIMATION_DURATION; } else { mCurrentOffset = mFinalOffset; } mNumScreens = getNumScreensExcludingEmpty(); if (Float.compare(mCurrentOffset, oldOffset) != 0) { setOffsetSafely(token); // Force the wallpaper offset steps to be set again, because another app // might have changed them mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); } if (mAnimating) { // If we are animating, keep updating the offset Message.obtain(this, MSG_APPLY_OFFSET, token).sendToTarget(); } private void scheduleUpdate() { if (!mWaitingForUpdate) { mChoreographer.postFrameCallback(this); mWaitingForUpdate = true; return; } case MSG_SET_NUM_PARALLAX: { // Set wallpaper offset steps (1 / (number of screens - 1)) mOffsetX = 1.0f / (msg.arg1 - 1); mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); return; } public void jumpToFinal() { case MSG_JUMP_TO_FINAL: { if (Float.compare(mCurrentOffset, mFinalOffset) != 0) { mCurrentOffset = mFinalOffset; setOffsetSafely(token); } mAnimating = false; return; } } public void onResume() { mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null; // Force the wallpaper offset steps to be set again, because another app might have changed // them mLastSetWallpaperOffsetSteps = 0f; } public void setWindowToken(IBinder token) { mWindowToken = token; private void setOffsetSafely(IBinder token) { try { mWM.setWallpaperOffsets(token, mCurrentOffset, 0.5f); } catch (IllegalArgumentException e) { Log.e(TAG, "Error updating wallpaper offset: " + e); } } } } No newline at end of file