Merge "Widget resizing can now displace items"
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
index 0199d01..0c5bbeb 100644
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -436,6 +436,8 @@
private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
ViewGroup parent = (ViewGroup) getParent();
+ if (parent == null) return;
+
final int count = parent.getChildCount();
if (!isChildrenDrawingOrderEnabled()) {
for (int i = 0; i < count; i++) {
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 7e4225b..d8ea6ef 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -38,6 +38,7 @@
public class DeleteDropTarget extends ButtonDropTarget {
private static int DELETE_ANIMATION_DURATION = 285;
+ private static int FLIND_DELETE_ANIMATION_DURATION = 350;
private static int MODE_FLING_DELETE_TO_TRASH = 0;
private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
@@ -307,7 +308,7 @@
private long mPrevTime;
private boolean mHasOffsetForScale;
- private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(1.5f);
+ private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
long startTime) {
@@ -373,7 +374,7 @@
final ViewConfiguration config = ViewConfiguration.get(mLauncher);
final DragLayer dragLayer = mLauncher.getDragLayer();
- final int duration = DELETE_ANIMATION_DURATION;
+ final int duration = FLIND_DELETE_ANIMATION_DURATION;
final long startTime = AnimationUtils.currentAnimationTimeMillis();
// NOTE: Because it takes time for the first frame of animation to actually be
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 2a1d65a..f2db487 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -63,7 +63,7 @@
static final int SCROLL_RIGHT = 1;
private static final float MAX_FLING_DEGREES = 35f;
- private static final int FLING_TO_DELETE_THRESHOLD_Y_VELOCITY = -1400;
+ private static final int FLING_TO_DELETE_THRESHOLD_Y_VELOCITY = -1500;
private Launcher mLauncher;
private Handler mHandler;
@@ -111,6 +111,7 @@
private InputMethodManager mInputMethodManager;
private int mLastTouch[] = new int[2];
+ private long mLastTouchUpTime = -1;
private int mDistanceSinceScroll = 0;
private int mTmpPoint[] = new int[2];
@@ -440,6 +441,18 @@
return mTmpPoint;
}
+ long getLastGestureUpTime() {
+ if (mDragging) {
+ return System.currentTimeMillis();
+ } else {
+ return mLastTouchUpTime;
+ }
+ }
+
+ void resetLastGestureUpTime() {
+ mLastTouchUpTime = -1;
+ }
+
/**
* Call this from a drag source view.
*/
@@ -467,6 +480,7 @@
mLastDropTarget = null;
break;
case MotionEvent.ACTION_UP:
+ mLastTouchUpTime = System.currentTimeMillis();
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);
if (vec != null) {
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 5636f99..a6aa595 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -22,7 +22,6 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 4c0974f..19b1c69 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -56,7 +56,6 @@
String spKey = LauncherApplication.getSharedPreferencesKey();
SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- final int screen = Launcher.getScreen();
final Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
if (intent == null) {
return;
@@ -74,17 +73,23 @@
}
}
- final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
- final boolean exists = LauncherModel.shortcutExists(context, name, intent);
+ // Lock on the app so that we don't try and get the items while apps are being added
+ LauncherApplication app = (LauncherApplication) context.getApplicationContext();
final int[] result = {INSTALL_SHORTCUT_SUCCESSFUL};
-
- // Try adding the target to the workspace screens incrementally, starting at the current
- // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
boolean found = false;
- for (int i = 0; i < (2 * Launcher.SCREEN_COUNT) + 1 && !found; ++i) {
- int si = screen + (int) ((i / 2f) + 0.5f) * ((i % 2 == 1) ? 1 : -1);
- if (0 <= si && si < Launcher.SCREEN_COUNT) {
- found = installShortcut(context, data, items, name, intent, si, exists, sp, result);
+ synchronized (app) {
+ final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
+ final boolean exists = LauncherModel.shortcutExists(context, name, intent);
+
+ // Try adding to the workspace screens incrementally, starting at the default or center
+ // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
+ final int screen = Launcher.DEFAULT_SCREEN;
+ for (int i = 0; i < (2 * Launcher.SCREEN_COUNT) + 1 && !found; ++i) {
+ int si = screen + (int) ((i / 2f) + 0.5f) * ((i % 2 == 1) ? 1 : -1);
+ if (0 <= si && si < Launcher.SCREEN_COUNT) {
+ found = installShortcut(context, data, items, name, intent, si, exists, sp,
+ result);
+ }
}
}
@@ -102,8 +107,8 @@
}
private boolean installShortcut(Context context, Intent data, ArrayList<ItemInfo> items,
- String name, Intent intent, int screen, boolean shortcutExists,
- SharedPreferences sharedPrefs, int[] result) {
+ String name, Intent intent, final int screen, boolean shortcutExists,
+ final SharedPreferences sharedPrefs, int[] result) {
if (findEmptyCell(context, items, mCoordinates, screen)) {
if (intent != null) {
if (intent.getAction() == null) {
@@ -122,10 +127,15 @@
newApps = sharedPrefs.getStringSet(NEW_APPS_LIST_KEY, newApps);
}
newApps.add(intent.toUri(0).toString());
- sharedPrefs.edit()
- .putInt(NEW_APPS_PAGE_KEY, screen)
- .putStringSet(NEW_APPS_LIST_KEY, newApps)
- .commit();
+ final Set<String> savedNewApps = newApps;
+ new Thread("setNewAppsThread") {
+ public void run() {
+ sharedPrefs.edit()
+ .putInt(NEW_APPS_PAGE_KEY, screen)
+ .putStringSet(NEW_APPS_LIST_KEY, savedNewApps)
+ .commit();
+ }
+ }.start();
// Update the Launcher db
LauncherApplication app = (LauncherApplication) context.getApplicationContext();
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index b3ce968..d451ad2 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -55,10 +55,10 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Debug;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -85,7 +85,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Advanceable;
@@ -123,6 +122,7 @@
static final boolean PROFILE_STARTUP = false;
static final boolean DEBUG_WIDGETS = false;
+ static final boolean DEBUG_STRICT_MODE = false;
private static final int MENU_GROUP_WALLPAPER = 1;
private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
@@ -182,6 +182,9 @@
private static final Object sLock = new Object();
private static int sScreen = DEFAULT_SCREEN;
+ // How long to wait before the new-shortcut animation automatically pans the workspace
+ private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10;
+
private final BroadcastReceiver mCloseSystemDialogsReceiver
= new CloseSystemDialogsIntentReceiver();
private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
@@ -289,6 +292,21 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
+ if (DEBUG_STRICT_MODE) {
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+ .detectDiskReads()
+ .detectDiskWrites()
+ .detectNetwork() // or .detectAll() for all detectable problems
+ .penaltyLog()
+ .build());
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectLeakedSqlLiteObjects()
+ .detectLeakedClosableObjects()
+ .penaltyLog()
+ .penaltyDeath()
+ .build());
+ }
+
super.onCreate(savedInstanceState);
LauncherApplication app = ((LauncherApplication)getApplication());
mSharedPrefs = getSharedPreferences(LauncherApplication.getSharedPreferencesKey(),
@@ -635,6 +653,7 @@
super.onPause();
mPaused = true;
mDragController.cancelDrag();
+ mDragController.resetLastGestureUpTime();
}
@Override
@@ -2341,7 +2360,6 @@
mStateAnimation = null;
}
final Resources res = getResources();
- final Launcher instance = this;
final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime);
final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime);
@@ -2521,9 +2539,6 @@
updateWallpaperVisibility(true);
showHotseat(animated);
if (animated) {
- final float oldScaleX = fromView.getScaleX();
- final float oldScaleY = fromView.getScaleY();
-
final LauncherViewPropertyAnimator scaleAnim =
new LauncherViewPropertyAnimator(fromView);
scaleAnim.
@@ -3258,27 +3273,46 @@
Runnable newAppsRunnable = new Runnable() {
@Override
public void run() {
- runNewAppsAnimation();
+ runNewAppsAnimation(false);
}
};
- if (mNewShortcutAnimatePage > -1 &&
- mNewShortcutAnimatePage != mWorkspace.getCurrentPage()) {
- mWorkspace.snapToPage(mNewShortcutAnimatePage, newAppsRunnable);
+
+ boolean willSnapPage = mNewShortcutAnimatePage > -1 &&
+ mNewShortcutAnimatePage != mWorkspace.getCurrentPage();
+ if (canRunNewAppsAnimation()) {
+ // If the user has not interacted recently, then either snap to the new page to show
+ // the new-apps animation or just run them if they are to appear on the current page
+ if (willSnapPage) {
+ mWorkspace.snapToPage(mNewShortcutAnimatePage, newAppsRunnable);
+ } else {
+ runNewAppsAnimation(false);
+ }
} else {
- newAppsRunnable.run();
+ // If the user has interacted recently, then just add the items in place if they
+ // are on another page (or just normally if they are added to the current page)
+ runNewAppsAnimation(willSnapPage);
}
}
mWorkspaceLoading = false;
}
+ private boolean canRunNewAppsAnimation() {
+ long diff = System.currentTimeMillis() - mDragController.getLastGestureUpTime();
+ return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000);
+ }
+
/**
* Runs a new animation that scales up icons that were added while Launcher was in the
* background.
+ *
+ * @param immediate whether to run the animation or show the results immediately
*/
- private void runNewAppsAnimation() {
+ private void runNewAppsAnimation(boolean immediate) {
AnimatorSet anim = new AnimatorSet();
Collection<Animator> bounceAnims = new ArrayList<Animator>();
+
+ // Order these new views spatially so that they animate in order
Collections.sort(mNewShortcutAnimateViews, new Comparator<View>() {
@Override
public int compare(View a, View b) {
@@ -3288,25 +3322,35 @@
return (alp.cellY * cellCountX + alp.cellX) - (blp.cellY * cellCountX + blp.cellX);
}
});
- for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) {
- View v = mNewShortcutAnimateViews.get(i);
- ValueAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(v,
- PropertyValuesHolder.ofFloat("alpha", 1f),
- PropertyValuesHolder.ofFloat("scaleX", 1f),
- PropertyValuesHolder.ofFloat("scaleY", 1f));
- bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
- bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
- bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator());
- bounceAnims.add(bounceAnim);
- }
- anim.playTogether(bounceAnims);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspace.postDelayed(mBuildLayersRunnable, 500);
+
+ // Animate each of the views in place (or show them immediately if requested)
+ if (immediate) {
+ for (View v : mNewShortcutAnimateViews) {
+ v.setAlpha(1f);
+ v.setScaleX(1f);
+ v.setScaleY(1f);
}
- });
- anim.start();
+ } else {
+ for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) {
+ View v = mNewShortcutAnimateViews.get(i);
+ ValueAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(v,
+ PropertyValuesHolder.ofFloat("alpha", 1f),
+ PropertyValuesHolder.ofFloat("scaleX", 1f),
+ PropertyValuesHolder.ofFloat("scaleY", 1f));
+ bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
+ bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
+ bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator());
+ bounceAnims.add(bounceAnim);
+ }
+ anim.playTogether(bounceAnims);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mWorkspace.postDelayed(mBuildLayersRunnable, 500);
+ }
+ });
+ anim.start();
+ }
// Clean up
mNewShortcutAnimatePage = -1;
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 604e73c..1fc39f6 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -17,7 +17,6 @@
package com.android.launcher2;
import android.animation.Animator;
-import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -29,7 +28,6 @@
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.ActionMode;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -42,8 +40,6 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
-import android.widget.Checkable;
-import android.widget.ImageView;
import android.widget.Scroller;
import com.android.launcher.R;
diff --git a/src/com/android/launcher2/StrokedTextView.java b/src/com/android/launcher2/StrokedTextView.java
index 20f9f48..4e28d17 100644
--- a/src/com/android/launcher2/StrokedTextView.java
+++ b/src/com/android/launcher2/StrokedTextView.java
@@ -89,7 +89,6 @@
protected void onDraw(Canvas canvas) {
if (mCache != null) {
if (mUpdateCachedBitmap) {
- final int gap = getCompoundDrawablePadding();
final int w = getMeasuredWidth();
final int h = getMeasuredHeight();
final String text = getText().toString();
diff --git a/src/com/android/launcher2/UninstallShortcutReceiver.java b/src/com/android/launcher2/UninstallShortcutReceiver.java
index eb4ee4c..3f6de7c 100644
--- a/src/com/android/launcher2/UninstallShortcutReceiver.java
+++ b/src/com/android/launcher2/UninstallShortcutReceiver.java
@@ -20,11 +20,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.ContentResolver;
+import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.widget.Toast;
import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
import com.android.launcher.R;
@@ -36,7 +39,16 @@
if (!ACTION_UNINSTALL_SHORTCUT.equals(data.getAction())) {
return;
}
+ String spKey = LauncherApplication.getSharedPreferencesKey();
+ SharedPreferences sharedPrefs = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ LauncherApplication app = (LauncherApplication) context.getApplicationContext();
+ synchronized (app) {
+ removeShortcut(context, data, sharedPrefs);
+ }
+ }
+
+ private void removeShortcut(Context context, Intent data, final SharedPreferences sharedPrefs) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
@@ -77,6 +89,29 @@
Toast.makeText(context, context.getString(R.string.shortcut_uninstalled, name),
Toast.LENGTH_SHORT).show();
}
+
+ // Remove any items due to be animated
+ boolean appRemoved;
+ Set<String> newApps = new HashSet<String>();
+ newApps = sharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps);
+ do {
+ appRemoved = newApps.remove(intent.toUri(0).toString());
+ } while (appRemoved);
+ if (appRemoved) {
+ final Set<String> savedNewApps = newApps;
+ new Thread("setNewAppsThread-remove") {
+ public void run() {
+ SharedPreferences.Editor editor = sharedPrefs.edit();
+ editor.putStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
+ savedNewApps);
+ if (savedNewApps.isEmpty()) {
+ // Reset the page index if there are no more items
+ editor.putInt(InstallShortcutReceiver.NEW_APPS_PAGE_KEY, -1);
+ }
+ editor.commit();
+ }
+ }.start();
+ }
}
}
}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index aa343b0..86f4611 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1838,7 +1838,6 @@
* Responsibility for the bitmap is transferred to the caller.
*/
public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
- final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Bitmap b;
if (v instanceof TextView) {