diff options
Diffstat (limited to 'src/com')
42 files changed, 3415 insertions, 1192 deletions
diff --git a/src/com/cyanogenmod/trebuchet/AllAppsList.java b/src/com/cyanogenmod/trebuchet/AllAppsList.java index cc0e8cf..bab47c9 100644 --- a/src/com/cyanogenmod/trebuchet/AllAppsList.java +++ b/src/com/cyanogenmod/trebuchet/AllAppsList.java @@ -135,9 +135,7 @@ class AllAppsList { // Find enabled activities and add them to the adapter // Also updates existing activities with new labels/icons - int count = matches.size(); - for (int i = 0; i < count; i++) { - final ResolveInfo info = matches.get(i); + for (final ResolveInfo info : matches) { ApplicationInfo applicationInfo = findApplicationInfoLocked( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); @@ -195,9 +193,7 @@ class AllAppsList { * Returns whether <em>apps</em> contains <em>component</em>. */ private static boolean findActivity(ArrayList<ApplicationInfo> apps, ComponentName component) { - final int N = apps.size(); - for (int i=0; i<N; i++) { - final ApplicationInfo info = apps.get(i); + for (final ApplicationInfo info : apps) { if (info.componentName.equals(component)) { return true; } diff --git a/src/com/cyanogenmod/trebuchet/AppWidgetResizeFrame.java b/src/com/cyanogenmod/trebuchet/AppWidgetResizeFrame.java index 39b5356..0493f76 100644 --- a/src/com/cyanogenmod/trebuchet/AppWidgetResizeFrame.java +++ b/src/com/cyanogenmod/trebuchet/AppWidgetResizeFrame.java @@ -13,7 +13,6 @@ import android.view.Gravity; import android.widget.FrameLayout; import android.widget.ImageView; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; public class AppWidgetResizeFrame extends FrameLayout { @@ -67,11 +66,6 @@ public class AppWidgetResizeFrame extends FrameLayout { private static Rect mTmpRect = new Rect(); - public static final int LEFT = 0; - public static final int TOP = 1; - public static final int RIGHT = 2; - public static final int BOTTOM = 3; - private Launcher mLauncher; public AppWidgetResizeFrame(Context context, diff --git a/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java b/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java index e4bb84a..3da7f8e 100644 --- a/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java +++ b/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java @@ -51,9 +51,7 @@ import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; @@ -61,7 +59,6 @@ import android.widget.GridLayout; import android.widget.ImageView; import android.widget.Toast; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.DropTarget.DragObject; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; @@ -86,16 +83,6 @@ class AsyncTaskPageData { LoadWidgetPreviewData } - AsyncTaskPageData(int p, ArrayList<Object> l, ArrayList<Bitmap> si, AsyncTaskCallback bgR, - AsyncTaskCallback postR) { - page = p; - items = l; - sourceImages = si; - generatedImages = new ArrayList<Bitmap>(); - maxImageWidth = maxImageHeight = -1; - doInBackgroundCallback = bgR; - postExecuteCallback = postR; - } AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR, AsyncTaskCallback postR) { page = p; @@ -269,7 +256,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Save and Restore private int mSaveInstanceStateItemIndex = -1; private PagedViewIcon mPressedIcon; - private int mRestorePage = -1; // Content private ContentType mContentType; @@ -293,18 +279,15 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private int mContentWidth; private int mAppIconSize; private int mMaxAppCellCountX, mMaxAppCellCountY; - private int mMaxWidgetSpan, mMinWidgetSpan; private int mWidgetCountX, mWidgetCountY; private int mWidgetWidthGap, mWidgetHeightGap; - private final float sWidgetPreviewIconPaddingPercentage = 0.25f; + private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; private PagedViewCellLayout mWidgetSpacingLayout; private int mNumAppsPages = 0; private int mNumWidgetPages = 0; // Relating to the scroll and overscroll effects Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f); - private static float CAMERA_DISTANCE = 6500; - private static final float TRANSITION_SCALE_FACTOR = 0.74f; private static final float TRANSITION_PIVOT = 0.65f; private static final float TRANSITION_MAX_ROTATION = 22; private static final float TRANSITION_SCREEN_ROTATION = 12.5f; @@ -432,11 +415,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0); a.recycle(); mWidgetSpacingLayout = new PagedViewCellLayout(getContext()); - - // The max widget span is the length N, such that NxN is the largest bounds that the widget - // preview can be before applying the widget scaling - mMinWidgetSpan = 1; - mMaxWidgetSpan = 3; } @Override @@ -586,7 +564,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mWidgetSpacingLayout.measure(widthSpec, heightSpec); mContentWidth = mWidgetSpacingLayout.getContentWidth(); - AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost(); + AppsCustomizeTabHost host = getTabHost(); final boolean hostIsTransitioning = host.isTransitioning(); // Restore the page @@ -634,7 +612,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (!isDataReady()) { - boolean isReady = false; + boolean isReady; if (mContentType == AppsCustomizePagedView.ContentType.Widgets || mJoinWidgetsApps) { isReady = (!mApps.isEmpty() && !mWidgets.isEmpty()); } else { @@ -747,7 +725,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mLauncher.getWorkspace().beginDragShared(v, this); } - Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { + Bundle getDefaultOptionsForWidget(PendingAddWidgetInfo info) { Bundle options = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect); @@ -773,7 +751,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private void preloadWidget(final PendingAddWidgetInfo info) { final AppWidgetProviderInfo pInfo = info.info; - final Bundle options = getDefaultOptionsForWidget(mLauncher, info); + final Bundle options = getDefaultOptionsForWidget(info); if (pInfo.configure != null) { info.bindOptions = options; @@ -814,7 +792,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mWidgetCleanupState = WIDGET_INFLATED; hostView.setVisibility(INVISIBLE); int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info.spanX, - info.spanY, info, false); + info.spanY, false); // We want the first widget layout to be the correct size. This will be important // for width size reporting to the AppWidgetManager. @@ -912,7 +890,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int spanX = createItemInfo.spanX; int spanY = createItemInfo.spanY; int[] size = mLauncher.getWorkspace().estimateItemSize(spanX, spanY, - createWidgetInfo, true); + true); FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable(); float minScale = 1.25f; @@ -931,7 +909,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen (float) previewDrawable.getIntrinsicHeight()), Matrix.ScaleToFit.START); m.getValues(mv); - scale = (float) mv[0]; + scale = mv[0]; } else { PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo); @@ -1117,7 +1095,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Clean up all the async tasks Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); while (iter.hasNext()) { - AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); + AppsCustomizeAsyncTask task = iter.next(); task.cancel(false); iter.remove(); mDirtyPageContent.set(task.page, true); @@ -1151,9 +1129,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen updateCurrentTab(whichPage); // Update the thread priorities given the direction lookahead - Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); - while (iter.hasNext()) { - AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); + for (AppsCustomizeAsyncTask task : mRunningTasks) { int pageIndex = task.page; if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) || (mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) { @@ -1225,7 +1201,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen addView(layout); } } - public void syncAppsPageItems(int page, boolean immediate) { + public void syncAppsPageItems(int page) { // ensure that we have the right number of items on the pages int numCells = mCellCountX * mCellCountY; int startIndex = page * numCells; @@ -1233,8 +1209,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(page); layout.removeAllViewsOnPage(); - ArrayList<Object> items = new ArrayList<Object>(); - ArrayList<Bitmap> images = new ArrayList<Bitmap>(); for (int i = startIndex; i < endIndex; ++i) { ApplicationInfo info = mFilteredApps.get(i); PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( @@ -1248,10 +1222,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int index = i - startIndex; int x = index % mCellCountX; int y = index / mCellCountX; - layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1)); - - items.add(info); - images.add(info.iconBitmap); + layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x, y, 1, 1)); } layout.createHardwareLayers(); @@ -1273,7 +1244,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); int minPageDiff = Integer.MAX_VALUE; while (iter.hasNext()) { - AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); + AppsCustomizeAsyncTask task = iter.next(); minPageDiff = Math.abs(task.page - toPage); } @@ -1303,12 +1274,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen * Creates and executes a new AsyncTask to load a page of widget previews. */ private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets, - int cellWidth, int cellHeight, int cellCountX) { + int cellWidth, int cellHeight) { // Prune all tasks that are no longer needed Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); while (iter.hasNext()) { - AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); + AppsCustomizeAsyncTask task = iter.next(); int taskPage = task.page; if (taskPage < getAssociatedLowerPageBound(mCurrentPage) || taskPage > getAssociatedUpperPageBound(mCurrentPage)) { @@ -1328,7 +1299,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen try { try { Thread.sleep(sleepMs); - } catch (Exception e) {} + } catch (Exception e) { + // Ignore + } loadWidgetPreviewsInBackground(task, data); } finally { if (task.isCancelled()) { @@ -1501,7 +1474,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen c.setBitmap(null); // Draw the icon in the top left corner - int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage); + int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); int smallestSide = Math.min(bitmapWidth, bitmapHeight); float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), 1f); @@ -1520,6 +1493,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen (int) (mAppIconSize * iconScale)); } } catch (Resources.NotFoundException e) { + // Ignore } } @@ -1597,7 +1571,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen layout.setColumnCount(layout.getCellCountX()); for (int i = 0; i < items.size(); ++i) { Object rawInfo = items.get(i); - PendingAddItemInfo createItemInfo = null; + PendingAddItemInfo createItemInfo; PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate( R.layout.apps_customize_widget, layout, false); if (rawInfo instanceof AppWidgetProviderInfo) { @@ -1677,7 +1651,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mDeferredPrepareLoadWidgetPreviewsTasks.add(this); } else { prepareLoadWidgetPreviewsTask(page, items, - maxPreviewWidth, maxPreviewHeight, mWidgetCountX); + maxPreviewWidth, maxPreviewHeight); } } } @@ -1695,8 +1669,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Load each of the widget/shortcut previews ArrayList<Object> items = data.items; ArrayList<Bitmap> images = data.generatedImages; - int count = items.size(); - for (int i = 0; i < count; ++i) { + for (Object item : items) { if (task != null) { // Ensure we haven't been cancelled yet if (task.isCancelled()) break; @@ -1705,9 +1678,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen task.syncThreadPriority(); } - Object rawInfo = items.get(i); - if (rawInfo instanceof AppWidgetProviderInfo) { - AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo; + if (item instanceof AppWidgetProviderInfo) { + AppWidgetProviderInfo info = (AppWidgetProviderInfo) item; int[] cellSpans = Launcher.getSpanForWidget(mLauncher, info); int maxWidth = Math.min(data.maxImageWidth, @@ -1717,12 +1689,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen Bitmap b = getWidgetPreview(info.provider, info.previewImage, info.icon, cellSpans[0], cellSpans[1], maxWidth, maxHeight); images.add(b); - } else if (rawInfo instanceof ResolveInfo) { + } else if (item instanceof ResolveInfo) { // Fill in the shortcuts information - ResolveInfo info = (ResolveInfo) rawInfo; + ResolveInfo info = (ResolveInfo) item; images.add(getShortcutPreview(info, data.maxImageWidth, data.maxImageHeight)); - } else if (rawInfo instanceof LauncherActionInfo) { - LauncherActionInfo info = (LauncherActionInfo) rawInfo; + } else if (item instanceof LauncherActionInfo) { + LauncherActionInfo info = (LauncherActionInfo) item; images.add(getShortcutPreview(info)); } } @@ -1751,9 +1723,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen invalidate(); // Update all thread priorities - Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator(); - while (iter.hasNext()) { - AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next(); + for (AppsCustomizeAsyncTask task : mRunningTasks) { int pageIndex = task.page; task.setThreadPriority(getThreadPriorityForPage(pageIndex)); } @@ -1798,14 +1768,14 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen public void syncPageItems(int page, boolean immediate) { if (mJoinWidgetsApps) { if (page < mNumAppsPages) { - syncAppsPageItems(page, immediate); + syncAppsPageItems(page); } else { syncWidgetPageItems(page, immediate); } } else { switch (mContentType) { case Applications: - syncAppsPageItems(page, immediate); + syncAppsPageItems(page); break; case Widgets: syncWidgetPageItems(page, immediate); @@ -2187,9 +2157,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (v != null) { float scrollProgress = getScrollProgress(screenScroll, v, index); float rotation = -TRANSITION_MAX_ROTATION * scrollProgress; - v.setCameraDistance(mDensity * mCameraDistance); if (!mOverscrollTransformsDirty) { mOverscrollTransformsDirty = true; + v.setCameraDistance(mDensity * mCameraDistance); if (!mVertical) { v.setPivotX(v.getMeasuredWidth() * (index == 0 ? TRANSITION_PIVOT : 1 - TRANSITION_PIVOT)); v.setPivotY(v.getMeasuredHeight() * 0.5f); @@ -2238,16 +2208,17 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (!mVertical) { if (mScrollingIndicatorPosition == SCROLLING_INDICATOR_BOTTOM) { return R.id.paged_view_indicator_bottom; - } else { + } else if (mScrollingIndicatorPosition == SCROLLING_INDICATOR_TOP) { return R.id.paged_view_indicator_top; } } else { if (mScrollingIndicatorPosition == SCROLLING_INDICATOR_BOTTOM) { return R.id.paged_view_indicator_right; - } else { + } else if (mScrollingIndicatorPosition == SCROLLING_INDICATOR_TOP) { return R.id.paged_view_indicator_left; } } + return -1; } @Override @@ -2332,9 +2303,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) { // We add it in place, in alphabetical order - int count = list.size(); - for (int i = 0; i < count; ++i) { - ApplicationInfo info = list.get(i); + for (ApplicationInfo info : list) { int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator()); if (index < 0) { mApps.add(-(index + 1), info); @@ -2370,9 +2339,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) { // loop through all the apps and remove apps that have the same component - int length = list.size(); - for (int i = 0; i < length; ++i) { - ApplicationInfo info = list.get(i); + for (ApplicationInfo info : list) { int removeIndex = findAppByComponent(mApps, info); if (removeIndex > -1) { mApps.remove(removeIndex); @@ -2518,15 +2485,13 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen protected int getAssociatedLowerPageBound(int page) { final int count = getChildCount(); int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); - int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0); - return windowMinIndex; + return Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0); } protected int getAssociatedUpperPageBound(int page) { final int count = getChildCount(); int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); - int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1), + return Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1), count - 1); - return windowMaxIndex; } @Override @@ -2535,7 +2500,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int stringId = R.string.default_scroll_format; if (mJoinWidgetsApps) { - int count = 0; + int count; if (page < mNumAppsPages) { stringId = R.string.apps_customize_apps_scroll_format; diff --git a/src/com/cyanogenmod/trebuchet/AppsCustomizeTabHost.java b/src/com/cyanogenmod/trebuchet/AppsCustomizeTabHost.java index 5bffe76..af762ea 100644 --- a/src/com/cyanogenmod/trebuchet/AppsCustomizeTabHost.java +++ b/src/com/cyanogenmod/trebuchet/AppsCustomizeTabHost.java @@ -179,11 +179,8 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona public boolean onInterceptTouchEvent(MotionEvent ev) { // If we are mid transitioning to the workspace, then intercept touch events here so we // can ignore them, otherwise we just let all apps handle the touch events. - if (mInTransition && mTransitioningToWorkspace) { - return true; - } - return super.onInterceptTouchEvent(ev); - }; + return mInTransition && mTransitioningToWorkspace || super.onInterceptTouchEvent(ev); + } @Override public boolean onTouchEvent(MotionEvent event) { @@ -271,7 +268,7 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona mAnimationBuffer.setVisibility(View.VISIBLE); LayoutParams p = new FrameLayout.LayoutParams(child.getMeasuredWidth(), child.getMeasuredHeight()); - p.setMargins((int) child.getLeft(), (int) child.getTop(), 0, 0); + p.setMargins(child.getLeft(), child.getTop(), 0, 0); mAnimationBuffer.addView(child, p); // Toggle the new content diff --git a/src/com/cyanogenmod/trebuchet/BubbleTextView.java b/src/com/cyanogenmod/trebuchet/BubbleTextView.java index 4c94bc9..8a48b16 100644 --- a/src/com/cyanogenmod/trebuchet/BubbleTextView.java +++ b/src/com/cyanogenmod/trebuchet/BubbleTextView.java @@ -34,7 +34,6 @@ import android.widget.TextView; * too aggressive. */ public class BubbleTextView extends TextView implements ShortcutInfo.ShortcutListener { - static final float CORNER_RADIUS = 4.0f; static final float SHADOW_LARGE_RADIUS = 4.0f; static final float SHADOW_SMALL_RADIUS = 1.75f; static final float SHADOW_Y_OFFSET = 2.0f; diff --git a/src/com/cyanogenmod/trebuchet/ButtonDropTarget.java b/src/com/cyanogenmod/trebuchet/ButtonDropTarget.java index 8f819ea..9317d1d 100644 --- a/src/com/cyanogenmod/trebuchet/ButtonDropTarget.java +++ b/src/com/cyanogenmod/trebuchet/ButtonDropTarget.java @@ -71,9 +71,9 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro protected Drawable getCurrentDrawable() { Drawable[] drawables = getCompoundDrawables(); - for (int i = 0; i < drawables.length; ++i) { - if (drawables[i] != null) { - return drawables[i]; + for (Drawable drawable : drawables) { + if (drawable != null) { + return drawable; } } return null; diff --git a/src/com/cyanogenmod/trebuchet/CellLayout.java b/src/com/cyanogenmod/trebuchet/CellLayout.java index b70a34d..0521ef7 100644 --- a/src/com/cyanogenmod/trebuchet/CellLayout.java +++ b/src/com/cyanogenmod/trebuchet/CellLayout.java @@ -19,7 +19,6 @@ package com.cyanogenmod.trebuchet; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; @@ -49,7 +48,6 @@ import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.LayoutAnimationController; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.FolderIcon.FolderRingAnimator; import java.util.ArrayList; @@ -362,7 +360,7 @@ public class CellLayout extends ViewGroup { mOverScrollForegroundDrawable = mOverScrollRight; } - mForegroundAlpha = (int) Math.round((r * 255)); + mForegroundAlpha = Math.round((r * 255)); mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); invalidate(); } @@ -495,14 +493,12 @@ public class CellLayout extends ViewGroup { int previewOffset = FolderRingAnimator.sPreviewSize; // The folder outer / inner ring image(s) - for (int i = 0; i < mFolderOuterRings.size(); i++) { - FolderRingAnimator fra = mFolderOuterRings.get(i); - + for (FolderRingAnimator ringAnimator : mFolderOuterRings) { // Draw outer ring Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; - int width = (int) fra.getOuterRingSize(); + int width = (int) ringAnimator.getOuterRingSize(); int height = width; - cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); + cellToPoint(ringAnimator.mCellX, ringAnimator.mCellY, mTempLocation); int centerX = mTempLocation[0] + mCellWidth / 2; int centerY = mTempLocation[1] + previewOffset / 2; @@ -515,9 +511,9 @@ public class CellLayout extends ViewGroup { // Draw inner ring d = FolderRingAnimator.sSharedInnerRingDrawable; - width = (int) fra.getInnerRingSize(); + width = (int) ringAnimator.getInnerRingSize(); height = width; - cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); + cellToPoint(ringAnimator.mCellX, ringAnimator.mCellY, mTempLocation); centerX = mTempLocation[0] + mCellWidth / 2; centerY = mTempLocation[1] + previewOffset / 2; @@ -897,9 +893,8 @@ public class CellLayout extends ViewGroup { public float getDistanceFromCell(float x, float y, int[] cell) { cellToCenterPoint(cell[0], cell[1], mTmpPoint); - float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + + return (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + Math.pow(y - mTmpPoint[1], 2)); - return distance; } void setCellGaps(int widthGap, int heightGap) { @@ -1155,7 +1150,7 @@ public class CellLayout extends ViewGroup { va.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - float r = ((Float) animation.getAnimatedValue()).floatValue(); + float r = (Float) animation.getAnimatedValue(); lp.x = (int) ((1 - r) * oldX + r * newX); lp.y = (int) ((1 - r) * oldY + r * newY); child.requestLayout(); @@ -1456,9 +1451,6 @@ public class CellLayout extends ViewGroup { hitMaxY |= ySize >= spanY; incX = !incX; } - incX = true; - hitMaxX = xSize >= spanX; - hitMaxY = ySize >= spanY; } final int[] cellXY = mTmpXY; cellToCenterPoint(x, y, cellXY); @@ -1711,9 +1703,9 @@ public class CellLayout extends ViewGroup { } private void completeSetOfViewsToMove(ArrayList<View> views, Rect boundingRect, int[] direction, - boolean[][] occupied, View dragView, ItemConfiguration currentState) { + View dragView, ItemConfiguration currentState) { Rect r0 = new Rect(boundingRect); - int minRuns = 0; + int minRuns; // The first thing we do is to reduce the bounding rect to first or last row or column, // depending on the direction. Then, we add any necessary views that are already contained @@ -1761,7 +1753,7 @@ public class CellLayout extends ViewGroup { @SuppressWarnings("unchecked") ArrayList<View> dup = (ArrayList<View>) views.clone(); if (push) { - completeSetOfViewsToMove(dup, boundingRect, direction, mTmpOccupied, dragView, + completeSetOfViewsToMove(dup, boundingRect, direction, dragView, currentState); } @@ -1984,9 +1976,7 @@ public class CellLayout extends ViewGroup { private void copyOccupiedArray(boolean[][] occupied) { for (int i = 0; i < mCountX; i++) { - for (int j = 0; j < mCountY; j++) { - occupied[i][j] = mOccupied[i][j]; - } + System.arraycopy(mOccupied[i], 0, occupied[i], 0, mCountY); } } @@ -2003,10 +1993,9 @@ public class CellLayout extends ViewGroup { int result[] = new int[2]; result = findNearestArea(pixelX, pixelY, spanX, spanY, result); - boolean success = false; // First we try the exact nearest position of the item being dragged, // we will then want to try to move this around to other neighbouring positions - success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, + boolean success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, solution); if (!success) { @@ -2181,7 +2170,7 @@ public class CellLayout extends ViewGroup { va.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - float r = ((Float) animation.getAnimatedValue()).floatValue(); + float r = (Float) animation.getAnimatedValue(); float x = r * finalDeltaX + (1 - r) * initDeltaX; float y = r * finalDeltaY + (1 - r) * initDeltaY; child.setTranslationX(x); @@ -2237,9 +2226,7 @@ public class CellLayout extends ViewGroup { private void commitTempPlacement() { for (int i = 0; i < mCountX; i++) { - for (int j = 0; j < mCountY; j++) { - mOccupied[i][j] = mTmpOccupied[i][j]; - } + System.arraycopy(mTmpOccupied[i], 0, mOccupied[i], 0, mCountY); } int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { @@ -2271,7 +2258,7 @@ public class CellLayout extends ViewGroup { } ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, - int spanX, int spanY, View dragView, ItemConfiguration solution) { + int spanX, int spanY, ItemConfiguration solution) { int[] result = new int[2]; int[] resultSpan = new int[2]; findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, @@ -2451,7 +2438,7 @@ public class CellLayout extends ViewGroup { // We attempt the approach which doesn't shuffle views at all ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, - minSpanY, spanX, spanY, dragView, new ItemConfiguration()); + minSpanY, spanX, spanY, new ItemConfiguration()); ItemConfiguration finalSolution = null; if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { @@ -2699,7 +2686,6 @@ public class CellLayout extends ViewGroup { // intersecting intersectX = -1; intersectY = -1; - continue; } } @@ -3064,8 +3050,8 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { leftMargin - rightMargin; height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - topMargin - bottomMargin; - x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); - y = (int) (myCellY * (cellHeight + heightGap) + topMargin); + x = myCellX * (cellWidth + widthGap) + leftMargin; + y = myCellY * (cellHeight + heightGap) + topMargin; } } diff --git a/src/com/cyanogenmod/trebuchet/Cling.java b/src/com/cyanogenmod/trebuchet/Cling.java index 00a4464..510121b 100644 --- a/src/com/cyanogenmod/trebuchet/Cling.java +++ b/src/com/cyanogenmod/trebuchet/Cling.java @@ -210,7 +210,7 @@ public class Cling extends FrameLayout { } } return true; - }; + } @Override protected void dispatchDraw(Canvas canvas) { @@ -283,10 +283,10 @@ public class Cling extends FrameLayout { canvas.drawBitmap(b, 0, 0, null); c.setBitmap(null); - b = null; + b.recycle(); } // Draw the rest of the cling super.dispatchDraw(canvas); - }; + } } diff --git a/src/com/cyanogenmod/trebuchet/DeleteDropTarget.java b/src/com/cyanogenmod/trebuchet/DeleteDropTarget.java index 2cc872a..55381d4 100644 --- a/src/com/cyanogenmod/trebuchet/DeleteDropTarget.java +++ b/src/com/cyanogenmod/trebuchet/DeleteDropTarget.java @@ -348,7 +348,7 @@ public class DeleteDropTarget extends ButtonDropTarget { @Override public void onAnimationUpdate(ValueAnimator animation) { final DragView dragView = (DragView) dragLayer.getAnimatedView(); - float t = ((Float) animation.getAnimatedValue()).floatValue(); + float t = (Float) animation.getAnimatedValue(); float tp = scaleAlphaInterpolator.getInterpolation(t); float initialScale = dragView.getInitialScale(); float finalAlpha = 0.5f; @@ -396,7 +396,7 @@ public class DeleteDropTarget extends ButtonDropTarget { @Override public void onAnimationUpdate(ValueAnimator animation) { final DragView dragView = (DragView) mDragLayer.getAnimatedView(); - float t = ((Float) animation.getAnimatedValue()).floatValue(); + float t = (Float) animation.getAnimatedValue(); long curTime = AnimationUtils.currentAnimationTimeMillis(); if (!mHasOffsetForScale) { @@ -420,7 +420,7 @@ public class DeleteDropTarget extends ButtonDropTarget { mVelocity.y *= mFriction; mPrevTime = curTime; } - }; + } private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer, DragObject d, PointF vel, final long startTime, final int duration, ViewConfiguration config) { diff --git a/src/com/cyanogenmod/trebuchet/DragController.java b/src/com/cyanogenmod/trebuchet/DragController.java index da75b8f..071948c 100644 --- a/src/com/cyanogenmod/trebuchet/DragController.java +++ b/src/com/cyanogenmod/trebuchet/DragController.java @@ -33,8 +33,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.inputmethod.InputMethodManager; -import com.cyanogenmod.trebuchet.R; - import java.util.ArrayList; /** @@ -519,7 +517,7 @@ public class DragController { if (mScrollState == SCROLL_OUTSIDE_ZONE) { mScrollState = SCROLL_WAITING_IN_ZONE; if (mDragScroller.onEnterScrollArea(x, y, SCROLL_LEFT)) { - mLauncher.getDragLayer().onEnterScrollArea(SCROLL_LEFT); + mLauncher.getDragLayer().onEnterScrollArea(); mScrollRunnable.setDirection(SCROLL_LEFT); mHandler.postDelayed(mScrollRunnable, delay); } @@ -528,7 +526,7 @@ public class DragController { if (mScrollState == SCROLL_OUTSIDE_ZONE) { mScrollState = SCROLL_WAITING_IN_ZONE; if (mDragScroller.onEnterScrollArea(x, y, SCROLL_RIGHT)) { - mLauncher.getDragLayer().onEnterScrollArea(SCROLL_RIGHT); + mLauncher.getDragLayer().onEnterScrollArea(); mScrollRunnable.setDirection(SCROLL_RIGHT); mHandler.postDelayed(mScrollRunnable, delay); } diff --git a/src/com/cyanogenmod/trebuchet/DragLayer.java b/src/com/cyanogenmod/trebuchet/DragLayer.java index 892cd48..420dfd5 100644 --- a/src/com/cyanogenmod/trebuchet/DragLayer.java +++ b/src/com/cyanogenmod/trebuchet/DragLayer.java @@ -104,18 +104,12 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) { getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect); - if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) { - return true; - } - return false; + return mHitRect.contains((int) ev.getX(), (int) ev.getY()); } private boolean isEventOverFolder(Folder folder, MotionEvent ev) { getDescendantRectRelativeToSelf(folder, mHitRect); - if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) { - return true; - } - return false; + return mHitRect.contains((int) ev.getX(), (int) ev.getY()); } private boolean handleTouchDown(MotionEvent ev, boolean intercept) { @@ -732,7 +726,7 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang private Drawable mLeftHoverDrawable; private Drawable mRightHoverDrawable; - void onEnterScrollArea(int direction) { + void onEnterScrollArea() { mInScrollArea = true; invalidate(); } diff --git a/src/com/cyanogenmod/trebuchet/FocusHelper.java b/src/com/cyanogenmod/trebuchet/FocusHelper.java index d87fc67..0ac6e24 100644 --- a/src/com/cyanogenmod/trebuchet/FocusHelper.java +++ b/src/com/cyanogenmod/trebuchet/FocusHelper.java @@ -139,7 +139,7 @@ public class FocusHelper { final TabWidget tabs = tabHost.getTabWidget(); final int widgetIndex = parent.indexOfChild(w); final int widgetCount = parent.getChildCount(); - final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent)); + final int pageIndex = container.indexToPage(container.indexOfChild(parent)); final int pageCount = container.getChildCount(); final int cellCountX = parent.getCellCountX(); final int cellCountY = parent.getCellCountY(); @@ -148,7 +148,7 @@ public class FocusHelper { final int action = e.getAction(); final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - ViewGroup newParent = null; + ViewGroup newParent; // Now that we load items in the bg asynchronously, we can't just focus // child siblings willy-nilly View child = null; @@ -299,7 +299,7 @@ public class FocusHelper { final TabWidget tabs = tabHost.getTabWidget(); final int iconIndex = itemContainer.indexOfChild(v); final int itemCount = itemContainer.getChildCount(); - final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout)); + final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); final int pageCount = container.getChildCount(); final int x = iconIndex % countX; @@ -307,10 +307,10 @@ public class FocusHelper { final int action = e.getAction(); final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - ViewGroup newParent = null; + ViewGroup newParent; // Side pages do not always load synchronously, so check before focusing child siblings // willy-nilly - View child = null; + View child; boolean wasHandled = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: diff --git a/src/com/cyanogenmod/trebuchet/FocusOnlyTabWidget.java b/src/com/cyanogenmod/trebuchet/FocusOnlyTabWidget.java index 795b621..96bf589 100644 --- a/src/com/cyanogenmod/trebuchet/FocusOnlyTabWidget.java +++ b/src/com/cyanogenmod/trebuchet/FocusOnlyTabWidget.java @@ -72,15 +72,11 @@ public class FocusOnlyTabWidget extends TabWidget { super.onFocusChange(tab, true); } } - public void superOnFocusChange(View v, boolean hasFocus) { - super.onFocusChange(v, hasFocus); - } @Override public void onFocusChange(android.view.View v, boolean hasFocus) { if (v == this && hasFocus && getTabCount() > 0) { getSelectedTab().requestFocus(); - return; } } } diff --git a/src/com/cyanogenmod/trebuchet/Folder.java b/src/com/cyanogenmod/trebuchet/Folder.java index 465f32c..d2a9dea 100644 --- a/src/com/cyanogenmod/trebuchet/Folder.java +++ b/src/com/cyanogenmod/trebuchet/Folder.java @@ -339,8 +339,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private void placeInReadingOrder(ArrayList<ShortcutInfo> items) { int maxX = 0; int count = items.size(); - for (int i = 0; i < count; i++) { - ShortcutInfo item = items.get(i); + for (ShortcutInfo item : items) { if (item.cellX > maxX) { maxX = item.cellX; } @@ -365,8 +364,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList setupContentForNumItems(children.size()); placeInReadingOrder(children); int count = 0; - for (int i = 0; i < children.size(); i++) { - ShortcutInfo child = (ShortcutInfo) children.get(i); + for (ShortcutInfo child : children) { if (!createAndAddShortcut(child)) { overflow.add(child); } else { @@ -585,11 +583,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList }; boolean readingOrderGreaterThan(int[] v1, int[] v2) { - if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) { - return true; - } else { - return false; - } + return v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0]); } private void realTimeReorder(int[] empty, int[] target) { @@ -750,11 +744,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private void updateItemLocationsInDatabase() { ArrayList<View> list = getItemsInReadingOrder(); - for (int i = 0; i < list.size(); i++) { - View v = list.get(i); + for (View v : list) { ItemInfo info = (ItemInfo) v.getTag(); LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0, - info.cellX, info.cellY); + info.cellX, info.cellY); } } @@ -902,8 +895,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } mContent.removeAllViews(); - for (int i = 0; i < list.size(); i++) { - View v = list.get(i); + for (View v : list) { mContent.getVacantCell(vacant, 1, 1); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams(); lp.cellX = vacant[0]; @@ -915,8 +907,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0, info.cellX, info.cellY); } - boolean insert = false; - mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true); + mContent.addViewToCellLayout(v, 0, (int) info.id, lp, true); } mItemsInvalidated = true; } diff --git a/src/com/cyanogenmod/trebuchet/FolderIcon.java b/src/com/cyanogenmod/trebuchet/FolderIcon.java index e9aaab5..b67e0bd 100644 --- a/src/com/cyanogenmod/trebuchet/FolderIcon.java +++ b/src/com/cyanogenmod/trebuchet/FolderIcon.java @@ -41,12 +41,11 @@ import android.widget.TextView; import com.cyanogenmod.trebuchet.DropTarget.DragObject; import com.cyanogenmod.trebuchet.FolderInfo.FolderListener; -import com.cyanogenmod.trebuchet.preference.PreferencesProvider; import java.util.ArrayList; /** - * An icon that can appear on in the workspace representing an {@link UserFolder}. + * An icon that can appear on in the workspace representing an {@link Folder}. */ public class FolderIcon extends LinearLayout implements FolderListener { private Launcher mLauncher; @@ -113,15 +112,8 @@ public class FolderIcon extends LinearLayout implements FolderListener { mLongPressHelper = new CheckLongPressHelper(this); } - public boolean isDropEnabled() { - final ViewGroup cellLayoutChildren = (ViewGroup) getParent(); - final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent(); - final Workspace workspace = (Workspace) cellLayout.getParent(); - return !workspace.isSmall(); - } - static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, - FolderInfo folderInfo, IconCache iconCache) { + FolderInfo folderInfo) { @SuppressWarnings("all") // suppress dead code warning final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION; if (error) { @@ -297,8 +289,8 @@ public class FolderIcon extends LinearLayout implements FolderListener { !mFolder.isFull() && item != mInfo && !mInfo.opened); } - public boolean acceptDrop(Object dragInfo) { - final ItemInfo item = (ItemInfo) dragInfo; + public boolean acceptDrop(ItemInfo dragInfo) { + final ItemInfo item = dragInfo; return !mFolder.isDestroyed() && willAcceptItem(item); } @@ -316,9 +308,6 @@ public class FolderIcon extends LinearLayout implements FolderListener { layout.showFolderAccept(mFolderRingAnimator); } - public void onDragOver(Object dragInfo) { - } - public void performCreateAnimation(final ShortcutInfo destInfo, final View destView, final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect, float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { @@ -334,7 +323,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { addItem(destInfo); // This will animate the dragView (srcView) into the new folder - onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null); + onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable); } public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) { @@ -348,17 +337,12 @@ public class FolderIcon extends LinearLayout implements FolderListener { onCompleteRunnable); } - public void onDragExit(Object dragInfo) { - onDragExit(); - } - public void onDragExit() { mFolderRingAnimator.animateToNaturalState(); } private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect, - float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable, - DragObject d) { + float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) { item.cellX = -1; item.cellY = -1; @@ -388,8 +372,8 @@ public class FolderIcon extends LinearLayout implements FolderListener { int[] center = new int[2]; float scale = getLocalCenterForIndex(index, center); - center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]); - center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]); + center[0] = Math.round(scaleRelativeToDragLayer * center[0]); + center[1] = Math.round(scaleRelativeToDragLayer * center[1]); to.offset(center[0] - animateView.getMeasuredWidth() / 2, center[1] - animateView.getMeasuredHeight() / 2); @@ -423,7 +407,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { FolderInfo folder = (FolderInfo) d.dragInfo; mFolder.notifyDrop(); for (ShortcutInfo fItem : folder.contents) { - onDrop(fItem, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d); + onDrop(fItem, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable); } mLauncher.removeFolder(folder); LauncherModel.deleteItemFromDatabase(mLauncher, folder); @@ -432,11 +416,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { item = (ShortcutInfo) d.dragInfo; } mFolder.notifyDrop(); - onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d); - } - - public DropTarget getDropTargetDelegate(DragObject d) { - return null; + onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable); } private void computePreviewDrawingParams(int drawableSize, int totalSize) { @@ -488,8 +468,8 @@ public class FolderIcon extends LinearLayout implements FolderListener { float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2; float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2; - center[0] = (int) Math.round(offsetX); - center[1] = (int) Math.round(offsetY); + center[0] = Math.round(offsetX); + center[1] = Math.round(offsetY); return mParams.scale; } diff --git a/src/com/cyanogenmod/trebuchet/FolderInfo.java b/src/com/cyanogenmod/trebuchet/FolderInfo.java index 710b137..7c6941b 100644 --- a/src/com/cyanogenmod/trebuchet/FolderInfo.java +++ b/src/com/cyanogenmod/trebuchet/FolderInfo.java @@ -48,8 +48,8 @@ class FolderInfo extends ItemInfo { */ public void add(ShortcutInfo item) { contents.add(item); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onAdd(item); + for (FolderListener listener : listeners) { + listener.onAdd(item); } itemsChanged(); } @@ -61,16 +61,16 @@ class FolderInfo extends ItemInfo { */ public void remove(ShortcutInfo item) { contents.remove(item); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onRemove(item); + for (FolderListener listener : listeners) { + listener.onRemove(item); } itemsChanged(); } public void setTitle(CharSequence title) { this.title = title; - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onTitleChanged(title); + for (FolderListener listener : listeners) { + listener.onTitleChanged(title); } } @@ -91,8 +91,8 @@ class FolderInfo extends ItemInfo { } void itemsChanged() { - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onItemsChanged(); + for (FolderListener listener : listeners) { + listener.onItemsChanged(); } } diff --git a/src/com/cyanogenmod/trebuchet/HandleView.java b/src/com/cyanogenmod/trebuchet/HandleView.java deleted file mode 100644 index 8944888..0000000 --- a/src/com/cyanogenmod/trebuchet/HandleView.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - - -package com.cyanogenmod.trebuchet; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageView; - -import com.cyanogenmod.trebuchet.R; - -public class HandleView extends ImageView { - private static final int ORIENTATION_HORIZONTAL = 1; - - private Launcher mLauncher; - private int mOrientation = ORIENTATION_HORIZONTAL; - - public HandleView(Context context) { - super(context); - } - - public HandleView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public HandleView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HandleView, defStyle, 0); - mOrientation = a.getInt(R.styleable.HandleView_direction, ORIENTATION_HORIZONTAL); - a.recycle(); - - setContentDescription(context.getString(R.string.all_apps_button_label)); - } - - @Override - public View focusSearch(int direction) { - View newFocus = super.focusSearch(direction); - if (newFocus == null && !mLauncher.isAllAppsVisible()) { - final Workspace workspace = mLauncher.getWorkspace(); - workspace.dispatchUnhandledMove(null, direction); - return (mOrientation == ORIENTATION_HORIZONTAL && direction == FOCUS_DOWN) ? - this : workspace; - } - return newFocus; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN && mLauncher.isAllAppsVisible()) { - return false; - } - return super.onTouchEvent(ev); - } - - void setLauncher(Launcher launcher) { - mLauncher = launcher; - } -} diff --git a/src/com/cyanogenmod/trebuchet/Hotseat.java b/src/com/cyanogenmod/trebuchet/Hotseat.java index 600c254..d52cb0c 100644 --- a/src/com/cyanogenmod/trebuchet/Hotseat.java +++ b/src/com/cyanogenmod/trebuchet/Hotseat.java @@ -18,19 +18,14 @@ package com.cyanogenmod.trebuchet; import android.content.Context; import android.content.res.Configuration; -import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; public class Hotseat extends PagedView { - private Launcher mLauncher; - private CellLayout mContent; - private int mCellCount; private boolean mTransposeLayoutWithOrientation; @@ -83,10 +78,7 @@ public class Hotseat extends PagedView { // No data needed setDataIsReady(); - } - public void setup(Launcher launcher) { - mLauncher = launcher; setOnKeyListener(new HotseatIconKeyEventListener()); } diff --git a/src/com/cyanogenmod/trebuchet/InstallShortcutReceiver.java b/src/com/cyanogenmod/trebuchet/InstallShortcutReceiver.java index c9627d7..10bdb72 100644 --- a/src/com/cyanogenmod/trebuchet/InstallShortcutReceiver.java +++ b/src/com/cyanogenmod/trebuchet/InstallShortcutReceiver.java @@ -190,7 +190,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { newApps = sharedPrefs.getStringSet(NEW_APPS_LIST_KEY, newApps); } synchronized (newApps) { - newApps.add(intent.toUri(0).toString()); + newApps.add(intent.toUri(0)); } final Set<String> savedNewApps = newApps; new Thread("setNewAppsThread") { @@ -231,10 +231,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { final int yCount = LauncherModel.getCellCountY(); boolean[][] occupied = new boolean[xCount][yCount]; - ItemInfo item = null; int cellX, cellY, spanX, spanY; - for (int i = 0; i < items.size(); ++i) { - item = items.get(i); + for (ItemInfo item : items) { if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { if (item.screen == screen) { cellX = item.cellX; diff --git a/src/com/cyanogenmod/trebuchet/InterruptibleInOutAnimator.java b/src/com/cyanogenmod/trebuchet/InterruptibleInOutAnimator.java index 8183ce4..ea847d7 100644 --- a/src/com/cyanogenmod/trebuchet/InterruptibleInOutAnimator.java +++ b/src/com/cyanogenmod/trebuchet/InterruptibleInOutAnimator.java @@ -62,7 +62,7 @@ public class InterruptibleInOutAnimator { final long currentPlayTime = mAnimator.getCurrentPlayTime(); final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue; final float startValue = mFirstRun ? mOriginalFromValue : - ((Float) mAnimator.getAnimatedValue()).floatValue(); + (Float) mAnimator.getAnimatedValue(); // Make sure it's stopped before we modify any values cancel(); diff --git a/src/com/cyanogenmod/trebuchet/ItemInfo.java b/src/com/cyanogenmod/trebuchet/ItemInfo.java index 794903c..11be869 100644 --- a/src/com/cyanogenmod/trebuchet/ItemInfo.java +++ b/src/com/cyanogenmod/trebuchet/ItemInfo.java @@ -23,6 +23,7 @@ import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Arrays; /** * Represents an item in the launcher. @@ -189,6 +190,6 @@ class ItemInfo { public String toString() { return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX - + " spanY=" + spanY + " dropPos=" + dropPos + ")"; + + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")"; } } diff --git a/src/com/cyanogenmod/trebuchet/Launcher.java b/src/com/cyanogenmod/trebuchet/Launcher.java index e8efcc6..5318766 100644 --- a/src/com/cyanogenmod/trebuchet/Launcher.java +++ b/src/com/cyanogenmod/trebuchet/Launcher.java @@ -44,7 +44,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.Intent.ShortcutIconResource; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -100,7 +99,6 @@ import android.widget.TextView; import android.widget.Toast; import com.android.common.Search; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.DropTarget.DragObject; import com.cyanogenmod.trebuchet.preference.*; @@ -127,7 +125,6 @@ public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, View.OnTouchListener { private static final String TAG = "Trebuchet.Launcher"; - static final boolean LOGD = false; static final boolean PROFILE_STARTUP = false; static final boolean DEBUG_WIDGETS = false; @@ -160,7 +157,6 @@ public final class Launcher extends Activity static final int DIALOG_CREATE_ACTION = 2; private static final String PREFERENCES = "launcher.preferences"; - static final String FORCE_ENABLE_ROTATION_PROPERTY = "debug.force_enable_rotation"; static final String DUMP_STATE_PROPERTY = "debug.dumpstate"; // The Intent extra that defines whether to ignore the launch animation @@ -197,7 +193,7 @@ public final class Launcher extends Activity "com.android.launcher.toolbar_voice_search_icon"; /** The different states that Launcher can be in. */ - private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED }; + private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED } private State mState = State.WORKSPACE; private AnimatorSet mStateAnimation; private AnimatorSet mDividerAnimator; @@ -208,11 +204,8 @@ public final class Launcher extends Activity private static final int SHOW_CLING_DURATION = 550; private static final int DISMISS_CLING_DURATION = 250; - 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 static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10; private final BroadcastReceiver mCloseSystemDialogsReceiver = new CloseSystemDialogsIntentReceiver(); @@ -237,7 +230,6 @@ public final class Launcher extends Activity private FolderInfo mFolderInfo; private Hotseat mHotseat; - private View mAllAppsButton; private SearchDropTargetBar mSearchDropTargetBar; private AppsCustomizeTabHost mAppsCustomizeTabHost; @@ -262,8 +254,6 @@ public final class Launcher extends Activity // Keep track of whether the user has left launcher private static boolean sPausedFromUserAction = false; - private Bundle mSavedInstanceState; - private LauncherModel mModel; private IconCache mIconCache; private boolean mUserPresent = true; @@ -287,7 +277,7 @@ public final class Launcher extends Activity // Determines how long to wait after a rotation before restoring the screen orientation to // match the sensor state. - private final int mRestoreScreenOrientationDelay = 500; + private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500; // External icons saved in case of resource changes, orientation, etc. private static Drawable.ConstantState[] sGlobalSearchIcon = new Drawable.ConstantState[2]; @@ -346,7 +336,7 @@ public final class Launcher extends Activity private boolean doesFileExist(String filename) { - FileInputStream fis = null; + FileInputStream fis; try { fis = openFileInput(filename); fis.close(); @@ -601,18 +591,6 @@ public final class Launcher extends Activity return !mModel.isLoadingWorkspace(); } - static int getScreen() { - synchronized (sLock) { - return sScreen; - } - } - - static void setScreen(int screen) { - synchronized (sLock) { - sScreen = screen; - } - } - /** * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have * a configuration step, this allows the proper animations to run after other transitions. @@ -710,8 +688,7 @@ public final class Launcher extends Activity public void run() { completeAddAppWidget(appWidgetId, mPendingAddInfo.container, mPendingAddInfo.screen, layout, null); - exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false, - null); + exitSpringLoadedDragModeDelayed(true, false, null); } }; } else if (resultCode == RESULT_CANCELED) { @@ -719,8 +696,7 @@ public final class Launcher extends Activity onCompleteRunnable = new Runnable() { @Override public void run() { - exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false, - null); + exitSpringLoadedDragModeDelayed(false, false, null); } }; } @@ -730,7 +706,9 @@ public final class Launcher extends Activity animationType, boundWidget, true); } else { // The animated view may be null in the case of a rotation during widget configuration - onCompleteRunnable.run(); + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } } } @@ -857,9 +835,9 @@ public final class Launcher extends Activity private static State intToState(int stateOrdinal) { State state = State.WORKSPACE; final State[] stateValues = State.values(); - for (int i = 0; i < stateValues.length; i++) { - if (stateValues[i].ordinal() == stateOrdinal) { - state = stateValues[i]; + for (State stateValue : stateValues) { + if (stateValue.ordinal() == stateOrdinal) { + state = stateValue; break; } } @@ -933,17 +911,14 @@ public final class Launcher extends Activity mDragLayer = (DragLayer) findViewById(R.id.drag_layer); mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace); - mQsbDivider = (ImageView) findViewById(R.id.qsb_divider); - mDockDivider = (ImageView) findViewById(R.id.dock_divider); + mQsbDivider = findViewById(R.id.qsb_divider); + mDockDivider = findViewById(R.id.dock_divider); // Setup the drag layer mDragLayer.setup(this, dragController); // Setup the hotseat mHotseat = (Hotseat) findViewById(R.id.hotseat); - if (mHotseat != null) { - mHotseat.setup(this); - } // Setup the workspace mWorkspace.setHapticFeedbackEnabled(false); @@ -956,11 +931,11 @@ public final class Launcher extends Activity // Hide the search divider if we are hiding search bar if (!mShowSearchBar && getCurrentOrientation() == Configuration.ORIENTATION_LANDSCAPE) { - ((View) findViewById(R.id.qsb_divider)).setVisibility(View.GONE); + findViewById(R.id.qsb_divider).setVisibility(View.GONE); } if (!mShowDockDivider) { - ((View) findViewById(R.id.dock_divider)).setVisibility(View.GONE); + findViewById(R.id.dock_divider).setVisibility(View.GONE); } // Setup AppsCustomize @@ -1061,7 +1036,7 @@ public final class Launcher extends Activity info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); info.container = ItemInfo.NO_ID; - mWorkspace.addApplicationShortcut(info, layout, container, screen, cellXY[0], cellXY[1], + mWorkspace.addApplicationShortcut(info, layout, container, screen, isWorkspaceLocked(), cellX, cellY); } else { Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data); @@ -1080,7 +1055,7 @@ public final class Launcher extends Activity int[] touchXY = mPendingAddInfo.dropPos; CellLayout layout = getCellLayout(container, screen); - boolean foundCellSpan = false; + boolean foundCellSpan; ShortcutInfo info = mModel.infoFromShortcutIntent(this, data, null); if (info == null) { @@ -1101,7 +1076,7 @@ public final class Launcher extends Activity } DragObject dragObject = new DragObject(); dragObject.dragInfo = info; - if (mWorkspace.addToExistingFolderIfNecessary(view, layout, cellXY, 0, dragObject, + if (mWorkspace.addToExistingFolderIfNecessary(layout, cellXY, 0, dragObject, true)) { return; } @@ -1177,7 +1152,7 @@ public final class Launcher extends Activity int[] cellXY = mTmpAddItemCellCoordinates; int[] touchXY = mPendingAddInfo.dropPos; int[] finalSpan = new int[2]; - boolean foundCellSpan = false; + boolean foundCellSpan; if (mPendingAddInfo.cellX >= 0 && mPendingAddInfo.cellY >= 0) { cellXY[0] = mPendingAddInfo.cellX; cellXY[1] = mPendingAddInfo.cellY; @@ -1251,7 +1226,7 @@ public final class Launcher extends Activity int screen = mPendingAddInfo.screen; CellLayout layout = getCellLayout(container, screen); - boolean foundCellSpan = false; + boolean foundCellSpan; Intent data = createActionIntent(action); @@ -1277,7 +1252,7 @@ public final class Launcher extends Activity } DragObject dragObject = new DragObject(); dragObject.dragInfo = info; - if (mWorkspace.addToExistingFolderIfNecessary(view, layout, cellXY, 0, dragObject, + if (mWorkspace.addToExistingFolderIfNecessary(layout, cellXY, 0, dragObject, true)) { return; } @@ -1291,14 +1266,13 @@ public final class Launcher extends Activity if (!foundCellSpan) { showOutOfSpaceMessage(isHotseatLayout(layout)); - return; - } - - LauncherModel.addItemToDatabase(this, info, container, screen, cellXY[0], cellXY[1], false); + } else if (cellXY != null) { + LauncherModel.addItemToDatabase(this, info, container, screen, cellXY[0], cellXY[1], false); - if (!mRestoring) { - mWorkspace.addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, - isWorkspaceLocked()); + if (!mRestoring) { + mWorkspace.addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, + isWorkspaceLocked()); + } } } @@ -1663,7 +1637,7 @@ public final class Launcher extends Activity /** * Indicates that we want global search for this activity by setting the globalSearch - * argument for {@link #startSearch} to true. + * argument for startSearch to true. */ @Override public void startSearch(String initialQuery, boolean selectInitialQuery, @@ -1945,7 +1919,7 @@ public final class Launcher extends Activity appWidgetId = getAppWidgetHost().allocateAppWidgetId(); Bundle options = info.bindOptions; - boolean success = false; + boolean success; if (options != null) { success = mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.componentName, options); @@ -1987,7 +1961,7 @@ public final class Launcher extends Activity // Create the view FolderIcon newFolder = - FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo, mIconCache); + FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo); if (mHideIconLabels) { newFolder.setTextVisible(false); } @@ -2005,18 +1979,7 @@ public final class Launcher extends Activity final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER); Intent chooser = Intent.createChooser(pickWallpaper, getText(R.string.chooser_wallpaper)); - // NOTE: Adds a configure option to the chooser if the wallpaper supports it - // Removed in Eclair MR1 -// WallpaperManager wm = (WallpaperManager) -// getSystemService(Context.WALLPAPER_SERVICE); -// WallpaperInfo wi = wm.getWallpaperInfo(); -// if (wi != null && wi.getSettingsActivity() != null) { -// LabeledIntent li = new LabeledIntent(getPackageName(), -// R.string.configure_wallpaper, 0); -// li.setClassName(wi.getPackageName(), wi.getSettingsActivity()); -// chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { li }); -// } - startActivityForResult(chooser, REQUEST_PICK_WALLPAPER); + processWallpaper(chooser); } /** @@ -2116,12 +2079,6 @@ public final class Launcher extends Activity FolderIcon fi = (FolderIcon) v; handleFolderClick(fi); } - } else if (v == mAllAppsButton) { - if (isAllAppsVisible()) { - showWorkspace(true); - } else { - onClickAllAppsButton(v); - } } } @@ -2168,21 +2125,6 @@ public final class Launcher extends Activity } } - /** - * Event handler for the "grid" button that appears on the home screen, which - * enters all apps mode. - * - * @param v The view that was clicked. - */ - public void onClickAllAppsButton(View v) { - showAllApps(true); - } - - public void onTouchDownAllAppsButton(View v) { - // Provide the same haptic feedback that the system offers for virtual keys. - v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); - } - public void onClickAppMarketButton(View v) { if (mAppMarketIntent != null) { startActivitySafely(v, mAppMarketIntent, "app market"); @@ -2478,7 +2420,7 @@ public final class Launcher extends Activity // There was a one-off crash where the folder had a parent already. if (folder.getParent() == null) { mDragLayer.addView(folder); - mDragController.addDropTarget((DropTarget) folder); + mDragController.addDropTarget(folder); } else { Log.w(TAG, "Opening folder (" + folder + ") which already has a parent (" + folder.getParent() + ")."); @@ -2639,10 +2581,9 @@ public final class Launcher extends Activity /** * Helper method for the cameraZoomIn/cameraZoomOut animations * @param view The view being animated - * @param state The state that we are moving in or out of (eg. APPS_CUSTOMIZE) - * @param scaleFactor The scale factor used for the zoom + * */ - private void setPivotsForZoom(View view, float scaleFactor) { + private void setPivotsForZoom(View view) { view.setPivotX(view.getWidth() / 2.0f); view.setPivotY(view.getHeight() / 2.0f); } @@ -2770,7 +2711,7 @@ public final class Launcher extends Activity final int startDelay = res.getInteger(R.integer.config_workspaceAppsCustomizeAnimationStagger); - setPivotsForZoom(toView, scale); + setPivotsForZoom(toView); // Shrink workspaces away if going to AppsCustomize from workspace Animator workspaceAnim = @@ -2859,7 +2800,7 @@ public final class Launcher extends Activity // If any of the objects being animated haven't been measured/laid out // yet, delay the animation until we get a layout pass - if ((((LauncherTransitionable) toView).getContent().getMeasuredWidth() == 0) || + if ((toView.getContent().getMeasuredWidth() == 0) || (mWorkspace.getMeasuredWidth() == 0) || (toView.getMeasuredWidth() == 0)) { observer = mWorkspace.getViewTreeObserver(); @@ -2875,7 +2816,7 @@ public final class Launcher extends Activity // we waited for a layout/draw pass if (mStateAnimation != stateAnimation) return; - setPivotsForZoom(toView, scale); + setPivotsForZoom(toView); dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); toView.post(new Runnable() { @@ -2934,7 +2875,7 @@ public final class Launcher extends Activity * @param animated If true, the transition will be animated. */ private void hideAppsCustomizeHelper(State toState, final boolean animated, - final boolean springLoaded, final Runnable onCompleteRunnable) { + final Runnable onCompleteRunnable) { if (mStateAnimation != null) { mStateAnimation.cancel(); @@ -2960,7 +2901,7 @@ public final class Launcher extends Activity Workspace.State.SPRING_LOADED, animated); } - setPivotsForZoom(fromView, scaleFactor); + setPivotsForZoom(fromView); updateWallpaperVisibility(true); showHotseat(animated); if (animated) { @@ -3071,7 +3012,7 @@ public final class Launcher extends Activity if (mState != State.WORKSPACE) { boolean wasInSpringLoadedMode = (mState == State.APPS_CUSTOMIZE_SPRING_LOADED); mWorkspace.setVisibility(View.VISIBLE); - hideAppsCustomizeHelper(State.WORKSPACE, animated, false, onCompleteRunnable); + hideAppsCustomizeHelper(State.WORKSPACE, animated, onCompleteRunnable); // Show the search bar (only animate if we were showing the drop target bar in spring // loaded mode) @@ -3081,11 +3022,6 @@ public final class Launcher extends Activity // We only need to animate in the dock divider if we're going from spring loaded mode showDockDivider(animated && wasInSpringLoadedMode); - - // Set focus to the AppsCustomize button - if (mAllAppsButton != null) { - mAllAppsButton.requestFocus(); - } } mWorkspace.flashScrollingIndicator(animated); @@ -3123,7 +3059,7 @@ public final class Launcher extends Activity void enterSpringLoadedDragMode() { if (isAllAppsVisible()) { - hideAppsCustomizeHelper(State.APPS_CUSTOMIZE_SPRING_LOADED, true, true, null); + hideAppsCustomizeHelper(State.APPS_CUSTOMIZE_SPRING_LOADED, true, null); hideDockDivider(); mState = State.APPS_CUSTOMIZE_SPRING_LOADED; } @@ -3248,16 +3184,6 @@ public final class Launcher extends Activity } } - /** - * Add an item from all apps or customize onto the given workspace screen. - * If layout is null, add to the current screen. - */ - void addExternalItemToScreen(ItemInfo itemInfo, final CellLayout layout) { - if (!mWorkspace.addExternalItemToScreen(itemInfo, layout)) { - showOutOfSpaceMessage(isHotseatLayout(layout)); - } - } - public int getCurrentOrientation() { return getResources().getConfiguration().orientation; } @@ -3406,7 +3332,7 @@ public final class Launcher extends Activity private void updateGlobalSearchIcon(Drawable.ConstantState d) { final View searchButtonContainer = findViewById(R.id.search_button_container); - final View searchButton = (ImageView) findViewById(R.id.search_button); + final View searchButton = findViewById(R.id.search_button); updateButtonWithDrawable(R.id.search_button, d); invalidatePressedFocusedStates(searchButtonContainer, searchButton); } @@ -3770,7 +3696,7 @@ public final class Launcher extends Activity case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: ShortcutInfo info = (ShortcutInfo) item; - String uri = info.intent.toUri(0).toString(); + String uri = info.intent.toUri(0); View shortcut = createShortcut(info); workspace.addInScreen(shortcut, item.container, item.screen, item.cellX, item.cellY, 1, 1, false); @@ -3794,7 +3720,7 @@ public final class Launcher extends Activity case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()), - (FolderInfo) item, mIconCache); + (FolderInfo) item); if (!mHideIconLabels) { newFolder.setTextVisible(false); } @@ -3876,8 +3802,8 @@ public final class Launcher extends Activity // If we received the result of any pending adds while the loader was running (e.g. the // widget configuration forced an orientation change), process them now. - for (int i = 0; i < sPendingAddList.size(); i++) { - completeAdd(sPendingAddList.get(i)); + for (PendingAddArguments pendingAdd : sPendingAddList) { + completeAdd(pendingAdd); } sPendingAddList.clear(); @@ -3956,7 +3882,7 @@ public final class Launcher extends Activity PropertyValuesHolder.ofFloat("scaleY", 1f)); bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); - bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator()); + bounceAnim.setInterpolator(new PagedView.OvershootInterpolator()); bounceAnims.add(bounceAnim); } anim.playTogether(bounceAnims); @@ -4115,20 +4041,14 @@ public final class Launcher extends Activity return oriMap[(d.getRotation() + indexOffset) % 4]; } - public boolean isRotationEnabled() { - boolean forceEnableRotation = doesFileExist(FORCE_ENABLE_ROTATION_PROPERTY); - boolean enableRotation = forceEnableRotation || - getResources().getBoolean(R.bool.allow_rotation) || mAutoRotate; - return enableRotation; - } public void lockScreenOrientation() { - if (isRotationEnabled()) { + if (mAutoRotate) { setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources() .getConfiguration().orientation)); } } public void unlockScreenOrientation(boolean immediate) { - if (isRotationEnabled()) { + if (mAutoRotate) { if (immediate) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } else { @@ -4136,7 +4056,7 @@ public final class Launcher extends Activity public void run() { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } - }, mRestoreScreenOrientationDelay); + }, RESTORE_SCREEN_ORIENTATION_DELAY); } } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); @@ -4146,9 +4066,8 @@ public final class Launcher extends Activity /* Cling related */ private boolean isClingsEnabled() { // disable clings when running in a test harness - if(ActivityManager.isRunningInTestHarness()) return false; + return !ActivityManager.isRunningInTestHarness(); - return true; } private Cling initCling(int clingId, int[] positionData, boolean animate, int delay) { @@ -4199,7 +4118,7 @@ public final class Launcher extends Activity editor.commit(); } }.start(); - }; + } }); anim.start(); mHideFromAccessibilityHelper.restoreImportantForAccessibility(mDragLayer); @@ -4286,10 +4205,7 @@ public final class Launcher extends Activity } public boolean isFolderClingVisible() { Cling cling = (Cling) findViewById(R.id.folder_cling); - if (cling != null) { - return cling.getVisibility() == View.VISIBLE; - } - return false; + return cling != null && cling.getVisibility() == View.VISIBLE; } public void dismissWorkspaceCling(View v) { Cling cling = (Cling) findViewById(R.id.workspace_cling); @@ -4329,7 +4245,7 @@ public final class Launcher extends Activity Log.d(TAG, "mWorkspaceLoading=" + mWorkspaceLoading); Log.d(TAG, "mRestoring=" + mRestoring); Log.d(TAG, "mWaitingForResult=" + mWaitingForResult); - Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState); + Log.d(TAG, "mSavedInstanceState=" + mSavedState); Log.d(TAG, "sFolders.size=" + sFolders.size()); mModel.dumpState(); @@ -4344,8 +4260,8 @@ public final class Launcher extends Activity super.dump(prefix, fd, writer, args); writer.println(" "); writer.println("Debug logs: "); - for (int i = 0; i < sDumpLogs.size(); i++) { - writer.println(" " + sDumpLogs.get(i)); + for (String dumpLog : sDumpLogs) { + writer.println(" " + dumpLog); } } @@ -4353,8 +4269,8 @@ public final class Launcher extends Activity Log.d(TAG, ""); Log.d(TAG, "*********************"); Log.d(TAG, "Launcher debug logs: "); - for (int i = 0; i < sDumpLogs.size(); i++) { - Log.d(TAG, " " + sDumpLogs.get(i)); + for (String dumpLog : sDumpLogs) { + Log.d(TAG, " " + dumpLog); } Log.d(TAG, "*********************"); Log.d(TAG, ""); diff --git a/src/com/cyanogenmod/trebuchet/LauncherAppWidgetHostView.java b/src/com/cyanogenmod/trebuchet/LauncherAppWidgetHostView.java index 81c218b..d87c536 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherAppWidgetHostView.java +++ b/src/com/cyanogenmod/trebuchet/LauncherAppWidgetHostView.java @@ -56,10 +56,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView { public boolean orientationChangedSincedInflation() { int orientation = mContext.getResources().getConfiguration().orientation; - if (mPreviousOrientation != orientation) { - return true; - } - return false; + return mPreviousOrientation != orientation; } public boolean onInterceptTouchEvent(MotionEvent ev) { diff --git a/src/com/cyanogenmod/trebuchet/LauncherModel.java b/src/com/cyanogenmod/trebuchet/LauncherModel.java index 36a8043..fdcaba1 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherModel.java +++ b/src/com/cyanogenmod/trebuchet/LauncherModel.java @@ -27,7 +27,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; -import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -47,13 +46,11 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; -import com.cyanogenmod.trebuchet.R; -import com.cyanogenmod.trebuchet.InstallWidgetReceiver.WidgetMimeTypeHandlerData; - import java.lang.ref.WeakReference; import java.net.URISyntaxException; import java.text.Collator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -68,13 +65,11 @@ import java.util.Set; * for the Launcher. */ public class LauncherModel extends BroadcastReceiver { - static final boolean DEBUG_LOADERS = false; + private static final boolean DEBUG_LOADERS = false; private static final String TAG = "Trebuchet.LauncherModel"; private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons private final boolean mAppsCanBeOnExternalStorage; - private int mBatchSize; // 0 is all apps at once - private int mAllAppsLoadDelay; // milliseconds between batches private final LauncherApplication mApp; private final Object mLock = new Object(); @@ -173,8 +168,6 @@ public class LauncherModel extends BroadcastReceiver { mIconCache.getFullResDefaultActivityIcon(), app); final Resources res = app.getResources(); - mAllAppsLoadDelay = res.getInteger(R.integer.config_allAppsBatchLoadDelay); - mBatchSize = res.getInteger(R.integer.config_allAppsBatchSize); Configuration config = res.getConfiguration(); mPreviousConfigMcc = config.mcc; } @@ -182,9 +175,6 @@ public class LauncherModel extends BroadcastReceiver { /** Runs the specified runnable immediately if called from the main thread, otherwise it is * posted on the main thread handler. */ private void runOnMainThread(Runnable r) { - runOnMainThread(r, 0); - } - private void runOnMainThread(Runnable r, int type) { if (sWorkerThread.getThreadId() == Process.myTid()) { // If we are on the worker thread, post onto the main handler mHandler.post(r); @@ -318,7 +308,7 @@ public class LauncherModel extends BroadcastReceiver { } static void updateItemInDatabaseHelper(Context context, final ContentValues values, - final ItemInfo item, final String callingFunction) { + final ItemInfo item) { final long itemId = item.id; final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false); final ContentResolver cr = context.getContentResolver(); @@ -393,7 +383,7 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites.CELLY, item.cellY); values.put(LauncherSettings.Favorites.SCREEN, item.screen); - updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase"); + updateItemInDatabaseHelper(context, values, item); } /** @@ -428,7 +418,7 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites.SPANY, item.spanY); values.put(LauncherSettings.Favorites.SCREEN, item.screen); - updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase"); + updateItemInDatabaseHelper(context, values, item); } /** @@ -438,7 +428,7 @@ public class LauncherModel extends BroadcastReceiver { final ContentValues values = new ContentValues(); item.onAddToDatabase(values); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); - updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase"); + updateItemInDatabaseHelper(context, values, item); } /** @@ -527,12 +517,14 @@ public class LauncherModel extends BroadcastReceiver { break; } - folderInfo.title = c.getString(titleIndex); - folderInfo.id = id; - folderInfo.container = c.getInt(containerIndex); - folderInfo.screen = c.getInt(screenIndex); - folderInfo.cellX = c.getInt(cellXIndex); - folderInfo.cellY = c.getInt(cellYIndex); + if (folderInfo != null) { + folderInfo.title = c.getString(titleIndex); + folderInfo.id = id; + folderInfo.container = c.getInt(containerIndex); + folderInfo.screen = c.getInt(screenIndex); + folderInfo.cellX = c.getInt(cellXIndex); + folderInfo.cellY = c.getInt(cellYIndex); + } return folderInfo; } @@ -564,8 +556,6 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites._ID, item.id); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - Runnable r = new Runnable() { public void run() { String transaction = "DbDebug Add item (" + item.title + ") to db, id: " @@ -613,8 +603,7 @@ public class LauncherModel extends BroadcastReceiver { /** * Creates a new unique child id, for a given cell span across all layouts. */ - static int getCellLayoutChildId( - long container, int screen, int localCellX, int localCellY, int spanX, int spanY) { + static int getCellLayoutChildId(long container, int screen, int localCellX, int localCellY) { return (((int) container & 0xFF) << 24) | (screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); } @@ -1048,7 +1037,7 @@ public class LauncherModel extends BroadcastReceiver { // All Apps interface in the foreground, load All Apps first. Otherwise, load the // workspace first (default). final Callbacks cbk = mCallbacks.get(); - final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true; + final boolean loadWorkspaceFirst = cbk == null || !cbk.isAllAppsVisible(); keep_running: { // Elevate priority when Home launches for the first time to avoid @@ -1609,7 +1598,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); } } @@ -1626,7 +1615,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); } } @@ -1645,7 +1634,7 @@ public class LauncherModel extends BroadcastReceiver { if (postOnMainThread) { deferredBindRunnables.add(r); } else { - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); } } } @@ -1713,7 +1702,7 @@ public class LauncherModel extends BroadcastReceiver { } } }; - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); // Load items on the current page bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, @@ -1727,7 +1716,7 @@ public class LauncherModel extends BroadcastReceiver { } } }; - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); } // Load all the remaining pages (if we are loading synchronously, we want to defer this @@ -1756,7 +1745,7 @@ public class LauncherModel extends BroadcastReceiver { if (isLoadingSynchronously) { mDeferredBindRunnables.add(r); } else { - runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + runOnMainThread(r); } } @@ -1825,102 +1814,64 @@ public class LauncherModel extends BroadcastReceiver { final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - final PackageManager packageManager = mContext.getPackageManager(); - List<ResolveInfo> apps = null; - - int N = Integer.MAX_VALUE; - - int startIndex; - int i=0; - int batchSize = -1; - while (i < N && !mStopped) { - if (i == 0) { - mBgAllAppsList.clear(); - final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - apps = packageManager.queryIntentActivities(mainIntent, 0); - if (DEBUG_LOADERS) { - Log.d(TAG, "queryIntentActivities took " - + (SystemClock.uptimeMillis()-qiaTime) + "ms"); - } - if (apps == null) { - return; - } - N = apps.size(); - if (DEBUG_LOADERS) { - Log.d(TAG, "queryIntentActivities got " + N + " apps"); - } - if (N == 0) { - // There are no apps?!? - return; - } - if (mBatchSize == 0) { - batchSize = N; - } else { - batchSize = mBatchSize; - } + mBgAllAppsList.clear(); + final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - Collections.sort(apps, - new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache)); - if (DEBUG_LOADERS) { - Log.d(TAG, "sort took " - + (SystemClock.uptimeMillis()-sortTime) + "ms"); - } - } - - final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + final PackageManager packageManager = mContext.getPackageManager(); + List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); - startIndex = i; - for (int j=0; i<N && j<batchSize; j++) { - // This builds the icon bitmaps. - mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), - mIconCache, mLabelCache)); - i++; - } + if (DEBUG_LOADERS) { + Log.d(TAG, "queryIntentActivities took " + + (SystemClock.uptimeMillis()-qiaTime) + "ms"); + } + if (apps == null) { + return; + } + int N = apps.size(); + if (DEBUG_LOADERS) { + Log.d(TAG, "queryIntentActivities got " + N + " apps"); + } + if (N == 0) { + // There are no apps?!? + return; + } - final boolean first = i <= batchSize; - final Callbacks callbacks = tryGetCallbacks(oldCallbacks); - final ArrayList<ApplicationInfo> added = mBgAllAppsList.added; - mBgAllAppsList.added = new ArrayList<ApplicationInfo>(); + final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + Collections.sort(apps, + new ShortcutNameComparator(packageManager, mLabelCache)); + if (DEBUG_LOADERS) { + Log.d(TAG, "sort took " + + (SystemClock.uptimeMillis()-sortTime) + "ms"); + } - mHandler.post(new Runnable() { - public void run() { - final long t = SystemClock.uptimeMillis(); - if (callbacks != null) { - if (first) { - callbacks.bindAllApplications(added); - } else { - callbacks.bindAppsAdded(added); - } - if (DEBUG_LOADERS) { - Log.d(TAG, "bound " + added.size() + " apps in " - + (SystemClock.uptimeMillis() - t) + "ms"); - } - } else { - Log.i(TAG, "not binding apps: no Launcher activity"); - } - } - }); + for (ResolveInfo info : apps) { + // This builds the icon bitmaps. + mBgAllAppsList.add(new ApplicationInfo(packageManager, info, + mIconCache, mLabelCache)); + } - if (DEBUG_LOADERS) { - Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in " - + (SystemClock.uptimeMillis()-t2) + "ms"); - } + final Callbacks callbacks = tryGetCallbacks(oldCallbacks); + final ArrayList<ApplicationInfo> added = mBgAllAppsList.added; + mBgAllAppsList.added = new ArrayList<ApplicationInfo>(); - if (mAllAppsLoadDelay > 0 && i < N) { - try { + mHandler.post(new Runnable() { + public void run() { + final long t = SystemClock.uptimeMillis(); + if (callbacks != null) { + callbacks.bindAllApplications(added); if (DEBUG_LOADERS) { - Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms"); + Log.d(TAG, "bound " + added.size() + " apps in " + + (SystemClock.uptimeMillis() - t) + "ms"); } - Thread.sleep(mAllAppsLoadDelay); - } catch (InterruptedException exc) { } + } else { + Log.i(TAG, "not binding apps: no Launcher activity"); + } } - } + }); if (DEBUG_LOADERS) { Log.d(TAG, "cached all " + N + " apps in " - + (SystemClock.uptimeMillis()-t) + "ms" - + (mAllAppsLoadDelay > 0 ? " (including delay)" : "")); + + (SystemClock.uptimeMillis()-t) + "ms"); } } @@ -1959,25 +1910,24 @@ public class LauncherModel extends BroadcastReceiver { final Context context = mApp; final String[] packages = mPackages; - final int N = packages.length; switch (mOp) { case OP_ADD: - for (int i=0; i<N; i++) { - if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); - mBgAllAppsList.addPackage(context, packages[i]); + for (String p : packages) { + if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + p); + mBgAllAppsList.addPackage(context, p); } break; case OP_UPDATE: - for (int i=0; i<N; i++) { - if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); - mBgAllAppsList.updatePackage(context, packages[i]); + for (String p : packages) { + if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + p); + mBgAllAppsList.updatePackage(context, p); } break; case OP_REMOVE: case OP_UNAVAILABLE: - for (int i=0; i<N; i++) { - if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); - mBgAllAppsList.removePackage(packages[i]); + for (String p : packages) { + if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + p); + mBgAllAppsList.removePackage(p); } break; } @@ -2000,9 +1950,7 @@ public class LauncherModel extends BroadcastReceiver { if (mBgAllAppsList.removed.size() > 0) { mBgAllAppsList.removed.clear(); - for (int i = 0; i < N; ++i) { - removedPackageNames.add(packages[i]); - } + removedPackageNames.addAll(Arrays.asList(packages)); } final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; @@ -2016,7 +1964,7 @@ public class LauncherModel extends BroadcastReceiver { mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == cb && cb != null) { + if (callbacks == cb) { callbacks.bindAppsAdded(addedFinal); } } @@ -2027,7 +1975,7 @@ public class LauncherModel extends BroadcastReceiver { mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == cb && cb != null) { + if (callbacks == cb) { callbacks.bindAppsUpdated(modifiedFinal); } } @@ -2038,7 +1986,7 @@ public class LauncherModel extends BroadcastReceiver { mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == cb && cb != null) { + if (callbacks == cb) { callbacks.bindAppsRemoved(removedPackageNames, permanent); } } @@ -2049,7 +1997,7 @@ public class LauncherModel extends BroadcastReceiver { @Override public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == cb && cb != null) { + if (callbacks == cb) { callbacks.bindPackagesUpdated(); } } @@ -2268,59 +2216,6 @@ public class LauncherModel extends BroadcastReceiver { return info; } - /** - * Attempts to find an AppWidgetProviderInfo that matches the given component. - */ - AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context, - ComponentName component) { - List<AppWidgetProviderInfo> widgets = - AppWidgetManager.getInstance(context).getInstalledProviders(); - for (AppWidgetProviderInfo info : widgets) { - if (info.provider.equals(component)) { - return info; - } - } - return null; - } - - /** - * Returns a list of all the widgets that can handle configuration with a particular mimeType. - */ - List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) { - final PackageManager packageManager = context.getPackageManager(); - final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities = - new ArrayList<WidgetMimeTypeHandlerData>(); - - final Intent supportsIntent = - new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE); - supportsIntent.setType(mimeType); - - // Create a set of widget configuration components that we can test against - final List<AppWidgetProviderInfo> widgets = - AppWidgetManager.getInstance(context).getInstalledProviders(); - final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget = - new HashMap<ComponentName, AppWidgetProviderInfo>(); - for (AppWidgetProviderInfo info : widgets) { - configurationComponentToWidget.put(info.configure, info); - } - - // Run through each of the intents that can handle this type of clip data, and cross - // reference them with the components that are actual configuration components - final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent, - PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo info : activities) { - final ActivityInfo activityInfo = info.activityInfo; - final ComponentName infoComponent = new ComponentName(activityInfo.packageName, - activityInfo.name); - if (configurationComponentToWidget.containsKey(infoComponent)) { - supportedConfigurationActivities.add( - new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info, - configurationComponentToWidget.get(infoComponent))); - } - } - return supportedConfigurationActivities; - } - ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) { Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); @@ -2454,7 +2349,7 @@ public class LauncherModel extends BroadcastReceiver { final Collator collator = Collator.getInstance(); return new Comparator<AppWidgetProviderInfo>() { public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) { - return collator.compare(a.label.toString(), b.label.toString()); + return collator.compare(a.label, b.label); } }; } @@ -2499,7 +2394,7 @@ public class LauncherModel extends BroadcastReceiver { } return mCollator.compare(labelA, labelB); } - }; + } public static class WidgetAndShortcutNameComparator implements Comparator<Object> { private Collator mCollator; private PackageManager mPackageManager; @@ -2537,7 +2432,7 @@ public class LauncherModel extends BroadcastReceiver { } return mCollator.compare(labelA, labelB); } - }; + } public void dumpState() { Log.d(TAG, "mCallbacks=" + mCallbacks); diff --git a/src/com/cyanogenmod/trebuchet/LauncherProvider.java b/src/com/cyanogenmod/trebuchet/LauncherProvider.java index 4e4c1b2..45ae99c 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherProvider.java +++ b/src/com/cyanogenmod/trebuchet/LauncherProvider.java @@ -49,7 +49,6 @@ import android.util.AttributeSet; import android.util.Log; import android.util.Xml; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.LauncherSettings.Favorites; import org.xmlpull.v1.XmlPullParser; @@ -157,9 +156,8 @@ public class LauncherProvider extends ContentProvider { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.beginTransaction(); try { - int numValues = values.length; - for (int i = 0; i < numValues; i++) { - if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) { + for (ContentValues value : values) { + if (dbInsertAndCheck(mOpenHelper, db, args.table, null, value) < 0) { return 0; } } @@ -774,12 +772,12 @@ public class LauncherProvider extends ContentProvider { } } - private static final void beginDocument(XmlPullParser parser, String firstElementName) + private static void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException { int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { - ; + } if (type != XmlPullParser.START_TAG) { @@ -850,7 +848,7 @@ public class LauncherProvider extends ContentProvider { } else if (TAG_CLOCK.equals(name)) { added = addClockWidget(db, values); } else if (TAG_APPWIDGET.equals(name)) { - added = addAppWidget(parser, attrs, type, db, values, a, packageManager); + added = addAppWidget(parser, attrs, db, values, a, packageManager); } else if (TAG_SHORTCUT.equals(name)) { long id = addUriShortcut(db, values, a); added = id >= 0; @@ -990,9 +988,8 @@ public class LauncherProvider extends ContentProvider { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders(); if (providers == null) return null; - final int providerCount = providers.size(); - for (int i = 0; i < providerCount; i++) { - ComponentName provider = providers.get(i).provider; + for (AppWidgetProviderInfo p : providers) { + ComponentName provider = p.provider; if (provider != null && provider.getPackageName().equals(packageName)) { return provider; } @@ -1011,7 +1008,7 @@ public class LauncherProvider extends ContentProvider { return addAppWidget(db, values, cn, 2, 2, null); } - private boolean addAppWidget(XmlResourceParser parser, AttributeSet attrs, int type, + private boolean addAppWidget(XmlResourceParser parser, AttributeSet attrs, SQLiteDatabase db, ContentValues values, TypedArray a, PackageManager packageManager) throws XmlPullParserException, IOException { @@ -1044,6 +1041,7 @@ public class LauncherProvider extends ContentProvider { // Read the extras Bundle extras = new Bundle(); int widgetDepth = parser.getDepth(); + int type; while ((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > widgetDepth) { if (type != XmlPullParser.START_TAG) { diff --git a/src/com/cyanogenmod/trebuchet/PagedView.java b/src/com/cyanogenmod/trebuchet/PagedView.java index a2b353f..0076b83 100644 --- a/src/com/cyanogenmod/trebuchet/PagedView.java +++ b/src/com/cyanogenmod/trebuchet/PagedView.java @@ -177,7 +177,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected boolean mUsePagingTouchSlop = true; // If true, the subclass should directly update scrollX itself in its computeScroll method - // (SmoothPagedView does this) protected boolean mDeferScrollUpdate = false; protected boolean mIsPageMoving = false; @@ -461,7 +460,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mSmoothingTime = System.nanoTime() / NANOTIME_DIV; } - // we moved this functionality to a helper function so SmoothPagedView can reuse it protected boolean computeScrollHelper() { if (mScroller.computeScrollOffset()) { // Don't bother scrolling if the page does not need to be moved @@ -1696,6 +1694,30 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } + public static class OvershootInterpolator implements Interpolator { + private static final float DEFAULT_TENSION = 1.3f; + private float mTension; + + public OvershootInterpolator() { + mTension = DEFAULT_TENSION; + } + + public void setDistance(int distance) { + mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION; + } + + public void disableSettle() { + mTension = 0.f; + } + + public float getInterpolation(float t) { + // _o(t) = t * t * ((tension + 1) * t + tension) + // o(t) = _o(t - 1) + 1 + t -= 1.0f; + return t * t * ((mTension + 1) * t + mTension) + 1.0f; + } + } + protected Interpolator getScrollInterpolator() { return new QuintInterpolator(); } diff --git a/src/com/cyanogenmod/trebuchet/ShortcutInfo.java b/src/com/cyanogenmod/trebuchet/ShortcutInfo.java index 3c1f985..0a8dbf9 100644 --- a/src/com/cyanogenmod/trebuchet/ShortcutInfo.java +++ b/src/com/cyanogenmod/trebuchet/ShortcutInfo.java @@ -17,6 +17,7 @@ package com.cyanogenmod.trebuchet; import java.util.ArrayList; +import java.util.Arrays; import android.content.ComponentName; import android.content.ContentValues; @@ -169,7 +170,7 @@ class ShortcutInfo extends ItemInfo { return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY - + " dropPos=" + dropPos + ")"; + + " dropPos=" + Arrays.toString(dropPos) + ")"; } public static void dumpShortcutInfoList(String tag, String label, diff --git a/src/com/cyanogenmod/trebuchet/SmoothPagedView.java b/src/com/cyanogenmod/trebuchet/SmoothPagedView.java deleted file mode 100644 index 86caf9e..0000000 --- a/src/com/cyanogenmod/trebuchet/SmoothPagedView.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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. - */ - -package com.cyanogenmod.trebuchet; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.animation.Interpolator; -import android.widget.Scroller; - -public abstract class SmoothPagedView extends PagedView { - private static final float SMOOTHING_SPEED = 0.75f; - private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED)); - - private float mBaseLineFlingVelocity; - private float mFlingVelocityInfluence; - - static final int DEFAULT_MODE = 0; - static final int X_LARGE_MODE = 1; - - int mScrollMode; - - private Interpolator mScrollInterpolator; - - public static class OvershootInterpolator implements Interpolator { - private static final float DEFAULT_TENSION = 1.3f; - private float mTension; - - public OvershootInterpolator() { - mTension = DEFAULT_TENSION; - } - - public void setDistance(int distance) { - mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION; - } - - public void disableSettle() { - mTension = 0.f; - } - - public float getInterpolation(float t) { - // _o(t) = t * t * ((tension + 1) * t + tension) - // o(t) = _o(t - 1) + 1 - t -= 1.0f; - return t * t * ((mTension + 1) * t + mTension) + 1.0f; - } - } - - /** - * Used to inflate the Workspace from XML. - * - * @param context The application's context. - * @param attrs The attributes set containing the Workspace's customization values. - */ - public SmoothPagedView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - /** - * Used to inflate the Workspace from XML. - * - * @param context The application's context. - * @param attrs The attributes set containing the Workspace's customization values. - * @param defStyle Unused. - */ - public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mUsePagingTouchSlop = false; - - // This means that we'll take care of updating the scroll parameter ourselves (we do it - // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones - mDeferScrollUpdate = mScrollMode != X_LARGE_MODE; - } - - protected int getScrollMode() { - return X_LARGE_MODE; - } - - /** - * Initializes various states for this workspace. - */ - @Override - protected void init() { - super.init(); - - mScrollMode = getScrollMode(); - if (mScrollMode == DEFAULT_MODE) { - mBaseLineFlingVelocity = 2500.0f; - mFlingVelocityInfluence = 0.4f; - mScrollInterpolator = new OvershootInterpolator(); - mScroller = new Scroller(getContext(), mScrollInterpolator); - } - } - - @Override - protected void snapToDestination() { - if (mScrollMode == X_LARGE_MODE) { - super.snapToDestination(); - } else { - snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0); - } - } - - @Override - protected void snapToPageWithVelocity(int whichPage, int velocity) { - if (mScrollMode == X_LARGE_MODE) { - super.snapToPageWithVelocity(whichPage, velocity); - } else { - snapToPageWithVelocity(whichPage, 0, true); - } - } - - private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) { - // if (!mScroller.isFinished()) return; - - whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1)); - - final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage)); - final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); - final int delta = newX - mUnboundedScrollX; - int duration = (screenDelta + 1) * 100; - - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - - if (settle) { - ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta); - } else { - ((OvershootInterpolator) mScrollInterpolator).disableSettle(); - } - - velocity = Math.abs(velocity); - if (velocity > 0) { - duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence; - } else { - duration += 100; - } - - snapToPage(whichPage, delta, duration); - } - - @Override - protected void snapToPage(int whichPage) { - if (mScrollMode == X_LARGE_MODE) { - super.snapToPage(whichPage); - } else { - snapToPageWithVelocity(whichPage, 0, false); - } - } - - @Override - public void computeScroll() { - if (mScrollMode == X_LARGE_MODE) { - super.computeScroll(); - } else { - boolean scrollComputed = computeScrollHelper(); - - if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) { - final float now = System.nanoTime() / NANOTIME_DIV; - final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT); - - final float dx = mTouchX - mUnboundedScrollX; - scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY()); - mSmoothingTime = now; - - // Keep generating points as long as we're more than 1px away from the target - if (dx > 1.f || dx < -1.f) { - invalidate(); - } - } - } - } -} diff --git a/src/com/cyanogenmod/trebuchet/StrokedTextView.java b/src/com/cyanogenmod/trebuchet/StrokedTextView.java index 007ddf5..be2bd06 100644 --- a/src/com/cyanogenmod/trebuchet/StrokedTextView.java +++ b/src/com/cyanogenmod/trebuchet/StrokedTextView.java @@ -105,12 +105,12 @@ public class StrokedTextView extends TextView { final int drawableLeft = getPaddingLeft(); final int drawableTop = getPaddingTop(); final Drawable[] drawables = getCompoundDrawables(); - for (int i = 0; i < drawables.length; ++i) { - if (drawables[i] != null) { - drawables[i].setBounds(drawableLeft, drawableTop, - drawableLeft + drawables[i].getIntrinsicWidth(), - drawableTop + drawables[i].getIntrinsicHeight()); - drawables[i].draw(mCanvas); + for (Drawable drawable : drawables) { + if (drawable != null) { + drawable.setBounds(drawableLeft, drawableTop, + drawableLeft + drawable.getIntrinsicWidth(), + drawableTop + drawable.getIntrinsicHeight()); + drawable.draw(mCanvas); } } diff --git a/src/com/cyanogenmod/trebuchet/SymmetricalLinearTween.java b/src/com/cyanogenmod/trebuchet/SymmetricalLinearTween.java deleted file mode 100644 index 240305f..0000000 --- a/src/com/cyanogenmod/trebuchet/SymmetricalLinearTween.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -package com.cyanogenmod.trebuchet; - -import android.os.Handler; -import android.os.SystemClock; - -/** - * Provides an animation between 0.0f and 1.0f over a given duration. - */ -class SymmetricalLinearTween { - - private static final int FPS = 30; - private static final int FRAME_TIME = 1000 / FPS; - - Handler mHandler; - int mDuration; - TweenCallback mCallback; - - boolean mRunning; - long mBase; - boolean mDirection; - float mValue; - - /** - * @param duration milliseconds duration - * @param callback callbacks - */ - public SymmetricalLinearTween(boolean initial, int duration, TweenCallback callback) { - mValue = initial ? 1.0f : 0.0f; - mDirection = initial; - mDuration = duration; - mCallback = callback; - mHandler = new Handler(); - } - - /** - * Starts the tweening. - * - * @param direction If direction is true, the value goes towards 1.0f. If direction - * is false, the value goes towards 0.0f. - */ - public void start(boolean direction) { - start(direction, SystemClock.uptimeMillis()); - } - - /** - * Starts the tweening. - * - * @param direction If direction is true, the value goes towards 1.0f. If direction - * is false, the value goes towards 0.0f. - * @param baseTime The time to use as zero for this animation, in the - * {@link SystemClock.uptimeMillis} time base. This allows you to - * synchronize multiple animations. - */ - public void start(boolean direction, long baseTime) { - if (direction != mDirection) { - if (!mRunning) { - mBase = baseTime; - mRunning = true; - mCallback.onTweenStarted(); - long next = SystemClock.uptimeMillis() + FRAME_TIME; - mHandler.postAtTime(mTick, next); - } else { - // reverse direction - long now = SystemClock.uptimeMillis(); - long diff = now - mBase; - mBase = now + diff - mDuration; - } - mDirection = direction; - } - } - - Runnable mTick = new Runnable() { - public void run() { - long base = mBase; - long now = SystemClock.uptimeMillis(); - long diff = now-base; - int duration = mDuration; - float val = diff/(float)duration; - if (!mDirection) { - val = 1.0f - val; - } - if (val > 1.0f) { - val = 1.0f; - } else if (val < 0.0f) { - val = 0.0f; - } - float old = mValue; - mValue = val; - mCallback.onTweenValueChanged(val, old); - int frame = (int)(diff / FRAME_TIME); - long next = base + ((frame+1)*FRAME_TIME); - if (diff < duration) { - mHandler.postAtTime(this, next); - } - if (diff >= duration) { - mCallback.onTweenFinished(); - mRunning = false; - } - } - }; -} - diff --git a/src/com/cyanogenmod/trebuchet/TweenCallback.java b/src/com/cyanogenmod/trebuchet/TweenCallback.java deleted file mode 100644 index 88b8dff..0000000 --- a/src/com/cyanogenmod/trebuchet/TweenCallback.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -package com.cyanogenmod.trebuchet; - -interface TweenCallback { - void onTweenValueChanged(float value, float oldValue); - void onTweenStarted(); - void onTweenFinished(); -} - diff --git a/src/com/cyanogenmod/trebuchet/UninstallShortcutReceiver.java b/src/com/cyanogenmod/trebuchet/UninstallShortcutReceiver.java index 6f4f030..6df068a 100644 --- a/src/com/cyanogenmod/trebuchet/UninstallShortcutReceiver.java +++ b/src/com/cyanogenmod/trebuchet/UninstallShortcutReceiver.java @@ -141,7 +141,7 @@ public class UninstallShortcutReceiver extends BroadcastReceiver { newApps = sharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps); synchronized (newApps) { do { - appRemoved = newApps.remove(intent.toUri(0).toString()); + appRemoved = newApps.remove(intent.toUri(0)); } while (appRemoved); } if (appRemoved) { diff --git a/src/com/cyanogenmod/trebuchet/UserInitializeReceiver.java b/src/com/cyanogenmod/trebuchet/UserInitializeReceiver.java index db20ae9..9bd11a1 100644 --- a/src/com/cyanogenmod/trebuchet/UserInitializeReceiver.java +++ b/src/com/cyanogenmod/trebuchet/UserInitializeReceiver.java @@ -51,6 +51,7 @@ public class UserInitializeReceiver extends BroadcastReceiver { try { wpm.setResource(resid); } catch (IOException e) { + // Ignore } return; } diff --git a/src/com/cyanogenmod/trebuchet/Utilities.java b/src/com/cyanogenmod/trebuchet/Utilities.java index 5dca18b..b9520b3 100644 --- a/src/com/cyanogenmod/trebuchet/Utilities.java +++ b/src/com/cyanogenmod/trebuchet/Utilities.java @@ -16,8 +16,6 @@ package com.cyanogenmod.trebuchet; -import java.util.Random; - import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -34,8 +32,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; import android.util.DisplayMetrics; -import com.cyanogenmod.trebuchet.R; - /** * Various utilities shared amongst the Launcher's classes. */ @@ -249,27 +245,4 @@ final class Utilities { sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm)); sDisabledPaint.setAlpha(0x88); } - - /** Only works for positive numbers. */ - static int roundToPow2(int n) { - int orig = n; - n >>= 1; - int mask = 0x8000000; - while (mask != 0 && (n & mask) == 0) { - mask >>= 1; - } - while (mask != 0) { - n |= mask; - mask >>= 1; - } - n += 1; - if (n != orig) { - n <<= 1; - } - return n; - } - - static int generateRandomId() { - return new Random(System.currentTimeMillis()).nextInt(1 << 24); - } } diff --git a/src/com/cyanogenmod/trebuchet/WallpaperChooserDialogFragment.java b/src/com/cyanogenmod/trebuchet/WallpaperChooserDialogFragment.java index 091bf50..b140a41 100644 --- a/src/com/cyanogenmod/trebuchet/WallpaperChooserDialogFragment.java +++ b/src/com/cyanogenmod/trebuchet/WallpaperChooserDialogFragment.java @@ -34,20 +34,18 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.AdapterView; import android.widget.BaseAdapter; -import android.widget.Gallery; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.SpinnerAdapter; - -import com.cyanogenmod.trebuchet.R; +import com.cyanogenmod.trebuchet.widget.CustomAdapterView; +import com.cyanogenmod.trebuchet.widget.EcoGallery; import java.io.IOException; import java.util.ArrayList; public class WallpaperChooserDialogFragment extends DialogFragment implements - AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener { + CustomAdapterView.OnItemSelectedListener, CustomAdapterView.OnItemClickListener { private static final String TAG = "Trebuchet.WallpaperChooserDialogFragment"; private static final String EMBEDDED_KEY = "com.cyanogenmod.trebuchet." @@ -139,7 +137,7 @@ public class WallpaperChooserDialogFragment extends DialogFragment implements View view = inflater.inflate(R.layout.wallpaper_chooser, container, false); view.setBackground(mWallpaperDrawable); - final Gallery gallery = (Gallery) view.findViewById(R.id.gallery); + final EcoGallery gallery = (EcoGallery) view.findViewById(R.id.gallery); gallery.setCallbackDuringFling(false); gallery.setOnItemSelectedListener(this); gallery.setAdapter(new ImageAdapter(getActivity())); @@ -171,13 +169,13 @@ public class WallpaperChooserDialogFragment extends DialogFragment implements // Click handler for the Dialog's GridView @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + public void onItemClick(CustomAdapterView<?> parent, View view, int position, long id) { selectWallpaper(position); } // Selection handler for the embedded Gallery view @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + public void onItemSelected(CustomAdapterView<?> parent, View view, int position, long id) { if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) { mLoader.cancel(); } @@ -185,7 +183,7 @@ public class WallpaperChooserDialogFragment extends DialogFragment implements } @Override - public void onNothingSelected(AdapterView<?> parent) { + public void onNothingSelected(CustomAdapterView<?> parent) { } private void findWallpapers() { diff --git a/src/com/cyanogenmod/trebuchet/Workspace.java b/src/com/cyanogenmod/trebuchet/Workspace.java index fa0c9ec..81854d8 100644 --- a/src/com/cyanogenmod/trebuchet/Workspace.java +++ b/src/com/cyanogenmod/trebuchet/Workspace.java @@ -44,7 +44,6 @@ import android.graphics.Rect; import android.graphics.Region.Op; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.os.Build; import android.os.IBinder; import android.os.Parcelable; import android.util.AttributeSet; @@ -62,7 +61,6 @@ import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.TextView; -import com.cyanogenmod.trebuchet.R; import com.cyanogenmod.trebuchet.FolderIcon.FolderRingAnimator; import com.cyanogenmod.trebuchet.LauncherSettings.Favorites; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; @@ -78,7 +76,7 @@ import java.util.Set; * Each page contains a number of icons, folders or widgets the user can * interact with. A workspace is meant to be used with a fixed width only. */ -public class Workspace extends SmoothPagedView +public class Workspace extends PagedView implements DropTarget, DragSource, DragScroller, View.OnTouchListener, DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener { private static final String TAG = "Trebuchet.Workspace"; @@ -86,7 +84,6 @@ public class Workspace extends SmoothPagedView // Y rotation to apply to the workspace screens private static final float WORKSPACE_ROTATION = 12.5f; private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f; - private static float CAMERA_DISTANCE = 6500; private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0; private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375; @@ -110,7 +107,6 @@ public class Workspace extends SmoothPagedView private Drawable mBackground; boolean mDrawBackground = true; private float mBackgroundAlpha = 0; - private float mOverScrollMaxBackgroundAlpha = 0.0f; private float mWallpaperScrollRatio = 1.0f; @@ -121,7 +117,6 @@ public class Workspace extends SmoothPagedView private int[] mWallpaperOffsets = new int[2]; private Paint mPaint = new Paint(); private IBinder mWindowToken; - private static final float DEFAULT_WALLPAPER_SCREENS_SPAN = 2f; /** * CellInfo for the cell that is currently being dragged @@ -161,9 +156,7 @@ public class Workspace extends SmoothPagedView private int[] mTempCell = new int[2]; private int[] mTempEstimate = new int[2]; private float[] mDragViewVisualCenter = new float[2]; - private float[] mTempDragCoordinates = new float[2]; private float[] mTempCellLayoutCenterCoordinates = new float[2]; - private float[] mTempDragBottomRightCoordinates = new float[2]; private Matrix mTempInverseMatrix = new Matrix(); private SpringLoadedDragController mSpringLoadedDragController; @@ -175,7 +168,7 @@ public class Workspace extends SmoothPagedView // State variable that indicates whether the pages are small (ie when you're // in all apps or customize mode) - enum State { NORMAL, SPRING_LOADED, SMALL }; + enum State { NORMAL, SPRING_LOADED, SMALL } private State mState = State.NORMAL; private boolean mIsSwitchingState = false; @@ -203,7 +196,6 @@ public class Workspace extends SmoothPagedView private final Camera mCamera = new Camera(); private final float mTempFloat2[] = new float[2]; - enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM }; int mWallpaperWidth; int mWallpaperHeight; WallpaperOffsetInterpolator mWallpaperInterpolator; @@ -267,7 +259,6 @@ public class Workspace extends SmoothPagedView private float[] mOldScaleXs; private float[] mOldScaleYs; private float[] mOldBackgroundAlphas; - private float[] mOldBackgroundAlphaMultipliers; private float[] mOldAlphas; private float[] mOldRotations; private float[] mOldRotationYs; @@ -276,7 +267,6 @@ public class Workspace extends SmoothPagedView private float[] mNewScaleXs; private float[] mNewScaleYs; private float[] mNewBackgroundAlphas; - private float[] mNewBackgroundAlphaMultipliers; private float[] mNewAlphas; private float[] mNewRotations; private float[] mNewRotationYs; @@ -355,6 +345,8 @@ public class Workspace extends SmoothPagedView mHandleFadeInAdjacentScreens = true; mWallpaperManager = WallpaperManager.getInstance(context); + mUsePagingTouchSlop = false; + int cellCountX = DEFAULT_CELL_COUNT_X; int cellCountY = DEFAULT_CELL_COUNT_Y; @@ -456,11 +448,11 @@ public class Workspace extends SmoothPagedView // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each // dimension if unsuccessful public int[] estimateItemSize(int hSpan, int vSpan, - ItemInfo itemInfo, boolean springLoaded) { + boolean springLoaded) { int[] size = new int[2]; if (getChildCount() > 0) { CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0); - Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan); + Rect r = estimateItemPosition(cl, 0, 0, hSpan, vSpan); size[0] = r.width(); size[1] = r.height(); if (springLoaded) { @@ -474,8 +466,7 @@ public class Workspace extends SmoothPagedView return size; } } - public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo, - int hCell, int vCell, int hSpan, int vSpan) { + public Rect estimateItemPosition(CellLayout cl, int hCell, int vCell, int hSpan, int vSpan) { Rect r = new Rect(); cl.cellToRect(hCell, vCell, hSpan, vSpan, r); return r; @@ -507,7 +498,6 @@ public class Workspace extends SmoothPagedView protected void initWorkspace() { Context context = getContext(); mCurrentPage = mDefaultHomescreen; - Launcher.setScreen(mCurrentPage); LauncherApplication app = (LauncherApplication)context.getApplicationContext(); mIconCache = app.getIconCache(); setWillNotDraw(false); @@ -576,11 +566,6 @@ public class Workspace extends SmoothPagedView } @Override - protected int getScrollMode() { - return SmoothPagedView.X_LARGE_MODE; - } - - @Override public void onChildViewAdded(View parent, View child) { if (!(child instanceof CellLayout)) { throw new IllegalArgumentException("A Workspace can only have CellLayout children."); @@ -659,6 +644,12 @@ public class Workspace extends SmoothPagedView + " (was " + screen + "); skipping child"); return; } + } else if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + if (screen < 0 || screen >= mLauncher.getHotseat().getChildCount()) { + Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() + + " (was " + screen + "); skipping child"); + return; + } } final CellLayout layout; @@ -668,11 +659,7 @@ public class Workspace extends SmoothPagedView y = mLauncher.getHotseat().getCellYFromOrder(x); x = mLauncher.getHotseat().getCellXFromOrder(x); screen = mLauncher.getHotseat().getScreenFromOrder(screen); - if (screen < 0 || screen >= mLauncher.getHotseat().getChildCount()) { - layout = (CellLayout) mLauncher.getHotseat().getLayout(); - } else { - layout = (CellLayout) mLauncher.getHotseat().getPageAt(screen); - } + layout = (CellLayout) mLauncher.getHotseat().getPageAt(screen); child.setOnKeyListener(null); // Hide titles in the hotseat @@ -718,7 +705,7 @@ public class Workspace extends SmoothPagedView } // Get the canonical child id to uniquely represent this view in this screen - int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY); + int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y); boolean markCellsAsOccupied = !(child instanceof Folder); if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) { // TODO: This branch occurs when the workspace is adding views @@ -798,11 +785,7 @@ public class Workspace extends SmoothPagedView @Override public boolean dispatchUnhandledMove(View focused, int direction) { - if (isSmall() || !isFinishedSwitchingState()) { - // when the home screens are shrunken, shouldn't allow side-scrolling - return false; - } - return super.dispatchUnhandledMove(focused, direction); + return !isSmall() && isFinishedSwitchingState() && super.dispatchUnhandledMove(focused, direction); } @Override @@ -948,7 +931,6 @@ public class Workspace extends SmoothPagedView hideScrollingIndicator(false); } } - mOverScrollMaxBackgroundAlpha = 0.0f; if (mDelayedResizeRunnable != null) { mDelayedResizeRunnable.run(); @@ -969,12 +951,6 @@ public class Workspace extends SmoothPagedView } @Override - protected void notifyPageSwitchListener() { - super.notifyPageSwitchListener(); - Launcher.setScreen(mCurrentPage); - }; - - @Override protected int getScrollingIndicatorId() { switch (mScrollingIndicatorPosition) { case SCROLLING_INDICATOR_TOP: @@ -1043,7 +1019,7 @@ public class Workspace extends SmoothPagedView mWallpaperHeight = maxDim; } else { int screens = mWallpaperSize; - mWallpaperWidth = Math.max((int) (minDim * screens), maxDim); + mWallpaperWidth = Math.max(minDim * screens, maxDim); mWallpaperHeight = maxDim; } new Thread("setWallpaperDimension") { @@ -1341,7 +1317,7 @@ public class Workspace extends SmoothPagedView mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(startAlpha, finalAlpha); mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue()); + setBackgroundAlpha((Float) animation.getAnimatedValue()); } }); mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f)); @@ -1401,18 +1377,6 @@ public class Workspace extends SmoothPagedView } } - float overScrollBackgroundAlphaInterpolator(float r) { - float threshold = 0.08f; - - if (r > mOverScrollMaxBackgroundAlpha) { - mOverScrollMaxBackgroundAlpha = r; - } else if (r < mOverScrollMaxBackgroundAlpha) { - r = mOverScrollMaxBackgroundAlpha; - } - - return Math.min(r / threshold, 1.0f); - } - private void setChildrenBackgroundAlphaMultipliers(float a) { for (int i = 0; i < getChildCount(); i++) { CellLayout child = (CellLayout) getChildAt(i); @@ -2075,7 +2039,7 @@ public class Workspace extends SmoothPagedView public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { final Canvas canvas = new Canvas(); - int[] size = estimateItemSize(info.spanX, info.spanY, info, false); + int[] size = estimateItemSize(info.spanX, info.spanY, false); // The outline is used to visualize where the item will land if dropped mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0], @@ -2095,7 +2059,6 @@ public class Workspace extends SmoothPagedView mOldScaleXs = new float[childCount]; mOldScaleYs = new float[childCount]; mOldBackgroundAlphas = new float[childCount]; - mOldBackgroundAlphaMultipliers = new float[childCount]; mOldAlphas = new float[childCount]; mOldRotations = new float[childCount]; mOldRotationYs = new float[childCount]; @@ -2104,7 +2067,6 @@ public class Workspace extends SmoothPagedView mNewScaleXs = new float[childCount]; mNewScaleYs = new float[childCount]; mNewBackgroundAlphas = new float[childCount]; - mNewBackgroundAlphaMultipliers = new float[childCount]; mNewAlphas = new float[childCount]; mNewRotations = new float[childCount]; mNewRotationYs = new float[childCount]; @@ -2165,8 +2127,7 @@ public class Workspace extends SmoothPagedView float scale = finalScaleFactor; float finalAlpha = (!mFadeInAdjacentScreens || stateIsSpringLoaded || (i == mCurrentPage)) ? 1f : 0f; - float currentAlpha = cl.getShortcutsAndWidgets().getAlpha(); - float initialAlpha = currentAlpha; + float initialAlpha = cl.getShortcutsAndWidgets().getAlpha(); // Tablet effect if (mTransitionEffect == TransitionEffect.Tablet || stateIsSmall || stateIsSpringLoaded) { @@ -2600,8 +2561,8 @@ public class Workspace extends SmoothPagedView } void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen, - int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) { - View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info); + boolean insertAtFirst, int intersectX, int intersectY) { + View view = mLauncher.createShortcut(R.layout.application, target, info); final int[] cellXY = new int[2]; target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); @@ -2637,8 +2598,8 @@ public class Workspace extends SmoothPagedView mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null); } - int spanX = 1; - int spanY = 1; + int spanX; + int spanY; if (mDragInfo != null) { final CellLayout.CellInfo dragCellInfo = mDragInfo; spanX = dragCellInfo.spanX; @@ -2714,7 +2675,7 @@ public class Workspace extends SmoothPagedView return (aboveShortcut && willBecomeShortcut); } - boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell, + boolean willAddToExistingUserFolder(ItemInfo dragInfo, CellLayout target, int[] targetCell, float distance) { if (distance > mMaxDistanceForFolderCreation) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); @@ -2791,7 +2752,7 @@ public class Workspace extends SmoothPagedView return false; } - boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, + boolean addToExistingFolderIfNecessary(CellLayout target, int[] targetCell, float distance, DragObject d, boolean external) { if (distance > mMaxDistanceForFolderCreation) return false; @@ -2801,7 +2762,7 @@ public class Workspace extends SmoothPagedView if (dropOverView instanceof FolderIcon) { FolderIcon fi = (FolderIcon) dropOverView; - if (fi.acceptDrop(d.dragInfo)) { + if (fi.acceptDrop((ItemInfo)d.dragInfo)) { fi.onDrop(d); // if the drag started here, we need to remove it from the workspace @@ -2867,7 +2828,7 @@ public class Workspace extends SmoothPagedView return; } - if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, + if (addToExistingFolderIfNecessary(dropTargetLayout, mTargetCell, distance, d, false)) { return; } @@ -2922,7 +2883,7 @@ public class Workspace extends SmoothPagedView lp.cellVSpan = item.spanY; lp.isLockedToGrid = true; cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen, - mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); + mTargetCell[0], mTargetCell[1])); if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && cell instanceof LauncherAppWidgetHostView) { @@ -3021,19 +2982,6 @@ public class Workspace extends SmoothPagedView } } - public void getViewLocationRelativeToSelf(View v, int[] location) { - getLocationInWindow(location); - int x = location[0]; - int y = location[1]; - - v.getLocationInWindow(location); - int vX = location[0]; - int vY = location[1]; - - location[0] = vX - x; - location[1] = vY - y; - } - public void onDragEnter(DragObject d) { mDragEnforcer.onDragEnter(); mCreateUserFolderOnDrop = false; @@ -3188,7 +3136,7 @@ public class Workspace extends SmoothPagedView private void cleanupAddToFolder() { if (mDragOverFolderIcon != null) { - mDragOverFolderIcon.onDragExit(null); + mDragOverFolderIcon.onDragExit(); mDragOverFolderIcon = null; } } @@ -3272,45 +3220,6 @@ public class Workspace extends SmoothPagedView /* * - * Returns true if the passed CellLayout cl overlaps with dragView - * - */ - boolean overlaps(CellLayout cl, DragView dragView, - int dragViewX, int dragViewY, Matrix cachedInverseMatrix) { - // Transform the coordinates of the item being dragged to the CellLayout's coordinates - final float[] draggedItemTopLeft = mTempDragCoordinates; - draggedItemTopLeft[0] = dragViewX; - draggedItemTopLeft[1] = dragViewY; - final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates; - draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth(); - draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight(); - - // Transform the dragged item's top left coordinates - // to the CellLayout's local coordinates - mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix); - float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]); - float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]); - - if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) { - // Transform the dragged item's bottom right coordinates - // to the CellLayout's local coordinates - mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix); - float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]); - float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]); - - if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) { - float overlap = (overlapRegionRight - overlapRegionLeft) * - (overlapRegionBottom - overlapRegionTop); - if (overlap > 0) { - return true; - } - } - } - return false; - } - - /* - * * This method returns the CellLayout that is currently being dragged to. In order to drag * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one @@ -3318,8 +3227,7 @@ public class Workspace extends SmoothPagedView * Return null if no CellLayout is currently being dragged over * */ - private CellLayout findMatchingPageForDragOver( - DragView dragView, float originX, float originY, boolean exact) { + private CellLayout findMatchingPageForDragOver(float originX, float originY, boolean exact) { // We loop through all the screens (ie CellLayouts) and see which ones overlap // with the item being dragged and then choose the one that's closest to the touch point final int screenCount = getChildCount(); @@ -3426,7 +3334,7 @@ public class Workspace extends SmoothPagedView } } if (layout == null) { - layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false); + layout = findMatchingPageForDragOver(d.x, d.y, false); } if (layout != mDragTargetLayout) { @@ -3554,8 +3462,6 @@ public class Workspace extends SmoothPagedView if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) { setDragMode(DRAG_MODE_NONE); } - - return; } class FolderCreationAlarmListener implements OnAlarmListener { @@ -3637,7 +3543,7 @@ public class Workspace extends SmoothPagedView */ public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) { if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) { - onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false); + onDropExternal(dragInfo.dropPos, dragInfo, layout, false); return true; } mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout)); @@ -3690,7 +3596,7 @@ public class Workspace extends SmoothPagedView boolean findNearestVacantCell = true; if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { - mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY, + mTargetCell = findNearestArea(touchXY[0], touchXY[1], spanX, spanY, cellLayout, mTargetCell); float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); @@ -3768,7 +3674,7 @@ public class Workspace extends SmoothPagedView animationStyle, finalView, true); } else { // This is for other drag/drop cases, like dragging from All Apps - View view = null; + View view; switch (info.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: @@ -3782,7 +3688,7 @@ public class Workspace extends SmoothPagedView break; case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout, - (FolderInfo) info, mIconCache); + (FolderInfo) info); if (mHideIconLabels) { ((FolderIcon) view).setTextVisible(false); } @@ -3794,7 +3700,7 @@ public class Workspace extends SmoothPagedView // First we find the cell nearest to point at which the item is // dropped, without any consideration to whether there is an item there. if (touchXY != null) { - mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY, + mTargetCell = findNearestArea(touchXY[0], touchXY[1], spanX, spanY, cellLayout, mTargetCell); float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); @@ -3803,7 +3709,7 @@ public class Workspace extends SmoothPagedView true, d.dragView, d.postAnimationRunnable)) { return; } - if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d, + if (addToExistingFolderIfNecessary(cellLayout, mTargetCell, distance, d, true)) { return; } @@ -3841,7 +3747,7 @@ public class Workspace extends SmoothPagedView public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) { int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX, - widgetInfo.spanY, widgetInfo, false); + widgetInfo.spanY, false); int visibility = layout.getVisibility(); layout.setVisibility(VISIBLE); @@ -3867,7 +3773,7 @@ public class Workspace extends SmoothPagedView int spanX = info.spanX; int spanY = info.spanY; - Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY); + Rect r = estimateItemPosition(layout, targetCell[0], targetCell[1], spanX, spanY); loc[0] = r.left; loc[1] = r.top; @@ -3932,7 +3838,7 @@ public class Workspace extends SmoothPagedView if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) { endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE; } else { - endStyle = DragLayer.ANIMATION_END_DISAPPEAR;; + endStyle = DragLayer.ANIMATION_END_DISAPPEAR; } Runnable onComplete = new Runnable() { @@ -3991,16 +3897,6 @@ public class Workspace extends SmoothPagedView } /** - * Return the current CellInfo describing our current drag; this method exists - * so that Launcher can sync this object with the correct info when the activity is created/ - * destroyed - * - */ - public CellLayout.CellInfo getDragInfo() { - return mDragInfo; - } - - /** * Calculate the nearest cell where the given object would be dropped. * * pixelX and pixelY should be in the coordinate system of layout @@ -4048,9 +3944,9 @@ public class Workspace extends SmoothPagedView cellLayout = (CellLayout) getChildAt(mDragInfo.screen); } cellLayout.onDropChild(mDragInfo.cell); - } - if (mDragInfo.cell != null) { - mDragInfo.cell.setVisibility(VISIBLE); + if (mDragInfo.cell != null) { + mDragInfo.cell.setVisibility(VISIBLE); + } } mDragOutline = null; mDragInfo = null; @@ -4102,12 +3998,6 @@ public class Workspace extends SmoothPagedView } @Override - protected void onRestoreInstanceState(Parcelable state) { - super.onRestoreInstanceState(state); - Launcher.setScreen(mCurrentPage); - } - - @Override protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { // We don't dispatch restoreInstanceState to our children using this code path. // Some pages will be restored immediately as their items are bound immediately, and @@ -4346,8 +4236,7 @@ public class Workspace extends SmoothPagedView final ArrayList<ShortcutInfo> appsToRemoveFromFolder = new ArrayList<ShortcutInfo>(); - for (int k = 0; k < contentsCount; k++) { - final ShortcutInfo appInfo = contents.get(k); + for (final ShortcutInfo appInfo : contents) { final Intent intent = appInfo.intent; final ComponentName name = intent.getComponent(); @@ -4423,7 +4312,9 @@ public class Workspace extends SmoothPagedView for (ItemInfo info : shortcuts) { LauncherModel.deleteItemFromDatabase(context, info); } - } catch (URISyntaxException e) {} + } catch (URISyntaxException e) { + // Ignore + } } } } @@ -4447,9 +4338,7 @@ public class Workspace extends SmoothPagedView final ComponentName name = intent.getComponent(); if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { - final int appCount = apps.size(); - for (int k = 0; k < appCount; k++) { - ApplicationInfo app = apps.get(k); + for (ApplicationInfo app : apps) { if (app.componentName.equals(name)) { BubbleTextView shortcut = (BubbleTextView) view; info.updateIcon(mIconCache); diff --git a/src/com/cyanogenmod/trebuchet/preference/DoubleNumberPickerPreference.java b/src/com/cyanogenmod/trebuchet/preference/DoubleNumberPickerPreference.java index 1a38639..81b766a 100644 --- a/src/com/cyanogenmod/trebuchet/preference/DoubleNumberPickerPreference.java +++ b/src/com/cyanogenmod/trebuchet/preference/DoubleNumberPickerPreference.java @@ -160,7 +160,7 @@ public class DoubleNumberPickerPreference extends DialogPreference { @Override protected void onDialogClosed(boolean positiveResult) { if (positiveResult) { - persistString(mNumberPicker1.getValue() + "|" + mNumberPicker2.getValue());; + persistString(mNumberPicker1.getValue() + "|" + mNumberPicker2.getValue()); } } diff --git a/src/com/cyanogenmod/trebuchet/preference/HiddenAppsActivity.java b/src/com/cyanogenmod/trebuchet/preference/HiddenAppsActivity.java index 6eef205..05aea7f 100644 --- a/src/com/cyanogenmod/trebuchet/preference/HiddenAppsActivity.java +++ b/src/com/cyanogenmod/trebuchet/preference/HiddenAppsActivity.java @@ -110,7 +110,7 @@ public class HiddenAppsActivity extends ListActivity implements MenuItem.OnMenuI } private void restore() { - List<ComponentName> apps = new ArrayList(); + List<ComponentName> apps = new ArrayList<ComponentName>(); String[] flattened = PreferenceManager.getDefaultSharedPreferences(this) .getString("ui_drawer_hidden_apps", "").split("\\|"); for (String flat : flattened) { diff --git a/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java b/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java index 98cfd1a..8d747ce 100644 --- a/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java +++ b/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java @@ -69,7 +69,7 @@ public final class PreferencesProvider { } } public static int getCellCountY(int def) { - String[] values = getString("ui_homescreen_grid", def + "|0").split("\\|");; + String[] values = getString("ui_homescreen_grid", def + "|0").split("\\|"); try { return Integer.parseInt(values[0]); } catch (NumberFormatException e) { diff --git a/src/com/cyanogenmod/trebuchet/widget/CustomAbsSpinner.java b/src/com/cyanogenmod/trebuchet/widget/CustomAbsSpinner.java new file mode 100644 index 0000000..7861f50 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/widget/CustomAbsSpinner.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * Copyright (C) 2013 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. + */ + +package com.cyanogenmod.trebuchet.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.widget.ArrayAdapter; +import android.widget.SpinnerAdapter; +import com.cyanogenmod.trebuchet.R; + +public abstract class CustomAbsSpinner extends CustomAdapterView<SpinnerAdapter> { + + SpinnerAdapter mAdapter; + + int mHeightMeasureSpec; + int mWidthMeasureSpec; + boolean mBlockLayoutRequests; + int mSelectionLeftPadding = 0; + int mSelectionTopPadding = 0; + int mSelectionRightPadding = 0; + int mSelectionBottomPadding = 0; + Rect mSpinnerPadding = new Rect(); + View mSelectedView = null; + Interpolator mInterpolator; + + RecycleBin mRecycler = new RecycleBin(); + private DataSetObserver mDataSetObserver; + + + /** Temporary frame to hold a child View's frame rectangle */ + private Rect mTouchFrame; + + public CustomAbsSpinner(Context context) { + super(context); + initAbsSpinner(); + } + + public CustomAbsSpinner(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CustomAbsSpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initAbsSpinner(); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.CustomAbsSpinner, defStyle, 0); + + CharSequence[] entries = a.getTextArray(R.styleable.CustomAbsSpinner_entries); + if (entries != null) { + ArrayAdapter<CharSequence> adapter = + new ArrayAdapter<CharSequence>(context, + android.R.layout.simple_spinner_item, entries); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + setAdapter(adapter); + } + + a.recycle(); + } + + /** + * Common code for different constructor flavors + */ + private void initAbsSpinner() { + setFocusable(true); + setWillNotDraw(false); + } + + + /** + * The Adapter is used to provide the data which backs this Spinner. + * It also provides methods to transform spinner items based on their position + * relative to the selected item. + * @param adapter The SpinnerAdapter to use for this Spinner + */ + @Override + public void setAdapter(SpinnerAdapter adapter) { + if (null != mAdapter) { + mAdapter.unregisterDataSetObserver(mDataSetObserver); + resetList(); + } + + mAdapter = adapter; + + mOldSelectedPosition = INVALID_POSITION; + mOldSelectedRowId = INVALID_ROW_ID; + + if (mAdapter != null) { + mOldItemCount = mItemCount; + mItemCount = mAdapter.getCount(); + checkFocus(); + + mDataSetObserver = new AdapterDataSetObserver(); + mAdapter.registerDataSetObserver(mDataSetObserver); + + int position = mItemCount > 0 ? 0 : INVALID_POSITION; + + setSelectedPositionInt(position); + setNextSelectedPositionInt(position); + + if (mItemCount == 0) { + // Nothing selected + checkSelectionChanged(); + } + + } else { + checkFocus(); + resetList(); + // Nothing selected + checkSelectionChanged(); + } + + requestLayout(); + } + + /** + * Clear out all children from the list + */ + void resetList() { + mDataChanged = false; + mNeedSync = false; + + removeAllViewsInLayout(); + mOldSelectedPosition = INVALID_POSITION; + mOldSelectedRowId = INVALID_ROW_ID; + + setSelectedPositionInt(INVALID_POSITION); + setNextSelectedPositionInt(INVALID_POSITION); + invalidate(); + } + + /** + * @see android.view.View#measure(int, int) + * + * Figure out the dimensions of this Spinner. The width comes from + * the widthMeasureSpec as Spinnners can't have their width set to + * UNSPECIFIED. The height is based on the height of the selected item + * plus padding. + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize; + int heightSize; + + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + + mSpinnerPadding.left = paddingLeft > mSelectionLeftPadding ? paddingLeft + : mSelectionLeftPadding; + mSpinnerPadding.top = paddingTop > mSelectionTopPadding ? paddingTop + : mSelectionTopPadding; + mSpinnerPadding.right = paddingRight > mSelectionRightPadding ? paddingRight + : mSelectionRightPadding; + mSpinnerPadding.bottom = paddingBottom > mSelectionBottomPadding ? paddingBottom + : mSelectionBottomPadding; + + if (mDataChanged) { + handleDataChanged(); + } + + int preferredHeight = 0; + int preferredWidth = 0; + boolean needsMeasuring = true; + + int selectedPosition = getSelectedItemPosition(); + if (selectedPosition >= 0 && mAdapter != null) { + // Try looking in the recycler. (Maybe we were measured once already) + View view = mRecycler.get(); + if (view == null) { + // Make a new one + view = mAdapter.getView(selectedPosition, null, this); + } + + if (view != null) { + // Put in recycler for re-measuring and/or layout + mRecycler.add(selectedPosition, view); + } + + if (view != null) { + if (view.getLayoutParams() == null) { + mBlockLayoutRequests = true; + view.setLayoutParams(generateDefaultLayoutParams()); + mBlockLayoutRequests = false; + } + measureChild(view, widthMeasureSpec, heightMeasureSpec); + + preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom; + preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right; + + needsMeasuring = false; + } + } + + if (needsMeasuring) { + // No views -- just use padding + preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom; + if (widthMode == MeasureSpec.UNSPECIFIED) { + preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right; + } + } + + preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight()); + preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth()); + + heightSize = resolveSize(preferredHeight, heightMeasureSpec); + widthSize = resolveSize(preferredWidth, widthMeasureSpec); + + setMeasuredDimension(widthSize, heightSize); + mHeightMeasureSpec = heightMeasureSpec; + mWidthMeasureSpec = widthMeasureSpec; + } + + + int getChildHeight(View child) { + return child.getMeasuredHeight(); + } + + int getChildWidth(View child) { + return child.getMeasuredWidth(); + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + void recycleAllViews() { + int childCount = getChildCount(); + final CustomAbsSpinner.RecycleBin recycleBin = mRecycler; + + // All views go in recycler + for (int i=0; i<childCount; i++) { + View v = getChildAt(i); + int index = mFirstPosition + i; + recycleBin.put(index, v); + } + } + + @Override + void handleDataChanged() { + // FIXME -- this is called from both measure and layout. + // This is harmless right now, but we don't want to do redundant work if + // this gets more complicated + super.handleDataChanged(); + } + + + + /** + * Jump directly to a specific item in the adapter data. + */ + public void setSelection(int position, boolean animate) { + // Animate only if requested position is already on screen somewhere + boolean shouldAnimate = animate && mFirstPosition <= position && + position <= mFirstPosition + getChildCount() - 1; + setSelectionInt(position, shouldAnimate); + } + + + @Override + public void setSelection(int position) { + setNextSelectedPositionInt(position); + requestLayout(); + invalidate(); + } + + + /** + * Makes the item at the supplied position selected. + * + * @param position Position to select + * @param animate Should the transition be animated + * + */ + void setSelectionInt(int position, boolean animate) { + if (position != mOldSelectedPosition) { + mBlockLayoutRequests = true; + int delta = position - mSelectedPosition; + setNextSelectedPositionInt(position); + layout(delta, animate); + mBlockLayoutRequests = false; + } + } + + abstract void layout(int delta, boolean animate); + + @Override + public View getSelectedView() { + if (mItemCount > 0 && mSelectedPosition >= 0) { + return getChildAt(mSelectedPosition - mFirstPosition); + } else { + return null; + } + } + + /** + * Override to prevent spamming ourselves with layout requests + * as we place views + * + * @see android.view.View#requestLayout() + */ + @Override + public void requestLayout() { + if (!mBlockLayoutRequests) { + super.requestLayout(); + } + } + + + + @Override + public SpinnerAdapter getAdapter() { + return mAdapter; + } + + @Override + public int getCount() { + return mItemCount; + } + + /** + * Maps a point to a position in the list. + * + * @param x X in local coordinate + * @param y Y in local coordinate + * @return The position of the item which contains the specified point, or + * {@link #INVALID_POSITION} if the point does not intersect an item. + */ + public int pointToPosition(int x, int y) { + Rect frame = mTouchFrame; + if (frame == null) { + mTouchFrame = new Rect(); + frame = mTouchFrame; + } + + final int count = getChildCount(); + for (int i = count - 1; i >= 0; i--) { + View child = getChildAt(i); + if (child.getVisibility() == View.VISIBLE) { + child.getHitRect(frame); + if (frame.contains(x, y)) { + return mFirstPosition + i; + } + } + } + return INVALID_POSITION; + } + + static class SavedState extends BaseSavedState { + long selectedId; + int position; + + /** + * Constructor called from {@link CustomAbsSpinner#onSaveInstanceState()} + */ + SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + selectedId = in.readLong(); + position = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeLong(selectedId); + out.writeInt(position); + } + + @Override + public String toString() { + return "AbsSpinner.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " selectedId=" + selectedId + + " position=" + position + "}"; + } + + public static final Parcelable.Creator<SavedState> CREATOR + = new Parcelable.Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.selectedId = getSelectedItemId(); + if (ss.selectedId >= 0) { + ss.position = getSelectedItemPosition(); + } else { + ss.position = INVALID_POSITION; + } + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + + super.onRestoreInstanceState(ss.getSuperState()); + + if (ss.selectedId >= 0) { + mDataChanged = true; + mNeedSync = true; + mSyncRowId = ss.selectedId; + mSyncPosition = ss.position; + mSyncMode = SYNC_SELECTED_POSITION; + requestLayout(); + } + } + + class RecycleBin { + private SparseArray<View> mScrapHeap = new SparseArray<View>(); + + public void put(int position, View v) { + mScrapHeap.put(position, v); + } + + public void add(int position, View v) { + mScrapHeap.put(mScrapHeap.size(), v); + } + public View get() { + if (mScrapHeap.size() < 1) return null; + + View result = mScrapHeap.valueAt(0); + int key = mScrapHeap.keyAt(0); + + if (result != null) { + mScrapHeap.delete(key); + } + return result; + } + + View get(int position) { + // System.out.print("Looking for " + position); + View result = mScrapHeap.get(position); + if (result != null) { + // System.out.println(" HIT"); + mScrapHeap.delete(position); + } else { + // System.out.println(" MISS"); + } + return result; + } + + View peek(int position) { + // System.out.print("Looking for " + position); + return mScrapHeap.get(position); + } + + void clear() { + final SparseArray<View> scrapHeap = mScrapHeap; + + final int count = scrapHeap.size(); + for (int i = 0; i < count; i++) { + final View view = scrapHeap.valueAt(i); + if (view != null) { + removeDetachedView(view, true); + } + } + + scrapHeap.clear(); + } + } +} diff --git a/src/com/cyanogenmod/trebuchet/widget/CustomAdapterView.java b/src/com/cyanogenmod/trebuchet/widget/CustomAdapterView.java new file mode 100644 index 0000000..fd3e8f5 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/widget/CustomAdapterView.java @@ -0,0 +1,1130 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * Copyright (C) 2013 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. + */ + +package com.cyanogenmod.trebuchet.widget; + +import android.content.Context; +import android.database.DataSetObserver; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.ContextMenu; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.widget.Adapter; +import android.widget.ListView; + +public abstract class CustomAdapterView<T extends Adapter> extends ViewGroup { + + /** + * The item view type returned by {@link Adapter#getItemViewType(int)} when + * the adapter does not want the item's view recycled. + */ + public static final int ITEM_VIEW_TYPE_IGNORE = -1; + + /** + * The item view type returned by {@link Adapter#getItemViewType(int)} when + * the item is a header or footer. + */ + public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2; + + /** + * The position of the first child displayed + */ + int mFirstPosition = 0; + + /** + * The offset in pixels from the top of the AdapterView to the top + * of the view to select during the next layout. + */ + int mSpecificTop; + + /** + * Position from which to start looking for mSyncRowId + */ + int mSyncPosition; + + /** + * Row id to look for when data has changed + */ + long mSyncRowId = INVALID_ROW_ID; + + /** + * Height of the view when mSyncPosition and mSyncRowId where set + */ + long mSyncHeight; + + /** + * True if we need to sync to mSyncRowId + */ + boolean mNeedSync = false; + + /** + * Indicates whether to sync based on the selection or position. Possible + * values are {@link #SYNC_SELECTED_POSITION} or + * {@link #SYNC_FIRST_POSITION}. + */ + int mSyncMode; + + /** + * Our height after the last layout + */ + private int mLayoutHeight; + + /** + * Sync based on the selected child + */ + static final int SYNC_SELECTED_POSITION = 0; + + /** + * Sync based on the first child displayed + */ + static final int SYNC_FIRST_POSITION = 1; + + /** + * Maximum amount of time to spend in {@link #findSyncPosition()} + */ + static final int SYNC_MAX_DURATION_MILLIS = 100; + + /** + * Indicates that this view is currently being laid out. + */ + boolean mInLayout = false; + + /** + * The listener that receives notifications when an item is selected. + */ + OnItemSelectedListener mOnItemSelectedListener; + + /** + * The listener that receives notifications when an item is clicked. + */ + OnItemClickListener mOnItemClickListener; + + /** + * The listener that receives notifications when an item is long clicked. + */ + OnItemLongClickListener mOnItemLongClickListener; + + /** + * True if the data has changed since the last layout + */ + boolean mDataChanged; + + /** + * The position within the adapter's data set of the item to select + * during the next layout. + */ + int mNextSelectedPosition = INVALID_POSITION; + + /** + * The item id of the item to select during the next layout. + */ + long mNextSelectedRowId = INVALID_ROW_ID; + + /** + * The position within the adapter's data set of the currently selected item. + */ + int mSelectedPosition = INVALID_POSITION; + + /** + * The item id of the currently selected item. + */ + long mSelectedRowId = INVALID_ROW_ID; + + /** + * View to show if there are no items to show. + */ + private View mEmptyView; + + /** + * The number of items in the current adapter. + */ + int mItemCount; + + /** + * The number of items in the adapter before a data changed event occured. + */ + int mOldItemCount; + + /** + * Represents an invalid position. All valid positions are in the range 0 to 1 less than the + * number of items in the current adapter. + */ + public static final int INVALID_POSITION = -1; + + /** + * Represents an empty or invalid row id + */ + public static final long INVALID_ROW_ID = Long.MIN_VALUE; + + /** + * The last selected position we used when notifying + */ + int mOldSelectedPosition = INVALID_POSITION; + + /** + * The id of the last selected position we used when notifying + */ + long mOldSelectedRowId = INVALID_ROW_ID; + + /** + * Indicates what focusable state is requested when calling setFocusable(). + * In addition to this, this view has other criteria for actually + * determining the focusable state (such as whether its empty or the text + * filter is shown). + * + * @see #setFocusable(boolean) + * @see #checkFocus() + */ + private boolean mDesiredFocusableState; + private boolean mDesiredFocusableInTouchModeState; + + private SelectionNotifier mSelectionNotifier; + /** + * When set to true, calls to requestLayout() will not propagate up the parent hierarchy. + * This is used to layout the children during a layout pass. + */ + boolean mBlockLayoutRequests = false; + + public CustomAdapterView(Context context) { + super(context); + } + + public CustomAdapterView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomAdapterView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + + /** + * Interface definition for a callback to be invoked when an item in this + * AdapterView has been clicked. + */ + public interface OnItemClickListener { + + /** + * Callback method to be invoked when an item in this AdapterView has + * been clicked. + * <p> + * Implementers can call getItemAtPosition(position) if they need + * to access the data associated with the selected item. + * + * @param parent The AdapterView where the click happened. + * @param view The view within the AdapterView that was clicked (this + * will be a view provided by the adapter) + * @param position The position of the view in the adapter. + * @param id The row id of the item that was clicked. + */ + void onItemClick(CustomAdapterView<?> parent, View view, int position, long id); + } + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been clicked. + * + * @param listener The callback that will be invoked. + */ + public void setOnItemClickListener(OnItemClickListener listener) { + mOnItemClickListener = listener; + } + + /** + * @return The callback to be invoked with an item in this AdapterView has + * been clicked, or null id no callback has been set. + */ + public final OnItemClickListener getOnItemClickListener() { + return mOnItemClickListener; + } + + /** + * Call the OnItemClickListener, if it is defined. + * + * @param view The view within the AdapterView that was clicked. + * @param position The position of the view in the adapter. + * @param id The row id of the item that was clicked. + * @return True if there was an assigned OnItemClickListener that was + * called, false otherwise is returned. + */ + public boolean performItemClick(View view, int position, long id) { + if (mOnItemClickListener != null) { + playSoundEffect(SoundEffectConstants.CLICK); + mOnItemClickListener.onItemClick(this, view, position, id); + return true; + } + + return false; + } + + /** + * Interface definition for a callback to be invoked when an item in this + * view has been clicked and held. + */ + public interface OnItemLongClickListener { + /** + * Callback method to be invoked when an item in this view has been + * clicked and held. + * + * Implementers can call getItemAtPosition(position) if they need to access + * the data associated with the selected item. + * + * @param parent The AbsListView where the click happened + * @param view The view within the AbsListView that was clicked + * @param position The position of the view in the list + * @param id The row id of the item that was clicked + * + * @return true if the callback consumed the long click, false otherwise + */ + boolean onItemLongClick(CustomAdapterView<?> parent, View view, int position, long id); + } + + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been clicked and held + * + * @param listener The callback that will run + */ + public void setOnItemLongClickListener(OnItemLongClickListener listener) { + if (!isLongClickable()) { + setLongClickable(true); + } + mOnItemLongClickListener = listener; + } + + /** + * @return The callback to be invoked with an item in this AdapterView has + * been clicked and held, or null id no callback as been set. + */ + public final OnItemLongClickListener getOnItemLongClickListener() { + return mOnItemLongClickListener; + } + + /** + * Interface definition for a callback to be invoked when + * an item in this view has been selected. + */ + public interface OnItemSelectedListener { + /** + * Callback method to be invoked when an item in this view has been + * selected. + * + * Impelmenters can call getItemAtPosition(position) if they need to access the + * data associated with the selected item. + * + * @param parent The AdapterView where the selection happened + * @param view The view within the AdapterView that was clicked + * @param position The position of the view in the adapter + * @param id The row id of the item that is selected + */ + void onItemSelected(CustomAdapterView<?> parent, View view, int position, long id); + + /** + * Callback method to be invoked when the selection disappears from this + * view. The selection can disappear for instance when touch is activated + * or when the adapter becomes empty. + * + * @param parent The AdapterView that now contains no selected item. + */ + void onNothingSelected(CustomAdapterView<?> parent); + } + + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been selected. + * + * @param listener The callback that will run + */ + public void setOnItemSelectedListener(OnItemSelectedListener listener) { + mOnItemSelectedListener = listener; + } + + public final OnItemSelectedListener getOnItemSelectedListener() { + return mOnItemSelectedListener; + } + + /** + * Extra menu information provided to the + * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) } + * callback when a context menu is brought up for this AdapterView. + * + */ + public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo { + + public AdapterContextMenuInfo(View targetView, int position, long id) { + this.targetView = targetView; + this.position = position; + this.id = id; + } + + /** + * The child view for which the context menu is being displayed. This + * will be one of the children of this AdapterView. + */ + public View targetView; + + /** + * The position in the adapter for which the context menu is being + * displayed. + */ + public int position; + + /** + * The row id of the item for which the context menu is being displayed. + */ + public long id; + } + + /** + * Returns the adapter currently associated with this widget. + * + * @return The adapter used to provide this view's content. + */ + public abstract T getAdapter(); + + /** + * Sets the adapter that provides the data and the views to represent the data + * in this widget. + * + * @param adapter The adapter to use to create this view's content. + */ + public abstract void setAdapter(T adapter); + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child) { + throw new UnsupportedOperationException("addView(View) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param index Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, int index) { + throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param params Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, LayoutParams params) { + throw new UnsupportedOperationException("addView(View, LayoutParams) " + + "is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param index Ignored. + * @param params Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, int index, LayoutParams params) { + throw new UnsupportedOperationException("addView(View, int, LayoutParams) " + + "is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeView(View child) { + throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param index Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeViewAt(int index) { + throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeAllViews() { + throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView"); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mLayoutHeight = getHeight(); + } + + /** + * Return the position of the currently selected item within the adapter's data set + * + * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected. + */ + @ViewDebug.CapturedViewProperty + public int getSelectedItemPosition() { + return mNextSelectedPosition; + } + + /** + * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID} + * if nothing is selected. + */ + @ViewDebug.CapturedViewProperty + public long getSelectedItemId() { + return mNextSelectedRowId; + } + + /** + * @return The view corresponding to the currently selected item, or null + * if nothing is selected + */ + public abstract View getSelectedView(); + + /** + * @return The data corresponding to the currently selected item, or + * null if there is nothing selected. + */ + public Object getSelectedItem() { + T adapter = getAdapter(); + int selection = getSelectedItemPosition(); + if (adapter != null && adapter.getCount() > 0 && selection >= 0) { + return adapter.getItem(selection); + } else { + return null; + } + } + + /** + * @return The number of items owned by the Adapter associated with this + * AdapterView. (This is the number of data items, which may be + * larger than the number of visible view.) + */ + @ViewDebug.CapturedViewProperty + public int getCount() { + return mItemCount; + } + + /** + * Get the position within the adapter's data set for the view, where view is a an adapter item + * or a descendant of an adapter item. + * + * @param view an adapter item, or a descendant of an adapter item. This must be visible in this + * AdapterView at the time of the call. + * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION} + * if the view does not correspond to a list item (or it is not currently visible). + */ + public int getPositionForView(View view) { + View listItem = view; + try { + View v; + while (!(v = (View) listItem.getParent()).equals(this)) { + listItem = v; + } + } catch (ClassCastException e) { + // We made it up to the window without find this list view + return INVALID_POSITION; + } + + // Search the children for the list item + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + if (getChildAt(i).equals(listItem)) { + return mFirstPosition + i; + } + } + + // Child not found! + return INVALID_POSITION; + } + + /** + * Returns the position within the adapter's data set for the first item + * displayed on screen. + * + * @return The position within the adapter's data set + */ + public int getFirstVisiblePosition() { + return mFirstPosition; + } + + /** + * Returns the position within the adapter's data set for the last item + * displayed on screen. + * + * @return The position within the adapter's data set + */ + public int getLastVisiblePosition() { + return mFirstPosition + getChildCount() - 1; + } + + /** + * Sets the currently selected item. To support accessibility subclasses that + * override this method must invoke the overriden super method first. + * + * @param position Index (starting at 0) of the data item to be selected. + */ + public abstract void setSelection(int position); + + /** + * Sets the view to show if the adapter is empty + */ + public void setEmptyView(View emptyView) { + mEmptyView = emptyView; + + final T adapter = getAdapter(); + final boolean empty = ((adapter == null) || adapter.isEmpty()); + updateEmptyStatus(empty); + } + + /** + * When the current adapter is empty, the AdapterView can display a special view + * call the empty view. The empty view is used to provide feedback to the user + * that no data is available in this AdapterView. + * + * @return The view to show if the adapter is empty. + */ + public View getEmptyView() { + return mEmptyView; + } + + /** + * Indicates whether this view is in filter mode. Filter mode can for instance + * be enabled by a user when typing on the keyboard. + * + * @return True if the view is in filter mode, false otherwise. + */ + boolean isInFilterMode() { + return false; + } + + @Override + public void setFocusable(boolean focusable) { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + + mDesiredFocusableState = focusable; + if (!focusable) { + mDesiredFocusableInTouchModeState = false; + } + + super.setFocusable(focusable && (!empty || isInFilterMode())); + } + + @Override + public void setFocusableInTouchMode(boolean focusable) { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + + mDesiredFocusableInTouchModeState = focusable; + if (focusable) { + mDesiredFocusableState = true; + } + + super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode())); + } + + void checkFocus() { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + final boolean focusable = !empty || isInFilterMode(); + // The order in which we set focusable in touch mode/focusable may matter + // for the client, see View.setFocusableInTouchMode() comments for more + // details + super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState); + super.setFocusable(focusable && mDesiredFocusableState); + if (mEmptyView != null) { + updateEmptyStatus((adapter == null) || adapter.isEmpty()); + } + } + + /** + * Update the status of the list based on the empty parameter. If empty is true and + * we have an empty view, display it. In all the other cases, make sure that the listview + * is VISIBLE and that the empty view is GONE (if it's not null). + */ + private void updateEmptyStatus(boolean empty) { + if (isInFilterMode()) { + empty = false; + } + + if (empty) { + if (mEmptyView != null) { + mEmptyView.setVisibility(View.VISIBLE); + setVisibility(View.GONE); + } else { + // If the caller just removed our empty view, make sure the list view is visible + setVisibility(View.VISIBLE); + } + + // We are now GONE, so pending layouts will not be dispatched. + // Force one here to make sure that the state of the list matches + // the state of the adapter. + if (mDataChanged) { + this.onLayout(false, getLeft(), getTop(), getRight(), getBottom()); + } + } else { + if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); + setVisibility(View.VISIBLE); + } + } + + /** + * Gets the data associated with the specified position in the list. + * + * @param position Which data to get + * @return The data associated with the specified position in the list + */ + public Object getItemAtPosition(int position) { + T adapter = getAdapter(); + return (adapter == null || position < 0) ? null : adapter.getItem(position); + } + + public long getItemIdAtPosition(int position) { + T adapter = getAdapter(); + return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position); + } + + @Override + public void setOnClickListener(OnClickListener l) { + throw new RuntimeException("Don't call setOnClickListener for an AdapterView. " + + "You probably want setOnItemClickListener instead"); + } + + /** + * Override to prevent freezing of any views created by the adapter. + */ + @Override + protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { + dispatchFreezeSelfOnly(container); + } + + /** + * Override to prevent thawing of any views created by the adapter. + */ + @Override + protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { + dispatchThawSelfOnly(container); + } + + class AdapterDataSetObserver extends DataSetObserver { + + private Parcelable mInstanceState = null; + + @Override + public void onChanged() { + mDataChanged = true; + mOldItemCount = mItemCount; + mItemCount = getAdapter().getCount(); + + // Detect the case where a cursor that was previously invalidated has + // been repopulated with new data. + if (CustomAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null + && mOldItemCount == 0 && mItemCount > 0) { + CustomAdapterView.this.onRestoreInstanceState(mInstanceState); + mInstanceState = null; + } else { + rememberSyncState(); + } + checkFocus(); + requestLayout(); + } + + @Override + public void onInvalidated() { + mDataChanged = true; + + if (CustomAdapterView.this.getAdapter().hasStableIds()) { + // Remember the current state for the case where our hosting activity is being + // stopped and later restarted + mInstanceState = CustomAdapterView.this.onSaveInstanceState(); + } + + // Data is invalid so we should reset our state + mOldItemCount = mItemCount; + mItemCount = 0; + mSelectedPosition = INVALID_POSITION; + mSelectedRowId = INVALID_ROW_ID; + mNextSelectedPosition = INVALID_POSITION; + mNextSelectedRowId = INVALID_ROW_ID; + mNeedSync = false; + + checkFocus(); + requestLayout(); + } + + public void clearSavedState() { + mInstanceState = null; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + removeCallbacks(mSelectionNotifier); + } + + private class SelectionNotifier implements Runnable { + public void run() { + if (mDataChanged) { + // Data has changed between when this SelectionNotifier + // was posted and now. We need to wait until the AdapterView + // has been synched to the new data. + if (getAdapter() != null) { + post(this); + } + } else { + fireOnSelected(); + } + } + } + + void selectionChanged() { + if (mOnItemSelectedListener != null) { + if (mInLayout || mBlockLayoutRequests) { + // If we are in a layout traversal, defer notification + // by posting. This ensures that the view tree is + // in a consistent state and is able to accomodate + // new layout or invalidate requests. + if (mSelectionNotifier == null) { + mSelectionNotifier = new SelectionNotifier(); + } + post(mSelectionNotifier); + } else { + fireOnSelected(); + } + } + + // we fire selection events here not in View + if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + } + + private void fireOnSelected() { + if (mOnItemSelectedListener == null) + return; + + int selection = this.getSelectedItemPosition(); + if (selection >= 0) { + View v = getSelectedView(); + mOnItemSelectedListener.onItemSelected(this, v, selection, + getAdapter().getItemId(selection)); + } else { + mOnItemSelectedListener.onNothingSelected(this); + } + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + boolean populated = false; + // This is an exceptional case which occurs when a window gets the + // focus and sends a focus event via its focused child to announce + // current focus/selection. AdapterView fires selection but not focus + // events so we change the event type here. + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) { + event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + + // we send selection events only from AdapterView to avoid + // generation of such event for each child + View selectedView = getSelectedView(); + if (selectedView != null) { + populated = selectedView.dispatchPopulateAccessibilityEvent(event); + } + + if (!populated) { + if (selectedView != null) { + event.setEnabled(selectedView.isEnabled()); + } + event.setItemCount(getCount()); + event.setCurrentItemIndex(getSelectedItemPosition()); + } + + return populated; + } + + @Override + protected boolean canAnimate() { + return super.canAnimate() && mItemCount > 0; + } + + void handleDataChanged() { + final int count = mItemCount; + boolean found = false; + + if (count > 0) { + + int newPos; + + // Find the row we are supposed to sync to + if (mNeedSync) { + // Update this first, since setNextSelectedPositionInt inspects + // it + mNeedSync = false; + + // See if we can find a position in the new data with the same + // id as the old selection + newPos = findSyncPosition(); + if (newPos >= 0) { + // Verify that new selection is selectable + int selectablePos = lookForSelectablePosition(newPos, true); + if (selectablePos == newPos) { + // Same row id is selected + setNextSelectedPositionInt(newPos); + found = true; + } + } + } + if (!found) { + // Try to use the same position if we can't find matching data + newPos = getSelectedItemPosition(); + + // Pin position to the available range + if (newPos >= count) { + newPos = count - 1; + } + if (newPos < 0) { + newPos = 0; + } + + // Make sure we select something selectable -- first look down + int selectablePos = lookForSelectablePosition(newPos, true); + if (selectablePos < 0) { + // Looking down didn't work -- try looking up + selectablePos = lookForSelectablePosition(newPos, false); + } + if (selectablePos >= 0) { + setNextSelectedPositionInt(selectablePos); + checkSelectionChanged(); + found = true; + } + } + } + if (!found) { + // Nothing is selected + mSelectedPosition = INVALID_POSITION; + mSelectedRowId = INVALID_ROW_ID; + mNextSelectedPosition = INVALID_POSITION; + mNextSelectedRowId = INVALID_ROW_ID; + mNeedSync = false; + checkSelectionChanged(); + } + } + + void checkSelectionChanged() { + if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) { + selectionChanged(); + mOldSelectedPosition = mSelectedPosition; + mOldSelectedRowId = mSelectedRowId; + } + } + + /** + * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition + * and then alternates between moving up and moving down until 1) we find the right position, or + * 2) we run out of time, or 3) we have looked at every position + * + * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't + * be found + */ + int findSyncPosition() { + int count = mItemCount; + + if (count == 0) { + return INVALID_POSITION; + } + + long idToMatch = mSyncRowId; + int seed = mSyncPosition; + + // If there isn't a selection don't hunt for it + if (idToMatch == INVALID_ROW_ID) { + return INVALID_POSITION; + } + + // Pin seed to reasonable values + seed = Math.max(0, seed); + seed = Math.min(count - 1, seed); + + long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS; + + long rowId; + + // first position scanned so far + int first = seed; + + // last position scanned so far + int last = seed; + + // True if we should move down on the next iteration + boolean next = false; + + // True when we have looked at the first item in the data + boolean hitFirst; + + // True when we have looked at the last item in the data + boolean hitLast; + + // Get the item ID locally (instead of getItemIdAtPosition), so + // we need the adapter + T adapter = getAdapter(); + if (adapter == null) { + return INVALID_POSITION; + } + + while (SystemClock.uptimeMillis() <= endTime) { + rowId = adapter.getItemId(seed); + if (rowId == idToMatch) { + // Found it! + return seed; + } + + hitLast = last == count - 1; + hitFirst = first == 0; + + if (hitLast && hitFirst) { + // Looked at everything + break; + } + + if (hitFirst || (next && !hitLast)) { + // Either we hit the top, or we are trying to move down + last++; + seed = last; + // Try going up next time + next = false; + } else if (hitLast || (!next && !hitFirst)) { + // Either we hit the bottom, or we are trying to move up + first--; + seed = first; + // Try going down next time + next = true; + } + + } + + return INVALID_POSITION; + } + + /** + * Find a position that can be selected (i.e., is not a separator). + * + * @param position The starting position to look at. + * @param lookDown Whether to look down for other positions. + * @return The next selectable position starting at position and then searching either up or + * down. Returns {@link #INVALID_POSITION} if nothing can be found. + */ + int lookForSelectablePosition(int position, boolean lookDown) { + return position; + } + + /** + * Utility to keep mSelectedPosition and mSelectedRowId in sync + * @param position Our current position + */ + void setSelectedPositionInt(int position) { + mSelectedPosition = position; + mSelectedRowId = getItemIdAtPosition(position); + } + + /** + * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync + * @param position Intended value for mSelectedPosition the next time we go + * through layout + */ + void setNextSelectedPositionInt(int position) { + mNextSelectedPosition = position; + mNextSelectedRowId = getItemIdAtPosition(position); + // If we are trying to sync to the selection, update that too + if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) { + mSyncPosition = position; + mSyncRowId = mNextSelectedRowId; + } + } + + /** + * Remember enough information to restore the screen state when the data has + * changed. + * + */ + void rememberSyncState() { + if (getChildCount() > 0) { + mNeedSync = true; + mSyncHeight = mLayoutHeight; + if (mSelectedPosition >= 0) { + // Sync the selection state + View v = getChildAt(mSelectedPosition - mFirstPosition); + mSyncRowId = mNextSelectedRowId; + mSyncPosition = mNextSelectedPosition; + if (v != null) { + mSpecificTop = v.getTop(); + } + mSyncMode = SYNC_SELECTED_POSITION; + } else { + // Sync the based on the offset of the first view + View v = getChildAt(0); + T adapter = getAdapter(); + if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) { + mSyncRowId = adapter.getItemId(mFirstPosition); + } else { + mSyncRowId = NO_ID; + } + mSyncPosition = mFirstPosition; + if (v != null) { + mSpecificTop = v.getTop(); + } + mSyncMode = SYNC_FIRST_POSITION; + } + } + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/trebuchet/widget/EcoGallery.java b/src/com/cyanogenmod/trebuchet/widget/EcoGallery.java new file mode 100644 index 0000000..d70a37e --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/widget/EcoGallery.java @@ -0,0 +1,1415 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * Copyright (C) 2013 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. + */ + +package com.cyanogenmod.trebuchet.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.ContextMenu; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.animation.Transformation; +import android.widget.Scroller; +import com.cyanogenmod.trebuchet.R; + +import java.lang.reflect.Field; + +public class EcoGallery extends CustomAbsSpinner implements GestureDetector.OnGestureListener { + + private static final String TAG = "Gallery"; + + private static final boolean localLOGV = false; + + /** + * Duration in milliseconds from the start of a scroll during which we're + * unsure whether the user is scrolling or flinging. + */ + private static final int SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT = 250; + + private static final String LOG_TAG = null; + + /** + * Horizontal spacing between items. + */ + private int mSpacing = 0; + + /** + * How long the transition animation should run when a child view changes + * position, measured in milliseconds. + */ + private int mAnimationDuration = 200; + + /** + * The alpha of items that are not selected. + */ + private float mUnselectedAlpha; + + /** + * Left most edge of a child seen so far during layout. + */ + private int mLeftMost; + + /** + * Right most edge of a child seen so far during layout. + */ + private int mRightMost; + + private int mGravity; + + /** + * Helper for detecting touch gestures. + */ + private GestureDetector mGestureDetector; + + /** + * The position of the item that received the user's down touch. + */ + private int mDownTouchPosition; + + /** + * The view of the item that received the user's down touch. + */ + private View mDownTouchView; + + /** + * Executes the delta scrolls from a fling or scroll movement. + */ + private FlingRunnable mFlingRunnable = new FlingRunnable(); + + /** + * Sets mSuppressSelectionChanged = false. This is used to set it to false + * in the future. It will also trigger a selection changed. + */ + private Runnable mDisableSuppressSelectionChangedRunnable = new Runnable() { + public void run() { + mSuppressSelectionChanged = false; + selectionChanged(); + } + }; + + /** + * When fling runnable runs, it resets this to false. Any method along the + * path until the end of its run() can set this to true to abort any + * remaining fling. For example, if we've reached either the leftmost or + * rightmost item, we will set this to true. + */ + private boolean mShouldStopFling; + + /** + * The currently selected item's child. + */ + private View mSelectedChild; + + /** + * Whether to continuously callback on the item selected listener during a + * fling. + */ + private boolean mShouldCallbackDuringFling = true; + + /** + * Whether to callback when an item that is not selected is clicked. + */ + private boolean mShouldCallbackOnUnselectedItemClick = true; + + /** + * If true, do not callback to item selected listener. + */ + private boolean mSuppressSelectionChanged; + + /** + * If true, we have received the "invoke" (center or enter buttons) key + * down. This is checked before we action on the "invoke" key up, and is + * subsequently cleared. + */ + private boolean mReceivedInvokeKeyDown; + + private AdapterContextMenuInfo mContextMenuInfo; + + + /** + * If true, this onScroll is the first for this user's drag (remember, a + * drag sends many onScrolls). + */ + private boolean mIsFirstScroll; + + + /** + * If true the reflection calls failed and this widget will behave + * unpredictably if used further + */ + private boolean mBroken; + + public EcoGallery(Context context) { + this(context, null); + } + + public EcoGallery(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.ecoGalleryStyle); + } + + public EcoGallery(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mBroken = true; + + mGestureDetector = new GestureDetector(context, this); + mGestureDetector.setIsLongpressEnabled(true); + + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.EcoGallery, defStyle, 0); + + int index = a.getInt(R.styleable.EcoGallery_gravity, -1); + if (index >= 0) { + setGravity(index); + } + + int animationDuration = + a.getInt(R.styleable.EcoGallery_animationDuration, -1); + if (animationDuration > 0) { + setAnimationDuration(animationDuration); + } + + int spacing = + a.getDimensionPixelOffset(R.styleable.EcoGallery_spacing, 0); + setSpacing(spacing); + + float unselectedAlpha = a.getFloat( + R.styleable.EcoGallery_unselectedAlpha, 0.5f); + setUnselectedAlpha(unselectedAlpha); + + a.recycle(); + + // We draw the selected item last (because otherwise the item to the + // right overlaps it) + int FLAG_USE_CHILD_DRAWING_ORDER = 0x400; + int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800; + Class vgClass = ViewGroup.class; + + try { + Field childDrawingOrder = vgClass + .getDeclaredField("FLAG_USE_CHILD_DRAWING_ORDER"); + Field supportStaticTrans = vgClass + .getDeclaredField("FLAG_SUPPORT_STATIC_TRANSFORMATIONS"); + + childDrawingOrder.setAccessible(true); + supportStaticTrans.setAccessible(true); + + FLAG_USE_CHILD_DRAWING_ORDER = childDrawingOrder.getInt(this); + FLAG_SUPPORT_STATIC_TRANSFORMATIONS = supportStaticTrans.getInt(this); + } catch (NoSuchFieldException e) { + Log.e(LOG_TAG, e.getMessage(), e); + } catch (IllegalAccessException e) { + Log.e(LOG_TAG, e.getMessage(), e); + } + try { + // set new group flags + Field groupFlags = vgClass.getDeclaredField("mGroupFlags"); + groupFlags.setAccessible(true); + int groupFlagsValue = groupFlags.getInt(this); + + groupFlagsValue |= FLAG_USE_CHILD_DRAWING_ORDER; + groupFlagsValue |= FLAG_SUPPORT_STATIC_TRANSFORMATIONS; + + groupFlags.set(this, groupFlagsValue); + + // working! + mBroken = false; + } catch (NoSuchFieldException e) { + Log.e(LOG_TAG, e.getMessage(), e); + } catch (IllegalAccessException e) { + Log.e(LOG_TAG, e.getMessage(), e); + } + } + + /** + * @return Whether the widget is broken or working (functional) + */ + public boolean isBroken() { + return mBroken; + } + + /** + * Whether or not to callback on any {@link #getOnItemSelectedListener()} + * while the items are being flinged. If false, only the final selected item + * will cause the callback. If true, all items between the first and the + * final will cause callbacks. + * + * @param shouldCallback Whether or not to callback on the listener while + * the items are being flinged. + */ + public void setCallbackDuringFling(boolean shouldCallback) { + mShouldCallbackDuringFling = shouldCallback; + } + + /** + * Whether or not to callback when an item that is not selected is clicked. + * If false, the item will become selected (and re-centered). If true, the + * {@link #getOnItemClickListener()} will get the callback. + * + * @param shouldCallback Whether or not to callback on the listener when a + * item that is not selected is clicked. + * @hide + */ + public void setCallbackOnUnselectedItemClick(boolean shouldCallback) { + mShouldCallbackOnUnselectedItemClick = shouldCallback; + } + + /** + * Sets how long the transition animation should run when a child view + * changes position. Only relevant if animation is turned on. + * + * @param animationDurationMillis The duration of the transition, in + * milliseconds. + * + * @attr ref android.R.styleable#Gallery_animationDuration + */ + public void setAnimationDuration(int animationDurationMillis) { + mAnimationDuration = animationDurationMillis; + } + + /** + * Sets the spacing between items in a Gallery + * + * @param spacing The spacing in pixels between items in the Gallery + * + * @attr ref android.R.styleable#Gallery_spacing + */ + public void setSpacing(int spacing) { + mSpacing = spacing; + } + + /** + * Sets the alpha of items that are not selected in the Gallery. + * + * @param unselectedAlpha the alpha for the items that are not selected. + * + * @attr ref android.R.styleable#Gallery_unselectedAlpha + */ + public void setUnselectedAlpha(float unselectedAlpha) { + mUnselectedAlpha = unselectedAlpha; + } + + @Override + protected boolean getChildStaticTransformation(View child, Transformation t) { + + t.clear(); + t.setAlpha(child == mSelectedChild ? 1.0f : mUnselectedAlpha); + + return true; + } + + @Override + protected int computeHorizontalScrollExtent() { + // Only 1 item is considered to be selected + return 1; + } + + @Override + protected int computeHorizontalScrollOffset() { + // Current scroll position is the same as the selected position + return mSelectedPosition; + } + + @Override + protected int computeHorizontalScrollRange() { + // Scroll range is the same as the item count + return mItemCount; + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + /* + * Gallery expects EcoGallery.LayoutParams. + */ + return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + /* + * Remember that we are in layout to prevent more layout request from + * being generated. + */ + mInLayout = true; + layout(0, false); + + mInLayout = false; + } + + @Override + int getChildHeight(View child) { + return child.getMeasuredHeight(); + } + + /** + * Tracks a motion scroll. In reality, this is used to do just about any + * movement to items (touch scroll, arrow-key scroll, set an item as selected). + * + * @param deltaX Change in X from the previous event. + */ + void trackMotionScroll(int deltaX) { + + if (getChildCount() == 0) { + return; + } + + boolean toLeft = deltaX < 0; + + int limitedDeltaX = getLimitedMotionScrollAmount(toLeft, deltaX); + if (limitedDeltaX != deltaX) { + // The above call returned a limited amount, so stop any scrolls/flings + mFlingRunnable.endFling(false); + onFinishedMovement(); + } + + offsetChildrenLeftAndRight(limitedDeltaX); + + detachOffScreenChildren(toLeft); + + if (toLeft) { + // If moved left, there will be empty space on the right + fillToGalleryRight(); + } else { + // Similarly, empty space on the left + fillToGalleryLeft(); + } + + setSelectionToCenterChild(); + + invalidate(); + } + + int getLimitedMotionScrollAmount(boolean motionToLeft, int deltaX) { + int extremeItemPosition = motionToLeft ? mItemCount - 1 : 0; + View extremeChild = getChildAt(extremeItemPosition - mFirstPosition); + + if (extremeChild == null) { + return deltaX; + } + + int extremeChildCenter = getCenterOfView(extremeChild); + int galleryCenter = getCenterOfGallery(); + + if (motionToLeft) { + if (extremeChildCenter <= galleryCenter) { + + // The extreme child is past his boundary point! + return 0; + } + } else { + if (extremeChildCenter >= galleryCenter) { + + // The extreme child is past his boundary point! + return 0; + } + } + + int centerDifference = galleryCenter - extremeChildCenter; + + return motionToLeft + ? Math.max(centerDifference, deltaX) + : Math.min(centerDifference, deltaX); + } + + /** + * Offset the horizontal location of all children of this view by the + * specified number of pixels. + * + * @param offset the number of pixels to offset + */ + private void offsetChildrenLeftAndRight(int offset) { + for (int i = getChildCount() - 1; i >= 0; i--) { + getChildAt(i).offsetLeftAndRight(offset); + } + } + + /** + * @return The center of this Gallery. + */ + private int getCenterOfGallery() { + int paddingLeft = getPaddingLeft(); + return (getWidth() - paddingLeft - getPaddingRight()) / 2 + paddingLeft; + } + + /** + * @return The center of the given view. + */ + private static int getCenterOfView(View view) { + return view.getLeft() + view.getWidth() / 2; + } + + /** + * Detaches children that are off the screen (i.e.: Gallery bounds). + * + * @param toLeft Whether to detach children to the left of the Gallery, or + * to the right. + */ + private void detachOffScreenChildren(boolean toLeft) { + int numChildren = getChildCount(); + int firstPosition = mFirstPosition; + int start = 0; + int count = 0; + + if (toLeft) { + final int galleryLeft = getPaddingLeft(); + for (int i = 0; i < numChildren; i++) { + final View child = getChildAt(i); + if (child.getRight() >= galleryLeft) { + break; + } else { + count++; + mRecycler.add(firstPosition + i, child); + } + } + } else { + final int galleryRight = getWidth() - getPaddingRight(); + for (int i = numChildren - 1; i >= 0; i--) { + final View child = getChildAt(i); + if (child.getLeft() <= galleryRight) { + break; + } else { + start = i; + count++; + mRecycler.add(firstPosition + i, child); + } + } + } + + detachViewsFromParent(start, count); + + if (toLeft) { + mFirstPosition += count; + } + } + + /** + * Scrolls the items so that the selected item is in its 'slot' (its center + * is the gallery's center). + */ + private void scrollIntoSlots() { + + if (getChildCount() == 0 || mSelectedChild == null) return; + + int selectedCenter = getCenterOfView(mSelectedChild); + int targetCenter = getCenterOfGallery(); + + int scrollAmount = targetCenter - selectedCenter; + if (scrollAmount != 0) { + mFlingRunnable.startUsingDistance(scrollAmount); + } else { + onFinishedMovement(); + } + } + + private void onFinishedMovement() { + if (mSuppressSelectionChanged) { + mSuppressSelectionChanged = false; + + // We haven't been callbacking during the fling, so do it now + super.selectionChanged(); + } + invalidate(); + } + + @Override + void selectionChanged() { + if (!mSuppressSelectionChanged) { + super.selectionChanged(); + } + } + + /** + * Looks for the child that is closest to the center and sets it as the + * selected child. + */ + private void setSelectionToCenterChild() { + + View selView = mSelectedChild; + if (mSelectedChild == null) return; + + int galleryCenter = getCenterOfGallery(); + + // Common case where the current selected position is correct + if (selView.getLeft() <= galleryCenter && selView.getRight() >= galleryCenter) { + return; + } + + // TODO better search + int closestEdgeDistance = Integer.MAX_VALUE; + int newSelectedChildIndex = 0; + for (int i = getChildCount() - 1; i >= 0; i--) { + + View child = getChildAt(i); + + if (child.getLeft() <= galleryCenter && child.getRight() >= galleryCenter) { + // This child is in the center + newSelectedChildIndex = i; + break; + } + + int childClosestEdgeDistance = Math.min(Math.abs(child.getLeft() - galleryCenter), + Math.abs(child.getRight() - galleryCenter)); + if (childClosestEdgeDistance < closestEdgeDistance) { + closestEdgeDistance = childClosestEdgeDistance; + newSelectedChildIndex = i; + } + } + + int newPos = mFirstPosition + newSelectedChildIndex; + + if (newPos != mSelectedPosition) { + setSelectedPositionInt(newPos); + setNextSelectedPositionInt(newPos); + checkSelectionChanged(); + } + } + + /** + * Creates and positions all views for this Gallery. + * <p> + * We layout rarely, most of the time {@link #trackMotionScroll(int)} takes + * care of repositioning, adding, and removing children. + * + * @param delta Change in the selected position. +1 means the selection is + * moving to the right, so views are scrolling to the left. -1 + * means the selection is moving to the left. + */ + @Override + void layout(int delta, boolean animate) { + + int childrenLeft = mSpinnerPadding.left; + int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right; + + if (mDataChanged) { + handleDataChanged(); + } + + // Handle an empty gallery by removing all views. + if (mItemCount == 0) { + resetList(); + return; + } + + // Update to the new selected position. + if (mNextSelectedPosition >= 0) { + setSelectedPositionInt(mNextSelectedPosition); + } + + // All views go in recycler while we are in layout + recycleAllViews(); + + // Clear out old views + detachAllViewsFromParent(); + + /* + * These will be used to give initial positions to views entering the + * gallery as we scroll + */ + mRightMost = 0; + mLeftMost = 0; + + // Make selected view and center it + + /* + * mFirstPosition will be decreased as we add views to the left later + * on. The 0 for x will be offset in a couple lines down. + */ + mFirstPosition = mSelectedPosition; + View sel = makeAndAddView(mSelectedPosition, 0, 0, true); + + // Put the selected child in the center + int selectedOffset = childrenLeft + (childrenWidth / 2) - (sel.getWidth() / 2); + sel.offsetLeftAndRight(selectedOffset); + + fillToGalleryRight(); + fillToGalleryLeft(); + + invalidate(); + checkSelectionChanged(); + + mDataChanged = false; + mNeedSync = false; + setNextSelectedPositionInt(mSelectedPosition); + + updateSelectedItemMetadata(); + } + + private void fillToGalleryLeft() { + int itemSpacing = mSpacing; + int galleryLeft = getPaddingLeft(); + + // Set state for initial iteration + View prevIterationView = getChildAt(0); + int curPosition; + int curRightEdge; + + if (prevIterationView != null) { + curPosition = mFirstPosition - 1; + curRightEdge = prevIterationView.getLeft() - itemSpacing; + } else { + // No children available! + curPosition = 0; + curRightEdge = getRight() - getLeft() - getPaddingRight(); + mShouldStopFling = true; + } + + while (curRightEdge > galleryLeft && curPosition >= 0) { + prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition, + curRightEdge, false); + + // Remember some state + mFirstPosition = curPosition; + + // Set state for next iteration + curRightEdge = prevIterationView.getLeft() - itemSpacing; + curPosition--; + } + } + + private void fillToGalleryRight() { + int itemSpacing = mSpacing; + int galleryRight = getRight() - getLeft() - getPaddingRight(); + int numChildren = getChildCount(); + int numItems = mItemCount; + + // Set state for initial iteration + View prevIterationView = getChildAt(numChildren - 1); + int curPosition; + int curLeftEdge; + + if (prevIterationView != null) { + curPosition = mFirstPosition + numChildren; + curLeftEdge = prevIterationView.getRight() + itemSpacing; + } else { + mFirstPosition = curPosition = mItemCount - 1; + curLeftEdge = getPaddingLeft(); + mShouldStopFling = true; + } + + while (curLeftEdge < galleryRight && curPosition < numItems) { + prevIterationView = makeAndAddView(curPosition, curPosition - mSelectedPosition, + curLeftEdge, true); + + // Set state for next iteration + curLeftEdge = prevIterationView.getRight() + itemSpacing; + curPosition++; + } + } + + /** + * Obtain a view, either by pulling an existing view from the recycler or by + * getting a new one from the adapter. If we are animating, make sure there + * is enough information in the view's layout parameters to animate from the + * old to new positions. + * + * @param position Position in the gallery for the view to obtain + * @param offset Offset from the selected position + * @param x X-coordinate indicating where this view should be placed. This + * will either be the left or right edge of the view, depending on + * the fromLeft parameter + * @param fromLeft Are we positioning views based on the left edge? (i.e., + * building from left to right)? + * @return A view that has been added to the gallery + */ + private View makeAndAddView(int position, int offset, int x, + boolean fromLeft) { + + View child; + + child = mRecycler.get(); + // pass child as convertview + child = mAdapter.getView(position, child, this); + + // Position the view + setUpChild(child, offset, x, fromLeft); + + return child; + } + + /** + * Helper for makeAndAddView to set the position of a view and fill out its + * layout paramters. + * + * @param child The view to position + * @param offset Offset from the selected position + * @param x X-coordintate indicating where this view should be placed. This + * will either be the left or right edge of the view, depending on + * the fromLeft paramter + * @param fromLeft Are we posiitoning views based on the left edge? (i.e., + * building from left to right)? + */ + private void setUpChild(View child, int offset, int x, boolean fromLeft) { + + // Respect layout params that are already in the view. Otherwise + // make some up... + LayoutParams lp = (LayoutParams) + child.getLayoutParams(); + if (lp == null) { + lp = (LayoutParams) generateDefaultLayoutParams(); + } + + addViewInLayout(child, fromLeft ? -1 : 0, lp); + + child.setSelected(offset == 0); + + // Get measure specs + int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, + mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height); + int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, + mSpinnerPadding.left + mSpinnerPadding.right, lp.width); + + // Measure child + child.measure(childWidthSpec, childHeightSpec); + + int childLeft; + int childRight; + + // Position vertically based on gravity setting + int childTop = calculateTop(child, true); + int childBottom = childTop + child.getMeasuredHeight(); + + int width = child.getMeasuredWidth(); + if (fromLeft) { + childLeft = x; + childRight = childLeft + width; + } else { + childLeft = x - width; + childRight = x; + } + + child.layout(childLeft, childTop, childRight, childBottom); + } + + /** + * Figure out vertical placement based on mGravity + * + * @param child Child to place + * @return Where the top of the child should be + */ + private int calculateTop(View child, boolean duringLayout) { + int myHeight = duringLayout ? getMeasuredHeight() : getHeight(); + int childHeight = duringLayout ? child.getMeasuredHeight() : child.getHeight(); + + int childTop = 0; + + switch (mGravity) { + case Gravity.TOP: + childTop = mSpinnerPadding.top; + break; + case Gravity.CENTER_VERTICAL: + int availableSpace = myHeight - mSpinnerPadding.bottom + - mSpinnerPadding.top - childHeight; + childTop = mSpinnerPadding.top + (availableSpace / 2); + break; + case Gravity.BOTTOM: + childTop = myHeight - mSpinnerPadding.bottom - childHeight; + break; + } + return childTop; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + + // Give everything to the gesture detector + boolean retValue = mGestureDetector.onTouchEvent(event); + + int action = event.getAction(); + if (action == MotionEvent.ACTION_UP) { + // Helper method for lifted finger + onUp(); + } else if (action == MotionEvent.ACTION_CANCEL) { + onCancel(); + } + + return retValue; + } + + /** + * {@inheritDoc} + */ + public boolean onSingleTapUp(MotionEvent e) { + + if (mDownTouchPosition >= 0) { + + // An item tap should make it selected, so scroll to this child. + scrollToChild(mDownTouchPosition - mFirstPosition); + + // Also pass the click so the client knows, if it wants to. + if (mShouldCallbackOnUnselectedItemClick || mDownTouchPosition == mSelectedPosition) { + performItemClick(mDownTouchView, mDownTouchPosition, mAdapter + .getItemId(mDownTouchPosition)); + } + + return true; + } + + return false; + } + + /** + * {@inheritDoc} + */ + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + + if (!mShouldCallbackDuringFling) { + // We want to suppress selection changes + + // Remove any future code to set mSuppressSelectionChanged = false + removeCallbacks(mDisableSuppressSelectionChangedRunnable); + + // This will get reset once we scroll into slots + if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true; + } + + // Fling the gallery! + mFlingRunnable.startUsingVelocity((int) -velocityX); + + return true; + } + + /** + * {@inheritDoc} + */ + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + + if (localLOGV) Log.v(TAG, String.valueOf(e2.getX() - e1.getX())); + + /* + * Now's a good time to tell our parent to stop intercepting our events! + * The user has moved more than the slop amount, since GestureDetector + * ensures this before calling this method. Also, if a parent is more + * interested in this touch's events than we are, it would have + * intercepted them by now (for example, we can assume when a Gallery is + * in the ListView, a vertical scroll would not end up in this method + * since a ListView would have intercepted it by now). + */ + getParent().requestDisallowInterceptTouchEvent(true); + + // As the user scrolls, we want to callback selection changes so related- + // info on the screen is up-to-date with the gallery's selection + if (!mShouldCallbackDuringFling) { + if (mIsFirstScroll) { + /* + * We're not notifying the client of selection changes during + * the fling, and this scroll could possibly be a fling. Don't + * do selection changes until we're sure it is not a fling. + */ + if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true; + postDelayed(mDisableSuppressSelectionChangedRunnable, SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT); + } + } else { + if (mSuppressSelectionChanged) mSuppressSelectionChanged = false; + } + + // Track the motion + trackMotionScroll(-1 * (int) distanceX); + + mIsFirstScroll = false; + return true; + } + + /** + * {@inheritDoc} + */ + public boolean onDown(MotionEvent e) { + + // Kill any existing fling/scroll + mFlingRunnable.stop(false); + + // Get the item's view that was touched + mDownTouchPosition = pointToPosition((int) e.getX(), (int) e.getY()); + + if (mDownTouchPosition >= 0) { + mDownTouchView = getChildAt(mDownTouchPosition - mFirstPosition); + mDownTouchView.setPressed(true); + } + + // Reset the multiple-scroll tracking state + mIsFirstScroll = true; + + // Must return true to get matching events for this down event. + return true; + } + + /** + * Called when a touch event's action is MotionEvent.ACTION_UP. + */ + void onUp() { + + if (mFlingRunnable.mScroller.isFinished()) { + scrollIntoSlots(); + } + + dispatchUnpress(); + } + + /** + * Called when a touch event's action is MotionEvent.ACTION_CANCEL. + */ + void onCancel() { + onUp(); + } + + /** + * {@inheritDoc} + */ + public void onLongPress(MotionEvent e) { + + if (mDownTouchPosition < 0) { + return; + } + + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + long id = getItemIdAtPosition(mDownTouchPosition); + dispatchLongPress(mDownTouchView, mDownTouchPosition, id); + } + + // Unused methods from GestureDetector.OnGestureListener below + + /** + * {@inheritDoc} + */ + public void onShowPress(MotionEvent e) { + } + + // Unused methods from GestureDetector.OnGestureListener above + + private void dispatchPress(View child) { + + if (child != null) { + child.setPressed(true); + } + + setPressed(true); + } + + private void dispatchUnpress() { + + for (int i = getChildCount() - 1; i >= 0; i--) { + getChildAt(i).setPressed(false); + } + + setPressed(false); + } + + @Override + public void dispatchSetSelected(boolean selected) { + /* + * We don't want to pass the selected state given from its parent to its + * children since this widget itself has a selected state to give to its + * children. + */ + } + + @Override + protected void dispatchSetPressed(boolean pressed) { + + // Show the pressed state on the selected child + if (mSelectedChild != null) { + mSelectedChild.setPressed(pressed); + } + } + + @Override + protected ContextMenu.ContextMenuInfo getContextMenuInfo() { + return mContextMenuInfo; + } + + @Override + public boolean showContextMenuForChild(View originalView) { + + final int longPressPosition = getPositionForView(originalView); + if (longPressPosition < 0) { + return false; + } + + final long longPressId = mAdapter.getItemId(longPressPosition); + return dispatchLongPress(originalView, longPressPosition, longPressId); + } + + @Override + public boolean showContextMenu() { + + if (isPressed() && mSelectedPosition >= 0) { + int index = mSelectedPosition - mFirstPosition; + View v = getChildAt(index); + return dispatchLongPress(v, mSelectedPosition, mSelectedRowId); + } + + return false; + } + + private boolean dispatchLongPress(View view, int position, long id) { + boolean handled = false; + + if (mOnItemLongClickListener != null) { + handled = mOnItemLongClickListener.onItemLongClick(this, mDownTouchView, + mDownTouchPosition, id); + } + + if (!handled) { + mContextMenuInfo = new AdapterContextMenuInfo(view, position, id); + handled = super.showContextMenuForChild(this); + } + + if (handled) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + + return handled; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // Gallery steals all key events + return event.dispatch(this, null, null); + } + + /** + * Handles left, right, and clicking + * @see android.view.View#onKeyDown + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + + case KeyEvent.KEYCODE_DPAD_LEFT: + if (movePrevious()) { + playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); + } + return true; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (moveNext()) { + playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); + } + return true; + + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: + mReceivedInvokeKeyDown = true; + // fallthrough to default handling + } + + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: { + + if (mReceivedInvokeKeyDown) { + if (mItemCount > 0) { + + dispatchPress(mSelectedChild); + postDelayed(new Runnable() { + public void run() { + dispatchUnpress(); + } + }, ViewConfiguration.getPressedStateDuration()); + + int selectedIndex = mSelectedPosition - mFirstPosition; + performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter + .getItemId(mSelectedPosition)); + } + } + + // Clear the flag + mReceivedInvokeKeyDown = false; + + return true; + } + } + + return super.onKeyUp(keyCode, event); + } + + boolean movePrevious() { + if (mItemCount > 0 && mSelectedPosition > 0) { + scrollToChild(mSelectedPosition - mFirstPosition - 1); + return true; + } else { + return false; + } + } + + boolean moveNext() { + if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) { + scrollToChild(mSelectedPosition - mFirstPosition + 1); + return true; + } else { + return false; + } + } + + private boolean scrollToChild(int childPosition) { + View child = getChildAt(childPosition); + + if (child != null) { + int distance = getCenterOfGallery() - getCenterOfView(child); + mFlingRunnable.startUsingDistance(distance); + return true; + } + + return false; + } + + @Override + void setSelectedPositionInt(int position) { + super.setSelectedPositionInt(position); + + // Updates any metadata we keep about the selected item. + updateSelectedItemMetadata(); + } + + private void updateSelectedItemMetadata() { + + View oldSelectedChild = mSelectedChild; + + View child = mSelectedChild = getChildAt(mSelectedPosition - mFirstPosition); + if (child == null) { + return; + } + + child.setSelected(true); + child.setFocusable(true); + + if (hasFocus()) { + child.requestFocus(); + } + + // We unfocus the old child down here so the above hasFocus check + // returns true + if (oldSelectedChild != null) { + + // Make sure its drawable state doesn't contain 'selected' + oldSelectedChild.setSelected(false); + + // Make sure it is not focusable anymore, since otherwise arrow keys + // can make this one be focused + oldSelectedChild.setFocusable(false); + } + + } + + /** + * Describes how the child views are aligned. + * @param gravity + * + * @attr ref android.R.styleable#Gallery_gravity + */ + public void setGravity(int gravity) + { + if (mGravity != gravity) { + mGravity = gravity; + requestLayout(); + } + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + int selectedIndex = mSelectedPosition - mFirstPosition; + + // Just to be safe + if (selectedIndex < 0) return i; + + if (i == childCount - 1) { + // Draw the selected child last + return selectedIndex; + } else if (i >= selectedIndex) { + // Move the children to the right of the selected child earlier one + return i + 1; + } else { + // Keep the children to the left of the selected child the same + return i; + } + } + + @Override + protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); + + /* + * The gallery shows focus by focusing the selected item. So, give + * focus to our selected item instead. We steal keys from our + * selected item elsewhere. + */ + if (gainFocus && mSelectedChild != null) { + mSelectedChild.requestFocus(direction); + } + + } + + /** + * Responsible for fling behavior. Use {@link #startUsingVelocity(int)} to + * initiate a fling. Each frame of the fling is handled in {@link #run()}. + * A FlingRunnable will keep re-posting itself until the fling is done. + * + */ + private class FlingRunnable implements Runnable { + /** + * Tracks the decay of a fling scroll + */ + private Scroller mScroller; + + /** + * X value reported by mScroller on the previous fling + */ + private int mLastFlingX; + + public FlingRunnable() { + mScroller = new Scroller(getContext()); + } + + private void startCommon() { + // Remove any pending flings + removeCallbacks(this); + } + + public void startUsingVelocity(int initialVelocity) { + if (initialVelocity == 0) return; + + startCommon(); + + int initialX = initialVelocity < 0 ? Integer.MAX_VALUE : 0; + mLastFlingX = initialX; + mScroller.fling(initialX, 0, initialVelocity, 0, + 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); + post(this); + } + + public void startUsingDistance(int distance) { + if (distance == 0) return; + + startCommon(); + + mLastFlingX = 0; + mScroller.startScroll(0, 0, -distance, 0, mAnimationDuration); + post(this); + } + + public void stop(boolean scrollIntoSlots) { + removeCallbacks(this); + endFling(scrollIntoSlots); + } + + private void endFling(boolean scrollIntoSlots) { + /* + * Force the scroller's status to finished (without setting its + * position to the end) + */ + mScroller.forceFinished(true); + + if (scrollIntoSlots) scrollIntoSlots(); + } + + public void run() { + + if (mItemCount == 0) { + endFling(true); + return; + } + + mShouldStopFling = false; + + final Scroller scroller = mScroller; + boolean more = scroller.computeScrollOffset(); + final int x = scroller.getCurrX(); + + // Flip sign to convert finger direction to list items direction + // (e.g. finger moving down means list is moving towards the top) + int delta = mLastFlingX - x; + + // Pretend that each frame of a fling scroll is a touch scroll + if (delta > 0) { + // Moving towards the left. Use first view as mDownTouchPosition + mDownTouchPosition = mFirstPosition; + + // Don't fling more than 1 screen + delta = Math.min(getWidth() - getPaddingLeft() - getPaddingRight() - 1, delta); + } else { + // Moving towards the right. Use last view as mDownTouchPosition + int offsetToLast = getChildCount() - 1; + mDownTouchPosition = mFirstPosition + offsetToLast; + + // Don't fling more than 1 screen + delta = Math.max(-(getWidth() - getPaddingRight() - getPaddingLeft() - 1), delta); + } + + trackMotionScroll(delta); + + if (more && !mShouldStopFling) { + mLastFlingX = x; + post(this); + } else { + endFling(true); + } + } + + } + + /** + * Gallery extends LayoutParams to provide a place to hold current + * Transformation information along with previous position/transformation + * info. + * + */ + public static class LayoutParams extends ViewGroup.LayoutParams { + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int w, int h) { + super(w, h); + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + } +} |