Adding paging for the widget/shortcut/folder customization area and fixing bugs.

Adding pages for customization drawer with initial implementation of proposed flow
layout for widgets.  Fixes for keeping all apps, and widgets in sync with Launcher
Model, optimizations for reloading all apps pages when invalidating.  Adding some
animations for tab transitions and feedback when long pressing to add certain items.

Change-Id: I8d51749f3a91c964bed35681f3a9192200b0d93e
This commit is contained in:
Winson Chung 2010-08-09 16:03:15 -07:00
parent 321e9ee688
commit 80baf5a6b3
18 changed files with 1071 additions and 327 deletions

View File

@ -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" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 B

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -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" />

View File

@ -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" />

View File

@ -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" />

View File

@ -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" />

View File

@ -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>

View File

@ -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() {
// animate some feedback to the click
animateClickFeedback(v, new Runnable() {
@Override
public void onAnimationStart(Animation animation) {}
@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();
for (int i = startIndex; i < endIndex; ++i) {
ApplicationInfo info = mFilteredApps.get(i);
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) 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;
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
@ -2647,6 +2706,14 @@ public final class Launcher extends Activity
mAllAppsGrid.removeApps(apps);
}
/**
* A number of packages were updated.
*/
public void bindPackagesUpdated() {
// update the customization drawer contents
mCustomizePagedView.update();
}
/**
* Prints out out state for debugging.
*/

View File

@ -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();
}
}
});
}
}

View File

@ -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();
}

View File

@ -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 + ")";
}
}
}

View File

@ -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;
}
}

View File

@ -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) {
}
}