summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher2/AppsCustomizePagedView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher2/AppsCustomizePagedView.java')
-rw-r--r--src/com/android/launcher2/AppsCustomizePagedView.java465
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.
+ }
+}