diff options
Diffstat (limited to 'src/com/android/launcher2/CustomizePagedView.java')
-rw-r--r-- | src/com/android/launcher2/CustomizePagedView.java | 535 |
1 files changed, 535 insertions, 0 deletions
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; + } + } +} |