summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2010-08-09 16:03:15 -0700
committerWinson Chung <winsonc@google.com>2010-08-16 15:51:43 -0700
commit80baf5a6b3c62a62265f626d43d1167783c94131 (patch)
treeda3dba4d3920ffbae802ab256c19d5f0b590089b /src
parent321e9ee68848d9e782fd557f69cc070308ffbc9c (diff)
downloadandroid_packages_apps_Trebuchet-80baf5a6b3c62a62265f626d43d1167783c94131.tar.gz
android_packages_apps_Trebuchet-80baf5a6b3c62a62265f626d43d1167783c94131.tar.bz2
android_packages_apps_Trebuchet-80baf5a6b3c62a62265f626d43d1167783c94131.zip
Adding paging for the widget/shortcut/folder customization area and fixing bugs.
Adding pages for customization drawer with initial implementation of proposed flow layout for widgets. Fixes for keeping all apps, and widgets in sync with Launcher Model, optimizations for reloading all apps pages when invalidating. Adding some animations for tab transitions and feedback when long pressing to add certain items. Change-Id: I8d51749f3a91c964bed35681f3a9192200b0d93e
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher2/AllAppsPagedView.java104
-rw-r--r--src/com/android/launcher2/AllAppsTabbed.java43
-rw-r--r--src/com/android/launcher2/CustomizePagedView.java535
-rw-r--r--src/com/android/launcher2/FolderChooser.java37
-rw-r--r--src/com/android/launcher2/HomeCustomizationItemGallery.java67
-rw-r--r--src/com/android/launcher2/Launcher.java141
-rw-r--r--src/com/android/launcher2/LauncherModel.java10
-rw-r--r--src/com/android/launcher2/PagedView.java114
-rw-r--r--src/com/android/launcher2/PagedViewCellLayout.java96
-rw-r--r--src/com/android/launcher2/ShortcutChooser.java37
-rw-r--r--src/com/android/launcher2/WidgetChooser.java64
11 files changed, 945 insertions, 303 deletions
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index e0d248eb9..4e819371a 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -20,6 +20,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import android.animation.Animatable;
+import android.animation.AnimatableListenerAdapter;
+import android.animation.Animator;
+import android.animation.PropertyAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.TypedArray;
@@ -98,9 +102,11 @@ public class AllAppsPagedView extends PagedView
public void setAppFilter(int filterType) {
mAppFilter = filterType;
- mFilteredApps = rebuildFilteredApps(mApps);
- setCurrentScreen(0);
- invalidatePageData();
+ if (mApps != null) {
+ mFilteredApps = rebuildFilteredApps(mApps);
+ setCurrentScreen(0);
+ invalidatePageData();
+ }
}
@Override
@@ -156,22 +162,13 @@ public class AllAppsPagedView extends PagedView
if (childIndex == getCurrentScreen()) {
final ApplicationInfo app = (ApplicationInfo) v.getTag();
- AlphaAnimation anim = new AlphaAnimation(1.0f, 0.65f);
- anim.setDuration(100);
- anim.setFillAfter(true);
- anim.setRepeatMode(AlphaAnimation.REVERSE);
- anim.setRepeatCount(1);
- anim.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {}
+ // animate some feedback to the click
+ animateClickFeedback(v, new Runnable() {
@Override
- public void onAnimationRepeat(Animation animation) {
+ public void run() {
mLauncher.startActivitySafely(app.intent, app);
}
- @Override
- public void onAnimationEnd(Animation animation) {}
});
- v.startAnimation(anim);
}
}
@@ -223,26 +220,30 @@ public class AllAppsPagedView extends PagedView
@Override
public void setApps(ArrayList<ApplicationInfo> list) {
mApps = list;
- Collections.sort(mApps, new Comparator<ApplicationInfo>() {
- @Override
- public int compare(ApplicationInfo object1, ApplicationInfo object2) {
- return object1.title.toString().compareTo(object2.title.toString());
- }
- });
+ Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
mFilteredApps = rebuildFilteredApps(mApps);
invalidatePageData();
}
+ private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // we add it in place, in alphabetical order
+ final int count = list.size();
+ for (int i = 0; i < count; ++i) {
+ final ApplicationInfo info = list.get(i);
+ final int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ }
+ }
+ mFilteredApps = rebuildFilteredApps(mApps);
+ }
@Override
public void addApps(ArrayList<ApplicationInfo> list) {
- // TODO: we need to add it in place, in alphabetical order
- mApps.addAll(list);
- mFilteredApps.addAll(rebuildFilteredApps(list));
+ addAppsWithoutInvalidate(list);
invalidatePageData();
}
- @Override
- public void removeApps(ArrayList<ApplicationInfo> list) {
+ private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
// loop through all the apps and remove apps that have the same component
final int length = list.size();
for (int i = 0; i < length; ++i) {
@@ -251,14 +252,19 @@ public class AllAppsPagedView extends PagedView
mApps.remove(removeIndex);
}
}
- mFilteredApps = rebuildFilteredApps(list);
+ mFilteredApps = rebuildFilteredApps(mApps);
+ }
+ @Override
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ removeAppsWithoutInvalidate(list);
invalidatePageData();
}
@Override
public void updateApps(ArrayList<ApplicationInfo> list) {
- removeApps(list);
- addApps(list);
+ removeAppsWithoutInvalidate(list);
+ addAppsWithoutInvalidate(list);
+ invalidatePageData();
}
private int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
@@ -308,25 +314,43 @@ public class AllAppsPagedView extends PagedView
@Override
public void syncPageItems(int page) {
// ensure that we have the right number of items on the pages
- int numCells = mCellCountX * mCellCountY;
- int startIndex = page * numCells;
- int endIndex = Math.min(startIndex + numCells, mFilteredApps.size());
+ final int cellsPerPage = mCellCountX * mCellCountY;
+ final int startIndex = page * cellsPerPage;
+ final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
- // TODO: we can optimize by just re-applying to existing views
- layout.removeAllViews();
+
+ final int curNumPageItems = layout.getChildCount();
+ final int numPageItems = endIndex - startIndex;
+
+ // remove any extra items
+ int extraPageItemsDiff = curNumPageItems - numPageItems;
+ for (int i = 0; i < extraPageItemsDiff; ++i) {
+ layout.removeViewAt(numPageItems);
+ }
+ // add any necessary items
+ for (int i = curNumPageItems; i < numPageItems; ++i) {
+ TextView text = (TextView) mInflater.inflate(R.layout.all_apps_paged_view_application, layout, false);
+ text.setOnClickListener(this);
+ text.setOnLongClickListener(this);
+
+ layout.addViewToCellLayout(text, -1, i,
+ new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
+ }
+
+ // actually reapply to the existing text views
for (int i = startIndex; i < endIndex; ++i) {
+ int index = i - startIndex;
ApplicationInfo info = mFilteredApps.get(i);
- TextView text = (TextView) mInflater.inflate(R.layout.all_apps_paged_view_application, layout, false);
+ TextView text = (TextView) layout.getChildAt(index);
text.setCompoundDrawablesWithIntrinsicBounds(null,
new BitmapDrawable(info.iconBitmap), null, null);
text.setText(info.title);
text.setTag(info);
- text.setOnClickListener(this);
- text.setOnLongClickListener(this);
- int index = i - startIndex;
- layout.addViewToCellLayout(text, index, i,
- new PagedViewCellLayout.LayoutParams(index % mCellCountX, index / mCellCountX, 1, 1));
+ PagedViewCellLayout.LayoutParams params =
+ (PagedViewCellLayout.LayoutParams) text.getLayoutParams();
+ params.cellX = index % mCellCountX;
+ params.cellY = index / mCellCountX;
}
}
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index 0470cee3e..114da4ed2 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -18,6 +18,10 @@ package com.android.launcher2;
import java.util.ArrayList;
+import android.animation.Animatable;
+import android.animation.AnimatableListenerAdapter;
+import android.animation.Animator;
+import android.animation.PropertyAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
@@ -96,16 +100,30 @@ public class AllAppsTabbed extends TabHost implements AllAppsView {
setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
- String tag = getCurrentTabTag();
- if (tag == TAG_ALL) {
- mAllApps.setAppFilter(AllAppsPagedView.ALL_APPS_FLAG);
- } else if (tag == TAG_APPS) {
- mAllApps.setAppFilter(ApplicationInfo.APP_FLAG);
- } else if (tag == TAG_GAMES) {
- mAllApps.setAppFilter(ApplicationInfo.GAME_FLAG);
- } else if (tag == TAG_DOWNLOADED) {
- mAllApps.setAppFilter(ApplicationInfo.DOWNLOADED_FLAG);
- }
+ // animate the changing of the tab content by fading pages in and out
+ final int duration = 150;
+ final float alpha = mAllApps.getAlpha();
+ Animator alphaAnim = new PropertyAnimator(duration, mAllApps, "alpha", alpha, 0.0f);
+ alphaAnim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationEnd(Animatable animation) {
+ String tag = getCurrentTabTag();
+ if (tag == TAG_ALL) {
+ mAllApps.setAppFilter(AllAppsPagedView.ALL_APPS_FLAG);
+ } else if (tag == TAG_APPS) {
+ mAllApps.setAppFilter(ApplicationInfo.APP_FLAG);
+ } else if (tag == TAG_GAMES) {
+ mAllApps.setAppFilter(ApplicationInfo.GAME_FLAG);
+ } else if (tag == TAG_DOWNLOADED) {
+ mAllApps.setAppFilter(ApplicationInfo.DOWNLOADED_FLAG);
+ }
+
+ final float alpha = mAllApps.getAlpha();
+ Animator alphaAnim =
+ new PropertyAnimator(duration, mAllApps, "alpha", alpha, 1.0f);
+ alphaAnim.start();
+ }
+ });
+ alphaAnim.start();
}
});
@@ -135,9 +153,12 @@ public class AllAppsTabbed extends TabHost implements AllAppsView {
@Override
public void setVisibility(int visibility) {
+ final boolean isVisible = (visibility == View.VISIBLE);
super.setVisibility(visibility);
- float zoom = visibility == View.VISIBLE ? 1.0f : 0.0f;
+ float zoom = (isVisible ? 1.0f : 0.0f);
mAllApps.zoom(zoom, false);
+ if (!isVisible)
+ mAllApps.cleanup();
}
@Override
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
new file mode 100644
index 000000000..7679e398c
--- /dev/null
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2010 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.android.launcher2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.Bitmap.Config;
+import android.graphics.Region.Op;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.provider.LiveFolders;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+public class CustomizePagedView extends PagedView
+ implements View.OnLongClickListener,
+ DragSource {
+
+ public enum CustomizationType {
+ WidgetCustomization,
+ FolderCustomization,
+ ShortcutCustomization,
+ WallpaperCustomization
+ }
+
+ private static final String TAG = "CustomizeWorkspace";
+ private static final boolean DEBUG = false;
+
+ private Launcher mLauncher;
+ private DragController mDragController;
+ private PackageManager mPackageManager;
+
+ private CustomizationType mCustomizationType;
+
+ private PagedViewCellLayout mTmpWidgetLayout;
+ private ArrayList<ArrayList<PagedViewCellLayout.LayoutParams>> mWidgetPages;
+ private List<AppWidgetProviderInfo> mWidgetList;
+ private List<ResolveInfo> mFolderList;
+ private List<ResolveInfo> mShortcutList;
+
+ private int mCellCountX;
+ private int mCellCountY;
+
+ private final Canvas mCanvas = new Canvas();
+ private final LayoutInflater mInflater;
+
+ public CustomizePagedView(Context context) {
+ this(context, null);
+ }
+
+ public CustomizePagedView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mCellCountX = 8;
+ mCellCountY = 4;
+ mCustomizationType = CustomizationType.WidgetCustomization;
+ mWidgetPages = new ArrayList<ArrayList<PagedViewCellLayout.LayoutParams>>();
+ mTmpWidgetLayout = new PagedViewCellLayout(context);
+ mInflater = LayoutInflater.from(context);
+ setupPage(mTmpWidgetLayout);
+ setVisibility(View.GONE);
+ setSoundEffectsEnabled(false);
+ }
+
+ public void setLauncher(Launcher launcher) {
+ Context context = getContext();
+ mLauncher = launcher;
+ mPackageManager = context.getPackageManager();
+ }
+
+ public void update() {
+ Context context = getContext();
+
+ // get the list of widgets
+ mWidgetList = AppWidgetManager.getInstance(mLauncher).getInstalledProviders();
+ Collections.sort(mWidgetList, new Comparator<AppWidgetProviderInfo>() {
+ @Override
+ public int compare(AppWidgetProviderInfo object1, AppWidgetProviderInfo object2) {
+ return object1.label.compareTo(object2.label);
+ }
+ });
+
+ Comparator<ResolveInfo> resolveInfoComparator = new Comparator<ResolveInfo>() {
+ @Override
+ public int compare(ResolveInfo object1, ResolveInfo object2) {
+ return object1.loadLabel(mPackageManager).toString().compareTo(
+ object2.loadLabel(mPackageManager).toString());
+ }
+ };
+
+ // get the list of live folder intents
+ Intent liveFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
+ mFolderList = mPackageManager.queryIntentActivities(liveFolderIntent, 0);
+
+ // manually create a separate entry for creating a folder in Launcher
+ ResolveInfo folder = new ResolveInfo();
+ folder.icon = R.drawable.ic_launcher_folder;
+ folder.labelRes = R.string.group_folder;
+ folder.resolvePackageName = context.getPackageName();
+ mFolderList.add(0, folder);
+ Collections.sort(mFolderList, resolveInfoComparator);
+
+ // get the list of shortcuts
+ Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ mShortcutList = mPackageManager.queryIntentActivities(shortcutsIntent, 0);
+ Collections.sort(mShortcutList, resolveInfoComparator);
+
+ invalidatePageData();
+ }
+
+ public void setDragController(DragController dragger) {
+ mDragController = dragger;
+ }
+
+ public void setCustomizationFilter(CustomizationType filterType) {
+ mCustomizationType = filterType;
+ setCurrentScreen(0);
+ invalidatePageData();
+ }
+
+ @Override
+ public void onDropCompleted(View target, boolean success) {
+ // do nothing
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ if (!v.isInTouchMode()) {
+ return false;
+ }
+
+ final View animView = v;
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo) v.getTag();
+ LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(appWidgetInfo.provider);
+ dragInfo.minWidth = appWidgetInfo.minWidth;
+ dragInfo.minHeight = appWidgetInfo.minHeight;
+ mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY);
+ mLauncher.hideCustomizationDrawer();
+ return true;
+ case FolderCustomization:
+ // animate some feedback to the long press
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ // add the folder
+ ResolveInfo resolveInfo = (ResolveInfo) animView.getTag();
+ Intent createFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
+ if (resolveInfo.labelRes == R.string.group_folder) {
+ // Create app shortcuts is a special built-in case of shortcuts
+ createFolderIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
+ getContext().getString(R.string.group_folder));
+ } else {
+ ComponentName name = new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ createFolderIntent.setComponent(name);
+ }
+ mLauncher.prepareAddItemFromHomeCustomizationDrawer();
+ mLauncher.addLiveFolder(createFolderIntent);
+ }
+ });
+ return true;
+ case ShortcutCustomization:
+ // animate some feedback to the long press
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ // add the shortcut
+ ResolveInfo info = (ResolveInfo) animView.getTag();
+ Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ if (info.labelRes == R.string.group_applications) {
+ // Create app shortcuts is a special built-in case of shortcuts
+ createShortcutIntent.putExtra(
+ Intent.EXTRA_SHORTCUT_NAME,getContext().getString(
+ R.string.group_applications));
+ } else {
+ ComponentName name = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ createShortcutIntent.setComponent(name);
+ }
+ mLauncher.prepareAddItemFromHomeCustomizationDrawer();
+ mLauncher.processShortcut(createShortcutIntent);
+ }
+ });
+ return true;
+ }
+ return false;
+ }
+
+ private int relayoutWidgets() {
+ final int widgetCount = mWidgetList.size();
+ if (widgetCount == 0) return 0;
+
+ mWidgetPages.clear();
+ ArrayList<PagedViewCellLayout.LayoutParams> page =
+ new ArrayList<PagedViewCellLayout.LayoutParams>();
+ mWidgetPages.add(page);
+ int rowOffsetX = 0;
+ int rowOffsetY = 0;
+ int curRowHeight = 0;
+ // we only get the cell dims this way for the layout calculations because
+ // we know that we aren't going to change the dims when we construct it
+ // afterwards
+ for (int i = 0; i < widgetCount; ++i) {
+ AppWidgetProviderInfo info = mWidgetList.get(i);
+ PagedViewCellLayout.LayoutParams params;
+
+ final int cellSpanX = mTmpWidgetLayout.estimateCellHSpan(info.minWidth);
+ final int cellSpanY = mTmpWidgetLayout.estimateCellVSpan(info.minHeight);
+
+ if (((rowOffsetX + cellSpanX) <= mCellCountX) &&
+ ((rowOffsetY + cellSpanY) <= mCellCountY)) {
+ // just add to end of current row
+ params = new PagedViewCellLayout.LayoutParams(rowOffsetX, rowOffsetY,
+ cellSpanX, cellSpanY);
+
+ rowOffsetX += cellSpanX;
+ curRowHeight = Math.max(curRowHeight, cellSpanY);
+ } else {
+ /*
+ // fix all the items in this last row to be bottom aligned
+ int prevRowOffsetX = rowOffsetX;
+ for (int j = page.size() - 1; j >= 0; --j) {
+ PagedViewCellLayout.LayoutParams params = page.get(j);
+ // skip once we get to the previous row
+ if (params.cellX > prevRowOffsetX)
+ break;
+
+ params.cellY += curRowHeight - params.cellVSpan;
+ prevRowOffsetX = params.cellX;
+ }
+ */
+
+ // doesn't fit on current row, see if we can start a new row on
+ // this page
+ if ((rowOffsetY + curRowHeight + cellSpanY) > mCellCountY) {
+ // start a new page and add this item to it
+ page = new ArrayList<PagedViewCellLayout.LayoutParams>();
+ mWidgetPages.add(page);
+
+ params = new PagedViewCellLayout.LayoutParams(0, 0, cellSpanX, cellSpanY);
+ rowOffsetX = cellSpanX;
+ rowOffsetY = 0;
+ curRowHeight = cellSpanY;
+ } else {
+ // add it to the current page on this new row
+ params = new PagedViewCellLayout.LayoutParams(0, rowOffsetY + curRowHeight,
+ cellSpanX, cellSpanY);
+
+ rowOffsetX = cellSpanX;
+ rowOffsetY += curRowHeight;
+ curRowHeight = cellSpanY;
+ }
+ }
+
+ params.setTag(info);
+ page.add(params);
+ }
+ return mWidgetPages.size();
+ }
+
+ private Drawable getWidgetIcon(PagedViewCellLayout.LayoutParams params,
+ AppWidgetProviderInfo info) {
+ PackageManager packageManager = mLauncher.getPackageManager();
+ String packageName = info.provider.getPackageName();
+ Drawable drawable = null;
+ if (info.previewImage != 0) {
+ drawable = packageManager.getDrawable(packageName, info.previewImage, null);
+ if (drawable == null) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ } else {
+ return drawable;
+ }
+ }
+
+ // If we don't have a preview image, create a default one
+ if (drawable == null) {
+ Resources resources = mLauncher.getResources();
+
+ // Determine the size the widget will take in the layout
+ // Create a new bitmap to hold the widget preview
+ int[] dims = mTmpWidgetLayout.estimateCellDimensions(getMeasuredWidth(),
+ getMeasuredHeight(), params.cellHSpan, params.cellVSpan);
+ final int width = dims[0];
+ final int height = dims[1] - 35;
+ // TEMP
+ // TEMP: HACK ABOVE TO GET TEXT TO SHOW
+ // TEMP
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+ mCanvas.setBitmap(bitmap);
+ // For some reason, we must re-set the clip rect here, otherwise it will be wrong
+ mCanvas.clipRect(0, 0, width, height, Op.REPLACE);
+
+ Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
+ background.setBounds(0, 0, width, height);
+ background.draw(mCanvas);
+
+ // Draw the icon vertically centered, flush left
+ try {
+ Rect tmpRect = new Rect();
+ Drawable icon = null;
+ if (info.icon != 0) {
+ icon = packageManager.getDrawable(packageName, info.icon, null);
+ } else {
+ icon = resources.getDrawable(R.drawable.ic_launcher_application);
+ }
+ background.getPadding(tmpRect);
+
+ final int iconSize = Math.min(
+ Math.min(icon.getIntrinsicWidth(), width - tmpRect.left - tmpRect.right),
+ Math.min(icon.getIntrinsicHeight(), height - tmpRect.top - tmpRect.bottom));
+ final int left = (width / 2) - (iconSize / 2);
+ final int top = (height / 2) - (iconSize / 2);
+ icon.setBounds(new Rect(left, top, left + iconSize, top + iconSize));
+ icon.draw(mCanvas);
+ } catch (Resources.NotFoundException e) {
+ // if we can't find the icon, then just don't draw it
+ }
+
+ drawable = new BitmapDrawable(resources, bitmap);
+ }
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+ return drawable;
+ }
+
+ private void setupPage(PagedViewCellLayout layout) {
+ layout.setCellCount(mCellCountX, mCellCountY);
+ layout.setPadding(20, 10, 20, 0);
+ }
+
+ private void syncWidgetPages() {
+ if (mWidgetList == null) return;
+
+ // calculate the layout for all the widget pages first and ensure that
+ // we have the right number of pages
+ int numPages = relayoutWidgets();
+ int curNumPages = getChildCount();
+ // remove any extra pages after the "last" page
+ int extraPageDiff = curNumPages - numPages;
+ for (int i = 0; i < extraPageDiff; ++i) {
+ removeViewAt(numPages);
+ }
+ // add any necessary pages
+ for (int i = curNumPages; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+
+ private void syncWidgetPageItems(int page) {
+ // ensure that we have the right number of items on the pages
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ final ArrayList<PagedViewCellLayout.LayoutParams> list = mWidgetPages.get(page);
+ final int count = list.size();
+ layout.removeAllViews();
+ for (int i = 0; i < count; ++i) {
+ PagedViewCellLayout.LayoutParams params = list.get(i);
+ AppWidgetProviderInfo info = (AppWidgetProviderInfo) params.getTag();
+ final Drawable icon = getWidgetIcon(params, info);
+ TextView text = (TextView) mInflater.inflate(R.layout.customize_paged_view_widget,
+ layout, false);
+ text.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
+ text.setText(info.label);
+ text.setTag(info);
+ text.setOnLongClickListener(this);
+
+ layout.addViewToCellLayout(text, -1, mWidgetList.indexOf(info), params);
+ }
+ }
+
+ private void syncListPages(List<ResolveInfo> list) {
+ // ensure that we have the right number of pages
+ int numPages = (int) Math.ceil((float) list.size() / (mCellCountX * mCellCountY));
+ int curNumPages = getChildCount();
+ // remove any extra pages after the "last" page
+ int extraPageDiff = curNumPages - numPages;
+ for (int i = 0; i < extraPageDiff; ++i) {
+ removeViewAt(numPages);
+ }
+ // add any necessary pages
+ for (int i = curNumPages; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+
+ private void syncListPageItems(int page, List<ResolveInfo> list) {
+ // ensure that we have the right number of items on the pages
+ int numCells = mCellCountX * mCellCountY;
+ int startIndex = page * numCells;
+ int endIndex = Math.min(startIndex + numCells, list.size());
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ // TODO: we can optimize by just re-applying to existing views
+ layout.removeAllViews();
+ for (int i = startIndex; i < endIndex; ++i) {
+ ResolveInfo info = list.get(i);
+ Drawable image = info.loadIcon(mPackageManager);
+ TextView text = (TextView) mInflater.inflate(R.layout.customize_paged_view_item,
+ layout, false);
+ image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
+ text.setCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+ text.setText(info.loadLabel(mPackageManager));
+ text.setTag(info);
+ text.setOnLongClickListener(this);
+
+ final int index = i - startIndex;
+ final int x = index % mCellCountX;
+ final int y = index / mCellCountX;
+ layout.addViewToCellLayout(text, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+ }
+ }
+
+ private void syncWallpaperPages() {
+ // NOT CURRENTLY IMPLEMENTED
+ // ensure that we have the right number of pages
+ int numPages = 1;
+ int curNumPages = getChildCount();
+ // remove any extra pages after the "last" page
+ int extraPageDiff = curNumPages - numPages;
+ for (int i = 0; i < extraPageDiff; ++i) {
+ removeViewAt(numPages);
+ }
+ // add any necessary pages
+ for (int i = curNumPages; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+
+ private void syncWallpaperPageItems(int page) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ layout.removeAllViews();
+
+ TextView text = (TextView) mInflater.inflate(
+ R.layout.customize_paged_view_wallpaper_placeholder, layout, false);
+ // NOTE: this is just place holder text until MikeJurka implements wallpaper picker
+ text.setText("Wallpaper customization coming soon!");
+
+ layout.addViewToCellLayout(text, -1, 0, new PagedViewCellLayout.LayoutParams(0, 0, 3, 1));
+ }
+
+ @Override
+ public void syncPages() {
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ syncWidgetPages();
+ break;
+ case FolderCustomization:
+ syncListPages(mFolderList);
+ break;
+ case ShortcutCustomization:
+ syncListPages(mShortcutList);
+ break;
+ case WallpaperCustomization:
+ syncWallpaperPages();
+ break;
+ default:
+ removeAllViews();
+ setCurrentScreen(0);
+ break;
+ }
+
+ // only try and center the page if there is one page
+ final int childCount = getChildCount();
+ if (childCount == 1) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(0);
+ layout.enableCenteredContent(true);
+ } else {
+ for (int i = 0; i < childCount; ++i) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ layout.enableCenteredContent(false);
+ }
+ }
+
+ // bound the current page
+ setCurrentScreen(Math.max(0, Math.min(childCount - 1, getCurrentScreen())));
+ }
+
+ @Override
+ public void syncPageItems(int page) {
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ syncWidgetPageItems(page);
+ break;
+ case FolderCustomization:
+ syncListPageItems(page, mFolderList);
+ break;
+ case ShortcutCustomization:
+ syncListPageItems(page, mShortcutList);
+ break;
+ case WallpaperCustomization:
+ syncWallpaperPageItems(page);
+ break;
+ }
+ }
+}
diff --git a/src/com/android/launcher2/FolderChooser.java b/src/com/android/launcher2/FolderChooser.java
deleted file mode 100644
index b152ad5f5..000000000
--- a/src/com/android/launcher2/FolderChooser.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.launcher2;
-
-import com.android.launcher.R;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.provider.LiveFolders;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.AdapterView;
-
-public class FolderChooser extends HomeCustomizationItemGallery {
-
- public FolderChooser(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- // todo: this code sorta overlaps with other places
- ResolveInfo info = (ResolveInfo)getAdapter().getItem(position);
- mLauncher.prepareAddItemFromHomeCustomizationDrawer();
-
- Intent createFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
- if (info.labelRes == R.string.group_folder) {
- // Create app shortcuts is a special built-in case of shortcuts
- createFolderIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getContext().getString(R.string.group_folder));
- } else {
- ComponentName name = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
- createFolderIntent.setComponent(name);
- }
- mLauncher.addLiveFolder(createFolderIntent);
-
- return true;
- }
-}
diff --git a/src/com/android/launcher2/HomeCustomizationItemGallery.java b/src/com/android/launcher2/HomeCustomizationItemGallery.java
deleted file mode 100644
index 2eba49f14..000000000
--- a/src/com/android/launcher2/HomeCustomizationItemGallery.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2010 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.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.Gallery;
-
-public abstract class HomeCustomizationItemGallery extends Gallery
- implements Gallery.OnItemLongClickListener {
-
- protected Context mContext;
-
- protected Launcher mLauncher;
-
- protected int mMotionDownRawX;
- protected int mMotionDownRawY;
-
- public HomeCustomizationItemGallery(Context context, AttributeSet attrs) {
- super(context, attrs);
- setLongClickable(true);
- setOnItemLongClickListener(this);
- mContext = context;
-
- setCallbackDuringFling(false);
- }
-
- public void setLauncher(Launcher launcher) {
- mLauncher = launcher;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN && mLauncher.isAllAppsVisible()) {
- return false;
- }
-
- super.onTouchEvent(ev);
-
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mMotionDownRawX = (int) ev.getRawX();
- mMotionDownRawY = (int) ev.getRawY();
- }
- return true;
- }
-}
-
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index ccd6f6553..41f9e7dbb 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -16,8 +16,13 @@
package com.android.launcher2;
-import com.android.common.Search;
-import com.android.launcher.R;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
import android.animation.Animatable;
import android.animation.AnimatableListenerAdapter;
@@ -39,8 +44,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
+import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -50,6 +55,7 @@ import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -73,10 +79,12 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
+import android.view.View.OnLongClickListener;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputMethodManager;
@@ -84,17 +92,16 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
import android.widget.TabHost;
+import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.Toast;
+import android.widget.TabHost.OnTabChangeListener;
+import android.widget.TabHost.TabContentFactory;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import com.android.common.Search;
+import com.android.launcher.R;
/**
* Default launcher application.
@@ -166,6 +173,12 @@ public final class Launcher extends Activity
// Type: long
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
+ // tags for the customization tabs
+ private static final String WIDGETS_TAG = "widgets";
+ private static final String FOLDERS_TAG = "folders";
+ private static final String SHORTCUTS_TAG = "shortcuts";
+ private static final String WALLPAPERS_TAG = "wallpapers";
+
static final int APPWIDGET_HOST_ID = 1024;
private static final Object sLock = new Object();
@@ -192,6 +205,7 @@ public final class Launcher extends Activity
private HandleView mHandleView;
private AllAppsView mAllAppsGrid;
private TabHost mHomeCustomizationDrawer;
+ private CustomizePagedView mCustomizePagedView;
private Bundle mSavedState;
@@ -252,18 +266,72 @@ public final class Launcher extends Activity
if (mHomeCustomizationDrawer != null) {
mHomeCustomizationDrawer.setup();
+ // share the same customization workspace across all the tabs
+ mCustomizePagedView = new CustomizePagedView(this);
+ TabContentFactory contentFactory = new TabContentFactory() {
+ public View createTabContent(String tag) {
+ return mCustomizePagedView;
+ }
+ };
+
String widgetsLabel = getString(R.string.widgets_tab_label);
- mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("widgets")
- .setIndicator(widgetsLabel).setContent(R.id.widget_chooser));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(WIDGETS_TAG)
+ .setIndicator(widgetsLabel).setContent(contentFactory));
String foldersLabel = getString(R.string.folders_tab_label);
- mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("folders")
- .setIndicator(foldersLabel).setContent(R.id.folder_chooser));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(FOLDERS_TAG)
+ .setIndicator(foldersLabel).setContent(contentFactory));
String shortcutsLabel = getString(R.string.shortcuts_tab_label);
- mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("shortcuts")
- .setIndicator(shortcutsLabel).setContent(R.id.shortcut_chooser));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(SHORTCUTS_TAG)
+ .setIndicator(shortcutsLabel).setContent(contentFactory));
String wallpapersLabel = getString(R.string.wallpapers_tab_label);
- mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec("wallpapers")
- .setIndicator(wallpapersLabel).setContent(R.id.wallpaperstab));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(WALLPAPERS_TAG)
+ .setIndicator(wallpapersLabel).setContent(contentFactory));
+
+ // TEMP: just styling the tab widget to be a bit nicer until we get the actual
+ // new assets
+ TabWidget tabWidget = mHomeCustomizationDrawer.getTabWidget();
+ for (int i = 0; i < tabWidget.getChildCount(); ++i) {
+ RelativeLayout tab = (RelativeLayout) tabWidget.getChildTabViewAt(i);
+ TextView text = (TextView) tab.getChildAt(1);
+ text.setTextSize(20.0f);
+ text.setPadding(20, 0, 20, 0);
+ text.setShadowLayer(1.0f, 0.0f, 1.0f, Color.BLACK);
+ tab.setBackgroundDrawable(null);
+ }
+
+ mHomeCustomizationDrawer.setOnTabChangedListener(new OnTabChangeListener() {
+ public void onTabChanged(String tabId) {
+ // animate the changing of the tab content by fading pages in and out
+ final int duration = 150;
+ final float alpha = mCustomizePagedView.getAlpha();
+ Animator alphaAnim = new PropertyAnimator(duration, mCustomizePagedView,
+ "alpha", alpha, 0.0f);
+ alphaAnim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationEnd(Animatable animation) {
+ String tag = mHomeCustomizationDrawer.getCurrentTabTag();
+ if (tag == WIDGETS_TAG) {
+ mCustomizePagedView.setCustomizationFilter(
+ CustomizePagedView.CustomizationType.WidgetCustomization);
+ } else if (tag == FOLDERS_TAG) {
+ mCustomizePagedView.setCustomizationFilter(
+ CustomizePagedView.CustomizationType.FolderCustomization);
+ } else if (tag == SHORTCUTS_TAG) {
+ mCustomizePagedView.setCustomizationFilter(
+ CustomizePagedView.CustomizationType.ShortcutCustomization);
+ } else if (tag == WALLPAPERS_TAG) {
+ mCustomizePagedView.setCustomizationFilter(
+ CustomizePagedView.CustomizationType.WallpaperCustomization);
+ }
+
+ final float alpha = mCustomizePagedView.getAlpha();
+ Animator alphaAnim = new PropertyAnimator(duration, mCustomizePagedView,
+ "alpha", alpha, 1.0f);
+ alphaAnim.start();
+ }
+ });
+ alphaAnim.start();
+ }
+ });
mHomeCustomizationDrawer.setCurrentTab(0);
}
@@ -776,24 +844,10 @@ public final class Launcher extends Activity
mHandleView.setOnLongClickListener(this);
}
- WidgetChooser widgetChooser = (WidgetChooser) findViewById(R.id.widget_chooser);
- if (widgetChooser != null) {
- WidgetListAdapter widgetGalleryAdapter = new WidgetListAdapter(this);
- widgetChooser.setAdapter(widgetGalleryAdapter);
- widgetChooser.setDragController(dragController);
- widgetChooser.setLauncher(this);
-
- FolderChooser folderChooser = (FolderChooser) findViewById(R.id.folder_chooser);
- IntentListAdapter folderTypes = new FolderListAdapter(
- this, LiveFolders.ACTION_CREATE_LIVE_FOLDER);
- folderChooser.setAdapter(folderTypes);
- folderChooser.setLauncher(this);
-
- ShortcutChooser shortcutChooser = (ShortcutChooser) findViewById(R.id.shortcut_chooser);
- IntentListAdapter shortcutTypes = new IntentListAdapter(
- this, Intent.ACTION_CREATE_SHORTCUT);
- shortcutChooser.setAdapter(shortcutTypes);
- shortcutChooser.setLauncher(this);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.setLauncher(this);
+ mCustomizePagedView.setDragController(dragController);
+ mCustomizePagedView.update();
} else {
ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
hotseatLeft.setContentDescription(mHotseatLabels[0]);
@@ -2192,6 +2246,9 @@ public final class Launcher extends Activity
}
void showAllApps(boolean animated) {
+ if (mAllAppsGrid.isVisible())
+ return;
+
if (LauncherApplication.isScreenXLarge()) {
mWorkspace.shrinkToBottom(animated);
}
@@ -2199,6 +2256,7 @@ public final class Launcher extends Activity
if (LauncherApplication.isScreenXLarge() && animated) {
if (isCustomizationDrawerVisible()) {
cameraPan(mHomeCustomizationDrawer, (View) mAllAppsGrid);
+ mCustomizePagedView.cleanup();
} else {
cameraZoomOut((View) mAllAppsGrid, true);
}
@@ -2299,6 +2357,7 @@ public final class Launcher extends Activity
mWorkspace.unshrink();
}
cameraZoomIn(mHomeCustomizationDrawer);
+ mCustomizePagedView.cleanup();
}
}
@@ -2648,6 +2707,14 @@ public final class Launcher extends Activity
}
/**
+ * A number of packages were updated.
+ */
+ public void bindPackagesUpdated() {
+ // update the customization drawer contents
+ mCustomizePagedView.update();
+ }
+
+ /**
* Prints out out state for debugging.
*/
public void dumpState() {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 6c3ddd22f..797bf686c 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -104,6 +104,7 @@ public class LauncherModel extends BroadcastReceiver {
public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
+ public void bindPackagesUpdated();
public boolean isAllAppsVisible();
}
@@ -1320,6 +1321,15 @@ public class LauncherModel extends BroadcastReceiver {
}
});
}
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (callbacks == mCallbacks.get()) {
+ callbacks.bindPackagesUpdated();
+ }
+ }
+ });
}
}
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 26805e0b5..0e8ffa0fd 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -32,8 +33,14 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Animation.AnimationListener;
import android.widget.Scroller;
+import com.android.launcher.R;
+
/**
* An abstraction of the original Workspace which supports browsing through a
* sequential list of "pages" (or PagedViewCellLayouts).
@@ -81,16 +88,12 @@ public abstract class PagedView extends ViewGroup {
private ScreenSwitchListener mScreenSwitchListener;
private boolean mDimmedPagesDirty;
+ private final Handler mHandler = new Handler();
public interface ScreenSwitchListener {
void onScreenSwitch(View newScreen, int newScreenIndex);
}
- /**
- * Constructor
- *
- * @param context The application's context.
- */
public PagedView(Context context) {
this(context, null);
}
@@ -158,6 +161,7 @@ public abstract class PagedView extends ViewGroup {
mCurrentScreen = Math.max(0, Math.min(currentScreen, getScreenCount() - 1));
scrollTo(getChildOffset(mCurrentScreen) - getRelativeChildOffset(mCurrentScreen), 0);
+
invalidate();
notifyScreenSwitchListener();
}
@@ -457,6 +461,23 @@ public abstract class PagedView extends ViewGroup {
return mTouchState != TOUCH_STATE_REST;
}
+ protected void animateClickFeedback(View v, final Runnable r) {
+ // animate the view slightly to show click feedback running some logic after it is "pressed"
+ Animation anim = AnimationUtils.loadAnimation(getContext(),
+ R.anim.paged_view_click_feedback);
+ anim.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {}
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ r.run();
+ }
+ @Override
+ public void onAnimationEnd(Animation animation) {}
+ });
+ v.startAnimation(anim);
+ }
+
/*
* Determines if we should change the touch state to start scrolling after the
* user moves their touch point too far.
@@ -689,6 +710,10 @@ public abstract class PagedView extends ViewGroup {
if (!mScroller.isFinished()) mScroller.abortAnimation();
mScroller.startScroll(sX, 0, delta, 0, duration);
+
+ // only load some associated pages
+ loadAssociatedPages(mNextScreen);
+
invalidate();
}
@@ -775,13 +800,86 @@ public abstract class PagedView extends ViewGroup {
};
}
+ private void clearDimmedBitmaps(boolean skipCurrentScreens) {
+ final int count = getChildCount();
+ if (mCurrentScreen < count) {
+ if (skipCurrentScreens) {
+ int lowerScreenBound = Math.max(0, mCurrentScreen - 1);
+ int upperScreenBound = Math.min(mCurrentScreen + 1, count - 1);
+ for (int i = 0; i < count; ++i) {
+ if (i < lowerScreenBound || i > upperScreenBound) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ layout.clearDimmedBitmap();
+ }
+ }
+ } else {
+ for (int i = 0; i < count; ++i) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ layout.clearDimmedBitmap();
+ }
+ }
+ }
+ }
+ Runnable clearLayoutOtherDimmedBitmapsRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mScroller.isFinished()) {
+ clearDimmedBitmaps(true);
+ mHandler.removeMessages(0);
+ } else {
+ mHandler.postDelayed(clearLayoutOtherDimmedBitmapsRunnable, 50);
+ }
+ }
+ };
+ Runnable clearLayoutDimmedBitmapsRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mScroller.isFinished()) {
+ clearDimmedBitmaps(false);
+ mHandler.removeMessages(0);
+ } else {
+ mHandler.postDelayed(clearLayoutOtherDimmedBitmapsRunnable, 50);
+ }
+ }
+ };
+
+ // called when this paged view is no longer visible
+ public void cleanup() {
+ // clear all the layout dimmed bitmaps
+ mHandler.removeMessages(0);
+ mHandler.postDelayed(clearLayoutDimmedBitmapsRunnable, 500);
+ }
+
+ public void loadAssociatedPages(int screen) {
+ final int count = getChildCount();
+ if (screen < count) {
+ int lowerScreenBound = Math.max(0, screen - 1);
+ int upperScreenBound = Math.min(screen + 1, count - 1);
+ boolean hasDimmedBitmap = false;
+ for (int i = 0; i < count; ++i) {
+ if (lowerScreenBound <= i && i <= upperScreenBound) {
+ syncPageItems(i);
+ } else {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ if (layout.getChildCount() > 0) {
+ layout.removeAllViews();
+ }
+ hasDimmedBitmap |= layout.getDimmedBitmapAlpha() > 0.0f;
+ }
+ }
+
+ if (hasDimmedBitmap) {
+ mHandler.removeMessages(0);
+ mHandler.postDelayed(clearLayoutOtherDimmedBitmapsRunnable, 500);
+ }
+ }
+ }
+
public abstract void syncPages();
public abstract void syncPageItems(int page);
public void invalidatePageData() {
syncPages();
- for (int i = 0; i < getChildCount(); ++i) {
- syncPageItems(i);
- }
+ loadAssociatedPages(mCurrentScreen);
invalidateDimmedPages();
requestLayout();
}
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 6c9ff6dbe..16df2a499 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -55,6 +55,8 @@ public class PagedViewCellLayout extends ViewGroup {
private final Rect mLayoutRect = new Rect();
private final Rect mDimmedBitmapRect = new Rect();
+ private boolean mCenterContent;
+
private int mCellCountX;
private int mCellCountY;
private int mCellWidth;
@@ -236,13 +238,28 @@ public class PagedViewCellLayout extends ViewGroup {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
+ int offsetX = 0;
+ if (mCenterContent) {
+ // determine the max width of all the rows and center accordingly
+ int maxRowWidth = 0;
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ PagedViewCellLayout.LayoutParams lp =
+ (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
+ maxRowWidth = Math.max(maxRowWidth, lp.x + lp.width);
+ }
+ }
+ offsetX = (getMeasuredWidth() / 2) - (maxRowWidth / 2);
+ }
+
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
PagedViewCellLayout.LayoutParams lp =
(PagedViewCellLayout.LayoutParams) child.getLayoutParams();
- int childLeft = lp.x;
+ int childLeft = offsetX + lp.x;
int childTop = lp.y;
child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
}
@@ -261,6 +278,10 @@ public class PagedViewCellLayout extends ViewGroup {
return super.onTouchEvent(event) || true;
}
+ public void enableCenteredContent(boolean enabled) {
+ mCenterContent = enabled;
+ }
+
@Override
protected void setChildrenDrawingCacheEnabled(boolean enabled) {
final int count = getChildCount();
@@ -327,12 +348,32 @@ public class PagedViewCellLayout extends ViewGroup {
}
}
+ public void clearDimmedBitmap() {
+ setDimmedBitmapAlpha(0.0f);
+ if (mDimmedBitmap != null) {
+ mDimmedBitmap.recycle();
+ mDimmedBitmap = null;
+ }
+ }
+
private void setChildrenAlpha(float alpha) {
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).setAlpha(alpha);
}
}
+ public int[] getCellCountForDimensions(int width, int height) {
+ // Always assume we're working with the smallest span to make sure we
+ // reserve enough space in both orientations
+ int smallerSize = Math.min(mCellWidth, mCellHeight);
+
+ // Always round up to next largest cell
+ int spanX = (width + smallerSize) / smallerSize;
+ int spanY = (height + smallerSize) / smallerSize;
+
+ return new int[] { spanX, spanY };
+ }
+
/**
* Start dragging the specified child
*
@@ -343,6 +384,39 @@ public class PagedViewCellLayout extends ViewGroup {
lp.isDragging = true;
}
+ public int estimateCellHSpan(int width) {
+ return (width + mCellWidth) / mCellWidth;
+ }
+ public int estimateCellVSpan(int height) {
+ return (height + mCellHeight) / mCellHeight;
+ }
+ public int[] estimateCellDimensions(int approxWidth, int approxHeight,
+ int cellHSpan, int cellVSpan) {
+ // NOTE: we are disabling this until we find a good way to approximate this without fully
+ // measuring
+ /*
+ // we may want to use this before any measuring/layout happens, so we pass in an approximate
+ // size for the layout
+ int numWidthGaps = mCellCountX - 1;
+ int numHeightGaps = mCellCountY - 1;
+ int hSpaceLeft = approxWidth - mPaddingLeft
+ - mPaddingRight - (mCellWidth * mCellCountX);
+ int vSpaceLeft = approxHeight - mPaddingTop
+ - mPaddingBottom - (mCellHeight * mCellCountY);
+ int widthGap = hSpaceLeft / numWidthGaps;
+ int heightGap = vSpaceLeft / numHeightGaps;
+ int minGap = Math.min(widthGap, heightGap);
+ return new int[] {
+ (cellHSpan * mCellWidth) + ((cellHSpan - 1) * minGap),
+ (cellVSpan * mCellHeight) + ((cellVSpan - 1) * minGap)
+ };
+ */
+ return new int[] {
+ (cellHSpan * mCellWidth),
+ (cellVSpan * mCellHeight)
+ };
+ }
+
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
@@ -388,6 +462,9 @@ public class PagedViewCellLayout extends ViewGroup {
*/
public boolean isDragging;
+ // a data object that you can bind to this layout params
+ private Object mTag;
+
// X coordinate of the view in the layout.
@ViewDebug.ExportedProperty
int x;
@@ -395,6 +472,12 @@ public class PagedViewCellLayout extends ViewGroup {
@ViewDebug.ExportedProperty
int y;
+ public LayoutParams() {
+ super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ cellHSpan = 1;
+ cellVSpan = 1;
+ }
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
cellHSpan = 1;
@@ -440,8 +523,17 @@ public class PagedViewCellLayout extends ViewGroup {
y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
}
+ public Object getTag() {
+ return mTag;
+ }
+
+ public void setTag(Object tag) {
+ mTag = tag;
+ }
+
public String toString() {
- return "(" + this.cellX + ", " + this.cellY + ")";
+ return "(" + this.cellX + ", " + this.cellY + ", " +
+ this.cellHSpan + ", " + this.cellVSpan + ")";
}
}
}
diff --git a/src/com/android/launcher2/ShortcutChooser.java b/src/com/android/launcher2/ShortcutChooser.java
deleted file mode 100644
index 1e3e5d0b1..000000000
--- a/src/com/android/launcher2/ShortcutChooser.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.launcher2;
-
-import com.android.launcher.R;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.AdapterView;
-
-public class ShortcutChooser extends HomeCustomizationItemGallery {
-
- public ShortcutChooser(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- // todo: this code sorta overlaps with other places
- ResolveInfo info = (ResolveInfo)getAdapter().getItem(position);
- mLauncher.prepareAddItemFromHomeCustomizationDrawer();
-
- Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
- if (info.labelRes == R.string.group_applications) {
- // Create app shortcuts is a special built-in case of shortcuts
- createShortcutIntent.putExtra(
- Intent.EXTRA_SHORTCUT_NAME,getContext().getString(R.string.group_applications));
- } else {
- ComponentName name = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
- createShortcutIntent.setComponent(name);
- }
- mLauncher.processShortcut(createShortcutIntent);
-
- return true;
- }
-}
diff --git a/src/com/android/launcher2/WidgetChooser.java b/src/com/android/launcher2/WidgetChooser.java
deleted file mode 100644
index 2218e6dce..000000000
--- a/src/com/android/launcher2/WidgetChooser.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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.android.launcher2;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.TextView;
-
-public class WidgetChooser extends HomeCustomizationItemGallery implements DragSource {
- private DragController mDragController;
-
- public WidgetChooser(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setDragController(DragController dragger) {
- mDragController = dragger;
- }
-
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- Drawable[] drawables = ((TextView)view).getCompoundDrawables();
- Bitmap bmp = ((BitmapDrawable)drawables[1]).getBitmap();
- final int w = bmp.getWidth();
- final int h = bmp.getHeight();
-
- // We don't really have an accurate location to use. This will do.
- int screenX = mMotionDownRawX - (w / 2);
- int screenY = mMotionDownRawY - h;
-
- AppWidgetProviderInfo info = (AppWidgetProviderInfo)getAdapter().getItem(position);
- LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(info.provider);
- // TODO: Is this really the best place to do this?
- dragInfo.minWidth = info.minWidth;
- dragInfo.minHeight = info.minHeight;
- mDragController.startDrag(bmp, screenX, screenY,
- 0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY);
- mLauncher.hideCustomizationDrawer();
- return true;
- }
-
- public void onDropCompleted(View target, boolean success) {
- }
-}
-