Merge "Responsive caret drawable" into ub-launcher3-calgary
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9f30752..2bc0cae 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -35,6 +35,8 @@
<string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
<!-- SafeMode widget error string -->
<string name="safemode_widget_error">Widgets disabled in Safe mode</string>
+ <!-- Message shown when a shortcut is not available. It could have been temporarily disabled and may start working again after some time. -->
+ <string name="shortcut_not_available">Shortcut isn\'t available</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d668d2a..78e0aa0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -465,7 +465,11 @@
} 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);
+ }
}
}
@@ -2655,6 +2659,8 @@
int error = R.string.activity_not_available;
if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
error = R.string.safemode_shortcut_error;
+ } else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0) {
+ error = R.string.shortcut_not_available;
}
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
return;
@@ -4003,6 +4009,32 @@
}
}
+ @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 17c39fa..b465b3a 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -195,6 +195,7 @@
public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,
boolean forceAnimateIcons);
public void bindScreens(ArrayList<Long> orderedScreenIds);
+ public void finishFirstPageBind(ViewOnDrawExecutor executor);
public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -1282,7 +1283,11 @@
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 @@
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 @@
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<ItemInfo> currentWorkspaceItems = new ArrayList<>();
@@ -2551,12 +2560,24 @@
// 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 @@
};
deferredExecutor.execute(r);
- if (isLoadingSynchronously) {
+ if (validFirstPage) {
r = new Runnable() {
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
@@ -2821,9 +2842,13 @@
// Now add the new shortcuts to the map.
for (ShortcutInfoCompat shortcut : shortcuts) {
- ComponentKey targetComponent
- = new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle());
- mBgDeepShortcutMap.addToList(targetComponent, shortcut.getId());
+ boolean shouldShowInContainer = shortcut.isEnabled()
+ && (shortcut.isDeclaredInManifest() || shortcut.isDynamic());
+ if (shouldShowInContainer) {
+ ComponentKey targetComponent
+ = new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle());
+ mBgDeepShortcutMap.addToList(targetComponent, shortcut.getId());
+ }
}
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index c87bc08..00ac9bd 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -100,22 +100,28 @@
/**
* Indicates that the icon is disabled due to safe mode restrictions.
*/
- public static final int FLAG_DISABLED_SAFEMODE = 1;
+ public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
/**
* Indicates that the icon is disabled as the app is not available.
*/
- public static final int FLAG_DISABLED_NOT_AVAILABLE = 2;
+ public static final int FLAG_DISABLED_NOT_AVAILABLE = 1 << 1;
/**
* Indicates that the icon is disabled as the app is suspended
*/
- public static final int FLAG_DISABLED_SUSPENDED = 4;
+ public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
/**
* Indicates that the icon is disabled as the user is in quiet mode.
*/
- public static final int FLAG_DISABLED_QUIET_USER = 8;
+ public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
+
+
+ /**
+ * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
+ */
+ public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
/**
* Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
@@ -293,6 +299,11 @@
}
contentDescription = UserManagerCompat.getInstance(context)
.getBadgedLabelForUser(label, user);
+ if (shortcutInfo.isEnabled()) {
+ isDisabled &= ~FLAG_DISABLED_BY_PUBLISHER;
+ } else {
+ isDisabled |= FLAG_DISABLED_BY_PUBLISHER;
+ }
LauncherAppState launcherAppState = LauncherAppState.getInstance();
Drawable unbadgedIcon = launcherAppState.getShortcutManager()
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 3a513f1..ba48f26 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -43,6 +43,7 @@
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
+import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
@@ -718,7 +719,8 @@
}
mIsOpen = false;
mDeferContainerRemoval = false;
- cleanupDeferredDrag(true);
+ // Make the original icon visible in All Apps, but not in Workspace or Folders.
+ cleanupDeferredDrag(mDeferredDragIcon.getTag() instanceof AppInfo);
mLauncher.getDragController().removeDragListener(this);
mLauncher.getDragLayer().removeView(this);
}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
index 00553df..d7fcda6 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -26,7 +26,6 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.util.ComponentKey;
/**
* Wrapper class for {@link android.content.pm.ShortcutInfo}, representing deep shortcuts into apps.
@@ -101,6 +100,14 @@
return mShortcutInfo.isDeclaredInManifest();
}
+ public boolean isEnabled() {
+ return mShortcutInfo.isEnabled();
+ }
+
+ public boolean isDynamic() {
+ return mShortcutInfo.isDynamic();
+ }
+
public int getRank() {
return mShortcutInfo.getRank();
}
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 01808ba..9bd2882 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 @@
private View mAttachedView;
private boolean mCompleted;
+ private boolean mLoadAnimationCompleted;
+ private boolean mFirstDrawCompleted;
+
public ViewOnDrawExecutor(DeferredHandler handler) {
mHandler = handler;
}
@@ -72,19 +76,31 @@
@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);