From b5b9ad68b707154fcc2c3b04b1b6c0b17127e415 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Sat, 2 Apr 2016 11:23:39 -0700 Subject: Fading in the first screen, when launcher loads for the first time Bug: 29007436 Bug: 27705838 Change-Id: I95891d0bad19a67985b689bb96d6068dcd85004a --- src/com/android/launcher3/Launcher.java | 32 +++++++++++- src/com/android/launcher3/LauncherModel.java | 57 +++++++++++++++------- .../android/launcher3/util/ViewOnDrawExecutor.java | 22 +++++++-- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index d668d2a74..df856c1b6 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -465,7 +465,11 @@ public class Launcher extends Activity } else { // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground - mModel.startLoader(mWorkspace.getRestorePage()); + if (!mModel.startLoader(mWorkspace.getRestorePage())) { + // If we are not binding synchronously, show a fade in animation when + // the first page bind completes. + mDragLayer.setAlpha(0); + } } } @@ -4003,6 +4007,32 @@ public class Launcher extends Activity } } + @Override + public void finishFirstPageBind(final ViewOnDrawExecutor executor) { + Runnable r = new Runnable() { + public void run() { + finishFirstPageBind(executor); + } + }; + if (waitUntilResume(r)) { + return; + } + + Runnable onComplete = new Runnable() { + @Override + public void run() { + if (executor != null) { + executor.onLoadAnimationCompleted(); + } + } + }; + if (mDragLayer.getAlpha() < 1) { + mDragLayer.animate().alpha(1).withEndAction(onComplete).start(); + } else { + onComplete.run(); + } + } + /** * Callback saying that there aren't any more items to bind. * diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 456111115..e744e1868 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -195,6 +195,7 @@ public class LauncherModel extends BroadcastReceiver public void bindItems(ArrayList shortcuts, int start, int end, boolean forceAnimateIcons); public void bindScreens(ArrayList orderedScreenIds); + public void finishFirstPageBind(ViewOnDrawExecutor executor); public void finishBindingItems(); public void bindAppWidget(LauncherAppWidgetInfo info); public void bindAllApplications(ArrayList apps); @@ -1282,7 +1283,11 @@ public class LauncherModel extends BroadcastReceiver return (mCallbacks != null && mCallbacks.get() == callbacks); } - public void startLoader(int synchronousBindPage) { + /** + * Starts the loader. Tries to bind {@params synchronousBindPage} synchronously if possible. + * @return true if the page could be bound synchronously. + */ + public boolean startLoader(int synchronousBindPage) { // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems InstallShortcutReceiver.enableInstallQueue(); synchronized (mLock) { @@ -1302,12 +1307,14 @@ public class LauncherModel extends BroadcastReceiver if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded && mWorkspaceLoaded && mDeepShortcutsLoaded && !mIsLoaderTaskRunning) { mLoaderTask.runBindSynchronousPage(synchronousBindPage); + return true; } else { sWorkerThread.setPriority(Thread.NORM_PRIORITY); sWorker.post(mLoaderTask); } } } + return false; } public void stopLoader() { @@ -2508,17 +2515,19 @@ public class LauncherModel extends BroadcastReceiver orderedScreenIds.addAll(sBgWorkspaceScreens); } - final boolean isLoadingSynchronously = - synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE; - int currScreen = isLoadingSynchronously ? synchronizeBindPage : - oldCallbacks.getCurrentWorkspaceScreen(); - if (currScreen >= orderedScreenIds.size()) { - // There may be no workspace screens (just hotseat items and an empty page). - currScreen = PagedView.INVALID_RESTORE_PAGE; + final int currentScreen; + { + int currScreen = synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE + ? synchronizeBindPage : oldCallbacks.getCurrentWorkspaceScreen(); + if (currScreen >= orderedScreenIds.size()) { + // There may be no workspace screens (just hotseat items and an empty page). + currScreen = PagedView.INVALID_RESTORE_PAGE; + } + currentScreen = currScreen; } - final int currentScreen = currScreen; - final long currentScreenId = currentScreen < 0 - ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen); + final boolean validFirstPage = currentScreen >= 0; + final long currentScreenId = + validFirstPage ? orderedScreenIds.get(currentScreen) : INVALID_SCREEN_ID; // Separate the items that are on the current screen, and all the other remaining items ArrayList currentWorkspaceItems = new ArrayList<>(); @@ -2551,12 +2560,24 @@ public class LauncherModel extends BroadcastReceiver // Load items on the current page. bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, mainExecutor); - // In case of isLoadingSynchronously, only bind the first screen, and defer binding the - // remaining screens after first onDraw is called. This ensures that the first screen - // is immediately visible (eg. during rotation) - // In case of !isLoadingSynchronously, bind all pages one after other. - final Executor deferredExecutor = isLoadingSynchronously ? - new ViewOnDrawExecutor(mHandler) : mainExecutor; + // In case of validFirstPage, only bind the first screen, and defer binding the + // remaining screens after first onDraw (and an optional the fade animation whichever + // happens later). + // This ensures that the first screen is immediately visible (eg. during rotation) + // In case of !validFirstPage, bind all pages one after other. + final Executor deferredExecutor = + validFirstPage ? new ViewOnDrawExecutor(mHandler) : mainExecutor; + + mainExecutor.execute(new Runnable() { + @Override + public void run() { + Callbacks callbacks = tryGetCallbacks(oldCallbacks); + if (callbacks != null) { + callbacks.finishFirstPageBind( + validFirstPage ? (ViewOnDrawExecutor) deferredExecutor : null); + } + } + }); bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, deferredExecutor); @@ -2590,7 +2611,7 @@ public class LauncherModel extends BroadcastReceiver }; deferredExecutor.execute(r); - if (isLoadingSynchronously) { + if (validFirstPage) { r = new Runnable() { public void run() { Callbacks callbacks = tryGetCallbacks(oldCallbacks); diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java index 01808ba57..9bd288244 100644 --- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java +++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java @@ -16,6 +16,7 @@ package com.android.launcher3.util; +import android.util.Log; import android.view.View; import android.view.View.OnAttachStateChangeListener; import android.view.ViewTreeObserver.OnDrawListener; @@ -39,6 +40,9 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, private View mAttachedView; private boolean mCompleted; + private boolean mLoadAnimationCompleted; + private boolean mFirstDrawCompleted; + public ViewOnDrawExecutor(DeferredHandler handler) { mHandler = handler; } @@ -72,19 +76,31 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, @Override public void onDraw() { + mFirstDrawCompleted = true; mAttachedView.post(this); } + public void onLoadAnimationCompleted() { + mLoadAnimationCompleted = true; + if (mAttachedView != null) { + mAttachedView.post(this); + } + } + @Override public void run() { - for (final Runnable r : mTasks) { - mHandler.post(r); + // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called. + if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) { + for (final Runnable r : mTasks) { + mHandler.post(r); + } + markCompleted(); } - markCompleted(); } public void markCompleted() { mTasks.clear(); + mCompleted = true; if (mAttachedView != null) { mAttachedView.getViewTreeObserver().removeOnDrawListener(this); mAttachedView.removeOnAttachStateChangeListener(this); -- cgit v1.2.3