80baf5a6b3
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
377 lines
12 KiB
Java
377 lines
12 KiB
Java
/*
|
|
* 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 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;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.util.AttributeSet;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.animation.AlphaAnimation;
|
|
import android.view.animation.Animation;
|
|
import android.view.animation.AnimationUtils;
|
|
import android.view.animation.Animation.AnimationListener;
|
|
import android.widget.TextView;
|
|
|
|
import com.android.launcher.R;
|
|
|
|
/**
|
|
* An implementation of PagedView that populates the pages of the workspace
|
|
* with all of the user's applications.
|
|
*/
|
|
public class AllAppsPagedView extends PagedView
|
|
implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource,
|
|
PagedViewCellLayout.DimmedBitmapSetupListener {
|
|
|
|
private static final String TAG = "AllAppsPagedView";
|
|
private static final boolean DEBUG = false;
|
|
|
|
private Launcher mLauncher;
|
|
private DragController mDragController;
|
|
|
|
// preserve compatibility with 3D all apps:
|
|
// 0.0 -> hidden
|
|
// 1.0 -> shown and opaque
|
|
// intermediate values -> partially shown & partially opaque
|
|
private float mZoom;
|
|
|
|
// set of all applications
|
|
private ArrayList<ApplicationInfo> mApps;
|
|
private ArrayList<ApplicationInfo> mFilteredApps;
|
|
|
|
// the types of applications to filter
|
|
static final int ALL_APPS_FLAG = -1;
|
|
private int mAppFilter = ALL_APPS_FLAG;
|
|
|
|
private int mCellCountX;
|
|
private int mCellCountY;
|
|
|
|
private final LayoutInflater mInflater;
|
|
|
|
public AllAppsPagedView(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public AllAppsPagedView(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, defStyle, 0);
|
|
mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
|
|
mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
|
|
mInflater = LayoutInflater.from(context);
|
|
a.recycle();
|
|
setSoundEffectsEnabled(false);
|
|
}
|
|
|
|
@Override
|
|
public void setLauncher(Launcher launcher) {
|
|
mLauncher = launcher;
|
|
}
|
|
|
|
@Override
|
|
public void setDragController(DragController dragger) {
|
|
mDragController = dragger;
|
|
}
|
|
|
|
public void setAppFilter(int filterType) {
|
|
mAppFilter = filterType;
|
|
if (mApps != null) {
|
|
mFilteredApps = rebuildFilteredApps(mApps);
|
|
setCurrentScreen(0);
|
|
invalidatePageData();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void zoom(float zoom, boolean animate) {
|
|
mZoom = zoom;
|
|
cancelLongPress();
|
|
|
|
if (isVisible()) {
|
|
getParent().bringChildToFront(this);
|
|
setVisibility(View.VISIBLE);
|
|
if (animate) {
|
|
startAnimation(AnimationUtils.loadAnimation(getContext(),
|
|
R.anim.all_apps_2d_fade_in));
|
|
} else {
|
|
onAnimationEnd();
|
|
}
|
|
} else {
|
|
if (animate) {
|
|
startAnimation(AnimationUtils.loadAnimation(getContext(),
|
|
R.anim.all_apps_2d_fade_out));
|
|
} else {
|
|
onAnimationEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void onAnimationEnd() {
|
|
if (!isVisible()) {
|
|
setVisibility(View.GONE);
|
|
mZoom = 0.0f;
|
|
} else {
|
|
mZoom = 1.0f;
|
|
}
|
|
|
|
if (mLauncher != null)
|
|
mLauncher.zoomed(mZoom);
|
|
}
|
|
|
|
private int getChildIndexForGrandChild(View v) {
|
|
final int childCount = getChildCount();
|
|
for (int i = 0; i < childCount; ++i) {
|
|
PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
|
|
if (layout.indexOfChild(v) > -1) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public void onClick(View v) {
|
|
int childIndex = getChildIndexForGrandChild(v);
|
|
if (childIndex == getCurrentScreen()) {
|
|
final ApplicationInfo app = (ApplicationInfo) v.getTag();
|
|
|
|
// animate some feedback to the click
|
|
animateClickFeedback(v, new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
mLauncher.startActivitySafely(app.intent, app);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onLongClick(View v) {
|
|
if (!v.isInTouchMode()) {
|
|
return false;
|
|
}
|
|
|
|
ApplicationInfo app = (ApplicationInfo) v.getTag();
|
|
app = new ApplicationInfo(app);
|
|
|
|
mDragController.startDrag(v, this, app, DragController.DRAG_ACTION_COPY);
|
|
mLauncher.closeAllApps(true);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void onDropCompleted(View target, boolean success) {
|
|
// do nothing
|
|
}
|
|
|
|
@Override
|
|
public boolean isVisible() {
|
|
return mZoom > 0.001f;
|
|
}
|
|
|
|
@Override
|
|
public boolean isAnimating() {
|
|
return (getAnimation() != null);
|
|
}
|
|
|
|
private ArrayList<ApplicationInfo> rebuildFilteredApps(ArrayList<ApplicationInfo> apps) {
|
|
ArrayList<ApplicationInfo> filteredApps = new ArrayList<ApplicationInfo>();
|
|
if (mAppFilter == ALL_APPS_FLAG) {
|
|
return apps;
|
|
} else {
|
|
final int length = apps.size();
|
|
for (int i = 0; i < length; ++i) {
|
|
ApplicationInfo info = apps.get(i);
|
|
if ((info.flags & mAppFilter) > 0) {
|
|
filteredApps.add(info);
|
|
}
|
|
}
|
|
}
|
|
return filteredApps;
|
|
}
|
|
|
|
@Override
|
|
public void setApps(ArrayList<ApplicationInfo> list) {
|
|
mApps = list;
|
|
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) {
|
|
addAppsWithoutInvalidate(list);
|
|
invalidatePageData();
|
|
}
|
|
|
|
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) {
|
|
int removeIndex = findAppByComponent(mApps, list.get(i));
|
|
if (removeIndex > -1) {
|
|
mApps.remove(removeIndex);
|
|
}
|
|
}
|
|
mFilteredApps = rebuildFilteredApps(mApps);
|
|
}
|
|
@Override
|
|
public void removeApps(ArrayList<ApplicationInfo> list) {
|
|
removeAppsWithoutInvalidate(list);
|
|
invalidatePageData();
|
|
}
|
|
|
|
@Override
|
|
public void updateApps(ArrayList<ApplicationInfo> list) {
|
|
removeAppsWithoutInvalidate(list);
|
|
addAppsWithoutInvalidate(list);
|
|
invalidatePageData();
|
|
}
|
|
|
|
private int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
|
|
ComponentName removeComponent = item.intent.getComponent();
|
|
final int length = list.size();
|
|
for (int i = 0; i < length; ++i) {
|
|
ApplicationInfo info = list.get(i);
|
|
if (info.intent.getComponent().equals(removeComponent)) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public void dumpState() {
|
|
ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
|
|
}
|
|
|
|
@Override
|
|
public void surrender() {
|
|
// do nothing?
|
|
}
|
|
|
|
@Override
|
|
public void syncPages() {
|
|
// ensure that we have the right number of pages
|
|
int numPages = (int) Math.ceil((float) mFilteredApps.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());
|
|
layout.setCellCount(mCellCountX, mCellCountY);
|
|
layout.setDimmedBitmapSetupListener(this);
|
|
addView(layout);
|
|
}
|
|
|
|
// bound the current page
|
|
setCurrentScreen(Math.max(0, Math.min(numPages - 1, getCurrentScreen())));
|
|
}
|
|
|
|
@Override
|
|
public void syncPageItems(int page) {
|
|
// ensure that we have the right number of items on the pages
|
|
final int cellsPerPage = mCellCountX * mCellCountY;
|
|
final int startIndex = page * cellsPerPage;
|
|
final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
|
|
PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
|
|
|
|
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);
|
|
|
|
PagedViewCellLayout.LayoutParams params =
|
|
(PagedViewCellLayout.LayoutParams) text.getLayoutParams();
|
|
params.cellX = index % mCellCountX;
|
|
params.cellY = index / mCellCountX;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPreUpdateDimmedBitmap(PagedViewCellLayout layout) {
|
|
// disable all children text for now
|
|
final int childCount = layout.getChildCount();
|
|
for (int i = 0; i < childCount; ++i) {
|
|
TextView text = (TextView) layout.getChildAt(i);
|
|
text.setText("");
|
|
}
|
|
}
|
|
@Override
|
|
public void onPostUpdateDimmedBitmap(PagedViewCellLayout layout) {
|
|
// re-enable all children text
|
|
final int childCount = layout.getChildCount();
|
|
for (int i = 0; i < childCount; ++i) {
|
|
TextView text = (TextView) layout.getChildAt(i);
|
|
final ApplicationInfo info = (ApplicationInfo) text.getTag();
|
|
text.setText(info.title);
|
|
}
|
|
}
|
|
}
|