diff options
author | Winson Chung <winsonc@google.com> | 2011-04-14 16:08:02 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2011-04-22 12:53:59 -0700 |
commit | 785d2eb2b8d7072c8124300dd9168ff51a91cf38 (patch) | |
tree | a87bc934f8496b2dead1e508260d88c978a038ce /src/com/android/launcher2/AppsCustomizePagedView.java | |
parent | f579b5041afe8272c79f9f13001120d37eeeee7b (diff) | |
download | android_packages_apps_Trebuchet-785d2eb2b8d7072c8124300dd9168ff51a91cf38.tar.gz android_packages_apps_Trebuchet-785d2eb2b8d7072c8124300dd9168ff51a91cf38.tar.bz2 android_packages_apps_Trebuchet-785d2eb2b8d7072c8124300dd9168ff51a91cf38.zip |
Initial changes to merged AllApps/Customize pane in the Phone UI.
Change-Id: Ifa1676736033fe617dd0cca965156c38fa452948
Diffstat (limited to 'src/com/android/launcher2/AppsCustomizePagedView.java')
-rw-r--r-- | src/com/android/launcher2/AppsCustomizePagedView.java | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java new file mode 100644 index 000000000..6dc34ca1f --- /dev/null +++ b/src/com/android/launcher2/AppsCustomizePagedView.java @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2011 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.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.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Checkable; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.launcher.R; + +public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements + AllAppsView, View.OnClickListener, DragSource { + static final String LOG_TAG = "AppsCustomizePagedView"; + + /** + * The different content types that this paged view can show. + */ + public enum ContentType { + Applications, + Widgets + } + + // Refs + private Launcher mLauncher; + private DragController mDragController; + private final LayoutInflater mLayoutInflater; + private final PackageManager mPackageManager; + + // Content + private ContentType mContentType; + private ArrayList<ApplicationInfo> mApps; + private List<AppWidgetProviderInfo> mWidgets; + private List<ResolveInfo> mShortcuts; + + // Dimens + private int mContentWidth; + private float mWidgetScale; + private PagedViewCellLayout mWidgetSpacingLayout; + + public AppsCustomizePagedView(Context context, AttributeSet attrs) { + super(context, attrs); + mLayoutInflater = LayoutInflater.from(context); + mPackageManager = context.getPackageManager(); + mContentType = ContentType.Applications; + mApps = new ArrayList<ApplicationInfo>(); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, 0, 0); + mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6); + mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4); + a.recycle(); + + // Create a dummy page and set it up to find out the content width (used by our parent) + PagedViewCellLayout layout = new PagedViewCellLayout(context); + setupPage(layout); + mContentWidth = layout.getContentWidth(); + + // Create a dummy page that we can use to approximate the cell dimensions of widgets + mWidgetSpacingLayout = new PagedViewCellLayout(context); + mWidgetSpacingLayout.setCellCount(mCellCountX, mCellCountY); + } + + @Override + protected void init() { + super.init(); + mCenterPagesVertically = false; + + Context context = getContext(); + Resources r = context.getResources(); + setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f); + } + + public void onPackagesUpdated() { + // Get the list of widgets + mWidgets = AppWidgetManager.getInstance(mLauncher).getInstalledProviders(); + Collections.sort(mWidgets, LauncherModel.WIDGET_NAME_COMPARATOR); + + // Get the list of shortcuts + Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); + mShortcuts = mPackageManager.queryIntentActivities(shortcutsIntent, 0); + Collections.sort(mShortcuts, new LauncherModel.ShortcutNameComparator(mPackageManager)); + } + + @Override + public void onClick(View v) { + // Animate some feedback to the click + final ApplicationInfo appInfo = (ApplicationInfo) v.getTag(); + animateClickFeedback(v, new Runnable() { + @Override + public void run() { + mLauncher.startActivitySafely(appInfo.intent, appInfo); + } + }); + } + + /* + * PagedViewWithDraggableItems implementation + */ + @Override + protected void determineDraggingStart(android.view.MotionEvent ev) { + // Disable dragging by pulling an app down for now. + } + @Override + protected boolean beginDragging(View v) { + if (!super.beginDragging(v)) return false; + + // Make a copy of the ApplicationInfo + ApplicationInfo appInfo = new ApplicationInfo((ApplicationInfo) v.getTag()); + + // Show the uninstall button if the app is uninstallable. + if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) { + DeleteZone allAppsDeleteZone = (DeleteZone) + mLauncher.findViewById(R.id.all_apps_delete_zone); + allAppsDeleteZone.setDragAndDropEnabled(true); + + if ((appInfo.flags & ApplicationInfo.UPDATED_SYSTEM_APP_FLAG) != 0) { + allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps_system_app); + } else { + allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps); + } + } + + // Show the info button + ApplicationInfoDropTarget allAppsInfoButton = + (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target); + allAppsInfoButton.setDragAndDropEnabled(true); + + // Compose the drag image (top compound drawable, index is 1) + final TextView tv = (TextView) v; + final Drawable icon = tv.getCompoundDrawables()[1]; + Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), + Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + c.translate((v.getWidth() - icon.getIntrinsicWidth()) / 2, v.getPaddingTop()); + icon.draw(c); + + // Compose the visible rect of the drag image + Rect dragRect = null; + if (v instanceof TextView) { + int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size); + int top = v.getPaddingTop(); + int left = (b.getWidth() - iconSize) / 2; + int right = left + iconSize; + int bottom = top + iconSize; + dragRect = new Rect(left, top, right, bottom); + } + + // Start the drag + mLauncher.lockScreenOrientation(); + mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b); + mDragController.startDrag(v, b, this, appInfo, DragController.DRAG_ACTION_COPY, dragRect); + b.recycle(); + + // Hide the pane so that the user can drop onto the workspace + mLauncher.showWorkspace(true); + return true; + } + private void endDragging(boolean success) { + post(new Runnable() { + // Once the drag operation has fully completed, hence the post, we want to disable the + // deleteZone and the appInfoButton in all apps, and re-enable the instance which + // live in the workspace + public void run() { + // if onDestroy was called on Launcher, we might have already deleted the + // all apps delete zone / info button, so check if they are null + DeleteZone allAppsDeleteZone = + (DeleteZone) mLauncher.findViewById(R.id.all_apps_delete_zone); + ApplicationInfoDropTarget allAppsInfoButton = + (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target); + + if (allAppsDeleteZone != null) allAppsDeleteZone.setDragAndDropEnabled(false); + if (allAppsInfoButton != null) allAppsInfoButton.setDragAndDropEnabled(false); + } + }); + mLauncher.getWorkspace().onDragStopped(success); + mLauncher.unlockScreenOrientation(); + } + + /* + * DragSource implementation + */ + @Override + public void onDragViewVisible() {} + @Override + public void onDropCompleted(View target, Object dragInfo, boolean success) { + endDragging(success); + } + + public void setContentType(ContentType type) { + mContentType = type; + setCurrentPage(0); + invalidatePageData(); + } + + /* + * Apps PagedView implementation + */ + private void setupPage(PagedViewCellLayout layout) { + layout.setCellCount(mCellCountX, mCellCountY); + layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap); + layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, + mPageLayoutPaddingRight, mPageLayoutPaddingBottom); + + // We force a measure here to get around the fact that when we do layout calculations + // immediately after syncing, we don't have a proper width. + int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); + int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST); + layout.measure(widthSpec, heightSpec); + } + public void syncAppsPages() { + // Ensure that we have the right number of pages + Context context = getContext(); + int numPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY)); + for (int i = 0; i < numPages; ++i) { + PagedViewCellLayout layout = new PagedViewCellLayout(context); + setupPage(layout); + addView(layout); + } + } + public void syncAppsPageItems(int page) { + // ensure that we have the right number of items on the pages + int numPages = getPageCount(); + int numCells = mCellCountX * mCellCountY; + int startIndex = page * numCells; + int endIndex = Math.min(startIndex + numCells, mApps.size()); + PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page); + layout.removeAllViewsOnPage(); + for (int i = startIndex; i < endIndex; ++i) { + ApplicationInfo info = mApps.get(i); + PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( + R.layout.apps_customize_application, layout, false); + icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1)); + icon.setOnClickListener(this); + icon.setOnLongClickListener(this); + icon.setOnTouchListener(this); + + int index = i - startIndex; + int x = index % mCellCountX; + int y = index / mCellCountX; + setupPage(layout); + layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1)); + } + } + /* + * Widgets PagedView implementation + */ + private void setupPage(PagedViewExtendedLayout layout) { + layout.setGravity(Gravity.LEFT); + layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, + mPageLayoutPaddingRight, mPageLayoutPaddingBottom); + layout.setMinimumWidth(getPageContentWidth()); + } + private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h, + float scaleX, float scaleY) { + Canvas c = new Canvas(); + if (bitmap != null) c.setBitmap(bitmap); + c.save(); + c.scale(scaleX, scaleY); + Rect oldBounds = d.copyBounds(); + d.setBounds(x, y, x + w, y + h); + d.draw(c); + d.setBounds(oldBounds); // Restore the bounds + c.restore(); + } + private FastBitmapDrawable getWidgetPreview(AppWidgetProviderInfo info) { + // See CustomizePagedView.getWidgetPreview() + return null; + } + public void syncWidgetPages() { + // Ensure that we have the right number of pages + Context context = getContext(); + int numPages = mWidgets.size(); + for (int i = 0; i < numPages; ++i) { + PagedViewExtendedLayout layout = new PagedViewExtendedLayout(context); + setupPage(layout); + addView(layout); + } + } + public void syncWidgetPageItems(int page) { + PagedViewExtendedLayout layout = (PagedViewExtendedLayout) getChildAt(page); + layout.removeAllViewsOnPage(); + for (int i = 0; i < 1; ++i) { + AppWidgetProviderInfo info = (AppWidgetProviderInfo) mWidgets.get(page); + FastBitmapDrawable icon = getWidgetPreview(info); + + ImageView image = new ImageView(getContext()); + image.setBackgroundColor(0x99FF0000); + image.setImageDrawable(icon); + layout.addView(image, new PagedViewExtendedLayout.LayoutParams()); + } + } + @Override + public void syncPages() { + removeAllViews(); + switch (mContentType) { + case Applications: + syncAppsPages(); + break; + case Widgets: + syncWidgetPages(); + break; + } + } + @Override + public void syncPageItems(int page) { + switch (mContentType) { + case Applications: + syncAppsPageItems(page); + break; + case Widgets: + syncWidgetPageItems(page); + break; + } + } + + /** + * Used by the parent to get the content width to set the tab bar to + * @return + */ + public int getPageContentWidth() { + return mContentWidth; + } + + /* + * AllAppsView implementation + */ + @Override + public void setup(Launcher launcher, DragController dragController) { + mLauncher = launcher; + mDragController = dragController; + } + @Override + public void zoom(float zoom, boolean animate) { + // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed() + } + @Override + public boolean isVisible() { + return (getVisibility() == VISIBLE); + } + @Override + public boolean isAnimating() { + return false; + } + @Override + public void setApps(ArrayList<ApplicationInfo> list) { + mApps = list; + Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR); + invalidatePageData(); + } + 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); + int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR); + if (index < 0) { + mApps.add(-(index + 1), info); + } + } + } + @Override + public void addApps(ArrayList<ApplicationInfo> list) { + addAppsWithoutInvalidate(list); + invalidatePageData(); + } + private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) { + ComponentName removeComponent = item.intent.getComponent(); + int length = list.size(); + for (int i = 0; i < length; ++i) { + ApplicationInfo info = list.get(i); + if (info.intent.getComponent().equals(removeComponent)) { + return i; + } + } + return -1; + } + 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); + int removeIndex = findAppByComponent(mApps, info); + if (removeIndex > -1) { + mApps.remove(removeIndex); + mPageViewIconCache.removeOutline(new PagedViewIconCache.Key(info)); + } + } + } + @Override + public void removeApps(ArrayList<ApplicationInfo> list) { + removeAppsWithoutInvalidate(list); + invalidatePageData(); + } + @Override + public void updateApps(ArrayList<ApplicationInfo> list) { + // We remove and re-add the updated applications list because it's properties may have + // changed (ie. the title), and this will ensure that the items will be in their proper + // place in the list. + removeAppsWithoutInvalidate(list); + addAppsWithoutInvalidate(list); + invalidatePageData(); + } + @Override + public void reset() { + setCurrentPage(0); + invalidatePageData(); + } + @Override + public void dumpState() { + // TODO: Dump information related to current list of Applications, Widgets, etc. + ApplicationInfo.dumpApplicationInfoList(LOG_TAG, "mApps", mApps); + dumpAppWidgetProviderInfoList(LOG_TAG, "mWidgets", mWidgets); + } + private void dumpAppWidgetProviderInfoList(String tag, String label, + List<AppWidgetProviderInfo> list) { + Log.d(tag, label + " size=" + list.size()); + for (AppWidgetProviderInfo info: list) { + Log.d(tag, " label=\"" + info.label + "\" previewImage=" + info.previewImage + + " resizeMode=" + info.resizeMode + " configure=" + info.configure + + " initialLayout=" + info.initialLayout + + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight); + } + } + @Override + public void surrender() { + // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we + // should stop this now. + } +} |