summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/anim/paged_view_click_feedback.xml23
-rw-r--r--res/drawable/default_widget_preview.9.pngbin541 -> 3976 bytes
-rw-r--r--res/layout-xlarge/all_apps_paged_view_application.xml3
-rw-r--r--res/layout-xlarge/customize_paged_view_item.xml30
-rw-r--r--res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml32
-rw-r--r--res/layout-xlarge/customize_paged_view_widget.xml30
-rw-r--r--res/layout-xlarge/launcher.xml30
-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
18 files changed, 1070 insertions, 326 deletions
diff --git a/res/anim/paged_view_click_feedback.xml b/res/anim/paged_view_click_feedback.xml
new file mode 100644
index 000000000..786d9744a
--- /dev/null
+++ b/res/anim/paged_view_click_feedback.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.65"
+ android:duration="100"
+ android:fillAfter="true"
+ android:repeatCount="1"
+ android:repeatMode="reverse" />
diff --git a/res/drawable/default_widget_preview.9.png b/res/drawable/default_widget_preview.9.png
index e966b1b79..b3ddada41 100644
--- a/res/drawable/default_widget_preview.9.png
+++ b/res/drawable/default_widget_preview.9.png
Binary files differ
diff --git a/res/layout-xlarge/all_apps_paged_view_application.xml b/res/layout-xlarge/all_apps_paged_view_application.xml
index 98c27377d..74487656c 100644
--- a/res/layout-xlarge/all_apps_paged_view_application.xml
+++ b/res/layout-xlarge/all_apps_paged_view_application.xml
@@ -18,12 +18,13 @@
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
android:textColor="#FFFFFFFF"
android:shadowColor="#FF000000"
android:shadowDx="0.0"
android:shadowDy="1.0"
+ android:shadowRadius="1.0"
android:maxLines="2"
android:fadingEdge="horizontal" />
diff --git a/res/layout-xlarge/customize_paged_view_item.xml b/res/layout-xlarge/customize_paged_view_item.xml
new file mode 100644
index 000000000..74487656c
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+
+ android:textColor="#FFFFFFFF"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml b/res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml
new file mode 100644
index 000000000..df73bcdc7
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_wallpaper_placeholder.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+
+ android:textColor="#FFFFFFFF"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+ android:drawableLeft="@drawable/ic_launcher_wallpaper"
+ android:drawablePadding="10dip"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
diff --git a/res/layout-xlarge/customize_paged_view_widget.xml b/res/layout-xlarge/customize_paged_view_widget.xml
new file mode 100644
index 000000000..74487656c
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_widget.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+
+ android:textColor="#FFFFFFFF"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
diff --git a/res/layout-xlarge/launcher.xml b/res/layout-xlarge/launcher.xml
index a1879efa6..3e00381d8 100644
--- a/res/layout-xlarge/launcher.xml
+++ b/res/layout-xlarge/launcher.xml
@@ -26,7 +26,7 @@
layout="@layout/all_apps_tabbed"
android:id="@+id/all_apps_view"
android:layout_width="match_parent"
- android:layout_height="500dip"
+ android:layout_height="550dip"
android:layout_gravity="top"/>
<!-- The workspace contains 5 screens of cells -->
@@ -112,38 +112,24 @@
<TabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
- android:layout_height="500dip"
+ android:layout_height="550dip"
android:layout_gravity="bottom">
<LinearLayout
android:orientation="vertical"
+ android:background="#40000000"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:tabStripEnabled="false"
+ android:paddingBottom="10dp" />
<FrameLayout
android:id="@android:id/tabcontent"
- android:background="#ff000000"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.android.launcher2.WidgetChooser
- android:id="@+id/widget_chooser"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.launcher2.FolderChooser
- android:id="@+id/folder_chooser"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.launcher2.ShortcutChooser
- android:id="@+id/shortcut_chooser"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <TextView
- android:id="@+id/wallpaperstab"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/wallpapers_temp_tab_text" />
</FrameLayout>
</LinearLayout>
</TabHost>
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) {
- }
-}
-