summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorChirayu Desai <chirayudesai1@gmail.com>2012-08-02 12:23:05 +0530
committerChirayu Desai <chirayudesai1@gmail.com>2012-08-02 12:32:27 +0530
commit4ca067e55ce5c0e756bce8cb11496589b8ab3ea0 (patch)
tree720e310c94e1f32cc50893461147e6eb18c4ae6d /src/com/android
parent262635a1a417326a4db253e0f06b9056670a8d33 (diff)
downloadandroid_packages_apps_Trebuchet-4ca067e55ce5c0e756bce8cb11496589b8ab3ea0.tar.gz
android_packages_apps_Trebuchet-4ca067e55ce5c0e756bce8cb11496589b8ab3ea0.tar.bz2
android_packages_apps_Trebuchet-4ca067e55ce5c0e756bce8cb11496589b8ab3ea0.zip
Rename Launcher to Trebuchet
Launcher2 is now Trebuchet application_name removed from localized strings and made un-translatable com.android.launcher is now com.cyanogenmod.trebuchet
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/launcher2/AccessibleTabView.java51
-rw-r--r--src/com/android/launcher2/AddAdapter.java103
-rw-r--r--src/com/android/launcher2/Alarm.java84
-rw-r--r--src/com/android/launcher2/AllAppsList.java221
-rw-r--r--src/com/android/launcher2/AllAppsView.java48
-rw-r--r--src/com/android/launcher2/AppWidgetResizeFrame.java429
-rw-r--r--src/com/android/launcher2/ApplicationInfo.java144
-rw-r--r--src/com/android/launcher2/AppsCustomizePagedView.java1899
-rw-r--r--src/com/android/launcher2/AppsCustomizeTabHost.java488
-rw-r--r--src/com/android/launcher2/BubbleTextView.java334
-rw-r--r--src/com/android/launcher2/ButtonDropTarget.java147
-rw-r--r--src/com/android/launcher2/CellLayout.java3022
-rw-r--r--src/com/android/launcher2/CheckLongPressHelper.java62
-rw-r--r--src/com/android/launcher2/Cling.java278
-rw-r--r--src/com/android/launcher2/DeferredHandler.java112
-rw-r--r--src/com/android/launcher2/DeleteDropTarget.java438
-rw-r--r--src/com/android/launcher2/DragController.java809
-rw-r--r--src/com/android/launcher2/DragLayer.java766
-rw-r--r--src/com/android/launcher2/DragScroller.java40
-rw-r--r--src/com/android/launcher2/DragSource.java45
-rw-r--r--src/com/android/launcher2/DragView.java292
-rw-r--r--src/com/android/launcher2/DrawableStateProxyView.java69
-rw-r--r--src/com/android/launcher2/DropTarget.java184
-rw-r--r--src/com/android/launcher2/FastBitmapDrawable.java108
-rw-r--r--src/com/android/launcher2/FocusHelper.java898
-rw-r--r--src/com/android/launcher2/FocusOnlyTabWidget.java86
-rw-r--r--src/com/android/launcher2/Folder.java1105
-rw-r--r--src/com/android/launcher2/FolderEditText.java36
-rw-r--r--src/com/android/launcher2/FolderIcon.java631
-rw-r--r--src/com/android/launcher2/FolderInfo.java116
-rw-r--r--src/com/android/launcher2/HandleView.java76
-rw-r--r--src/com/android/launcher2/HolographicImageView.java54
-rw-r--r--src/com/android/launcher2/HolographicLinearLayout.java85
-rw-r--r--src/com/android/launcher2/HolographicOutlineHelper.java218
-rw-r--r--src/com/android/launcher2/HolographicViewHelper.java84
-rw-r--r--src/com/android/launcher2/Hotseat.java137
-rw-r--r--src/com/android/launcher2/IconCache.java229
-rw-r--r--src/com/android/launcher2/InfoDropTarget.java127
-rw-r--r--src/com/android/launcher2/InstallShortcutReceiver.java252
-rw-r--r--src/com/android/launcher2/InstallWidgetReceiver.java195
-rw-r--r--src/com/android/launcher2/InterruptibleInOutAnimator.java130
-rw-r--r--src/com/android/launcher2/ItemInfo.java188
-rw-r--r--src/com/android/launcher2/Launcher.java3710
-rw-r--r--src/com/android/launcher2/LauncherAnimatorUpdateListener.java30
-rw-r--r--src/com/android/launcher2/LauncherAppWidgetHost.java45
-rw-r--r--src/com/android/launcher2/LauncherAppWidgetHostView.java104
-rw-r--r--src/com/android/launcher2/LauncherAppWidgetInfo.java98
-rw-r--r--src/com/android/launcher2/LauncherApplication.java145
-rw-r--r--src/com/android/launcher2/LauncherModel.java2176
-rw-r--r--src/com/android/launcher2/LauncherProvider.java1178
-rw-r--r--src/com/android/launcher2/LauncherSettings.java236
-rw-r--r--src/com/android/launcher2/LauncherViewPropertyAnimator.java255
-rw-r--r--src/com/android/launcher2/PagedView.java1913
-rw-r--r--src/com/android/launcher2/PagedViewCellLayout.java516
-rw-r--r--src/com/android/launcher2/PagedViewCellLayoutChildren.java160
-rw-r--r--src/com/android/launcher2/PagedViewGridLayout.java141
-rw-r--r--src/com/android/launcher2/PagedViewIcon.java92
-rw-r--r--src/com/android/launcher2/PagedViewIconCache.java133
-rw-r--r--src/com/android/launcher2/PagedViewWidget.java223
-rw-r--r--src/com/android/launcher2/PagedViewWidgetImageView.java57
-rw-r--r--src/com/android/launcher2/PagedViewWithDraggableItems.java178
-rw-r--r--src/com/android/launcher2/PendingAddItemInfo.java104
-rw-r--r--src/com/android/launcher2/PreloadReceiver.java37
-rw-r--r--src/com/android/launcher2/RocketLauncher.java417
-rw-r--r--src/com/android/launcher2/SearchDropTargetBar.java242
-rw-r--r--src/com/android/launcher2/ShortcutAndWidgetContainer.java188
-rw-r--r--src/com/android/launcher2/ShortcutInfo.java173
-rw-r--r--src/com/android/launcher2/SmoothPagedView.java188
-rw-r--r--src/com/android/launcher2/SpringLoadedDragController.java62
-rw-r--r--src/com/android/launcher2/StrokedTextView.java138
-rw-r--r--src/com/android/launcher2/SymmetricalLinearTween.java118
-rw-r--r--src/com/android/launcher2/TweenCallback.java24
-rw-r--r--src/com/android/launcher2/UninstallShortcutReceiver.java166
-rw-r--r--src/com/android/launcher2/Utilities.java278
-rw-r--r--src/com/android/launcher2/WallpaperChooser.java47
-rw-r--r--src/com/android/launcher2/WallpaperChooserDialogFragment.java360
-rw-r--r--src/com/android/launcher2/Workspace.java3781
77 files changed, 0 insertions, 32533 deletions
diff --git a/src/com/android/launcher2/AccessibleTabView.java b/src/com/android/launcher2/AccessibleTabView.java
deleted file mode 100644
index 101f139e7..000000000
--- a/src/com/android/launcher2/AccessibleTabView.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.TextView;
-
-/**
- * We use a custom tab view to process our own focus traversals.
- */
-public class AccessibleTabView extends TextView {
- public AccessibleTabView(Context context) {
- super(context);
- }
-
- public AccessibleTabView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public AccessibleTabView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return FocusHelper.handleTabKeyEvent(this, keyCode, event)
- || super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return FocusHelper.handleTabKeyEvent(this, keyCode, event)
- || super.onKeyUp(keyCode, event);
- }
-}
diff --git a/src/com/android/launcher2/AddAdapter.java b/src/com/android/launcher2/AddAdapter.java
deleted file mode 100644
index c2a424b00..000000000
--- a/src/com/android/launcher2/AddAdapter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-import com.android.launcher.R;
-
-/**
- * Adapter showing the types of items that can be added to a {@link Workspace}.
- */
-public class AddAdapter extends BaseAdapter {
-
- private final LayoutInflater mInflater;
-
- private final ArrayList<ListItem> mItems = new ArrayList<ListItem>();
-
- public static final int ITEM_SHORTCUT = 0;
- public static final int ITEM_APPWIDGET = 1;
- public static final int ITEM_APPLICATION = 2;
- public static final int ITEM_WALLPAPER = 3;
-
- /**
- * Specific item in our list.
- */
- public class ListItem {
- public final CharSequence text;
- public final Drawable image;
- public final int actionTag;
-
- public ListItem(Resources res, int textResourceId, int imageResourceId, int actionTag) {
- text = res.getString(textResourceId);
- if (imageResourceId != -1) {
- image = res.getDrawable(imageResourceId);
- } else {
- image = null;
- }
- this.actionTag = actionTag;
- }
- }
-
- public AddAdapter(Launcher launcher) {
- super();
-
- mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- // Create default actions
- Resources res = launcher.getResources();
-
- mItems.add(new ListItem(res, R.string.group_wallpapers,
- R.drawable.ic_launcher_wallpaper, ITEM_WALLPAPER));
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- ListItem item = (ListItem) getItem(position);
-
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.add_list_item, parent, false);
- }
-
- TextView textView = (TextView) convertView;
- textView.setTag(item);
- textView.setText(item.text);
- textView.setCompoundDrawablesWithIntrinsicBounds(item.image, null, null, null);
-
- return convertView;
- }
-
- public int getCount() {
- return mItems.size();
- }
-
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-}
diff --git a/src/com/android/launcher2/Alarm.java b/src/com/android/launcher2/Alarm.java
deleted file mode 100644
index 7cd21c327..000000000
--- a/src/com/android/launcher2/Alarm.java
+++ /dev/null
@@ -1,84 +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.os.Handler;
-
-public class Alarm implements Runnable{
- // if we reach this time and the alarm hasn't been cancelled, call the listener
- private long mAlarmTriggerTime;
-
- // if we've scheduled a call to run() (ie called mHandler.postDelayed), this variable is true.
- // We use this to avoid having multiple pending callbacks
- private boolean mWaitingForCallback;
-
- private Handler mHandler;
- private OnAlarmListener mAlarmListener;
- private boolean mAlarmPending = false;
-
- public Alarm() {
- mHandler = new Handler();
- }
-
- public void setOnAlarmListener(OnAlarmListener alarmListener) {
- mAlarmListener = alarmListener;
- }
-
- // Sets the alarm to go off in a certain number of milliseconds. If the alarm is already set,
- // it's overwritten and only the new alarm setting is used
- public void setAlarm(long millisecondsInFuture) {
- long currentTime = System.currentTimeMillis();
- mAlarmPending = true;
- mAlarmTriggerTime = currentTime + millisecondsInFuture;
- if (!mWaitingForCallback) {
- mHandler.postDelayed(this, mAlarmTriggerTime - currentTime);
- mWaitingForCallback = true;
- }
- }
-
- public void cancelAlarm() {
- mAlarmTriggerTime = 0;
- mAlarmPending = false;
- }
-
- // this is called when our timer runs out
- public void run() {
- mWaitingForCallback = false;
- if (mAlarmTriggerTime != 0) {
- long currentTime = System.currentTimeMillis();
- if (mAlarmTriggerTime > currentTime) {
- // We still need to wait some time to trigger spring loaded mode--
- // post a new callback
- mHandler.postDelayed(this, Math.max(0, mAlarmTriggerTime - currentTime));
- mWaitingForCallback = true;
- } else {
- mAlarmPending = false;
- if (mAlarmListener != null) {
- mAlarmListener.onAlarm(this);
- }
- }
- }
- }
-
- public boolean alarmPending() {
- return mAlarmPending;
- }
-}
-
-interface OnAlarmListener {
- public void onAlarm(Alarm alarm);
-}
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
deleted file mode 100644
index 051b0bd1d..000000000
--- a/src/com/android/launcher2/AllAppsList.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2008 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.List;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-
-
-/**
- * Stores the list of all applications for the all apps view.
- */
-class AllAppsList {
- public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
-
- /** The list off all apps. */
- public ArrayList<ApplicationInfo> data =
- new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
- /** The list of apps that have been added since the last notify() call. */
- public ArrayList<ApplicationInfo> added =
- new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
- /** The list of apps that have been removed since the last notify() call. */
- public ArrayList<ApplicationInfo> removed = new ArrayList<ApplicationInfo>();
- /** The list of apps that have been modified since the last notify() call. */
- public ArrayList<ApplicationInfo> modified = new ArrayList<ApplicationInfo>();
-
- private IconCache mIconCache;
-
- /**
- * Boring constructor.
- */
- public AllAppsList(IconCache iconCache) {
- mIconCache = iconCache;
- }
-
- /**
- * Add the supplied ApplicationInfo objects to the list, and enqueue it into the
- * list to broadcast when notify() is called.
- *
- * If the app is already in the list, doesn't add it.
- */
- public void add(ApplicationInfo info) {
- if (findActivity(data, info.componentName)) {
- return;
- }
- data.add(info);
- added.add(info);
- }
-
- public void clear() {
- data.clear();
- // TODO: do we clear these too?
- added.clear();
- removed.clear();
- modified.clear();
- }
-
- public int size() {
- return data.size();
- }
-
- public ApplicationInfo get(int index) {
- return data.get(index);
- }
-
- /**
- * Add the icons for the supplied apk called packageName.
- */
- public void addPackage(Context context, String packageName) {
- final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
-
- if (matches.size() > 0) {
- for (ResolveInfo info : matches) {
- add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null));
- }
- }
- }
-
- /**
- * Remove the apps for the given apk identified by packageName.
- */
- public void removePackage(String packageName) {
- final List<ApplicationInfo> data = this.data;
- for (int i = data.size() - 1; i >= 0; i--) {
- ApplicationInfo info = data.get(i);
- final ComponentName component = info.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
- removed.add(info);
- data.remove(i);
- }
- }
- // This is more aggressive than it needs to be.
- mIconCache.flush();
- }
-
- /**
- * Add and remove icons for this package which has been updated.
- */
- public void updatePackage(Context context, String packageName) {
- final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
- if (matches.size() > 0) {
- // Find disabled/removed activities and remove them from data and add them
- // to the removed list.
- for (int i = data.size() - 1; i >= 0; i--) {
- final ApplicationInfo applicationInfo = data.get(i);
- final ComponentName component = applicationInfo.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
- if (!findActivity(matches, component)) {
- removed.add(applicationInfo);
- mIconCache.remove(component);
- data.remove(i);
- }
- }
- }
-
- // Find enabled activities and add them to the adapter
- // Also updates existing activities with new labels/icons
- int count = matches.size();
- for (int i = 0; i < count; i++) {
- final ResolveInfo info = matches.get(i);
- ApplicationInfo applicationInfo = findApplicationInfoLocked(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- if (applicationInfo == null) {
- add(new ApplicationInfo(context.getPackageManager(), info, mIconCache, null));
- } else {
- mIconCache.remove(applicationInfo.componentName);
- mIconCache.getTitleAndIcon(applicationInfo, info, null);
- modified.add(applicationInfo);
- }
- }
- } else {
- // Remove all data for this package.
- for (int i = data.size() - 1; i >= 0; i--) {
- final ApplicationInfo applicationInfo = data.get(i);
- final ComponentName component = applicationInfo.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
- removed.add(applicationInfo);
- mIconCache.remove(component);
- data.remove(i);
- }
- }
- }
- }
-
- /**
- * Query the package manager for MAIN/LAUNCHER activities in the supplied package.
- */
- private static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
- final PackageManager packageManager = context.getPackageManager();
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- mainIntent.setPackage(packageName);
-
- final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- return apps != null ? apps : new ArrayList<ResolveInfo>();
- }
-
- /**
- * Returns whether <em>apps</em> contains <em>component</em>.
- */
- private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) {
- final String className = component.getClassName();
- for (ResolveInfo info : apps) {
- final ActivityInfo activityInfo = info.activityInfo;
- if (activityInfo.name.equals(className)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether <em>apps</em> contains <em>component</em>.
- */
- private static boolean findActivity(ArrayList<ApplicationInfo> apps, ComponentName component) {
- final int N = apps.size();
- for (int i=0; i<N; i++) {
- final ApplicationInfo info = apps.get(i);
- if (info.componentName.equals(component)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Find an ApplicationInfo object for the given packageName and className.
- */
- private ApplicationInfo findApplicationInfoLocked(String packageName, String className) {
- for (ApplicationInfo info: data) {
- final ComponentName component = info.intent.getComponent();
- if (packageName.equals(component.getPackageName())
- && className.equals(component.getClassName())) {
- return info;
- }
- }
- return null;
- }
-}
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
deleted file mode 100644
index e8ca61fb3..000000000
--- a/src/com/android/launcher2/AllAppsView.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-public interface AllAppsView {
- public interface Watcher {
- public void zoomed(float zoom);
- }
-
- public void setup(Launcher launcher, DragController dragController);
-
- public void zoom(float zoom, boolean animate);
-
- public boolean isVisible();
-
- public boolean isAnimating();
-
- public void setApps(ArrayList<ApplicationInfo> list);
-
- public void addApps(ArrayList<ApplicationInfo> list);
-
- public void removeApps(ArrayList<ApplicationInfo> list);
-
- public void updateApps(ArrayList<ApplicationInfo> list);
-
- // Resets the AllApps page to the front
- public void reset();
-
- public void dumpState();
-
- public void surrender();
-}
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
deleted file mode 100644
index 882468624..000000000
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ /dev/null
@@ -1,429 +0,0 @@
-package com.android.launcher2;
-
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.graphics.Rect;
-import android.view.Gravity;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.launcher.R;
-
-public class AppWidgetResizeFrame extends FrameLayout {
- private LauncherAppWidgetHostView mWidgetView;
- private CellLayout mCellLayout;
- private DragLayer mDragLayer;
- private Workspace mWorkspace;
- private ImageView mLeftHandle;
- private ImageView mRightHandle;
- private ImageView mTopHandle;
- private ImageView mBottomHandle;
-
- private boolean mLeftBorderActive;
- private boolean mRightBorderActive;
- private boolean mTopBorderActive;
- private boolean mBottomBorderActive;
-
- private int mWidgetPaddingLeft;
- private int mWidgetPaddingRight;
- private int mWidgetPaddingTop;
- private int mWidgetPaddingBottom;
-
- private int mBaselineWidth;
- private int mBaselineHeight;
- private int mBaselineX;
- private int mBaselineY;
- private int mResizeMode;
-
- private int mRunningHInc;
- private int mRunningVInc;
- private int mMinHSpan;
- private int mMinVSpan;
- private int mDeltaX;
- private int mDeltaY;
- private int mDeltaXAddOn;
- private int mDeltaYAddOn;
-
- private int mBackgroundPadding;
- private int mTouchTargetWidth;
-
- int[] mDirectionVector = new int[2];
-
- final int SNAP_DURATION = 150;
- final int BACKGROUND_PADDING = 24;
- final float DIMMED_HANDLE_ALPHA = 0f;
- final float RESIZE_THRESHOLD = 0.66f;
-
- public static final int LEFT = 0;
- public static final int TOP = 1;
- public static final int RIGHT = 2;
- public static final int BOTTOM = 3;
-
- private Launcher mLauncher;
-
- public AppWidgetResizeFrame(Context context,
- LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
-
- super(context);
- mLauncher = (Launcher) context;
- mCellLayout = cellLayout;
- mWidgetView = widgetView;
- mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
- mDragLayer = dragLayer;
- mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
-
- final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
- int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
- mMinHSpan = result[0];
- mMinVSpan = result[1];
-
- setBackgroundResource(R.drawable.widget_resize_frame_holo);
- setPadding(0, 0, 0, 0);
-
- LayoutParams lp;
- mLeftHandle = new ImageView(context);
- mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
- Gravity.LEFT | Gravity.CENTER_VERTICAL);
- addView(mLeftHandle, lp);
-
- mRightHandle = new ImageView(context);
- mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
- Gravity.RIGHT | Gravity.CENTER_VERTICAL);
- addView(mRightHandle, lp);
-
- mTopHandle = new ImageView(context);
- mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_HORIZONTAL | Gravity.TOP);
- addView(mTopHandle, lp);
-
- mBottomHandle = new ImageView(context);
- mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
- addView(mBottomHandle, lp);
-
- Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
- widgetView.getAppWidgetInfo().provider, null);
- mWidgetPaddingLeft = p.left;
- mWidgetPaddingTop = p.top;
- mWidgetPaddingRight = p.right;
- mWidgetPaddingBottom = p.bottom;
-
- if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
- mTopHandle.setVisibility(GONE);
- mBottomHandle.setVisibility(GONE);
- } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
- mLeftHandle.setVisibility(GONE);
- mRightHandle.setVisibility(GONE);
- }
-
- final float density = mLauncher.getResources().getDisplayMetrics().density;
- mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
- mTouchTargetWidth = 2 * mBackgroundPadding;
-
- // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
- // cells (same if not resized, or different) will be marked as occupied when the resize
- // frame is dismissed.
- mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
- }
-
- public boolean beginResizeIfPointInRegion(int x, int y) {
- boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
- boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
- mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
- mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
- mTopBorderActive = (y < mTouchTargetWidth) && verticalActive;
- mBottomBorderActive = (y > getHeight() - mTouchTargetWidth) && verticalActive;
-
- boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
- || mTopBorderActive || mBottomBorderActive;
-
- mBaselineWidth = getMeasuredWidth();
- mBaselineHeight = getMeasuredHeight();
- mBaselineX = getLeft();
- mBaselineY = getTop();
-
- if (anyBordersActive) {
- mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
- mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
- mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
- mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
- }
- return anyBordersActive;
- }
-
- /**
- * Here we bound the deltas such that the frame cannot be stretched beyond the extents
- * of the CellLayout, and such that the frame's borders can't cross.
- */
- public void updateDeltas(int deltaX, int deltaY) {
- if (mLeftBorderActive) {
- mDeltaX = Math.max(-mBaselineX, deltaX);
- mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
- } else if (mRightBorderActive) {
- mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
- mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
- }
-
- if (mTopBorderActive) {
- mDeltaY = Math.max(-mBaselineY, deltaY);
- mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
- } else if (mBottomBorderActive) {
- mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
- mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
- }
- }
-
- public void visualizeResizeForDelta(int deltaX, int deltaY) {
- visualizeResizeForDelta(deltaX, deltaY, false);
- }
-
- /**
- * Based on the deltas, we resize the frame, and, if needed, we resize the widget.
- */
- private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) {
- updateDeltas(deltaX, deltaY);
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-
- if (mLeftBorderActive) {
- lp.x = mBaselineX + mDeltaX;
- lp.width = mBaselineWidth - mDeltaX;
- } else if (mRightBorderActive) {
- lp.width = mBaselineWidth + mDeltaX;
- }
-
- if (mTopBorderActive) {
- lp.y = mBaselineY + mDeltaY;
- lp.height = mBaselineHeight - mDeltaY;
- } else if (mBottomBorderActive) {
- lp.height = mBaselineHeight + mDeltaY;
- }
-
- resizeWidgetIfNeeded(onDismiss);
- requestLayout();
- }
-
- /**
- * Based on the current deltas, we determine if and how to resize the widget.
- */
- private void resizeWidgetIfNeeded(boolean onDismiss) {
- int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
- int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
-
- int deltaX = mDeltaX + mDeltaXAddOn;
- int deltaY = mDeltaY + mDeltaYAddOn;
-
- float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc;
- float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc;
-
- int hSpanInc = 0;
- int vSpanInc = 0;
- int cellXInc = 0;
- int cellYInc = 0;
-
- int countX = mCellLayout.getCountX();
- int countY = mCellLayout.getCountY();
-
- if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
- hSpanInc = Math.round(hSpanIncF);
- }
- if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
- vSpanInc = Math.round(vSpanIncF);
- }
-
- if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return;
-
-
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
-
- int spanX = lp.cellHSpan;
- int spanY = lp.cellVSpan;
- int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX;
- int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY;
-
- int hSpanDelta = 0;
- int vSpanDelta = 0;
-
- // For each border, we bound the resizing based on the minimum width, and the maximum
- // expandability.
- if (mLeftBorderActive) {
- cellXInc = Math.max(-cellX, hSpanInc);
- cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
- hSpanInc *= -1;
- hSpanInc = Math.min(cellX, hSpanInc);
- hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
- hSpanDelta = -hSpanInc;
-
- } else if (mRightBorderActive) {
- hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc);
- hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
- hSpanDelta = hSpanInc;
- }
-
- if (mTopBorderActive) {
- cellYInc = Math.max(-cellY, vSpanInc);
- cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
- vSpanInc *= -1;
- vSpanInc = Math.min(cellY, vSpanInc);
- vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
- vSpanDelta = -vSpanInc;
- } else if (mBottomBorderActive) {
- vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc);
- vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
- vSpanDelta = vSpanInc;
- }
-
- mDirectionVector[0] = 0;
- mDirectionVector[1] = 0;
- // Update the widget's dimensions and position according to the deltas computed above
- if (mLeftBorderActive || mRightBorderActive) {
- spanX += hSpanInc;
- cellX += cellXInc;
- mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
- }
-
- if (mTopBorderActive || mBottomBorderActive) {
- spanY += vSpanInc;
- cellY += cellYInc;
- mDirectionVector[1] = mTopBorderActive ? -1 : 1;
- }
-
- if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
-
- if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
- mDirectionVector, onDismiss)) {
- lp.tmpCellX = cellX;
- lp.tmpCellY = cellY;
- lp.cellHSpan = spanX;
- lp.cellVSpan = spanY;
- mRunningVInc += vSpanDelta;
- mRunningHInc += hSpanDelta;
- if (!onDismiss) {
- updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
- }
- }
- mWidgetView.requestLayout();
- }
-
- static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
- int spanX, int spanY) {
- Rect landMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.LANDSCAPE);
- Rect portMetrics = Workspace.getCellLayoutMetrics(launcher, CellLayout.PORTRAIT);
- final float density = launcher.getResources().getDisplayMetrics().density;
-
- // Compute landscape size
- int cellWidth = landMetrics.left;
- int cellHeight = landMetrics.top;
- int widthGap = landMetrics.right;
- int heightGap = landMetrics.bottom;
- int landWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
- int landHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
-
- // Compute portrait size
- cellWidth = portMetrics.left;
- cellHeight = portMetrics.top;
- widthGap = portMetrics.right;
- heightGap = portMetrics.bottom;
- int portWidth = (int) ((spanX * cellWidth + (spanX - 1) * widthGap) / density);
- int portHeight = (int) ((spanY * cellHeight + (spanY - 1) * heightGap) / density);
-
- widgetView.updateAppWidgetSize(null, portWidth, landHeight, landWidth, portHeight);
- }
-
- /**
- * This is the final step of the resize. Here we save the new widget size and position
- * to LauncherModel and animate the resize frame.
- */
- public void commitResize() {
- resizeWidgetIfNeeded(true);
- requestLayout();
- }
-
- public void onTouchUp() {
- int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
- int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
-
- mDeltaXAddOn = mRunningHInc * xThreshold;
- mDeltaYAddOn = mRunningVInc * yThreshold;
- mDeltaX = 0;
- mDeltaY = 0;
-
- post(new Runnable() {
- @Override
- public void run() {
- snapToWidget(true);
- }
- });
- }
-
- public void snapToWidget(boolean animate) {
- final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- int xOffset = mCellLayout.getLeft() + mCellLayout.getPaddingLeft() - mWorkspace.getScrollX();
- int yOffset = mCellLayout.getTop() + mCellLayout.getPaddingTop() - mWorkspace.getScrollY();
-
- int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
- mWidgetPaddingRight;
- int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
- mWidgetPaddingBottom;
-
- int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset + mWidgetPaddingLeft;
- int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset + mWidgetPaddingTop;
-
- // We need to make sure the frame stays within the bounds of the CellLayout
- if (newY < 0) {
- newHeight -= -newY;
- newY = 0;
- }
- if (newY + newHeight > mDragLayer.getHeight()) {
- newHeight -= newY + newHeight - mDragLayer.getHeight();
- }
-
- if (!animate) {
- lp.width = newWidth;
- lp.height = newHeight;
- lp.x = newX;
- lp.y = newY;
- mLeftHandle.setAlpha(1.0f);
- mRightHandle.setAlpha(1.0f);
- mTopHandle.setAlpha(1.0f);
- mBottomHandle.setAlpha(1.0f);
- requestLayout();
- } else {
- PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
- PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
- newHeight);
- PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
- PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
- ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
- ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f);
- ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f);
- ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f);
- ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f);
- oa.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- requestLayout();
- }
- });
- AnimatorSet set = new AnimatorSet();
- if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
- set.playTogether(oa, topOa, bottomOa);
- } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
- set.playTogether(oa, leftOa, rightOa);
- } else {
- set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
- }
-
- set.setDuration(SNAP_DURATION);
- set.start();
- }
- }
-}
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
deleted file mode 100644
index 281d59c68..000000000
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2008 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.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.graphics.Bitmap;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Represents an app in AllAppsView.
- */
-class ApplicationInfo extends ItemInfo {
- private static final String TAG = "Launcher2.ApplicationInfo";
-
- /**
- * The application name.
- */
- CharSequence title;
-
- /**
- * The intent used to start the application.
- */
- Intent intent;
-
- /**
- * A bitmap version of the application icon.
- */
- Bitmap iconBitmap;
-
- /**
- * The time at which the app was first installed.
- */
- long firstInstallTime;
-
- ComponentName componentName;
-
- static final int DOWNLOADED_FLAG = 1;
- static final int UPDATED_SYSTEM_APP_FLAG = 2;
-
- int flags = 0;
-
- ApplicationInfo() {
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
- }
-
- /**
- * Must not hold the Context.
- */
- public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,
- HashMap<Object, CharSequence> labelCache) {
- final String packageName = info.activityInfo.applicationInfo.packageName;
-
- this.componentName = new ComponentName(packageName, info.activityInfo.name);
- this.container = ItemInfo.NO_ID;
- this.setActivity(componentName,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- try {
- int appFlags = pm.getApplicationInfo(packageName, 0).flags;
- if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
- flags |= DOWNLOADED_FLAG;
-
- if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- flags |= UPDATED_SYSTEM_APP_FLAG;
- }
- }
- firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
- } catch (NameNotFoundException e) {
- Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
- }
-
- iconCache.getTitleAndIcon(this, info, labelCache);
- }
-
- public ApplicationInfo(ApplicationInfo info) {
- super(info);
- componentName = info.componentName;
- title = info.title.toString();
- intent = new Intent(info.intent);
- flags = info.flags;
- firstInstallTime = info.firstInstallTime;
- }
-
- /** Returns the package name that the shortcut's intent will resolve to, or an empty string if
- * none exists. */
- String getPackageName() {
- return super.getPackageName(intent);
- }
-
- /**
- * Creates the application intent based on a component name and various launch flags.
- * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
- *
- * @param className the class name of the component representing the intent
- * @param launchFlags the launch flags
- */
- final void setActivity(ComponentName className, int launchFlags) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(className);
- intent.setFlags(launchFlags);
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
- }
-
- @Override
- public String toString() {
- return "ApplicationInfo(title=" + title.toString() + ")";
- }
-
- public static void dumpApplicationInfoList(String tag, String label,
- ArrayList<ApplicationInfo> list) {
- Log.d(tag, label + " size=" + list.size());
- for (ApplicationInfo info: list) {
- Log.d(tag, " title=\"" + info.title + "\" iconBitmap="
- + info.iconBitmap + " firstInstallTime="
- + info.firstInstallTime);
- }
- }
-
- public ShortcutInfo makeShortcut() {
- return new ShortcutInfo(this);
- }
-}
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
deleted file mode 100644
index a50836168..000000000
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ /dev/null
@@ -1,1899 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.appwidget.AppWidgetHostView;
-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.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Insets;
-import android.graphics.MaskFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.TableMaskFilter;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Process;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.GridLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.lang.ref.WeakReference;
-
-/**
- * A simple callback interface which also provides the results of the task.
- */
-interface AsyncTaskCallback {
- void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data);
-}
-
-/**
- * The data needed to perform either of the custom AsyncTasks.
- */
-class AsyncTaskPageData {
- enum Type {
- LoadWidgetPreviewData
- }
-
- AsyncTaskPageData(int p, ArrayList<Object> l, ArrayList<Bitmap> si, AsyncTaskCallback bgR,
- AsyncTaskCallback postR) {
- page = p;
- items = l;
- sourceImages = si;
- generatedImages = new ArrayList<Bitmap>();
- maxImageWidth = maxImageHeight = -1;
- doInBackgroundCallback = bgR;
- postExecuteCallback = postR;
- }
- AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR,
- AsyncTaskCallback postR) {
- page = p;
- items = l;
- generatedImages = new ArrayList<Bitmap>();
- maxImageWidth = cw;
- maxImageHeight = ch;
- doInBackgroundCallback = bgR;
- postExecuteCallback = postR;
- }
- void cleanup(boolean cancelled) {
- // Clean up any references to source/generated bitmaps
- if (sourceImages != null) {
- if (cancelled) {
- for (Bitmap b : sourceImages) {
- b.recycle();
- }
- }
- sourceImages.clear();
- }
- if (generatedImages != null) {
- if (cancelled) {
- for (Bitmap b : generatedImages) {
- b.recycle();
- }
- }
- generatedImages.clear();
- }
- }
- int page;
- ArrayList<Object> items;
- ArrayList<Bitmap> sourceImages;
- ArrayList<Bitmap> generatedImages;
- int maxImageWidth;
- int maxImageHeight;
- AsyncTaskCallback doInBackgroundCallback;
- AsyncTaskCallback postExecuteCallback;
-}
-
-/**
- * A generic template for an async task used in AppsCustomize.
- */
-class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTaskPageData> {
- AppsCustomizeAsyncTask(int p, AsyncTaskPageData.Type ty) {
- page = p;
- threadPriority = Process.THREAD_PRIORITY_DEFAULT;
- dataType = ty;
- }
- @Override
- protected AsyncTaskPageData doInBackground(AsyncTaskPageData... params) {
- if (params.length != 1) return null;
- // Load each of the widget previews in the background
- params[0].doInBackgroundCallback.run(this, params[0]);
- return params[0];
- }
- @Override
- protected void onPostExecute(AsyncTaskPageData result) {
- // All the widget previews are loaded, so we can just callback to inflate the page
- result.postExecuteCallback.run(this, result);
- }
-
- void setThreadPriority(int p) {
- threadPriority = p;
- }
- void syncThreadPriority() {
- Process.setThreadPriority(threadPriority);
- }
-
- // The page that this async task is associated with
- AsyncTaskPageData.Type dataType;
- int page;
- int threadPriority;
-}
-
-abstract class WeakReferenceThreadLocal<T> {
- private ThreadLocal<WeakReference<T>> mThreadLocal;
- public WeakReferenceThreadLocal() {
- mThreadLocal = new ThreadLocal<WeakReference<T>>();
- }
-
- abstract T initialValue();
-
- public void set(T t) {
- mThreadLocal.set(new WeakReference<T>(t));
- }
-
- public T get() {
- WeakReference<T> reference = mThreadLocal.get();
- T obj;
- if (reference == null) {
- obj = initialValue();
- mThreadLocal.set(new WeakReference<T>(obj));
- return obj;
- } else {
- obj = reference.get();
- if (obj == null) {
- obj = initialValue();
- mThreadLocal.set(new WeakReference<T>(obj));
- }
- return obj;
- }
- }
-}
-
-class CanvasCache extends WeakReferenceThreadLocal<Canvas> {
- @Override
- protected Canvas initialValue() {
- return new Canvas();
- }
-}
-
-class PaintCache extends WeakReferenceThreadLocal<Paint> {
- @Override
- protected Paint initialValue() {
- return null;
- }
-}
-
-class BitmapCache extends WeakReferenceThreadLocal<Bitmap> {
- @Override
- protected Bitmap initialValue() {
- return null;
- }
-}
-
-class RectCache extends WeakReferenceThreadLocal<Rect> {
- @Override
- protected Rect initialValue() {
- return new Rect();
- }
-}
-
-/**
- * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
- */
-public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
- AllAppsView, View.OnClickListener, View.OnKeyListener, DragSource,
- PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
- LauncherTransitionable {
- static final String TAG = "AppsCustomizePagedView";
-
- /**
- * The different content types that this paged view can show.
- */
- public enum ContentType {
- Applications,
- Widgets
- }
-
- // Refs
- private Launcher mLauncher;
- private DragController mDragController;
- private final LayoutInflater mLayoutInflater;
- private final PackageManager mPackageManager;
-
- // Save and Restore
- private int mSaveInstanceStateItemIndex = -1;
- private PagedViewIcon mPressedIcon;
-
- // Content
- private ArrayList<ApplicationInfo> mApps;
- private ArrayList<Object> mWidgets;
-
- // Cling
- private boolean mHasShownAllAppsCling;
- private int mClingFocusedX;
- private int mClingFocusedY;
-
- // Caching
- private Canvas mCanvas;
- private Drawable mDefaultWidgetBackground;
- private IconCache mIconCache;
-
- // Dimens
- private int mContentWidth;
- private int mAppIconSize;
- private int mMaxAppCellCountX, mMaxAppCellCountY;
- private int mWidgetCountX, mWidgetCountY;
- private int mWidgetWidthGap, mWidgetHeightGap;
- private final float sWidgetPreviewIconPaddingPercentage = 0.25f;
- private PagedViewCellLayout mWidgetSpacingLayout;
- private int mNumAppsPages;
- private int mNumWidgetPages;
-
- // Relating to the scroll and overscroll effects
- Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f);
- private static float CAMERA_DISTANCE = 6500;
- private static float TRANSITION_SCALE_FACTOR = 0.74f;
- private static float TRANSITION_PIVOT = 0.65f;
- private static float TRANSITION_MAX_ROTATION = 22;
- private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
- private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);
- private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);
-
- // Previews & outlines
- ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
- private static final int sPageSleepDelay = 200;
-
- private Runnable mInflateWidgetRunnable = null;
- private Runnable mBindWidgetRunnable = null;
- static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
- static final int WIDGET_PRELOAD_PENDING = 0;
- static final int WIDGET_BOUND = 1;
- static final int WIDGET_INFLATED = 2;
- int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
- int mWidgetLoadingId = -1;
- PendingAddWidgetInfo mCreateWidgetInfo = null;
- private boolean mDraggingWidget = false;
-
- // Deferral of loading widget previews during launcher transitions
- private boolean mInTransition;
- private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems =
- new ArrayList<AsyncTaskPageData>();
- private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
- new ArrayList<Runnable>();
-
- // Used for drawing shortcut previews
- BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
- PaintCache mCachedShortcutPreviewPaint = new PaintCache();
- CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
-
- // Used for drawing widget previews
- CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
- RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
- RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
- PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
-
- public AppsCustomizePagedView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mLayoutInflater = LayoutInflater.from(context);
- mPackageManager = context.getPackageManager();
- mApps = new ArrayList<ApplicationInfo>();
- mWidgets = new ArrayList<Object>();
- mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();
- mCanvas = new Canvas();
- mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
-
- // Save the default widget preview background
- Resources resources = context.getResources();
- mDefaultWidgetBackground = resources.getDrawable(R.drawable.default_widget_preview_holo);
- mAppIconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
- mMaxAppCellCountX = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountX, -1);
- mMaxAppCellCountY = a.getInt(R.styleable.AppsCustomizePagedView_maxAppCellCountY, -1);
- mWidgetWidthGap =
- a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellWidthGap, 0);
- mWidgetHeightGap =
- a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 0);
- mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
- mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
- mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0);
- mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0);
- a.recycle();
- mWidgetSpacingLayout = new PagedViewCellLayout(getContext());
-
- // The padding on the non-matched dimension for the default widget preview icons
- // (top + bottom)
- mFadeInAdjacentScreens = false;
-
- // Unless otherwise specified this view is important for accessibility.
- if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
- }
-
- @Override
- protected void init() {
- super.init();
- mCenterPagesVertically = false;
-
- Context context = getContext();
- Resources r = context.getResources();
- setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
- }
-
- @Override
- protected void onUnhandledTap(MotionEvent ev) {
- if (LauncherApplication.isScreenLarge()) {
- // Dismiss AppsCustomize if we tap
- mLauncher.showWorkspace(true);
- }
- }
-
- /** Returns the item index of the center item on this page so that we can restore to this
- * item index when we rotate. */
- private int getMiddleComponentIndexOnCurrentPage() {
- int i = -1;
- if (getPageCount() > 0) {
- int currentPage = getCurrentPage();
- if (currentPage < mNumAppsPages) {
- PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(currentPage);
- PagedViewCellLayoutChildren childrenLayout = layout.getChildrenLayout();
- int numItemsPerPage = mCellCountX * mCellCountY;
- int childCount = childrenLayout.getChildCount();
- if (childCount > 0) {
- i = (currentPage * numItemsPerPage) + (childCount / 2);
- }
- } else {
- int numApps = mApps.size();
- PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
- int childCount = layout.getChildCount();
- if (childCount > 0) {
- i = numApps +
- ((currentPage - mNumAppsPages) * numItemsPerPage) + (childCount / 2);
- }
- }
- }
- return i;
- }
-
- /** Get the index of the item to restore to if we need to restore the current page. */
- int getSaveInstanceStateIndex() {
- if (mSaveInstanceStateItemIndex == -1) {
- mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
- }
- return mSaveInstanceStateItemIndex;
- }
-
- /** Returns the page in the current orientation which is expected to contain the specified
- * item index. */
- int getPageForComponent(int index) {
- if (index < 0) return 0;
-
- if (index < mApps.size()) {
- int numItemsPerPage = mCellCountX * mCellCountY;
- return (index / numItemsPerPage);
- } else {
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
- return mNumAppsPages + ((index - mApps.size()) / numItemsPerPage);
- }
- }
-
- /** Restores the page for an item at the specified index */
- void restorePageForIndex(int index) {
- if (index < 0) return;
- mSaveInstanceStateItemIndex = index;
- }
-
- private void updatePageCounts() {
- mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
- (float) (mWidgetCountX * mWidgetCountY));
- mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
- }
-
- protected void onDataReady(int width, int height) {
- // Note that we transpose the counts in portrait so that we get a similar layout
- boolean isLandscape = getResources().getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE;
- int maxCellCountX = Integer.MAX_VALUE;
- int maxCellCountY = Integer.MAX_VALUE;
- if (LauncherApplication.isScreenLarge()) {
- maxCellCountX = (isLandscape ? LauncherModel.getCellCountX() :
- LauncherModel.getCellCountY());
- maxCellCountY = (isLandscape ? LauncherModel.getCellCountY() :
- LauncherModel.getCellCountX());
- }
- if (mMaxAppCellCountX > -1) {
- maxCellCountX = Math.min(maxCellCountX, mMaxAppCellCountX);
- }
- if (mMaxAppCellCountY > -1) {
- maxCellCountY = Math.min(maxCellCountY, mMaxAppCellCountY);
- }
-
- // Now that the data is ready, we can calculate the content width, the number of cells to
- // use for each page
- mWidgetSpacingLayout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
- mWidgetSpacingLayout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
- mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
- mWidgetSpacingLayout.calculateCellCount(width, height, maxCellCountX, maxCellCountY);
- mCellCountX = mWidgetSpacingLayout.getCellCountX();
- mCellCountY = mWidgetSpacingLayout.getCellCountY();
- updatePageCounts();
-
- // Force a measure to update recalculate the gaps
- int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
- mWidgetSpacingLayout.measure(widthSpec, heightSpec);
- mContentWidth = mWidgetSpacingLayout.getContentWidth();
-
- AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost();
- final boolean hostIsTransitioning = host.isTransitioning();
-
- // Restore the page
- int page = getPageForComponent(mSaveInstanceStateItemIndex);
- invalidatePageData(Math.max(0, page), hostIsTransitioning);
-
- // Show All Apps cling if we are finished transitioning, otherwise, we will try again when
- // the transition completes in AppsCustomizeTabHost (otherwise the wrong offsets will be
- // returned while animating)
- if (!hostIsTransitioning) {
- post(new Runnable() {
- @Override
- public void run() {
- showAllAppsCling();
- }
- });
- }
- }
-
- void showAllAppsCling() {
- if (!mHasShownAllAppsCling && isDataReady()) {
- mHasShownAllAppsCling = true;
- // Calculate the position for the cling punch through
- int[] offset = new int[2];
- int[] pos = mWidgetSpacingLayout.estimateCellPosition(mClingFocusedX, mClingFocusedY);
- mLauncher.getDragLayer().getLocationInDragLayer(this, offset);
- // PagedViews are centered horizontally but top aligned
- pos[0] += (getMeasuredWidth() - mWidgetSpacingLayout.getMeasuredWidth()) / 2 +
- offset[0];
- pos[1] += offset[1];
- mLauncher.showFirstRunAllAppsCling(pos);
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
- if (!isDataReady()) {
- if (!mApps.isEmpty() && !mWidgets.isEmpty()) {
- setDataIsReady();
- setMeasuredDimension(width, height);
- onDataReady(width, height);
- }
- }
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- public void onPackagesUpdated() {
- // TODO: this isn't ideal, but we actually need to delay here. This call is triggered
- // by a broadcast receiver, and in order for it to work correctly, we need to know that
- // the AppWidgetService has already received and processed the same broadcast. Since there
- // is no guarantee about ordering of broadcast receipt, we just delay here. This is a
- // workaround until we add a callback from AppWidgetService to AppWidgetHost when widget
- // packages are added, updated or removed.
- postDelayed(new Runnable() {
- public void run() {
- updatePackages();
- }
- }, 1500);
- }
-
- public void updatePackages() {
- // Get the list of widgets and shortcuts
- mWidgets.clear();
- List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(mLauncher).getInstalledProviders();
- Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
- List<ResolveInfo> shortcuts = mPackageManager.queryIntentActivities(shortcutsIntent, 0);
- for (AppWidgetProviderInfo widget : widgets) {
- if (widget.minWidth > 0 && widget.minHeight > 0) {
- // Ensure that all widgets we show can be added on a workspace of this size
- int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
- int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
- int minSpanX = Math.min(spanXY[0], minSpanXY[0]);
- int minSpanY = Math.min(spanXY[1], minSpanXY[1]);
- if (minSpanX <= LauncherModel.getCellCountX() &&
- minSpanY <= LauncherModel.getCellCountY()) {
- mWidgets.add(widget);
- } else {
- Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" +
- widget.minWidth + ", " + widget.minHeight + ")");
- }
- } else {
- Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
- widget.minWidth + ", " + widget.minHeight + ")");
- }
- }
- mWidgets.addAll(shortcuts);
- Collections.sort(mWidgets,
- new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager));
- updatePageCounts();
- invalidateOnDataChange();
- }
-
- @Override
- public void onClick(View v) {
- // When we have exited all apps or are in transition, disregard clicks
- if (!mLauncher.isAllAppsCustomizeOpen() ||
- mLauncher.getWorkspace().isSwitchingState()) return;
-
- if (v instanceof PagedViewIcon) {
- // Animate some feedback to the click
- final ApplicationInfo appInfo = (ApplicationInfo) v.getTag();
-
- // Lock the drawable state to pressed until we return to Launcher
- if (mPressedIcon != null) {
- mPressedIcon.lockDrawableState();
- }
-
- // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
- // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
- // when Launcher resumes and we are still in AllApps.
- mLauncher.updateWallpaperVisibility(true);
- mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
-
- } else if (v instanceof PagedViewWidget) {
- // Let the user know that they have to long press to add a widget
- Toast.makeText(getContext(), R.string.long_press_widget_to_add,
- Toast.LENGTH_SHORT).show();
-
- // Create a little animation to show that the widget can move
- float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
- final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
- AnimatorSet bounce = new AnimatorSet();
- ValueAnimator tyuAnim = ObjectAnimator.ofFloat(p, "translationY", offsetY);
- tyuAnim.setDuration(125);
- ValueAnimator tydAnim = ObjectAnimator.ofFloat(p, "translationY", 0f);
- tydAnim.setDuration(100);
- bounce.play(tyuAnim).before(tydAnim);
- bounce.setInterpolator(new AccelerateInterpolator());
- bounce.start();
- }
- }
-
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleAppsCustomizeKeyEvent(v, keyCode, event);
- }
-
- /*
- * PagedViewWithDraggableItems implementation
- */
- @Override
- protected void determineDraggingStart(android.view.MotionEvent ev) {
- // Disable dragging by pulling an app down for now.
- }
-
- private void beginDraggingApplication(View v) {
- mLauncher.getWorkspace().onDragStartedWithItem(v);
- mLauncher.getWorkspace().beginDragShared(v, this);
- }
-
- private void preloadWidget(final PendingAddWidgetInfo info) {
- final AppWidgetProviderInfo pInfo = info.info;
- if (pInfo.configure != null) {
- return;
- }
-
- mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
- mBindWidgetRunnable = new Runnable() {
- @Override
- public void run() {
- mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
- if (AppWidgetManager.getInstance(mLauncher)
- .bindAppWidgetIdIfAllowed(mWidgetLoadingId, info.componentName)) {
- mWidgetCleanupState = WIDGET_BOUND;
- }
- }
- };
- post(mBindWidgetRunnable);
-
- mInflateWidgetRunnable = new Runnable() {
- @Override
- public void run() {
- AppWidgetHostView hostView = mLauncher.
- getAppWidgetHost().createView(getContext(), mWidgetLoadingId, pInfo);
- info.boundWidget = hostView;
- mWidgetCleanupState = WIDGET_INFLATED;
- hostView.setVisibility(INVISIBLE);
- int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info.spanX,
- info.spanY, info, false);
-
- // We want the first widget layout to be the correct size. This will be important
- // for width size reporting to the AppWidgetManager.
- DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
- unScaledSize[1]);
- lp.x = lp.y = 0;
- lp.customPosition = true;
- hostView.setLayoutParams(lp);
- mLauncher.getDragLayer().addView(hostView);
- }
- };
- post(mInflateWidgetRunnable);
- }
-
- @Override
- public void onShortPress(View v) {
- // We are anticipating a long press, and we use this time to load bind and instantiate
- // the widget. This will need to be cleaned up if it turns out no long press occurs.
- if (mCreateWidgetInfo != null) {
- // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
- cleanupWidgetPreloading(false);
- }
- mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
- preloadWidget(mCreateWidgetInfo);
- }
-
- private void cleanupWidgetPreloading(boolean widgetWasAdded) {
- if (!widgetWasAdded) {
- // If the widget was not added, we may need to do further cleanup.
- PendingAddWidgetInfo info = mCreateWidgetInfo;
- mCreateWidgetInfo = null;
-
- if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
- // We never did any preloading, so just remove pending callbacks to do so
- removeCallbacks(mBindWidgetRunnable);
- removeCallbacks(mInflateWidgetRunnable);
- } else if (mWidgetCleanupState == WIDGET_BOUND) {
- // Delete the widget id which was allocated
- if (mWidgetLoadingId != -1) {
- mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
- }
-
- // We never got around to inflating the widget, so remove the callback to do so.
- removeCallbacks(mInflateWidgetRunnable);
- } else if (mWidgetCleanupState == WIDGET_INFLATED) {
- // Delete the widget id which was allocated
- if (mWidgetLoadingId != -1) {
- mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
- }
-
- // The widget was inflated and added to the DragLayer -- remove it.
- AppWidgetHostView widget = info.boundWidget;
- mLauncher.getDragLayer().removeView(widget);
- }
- }
- mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
- mWidgetLoadingId = -1;
- mCreateWidgetInfo = null;
- PagedViewWidget.resetShortPressTarget();
- }
-
- @Override
- public void cleanUpShortPress(View v) {
- if (!mDraggingWidget) {
- cleanupWidgetPreloading(false);
- }
- }
-
- private boolean beginDraggingWidget(View v) {
- mDraggingWidget = true;
- // Get the widget preview as the drag representation
- ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
- PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
-
- // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
- // we abort the drag.
- if (image.getDrawable() == null) {
- mDraggingWidget = false;
- return false;
- }
-
- // Compose the drag image
- Bitmap preview;
- Bitmap outline;
- float scale = 1f;
- if (createItemInfo instanceof PendingAddWidgetInfo) {
- // This can happen in some weird cases involving multi-touch. We can't start dragging
- // the widget if this is null, so we break out.
- if (mCreateWidgetInfo == null) {
- return false;
- }
-
- PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo;
- createItemInfo = createWidgetInfo;
- int spanX = createItemInfo.spanX;
- int spanY = createItemInfo.spanY;
- int[] size = mLauncher.getWorkspace().estimateItemSize(spanX, spanY,
- createWidgetInfo, true);
-
- FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
- float minScale = 1.25f;
- int maxWidth, maxHeight;
- maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
- maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]);
- preview = getWidgetPreview(createWidgetInfo.componentName, createWidgetInfo.previewImage,
- createWidgetInfo.icon, spanX, spanY, maxWidth, maxHeight);
-
- // Determine the image view drawable scale relative to the preview
- float[] mv = new float[9];
- Matrix m = new Matrix();
- m.setRectToRect(
- new RectF(0f, 0f, (float) preview.getWidth(), (float) preview.getHeight()),
- new RectF(0f, 0f, (float) previewDrawable.getIntrinsicWidth(),
- (float) previewDrawable.getIntrinsicHeight()),
- Matrix.ScaleToFit.START);
- m.getValues(mv);
- scale = (float) mv[0];
- } else {
- PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
- Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo);
- preview = Bitmap.createBitmap(icon.getIntrinsicWidth(),
- icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-
- mCanvas.setBitmap(preview);
- mCanvas.save();
- renderDrawableToBitmap(icon, preview, 0, 0,
- icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
- mCanvas.restore();
- mCanvas.setBitmap(null);
- createItemInfo.spanX = createItemInfo.spanY = 1;
- }
-
- // We use a custom alpha clip table for the default widget previews
- Paint alphaClipPaint = null;
- if (createItemInfo instanceof PendingAddWidgetInfo) {
- if (((PendingAddWidgetInfo) createItemInfo).previewImage != 0) {
- MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(0, 255);
- alphaClipPaint = new Paint();
- alphaClipPaint.setMaskFilter(alphaClipTable);
- }
- }
-
- // Save the preview for the outline generation, then dim the preview
- outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
- false);
-
- // Start the drag
- alphaClipPaint = null;
- mLauncher.lockScreenOrientation();
- mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, alphaClipPaint);
- mDragController.startDrag(image, preview, this, createItemInfo,
- DragController.DRAG_ACTION_COPY, null, scale);
- outline.recycle();
- preview.recycle();
- return true;
- }
-
- @Override
- protected boolean beginDragging(final View v) {
- if (!super.beginDragging(v)) return false;
-
- if (v instanceof PagedViewIcon) {
- beginDraggingApplication(v);
- } else if (v instanceof PagedViewWidget) {
- if (!beginDraggingWidget(v)) {
- return false;
- }
- }
-
- // We delay entering spring-loaded mode slightly to make sure the UI
- // thready is free of any work.
- postDelayed(new Runnable() {
- @Override
- public void run() {
- // We don't enter spring-loaded mode if the drag has been cancelled
- if (mLauncher.getDragController().isDragging()) {
- // Dismiss the cling
- mLauncher.dismissAllAppsCling(null);
-
- // Reset the alpha on the dragged icon before we drag
- resetDrawableState();
-
- // Go into spring loaded mode (must happen before we startDrag())
- mLauncher.enterSpringLoadedDragMode();
- }
- }
- }, 150);
-
- return true;
- }
-
- /**
- * Clean up after dragging.
- *
- * @param target where the item was dragged to (can be null if the item was flung)
- */
- private void endDragging(View target, boolean isFlingToDelete, boolean success) {
- if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
- !(target instanceof DeleteDropTarget))) {
- // Exit spring loaded mode if we have not successfully dropped or have not handled the
- // drop in Workspace
- mLauncher.exitSpringLoadedDragMode();
- }
- mLauncher.unlockScreenOrientation(false);
- }
-
- @Override
- public View getContent() {
- return null;
- }
-
- @Override
- public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mInTransition = true;
- if (toWorkspace) {
- cancelAllTasks();
- }
- }
-
- @Override
- public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- }
-
- @Override
- public void onLauncherTransitionStep(Launcher l, float t) {
- }
-
- @Override
- public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mInTransition = false;
- for (AsyncTaskPageData d : mDeferredSyncWidgetPageItems) {
- onSyncWidgetPageItems(d);
- }
- mDeferredSyncWidgetPageItems.clear();
- for (Runnable r : mDeferredPrepareLoadWidgetPreviewsTasks) {
- r.run();
- }
- mDeferredPrepareLoadWidgetPreviewsTasks.clear();
- mForceDrawAllChildrenNextFrame = !toWorkspace;
- }
-
- @Override
- public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
- boolean success) {
- // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
- if (isFlingToDelete) return;
-
- endDragging(target, false, success);
-
- // Display an error message if the drag failed due to there not being enough space on the
- // target layout we were dropping on.
- if (!success) {
- boolean showOutOfSpaceMessage = false;
- if (target instanceof Workspace) {
- int currentScreen = mLauncher.getCurrentWorkspaceScreen();
- Workspace workspace = (Workspace) target;
- CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
- ItemInfo itemInfo = (ItemInfo) d.dragInfo;
- if (layout != null) {
- layout.calculateSpans(itemInfo);
- showOutOfSpaceMessage =
- !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
- }
- }
- if (showOutOfSpaceMessage) {
- mLauncher.showOutOfSpaceMessage(false);
- }
-
- d.deferDragViewCleanupPostAnimation = false;
- }
- cleanupWidgetPreloading(success);
- mDraggingWidget = false;
- }
-
- @Override
- public void onFlingToDeleteCompleted() {
- // We just dismiss the drag when we fling, so cleanup here
- endDragging(null, true, true);
- cleanupWidgetPreloading(false);
- mDraggingWidget = false;
- }
-
- @Override
- public boolean supportsFlingToDelete() {
- return true;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- cancelAllTasks();
- }
-
- public void clearAllWidgetPages() {
- cancelAllTasks();
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View v = getPageAt(i);
- if (v instanceof PagedViewGridLayout) {
- ((PagedViewGridLayout) v).removeAllViewsOnPage();
- mDirtyPageContent.set(i, true);
- }
- }
- }
-
- private void cancelAllTasks() {
- // Clean up all the async tasks
- Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
- while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
- task.cancel(false);
- iter.remove();
- mDirtyPageContent.set(task.page, true);
-
- // We've already preallocated the views for the data to load into, so clear them as well
- View v = getPageAt(task.page);
- if (v instanceof PagedViewGridLayout) {
- ((PagedViewGridLayout) v).removeAllViewsOnPage();
- }
- }
- mDeferredSyncWidgetPageItems.clear();
- mDeferredPrepareLoadWidgetPreviewsTasks.clear();
- }
-
- public void setContentType(ContentType type) {
- if (type == ContentType.Widgets) {
- invalidatePageData(mNumAppsPages, true);
- } else if (type == ContentType.Applications) {
- invalidatePageData(0, true);
- }
- }
-
- protected void snapToPage(int whichPage, int delta, int duration) {
- super.snapToPage(whichPage, delta, duration);
- updateCurrentTab(whichPage);
-
- // Update the thread priorities given the direction lookahead
- Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
- while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
- int pageIndex = task.page;
- if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
- (mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
- task.setThreadPriority(getThreadPriorityForPage(pageIndex));
- } else {
- task.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
- }
- }
- }
-
- private void updateCurrentTab(int currentPage) {
- AppsCustomizeTabHost tabHost = getTabHost();
- if (tabHost != null) {
- String tag = tabHost.getCurrentTabTag();
- if (tag != null) {
- if (currentPage >= mNumAppsPages &&
- !tag.equals(tabHost.getTabTagForContentType(ContentType.Widgets))) {
- tabHost.setCurrentTabFromContent(ContentType.Widgets);
- } else if (currentPage < mNumAppsPages &&
- !tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) {
- tabHost.setCurrentTabFromContent(ContentType.Applications);
- }
- }
- }
- }
-
- /*
- * Apps PagedView implementation
- */
- private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
- int childCount = layout.getChildCount();
- for (int i = 0; i < childCount; ++i) {
- layout.getChildAt(i).setVisibility(visibility);
- }
- }
- private void setupPage(PagedViewCellLayout layout) {
- layout.setCellCount(mCellCountX, mCellCountY);
- layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
- layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
- mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
-
- // Note: We force a measure here to get around the fact that when we do layout calculations
- // immediately after syncing, we don't have a proper width. That said, we already know the
- // expected page width, so we can actually optimize by hiding all the TextView-based
- // children that are expensive to measure, and let that happen naturally later.
- setVisibilityOnChildren(layout, View.GONE);
- int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
- layout.setMinimumWidth(getPageContentWidth());
- layout.measure(widthSpec, heightSpec);
- setVisibilityOnChildren(layout, View.VISIBLE);
- }
-
- public void syncAppsPageItems(int page, boolean immediate) {
- // 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, mApps.size());
- PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(page);
-
- layout.removeAllViewsOnPage();
- ArrayList<Object> items = new ArrayList<Object>();
- ArrayList<Bitmap> images = new ArrayList<Bitmap>();
- for (int i = startIndex; i < endIndex; ++i) {
- ApplicationInfo info = mApps.get(i);
- PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
- R.layout.apps_customize_application, layout, false);
- icon.applyFromApplicationInfo(info, true, this);
- icon.setOnClickListener(this);
- icon.setOnLongClickListener(this);
- icon.setOnTouchListener(this);
- icon.setOnKeyListener(this);
-
- int index = i - startIndex;
- int x = index % mCellCountX;
- int y = index / mCellCountX;
- layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
-
- items.add(info);
- images.add(info.iconBitmap);
- }
-
- layout.createHardwareLayers();
- }
-
- /**
- * A helper to return the priority for loading of the specified widget page.
- */
- private int getWidgetPageLoadPriority(int page) {
- // If we are snapping to another page, use that index as the target page index
- int toPage = mCurrentPage;
- if (mNextPage > -1) {
- toPage = mNextPage;
- }
-
- // We use the distance from the target page as an initial guess of priority, but if there
- // are no pages of higher priority than the page specified, then bump up the priority of
- // the specified page.
- Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
- int minPageDiff = Integer.MAX_VALUE;
- while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
- minPageDiff = Math.abs(task.page - toPage);
- }
-
- int rawPageDiff = Math.abs(page - toPage);
- return rawPageDiff - Math.min(rawPageDiff, minPageDiff);
- }
- /**
- * Return the appropriate thread priority for loading for a given page (we give the current
- * page much higher priority)
- */
- private int getThreadPriorityForPage(int page) {
- // TODO-APPS_CUSTOMIZE: detect number of cores and set thread priorities accordingly below
- int pageDiff = getWidgetPageLoadPriority(page);
- if (pageDiff <= 0) {
- return Process.THREAD_PRIORITY_LESS_FAVORABLE;
- } else if (pageDiff <= 1) {
- return Process.THREAD_PRIORITY_LOWEST;
- } else {
- return Process.THREAD_PRIORITY_LOWEST;
- }
- }
- private int getSleepForPage(int page) {
- int pageDiff = getWidgetPageLoadPriority(page);
- return Math.max(0, pageDiff * sPageSleepDelay);
- }
- /**
- * Creates and executes a new AsyncTask to load a page of widget previews.
- */
- private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets,
- int cellWidth, int cellHeight, int cellCountX) {
-
- // Prune all tasks that are no longer needed
- Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
- while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
- int taskPage = task.page;
- if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
- taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
- task.cancel(false);
- iter.remove();
- } else {
- task.setThreadPriority(getThreadPriorityForPage(taskPage));
- }
- }
-
- // We introduce a slight delay to order the loading of side pages so that we don't thrash
- final int sleepMs = getSleepForPage(page);
- AsyncTaskPageData pageData = new AsyncTaskPageData(page, widgets, cellWidth, cellHeight,
- new AsyncTaskCallback() {
- @Override
- public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
- try {
- try {
- Thread.sleep(sleepMs);
- } catch (Exception e) {}
- loadWidgetPreviewsInBackground(task, data);
- } finally {
- if (task.isCancelled()) {
- data.cleanup(true);
- }
- }
- }
- },
- new AsyncTaskCallback() {
- @Override
- public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
- mRunningTasks.remove(task);
- if (task.isCancelled()) return;
- // do cleanup inside onSyncWidgetPageItems
- onSyncWidgetPageItems(data);
- }
- });
-
- // Ensure that the task is appropriately prioritized and runs in parallel
- AppsCustomizeAsyncTask t = new AppsCustomizeAsyncTask(page,
- AsyncTaskPageData.Type.LoadWidgetPreviewData);
- t.setThreadPriority(getThreadPriorityForPage(page));
- t.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pageData);
- mRunningTasks.add(t);
- }
-
- /*
- * Widgets PagedView implementation
- */
- private void setupPage(PagedViewGridLayout layout) {
- layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
- mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
-
- // Note: We force a measure here to get around the fact that when we do layout calculations
- // immediately after syncing, we don't have a proper width.
- int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
- layout.setMinimumWidth(getPageContentWidth());
- layout.measure(widthSpec, heightSpec);
- }
-
- private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
- renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f);
- }
-
- private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h,
- float scale) {
- if (bitmap != null) {
- Canvas c = new Canvas(bitmap);
- c.scale(scale, scale);
- Rect oldBounds = d.copyBounds();
- d.setBounds(x, y, x + w, y + h);
- d.draw(c);
- d.setBounds(oldBounds); // Restore the bounds
- c.setBitmap(null);
- }
- }
-
- private Bitmap getShortcutPreview(ResolveInfo info, int maxWidth, int maxHeight) {
- Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get();
- final Canvas c = mCachedShortcutPreviewCanvas.get();
- if (tempBitmap == null ||
- tempBitmap.getWidth() != maxWidth ||
- tempBitmap.getHeight() != maxHeight) {
- tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
- mCachedShortcutPreviewBitmap.set(tempBitmap);
- } else {
- c.setBitmap(tempBitmap);
- c.drawColor(0, PorterDuff.Mode.CLEAR);
- c.setBitmap(null);
- }
- // Render the icon
- Drawable icon = mIconCache.getFullResIcon(info);
-
- int paddingTop =
- getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
- int paddingLeft =
- getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left);
- int paddingRight =
- getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
-
- int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
- float scaleSize = scaledIconWidth / (float) mAppIconSize;
-
- renderDrawableToBitmap(
- icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth);
-
- Bitmap preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
- c.setBitmap(preview);
- Paint p = mCachedShortcutPreviewPaint.get();
- if (p == null) {
- p = new Paint();
- ColorMatrix colorMatrix = new ColorMatrix();
- colorMatrix.setSaturation(0);
- p.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
- p.setAlpha((int) (255 * 0.06f));
- //float density = 1f;
- //p.setMaskFilter(new BlurMaskFilter(15*density, BlurMaskFilter.Blur.NORMAL));
- mCachedShortcutPreviewPaint.set(p);
- }
- c.drawBitmap(tempBitmap, 0, 0, p);
- c.setBitmap(null);
-
- renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize);
-
- return preview;
- }
-
- private Bitmap getWidgetPreview(ComponentName provider, int previewImage,
- int iconId, int cellHSpan, int cellVSpan, int maxWidth,
- int maxHeight) {
- // Load the preview image if possible
- String packageName = provider.getPackageName();
- if (maxWidth < 0) maxWidth = Integer.MAX_VALUE;
- if (maxHeight < 0) maxHeight = Integer.MAX_VALUE;
-
- Drawable drawable = null;
- if (previewImage != 0) {
- drawable = mPackageManager.getDrawable(packageName, previewImage, null);
- if (drawable == null) {
- Log.w(TAG, "Can't load widget preview drawable 0x" +
- Integer.toHexString(previewImage) + " for provider: " + provider);
- }
- }
-
- int bitmapWidth;
- int bitmapHeight;
- Bitmap defaultPreview = null;
- boolean widgetPreviewExists = (drawable != null);
- if (widgetPreviewExists) {
- bitmapWidth = drawable.getIntrinsicWidth();
- bitmapHeight = drawable.getIntrinsicHeight();
- } else {
- // Generate a preview image if we couldn't load one
- if (cellHSpan < 1) cellHSpan = 1;
- if (cellVSpan < 1) cellVSpan = 1;
-
- BitmapDrawable previewDrawable = (BitmapDrawable) getResources()
- .getDrawable(R.drawable.widget_preview_tile);
- final int previewDrawableWidth = previewDrawable
- .getIntrinsicWidth();
- final int previewDrawableHeight = previewDrawable
- .getIntrinsicHeight();
- bitmapWidth = previewDrawableWidth * cellHSpan; // subtract 2 dips
- bitmapHeight = previewDrawableHeight * cellVSpan;
-
- defaultPreview = Bitmap.createBitmap(bitmapWidth, bitmapHeight,
- Config.ARGB_8888);
- final Canvas c = mCachedAppWidgetPreviewCanvas.get();
- c.setBitmap(defaultPreview);
- previewDrawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
- previewDrawable.setTileModeXY(Shader.TileMode.REPEAT,
- Shader.TileMode.REPEAT);
- previewDrawable.draw(c);
- c.setBitmap(null);
-
- // Draw the icon in the top left corner
- int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
- int smallestSide = Math.min(bitmapWidth, bitmapHeight);
- float iconScale = Math.min((float) smallestSide
- / (mAppIconSize + 2 * minOffset), 1f);
-
- try {
- Drawable icon = null;
- int hoffset =
- (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
- int yoffset =
- (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
- if (iconId > 0)
- icon = mIconCache.getFullResIcon(packageName, iconId);
- Resources resources = mLauncher.getResources();
- if (icon != null) {
- renderDrawableToBitmap(icon, defaultPreview, hoffset,
- yoffset, (int) (mAppIconSize * iconScale),
- (int) (mAppIconSize * iconScale));
- }
- } catch (Resources.NotFoundException e) {
- }
- }
-
- // Scale to fit width only - let the widget preview be clipped in the
- // vertical dimension
- float scale = 1f;
- if (bitmapWidth > maxWidth) {
- scale = maxWidth / (float) bitmapWidth;
- }
- if (scale != 1f) {
- bitmapWidth = (int) (scale * bitmapWidth);
- bitmapHeight = (int) (scale * bitmapHeight);
- }
-
- Bitmap preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight,
- Config.ARGB_8888);
-
- // Draw the scaled preview into the final bitmap
- if (widgetPreviewExists) {
- renderDrawableToBitmap(drawable, preview, 0, 0, bitmapWidth,
- bitmapHeight);
- } else {
- final Canvas c = mCachedAppWidgetPreviewCanvas.get();
- final Rect src = mCachedAppWidgetPreviewSrcRect.get();
- final Rect dest = mCachedAppWidgetPreviewDestRect.get();
- c.setBitmap(preview);
- src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight());
- dest.set(0, 0, preview.getWidth(), preview.getHeight());
-
- Paint p = mCachedAppWidgetPreviewPaint.get();
- if (p == null) {
- p = new Paint();
- p.setFilterBitmap(true);
- mCachedAppWidgetPreviewPaint.set(p);
- }
- c.drawBitmap(defaultPreview, src, dest, p);
- c.setBitmap(null);
- }
- return preview;
- }
-
- public void syncWidgetPageItems(final int page, final boolean immediate) {
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-
- // Calculate the dimensions of each cell we are giving to each widget
- final ArrayList<Object> items = new ArrayList<Object>();
- int contentWidth = mWidgetSpacingLayout.getContentWidth();
- final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight
- - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX);
- int contentHeight = mWidgetSpacingLayout.getContentHeight();
- final int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom
- - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY);
-
- // Prepare the set of widgets to load previews for in the background
- int offset = (page - mNumAppsPages) * numItemsPerPage;
- for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) {
- items.add(mWidgets.get(i));
- }
-
- // Prepopulate the pages with the other widget info, and fill in the previews later
- final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
- layout.setColumnCount(layout.getCellCountX());
- for (int i = 0; i < items.size(); ++i) {
- Object rawInfo = items.get(i);
- PendingAddItemInfo createItemInfo = null;
- PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
- R.layout.apps_customize_widget, layout, false);
- if (rawInfo instanceof AppWidgetProviderInfo) {
- // Fill in the widget information
- AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
- createItemInfo = new PendingAddWidgetInfo(info, null, null);
-
- // Determine the widget spans and min resize spans.
- int[] spanXY = Launcher.getSpanForWidget(mLauncher, info);
- createItemInfo.spanX = spanXY[0];
- createItemInfo.spanY = spanXY[1];
- int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, info);
- createItemInfo.minSpanX = minSpanXY[0];
- createItemInfo.minSpanY = minSpanXY[1];
-
- widget.applyFromAppWidgetProviderInfo(info, -1, spanXY);
- widget.setTag(createItemInfo);
- widget.setShortPressListener(this);
- } else if (rawInfo instanceof ResolveInfo) {
- // Fill in the shortcuts information
- ResolveInfo info = (ResolveInfo) rawInfo;
- createItemInfo = new PendingAddShortcutInfo(info.activityInfo);
- createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
- createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
- info.activityInfo.name);
- widget.applyFromResolveInfo(mPackageManager, info);
- widget.setTag(createItemInfo);
- }
- widget.setOnClickListener(this);
- widget.setOnLongClickListener(this);
- widget.setOnTouchListener(this);
- widget.setOnKeyListener(this);
-
- // Layout each widget
- int ix = i % mWidgetCountX;
- int iy = i / mWidgetCountX;
- GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
- GridLayout.spec(iy, GridLayout.LEFT),
- GridLayout.spec(ix, GridLayout.TOP));
- lp.width = cellWidth;
- lp.height = cellHeight;
- lp.setGravity(Gravity.TOP | Gravity.LEFT);
- if (ix > 0) lp.leftMargin = mWidgetWidthGap;
- if (iy > 0) lp.topMargin = mWidgetHeightGap;
- layout.addView(widget, lp);
- }
-
- // wait until a call on onLayout to start loading, because
- // PagedViewWidget.getPreviewSize() will return 0 if it hasn't been laid out
- // TODO: can we do a measure/layout immediately?
- layout.setOnLayoutListener(new Runnable() {
- public void run() {
- // Load the widget previews
- int maxPreviewWidth = cellWidth;
- int maxPreviewHeight = cellHeight;
- if (layout.getChildCount() > 0) {
- PagedViewWidget w = (PagedViewWidget) layout.getChildAt(0);
- int[] maxSize = w.getPreviewSize();
- maxPreviewWidth = maxSize[0];
- maxPreviewHeight = maxSize[1];
- }
- if (immediate) {
- AsyncTaskPageData data = new AsyncTaskPageData(page, items,
- maxPreviewWidth, maxPreviewHeight, null, null);
- loadWidgetPreviewsInBackground(null, data);
- onSyncWidgetPageItems(data);
- } else {
- if (mInTransition) {
- mDeferredPrepareLoadWidgetPreviewsTasks.add(this);
- } else {
- prepareLoadWidgetPreviewsTask(page, items,
- maxPreviewWidth, maxPreviewHeight, mWidgetCountX);
- }
- }
- }
- });
- }
- private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
- AsyncTaskPageData data) {
- // loadWidgetPreviewsInBackground can be called without a task to load a set of widget
- // previews synchronously
- if (task != null) {
- // Ensure that this task starts running at the correct priority
- task.syncThreadPriority();
- }
-
- // Load each of the widget/shortcut previews
- ArrayList<Object> items = data.items;
- ArrayList<Bitmap> images = data.generatedImages;
- int count = items.size();
- for (int i = 0; i < count; ++i) {
- if (task != null) {
- // Ensure we haven't been cancelled yet
- if (task.isCancelled()) break;
- // Before work on each item, ensure that this task is running at the correct
- // priority
- task.syncThreadPriority();
- }
-
- Object rawInfo = items.get(i);
- if (rawInfo instanceof AppWidgetProviderInfo) {
- AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
- int[] cellSpans = Launcher.getSpanForWidget(mLauncher, info);
-
- int maxWidth = Math.min(data.maxImageWidth,
- mWidgetSpacingLayout.estimateCellWidth(cellSpans[0]));
- int maxHeight = Math.min(data.maxImageHeight,
- mWidgetSpacingLayout.estimateCellHeight(cellSpans[1]));
- Bitmap b = getWidgetPreview(info.provider, info.previewImage, info.icon,
- cellSpans[0], cellSpans[1], maxWidth, maxHeight);
- images.add(b);
- } else if (rawInfo instanceof ResolveInfo) {
- // Fill in the shortcuts information
- ResolveInfo info = (ResolveInfo) rawInfo;
- images.add(getShortcutPreview(info, data.maxImageWidth, data.maxImageHeight));
- }
- }
- }
-
- private void onSyncWidgetPageItems(AsyncTaskPageData data) {
- if (mInTransition) {
- mDeferredSyncWidgetPageItems.add(data);
- return;
- }
- try {
- int page = data.page;
- PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
- ArrayList<Object> items = data.items;
- int count = items.size();
- for (int i = 0; i < count; ++i) {
- PagedViewWidget widget = (PagedViewWidget) layout.getChildAt(i);
- if (widget != null) {
- Bitmap preview = data.generatedImages.get(i);
- widget.applyPreview(new FastBitmapDrawable(preview), i);
- }
- }
-
- layout.createHardwareLayer();
- invalidate();
-
- // Update all thread priorities
- Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
- while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
- int pageIndex = task.page;
- task.setThreadPriority(getThreadPriorityForPage(pageIndex));
- }
- } finally {
- data.cleanup(false);
- }
- }
-
- @Override
- public void syncPages() {
- removeAllViews();
- cancelAllTasks();
-
- Context context = getContext();
- for (int j = 0; j < mNumWidgetPages; ++j) {
- PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
- mWidgetCountY);
- setupPage(layout);
- addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
- }
-
- for (int i = 0; i < mNumAppsPages; ++i) {
- PagedViewCellLayout layout = new PagedViewCellLayout(context);
- setupPage(layout);
- addView(layout);
- }
- }
-
- @Override
- public void syncPageItems(int page, boolean immediate) {
- if (page < mNumAppsPages) {
- syncAppsPageItems(page, immediate);
- } else {
- syncWidgetPageItems(page, immediate);
- }
- }
-
- // We want our pages to be z-ordered such that the further a page is to the left, the higher
- // it is in the z-order. This is important to insure touch events are handled correctly.
- View getPageAt(int index) {
- return getChildAt(indexToPage(index));
- }
-
- @Override
- protected int indexToPage(int index) {
- return getChildCount() - index - 1;
- }
-
- // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
- @Override
- protected void screenScrolled(int screenCenter) {
- super.screenScrolled(screenCenter);
-
- for (int i = 0; i < getChildCount(); i++) {
- View v = getPageAt(i);
- if (v != null) {
- float scrollProgress = getScrollProgress(screenCenter, v, i);
-
- float interpolatedProgress =
- mZInterpolator.getInterpolation(Math.abs(Math.min(scrollProgress, 0)));
- float scale = (1 - interpolatedProgress) +
- interpolatedProgress * TRANSITION_SCALE_FACTOR;
- float translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth();
-
- float alpha;
-
- if (scrollProgress < 0) {
- alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
- 1 - Math.abs(scrollProgress)) : 1.0f;
- } else {
- // On large screens we need to fade the page as it nears its leftmost position
- alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
- }
-
- v.setCameraDistance(mDensity * CAMERA_DISTANCE);
- int pageWidth = v.getMeasuredWidth();
- int pageHeight = v.getMeasuredHeight();
-
- if (PERFORM_OVERSCROLL_ROTATION) {
- if (i == 0 && scrollProgress < 0) {
- // Overscroll to the left
- v.setPivotX(TRANSITION_PIVOT * pageWidth);
- v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
- scale = 1.0f;
- alpha = 1.0f;
- // On the first page, we don't want the page to have any lateral motion
- translationX = 0;
- } else if (i == getChildCount() - 1 && scrollProgress > 0) {
- // Overscroll to the right
- v.setPivotX((1 - TRANSITION_PIVOT) * pageWidth);
- v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
- scale = 1.0f;
- alpha = 1.0f;
- // On the last page, we don't want the page to have any lateral motion.
- translationX = 0;
- } else {
- v.setPivotY(pageHeight / 2.0f);
- v.setPivotX(pageWidth / 2.0f);
- v.setRotationY(0f);
- }
- }
-
- v.setTranslationX(translationX);
- v.setScaleX(scale);
- v.setScaleY(scale);
- v.setAlpha(alpha);
-
- // If the view has 0 alpha, we set it to be invisible so as to prevent
- // it from accepting touches
- if (alpha == 0) {
- v.setVisibility(INVISIBLE);
- } else if (v.getVisibility() != VISIBLE) {
- v.setVisibility(VISIBLE);
- }
- }
- }
- }
-
- protected void overScroll(float amount) {
- acceleratedOverScroll(amount);
- }
-
- /**
- * Used by the parent to get the content width to set the tab bar to
- * @return
- */
- public int getPageContentWidth() {
- return mContentWidth;
- }
-
- @Override
- protected void onPageEndMoving() {
- super.onPageEndMoving();
- mForceDrawAllChildrenNextFrame = true;
- // We reset the save index when we change pages so that it will be recalculated on next
- // rotation
- mSaveInstanceStateItemIndex = -1;
- }
-
- /*
- * AllAppsView implementation
- */
- @Override
- public void setup(Launcher launcher, DragController dragController) {
- mLauncher = launcher;
- mDragController = dragController;
- }
- @Override
- public void zoom(float zoom, boolean animate) {
- // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed()
- }
- @Override
- public boolean isVisible() {
- return (getVisibility() == VISIBLE);
- }
- @Override
- public boolean isAnimating() {
- return false;
- }
-
- /**
- * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
- * appropriately determine when to invalidate the PagedView page data. In cases where the data
- * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
- * next onMeasure() pass, which will trigger an invalidatePageData() itself.
- */
- private void invalidateOnDataChange() {
- if (!isDataReady()) {
- // The next layout pass will trigger data-ready if both widgets and apps are set, so
- // request a layout to trigger the page data when ready.
- requestLayout();
- } else {
- cancelAllTasks();
- invalidatePageData();
- }
- }
-
- @Override
- public void setApps(ArrayList<ApplicationInfo> list) {
- mApps = list;
- Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
- updatePageCounts();
- invalidateOnDataChange();
- }
- private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
- // We add it in place, in alphabetical order
- int count = list.size();
- for (int i = 0; i < count; ++i) {
- ApplicationInfo info = list.get(i);
- int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
- if (index < 0) {
- mApps.add(-(index + 1), info);
- }
- }
- }
- @Override
- public void addApps(ArrayList<ApplicationInfo> list) {
- addAppsWithoutInvalidate(list);
- updatePageCounts();
- invalidateOnDataChange();
- }
- private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
- ComponentName removeComponent = item.intent.getComponent();
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- ApplicationInfo info = list.get(i);
- if (info.intent.getComponent().equals(removeComponent)) {
- return i;
- }
- }
- return -1;
- }
- private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
- // loop through all the apps and remove apps that have the same component
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- ApplicationInfo info = list.get(i);
- int removeIndex = findAppByComponent(mApps, info);
- if (removeIndex > -1) {
- mApps.remove(removeIndex);
- }
- }
- }
- @Override
- public void removeApps(ArrayList<ApplicationInfo> list) {
- removeAppsWithoutInvalidate(list);
- updatePageCounts();
- invalidateOnDataChange();
- }
- @Override
- public void updateApps(ArrayList<ApplicationInfo> list) {
- // We remove and re-add the updated applications list because it's properties may have
- // changed (ie. the title), and this will ensure that the items will be in their proper
- // place in the list.
- removeAppsWithoutInvalidate(list);
- addAppsWithoutInvalidate(list);
- updatePageCounts();
- invalidateOnDataChange();
- }
-
- @Override
- public void reset() {
- // If we have reset, then we should not continue to restore the previous state
- mSaveInstanceStateItemIndex = -1;
-
- AppsCustomizeTabHost tabHost = getTabHost();
- String tag = tabHost.getCurrentTabTag();
- if (tag != null) {
- if (!tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) {
- tabHost.setCurrentTabFromContent(ContentType.Applications);
- }
- }
-
- if (mCurrentPage != 0) {
- invalidatePageData(0);
- }
- }
-
- private AppsCustomizeTabHost getTabHost() {
- return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
- }
-
- @Override
- public void dumpState() {
- // TODO: Dump information related to current list of Applications, Widgets, etc.
- ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
- dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
- }
-
- private void dumpAppWidgetProviderInfoList(String tag, String label,
- ArrayList<Object> list) {
- Log.d(tag, label + " size=" + list.size());
- for (Object i: list) {
- if (i instanceof AppWidgetProviderInfo) {
- AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
- Log.d(tag, " label=\"" + info.label + "\" previewImage=" + info.previewImage
- + " resizeMode=" + info.resizeMode + " configure=" + info.configure
- + " initialLayout=" + info.initialLayout
- + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
- } else if (i instanceof ResolveInfo) {
- ResolveInfo info = (ResolveInfo) i;
- Log.d(tag, " label=\"" + info.loadLabel(mPackageManager) + "\" icon="
- + info.icon);
- }
- }
- }
-
- @Override
- public void surrender() {
- // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
- // should stop this now.
-
- // Stop all background tasks
- cancelAllTasks();
- }
-
- @Override
- public void iconPressed(PagedViewIcon icon) {
- // Reset the previously pressed icon and store a reference to the pressed icon so that
- // we can reset it on return to Launcher (in Launcher.onResume())
- if (mPressedIcon != null) {
- mPressedIcon.resetDrawableState();
- }
- mPressedIcon = icon;
- }
-
- public void resetDrawableState() {
- if (mPressedIcon != null) {
- mPressedIcon.resetDrawableState();
- mPressedIcon = null;
- }
- }
-
- /*
- * We load an extra page on each side to prevent flashes from scrolling and loading of the
- * widget previews in the background with the AsyncTasks.
- */
- final static int sLookBehindPageCount = 2;
- final static int sLookAheadPageCount = 2;
- protected int getAssociatedLowerPageBound(int page) {
- final int count = getChildCount();
- int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
- int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0);
- return windowMinIndex;
- }
- protected int getAssociatedUpperPageBound(int page) {
- final int count = getChildCount();
- int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
- int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1),
- count - 1);
- return windowMaxIndex;
- }
-
- @Override
- protected String getCurrentPageDescription() {
- int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
- int stringId = R.string.default_scroll_format;
- int count = 0;
-
- if (page < mNumAppsPages) {
- stringId = R.string.apps_customize_apps_scroll_format;
- count = mNumAppsPages;
- } else {
- page -= mNumAppsPages;
- stringId = R.string.apps_customize_widgets_scroll_format;
- count = mNumWidgetPages;
- }
-
- return String.format(getContext().getString(stringId), page + 1, count);
- }
-}
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
deleted file mode 100644
index 9fa2f3237..000000000
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-
-public class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable,
- TabHost.OnTabChangeListener {
- static final String LOG_TAG = "AppsCustomizeTabHost";
-
- private static final String APPS_TAB_TAG = "APPS";
- private static final String WIDGETS_TAB_TAG = "WIDGETS";
-
- private final LayoutInflater mLayoutInflater;
- private ViewGroup mTabs;
- private ViewGroup mTabsContainer;
- private AppsCustomizePagedView mAppsCustomizePane;
- private boolean mSuppressContentCallback = false;
- private FrameLayout mAnimationBuffer;
- private LinearLayout mContent;
-
- private boolean mInTransition;
- private boolean mTransitioningToWorkspace;
- private boolean mResetAfterTransition;
- private Runnable mRelayoutAndMakeVisible;
-
- private Launcher mLauncher;
-
- public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
- super(context, attrs);
- mLayoutInflater = LayoutInflater.from(context);
- mRelayoutAndMakeVisible = new Runnable() {
- public void run() {
- mTabs.requestLayout();
- mTabsContainer.setAlpha(1f);
- }
- };
- }
-
- public void setup(Launcher launcher) {
- mLauncher = launcher;
- }
-
- /**
- * Convenience methods to select specific tabs. We want to set the content type immediately
- * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
- * reflects the new content (but doesn't do the animation and logic associated with changing
- * tabs manually).
- */
- private void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
- onTabChangedStart();
- onTabChangedEnd(type);
- }
- void selectAppsTab() {
- setContentTypeImmediate(AppsCustomizePagedView.ContentType.Applications);
- setCurrentTabByTag(APPS_TAB_TAG);
- }
- void selectWidgetsTab() {
- setContentTypeImmediate(AppsCustomizePagedView.ContentType.Widgets);
- setCurrentTabByTag(WIDGETS_TAB_TAG);
- }
-
- /**
- * Setup the tab host and create all necessary tabs.
- */
- @Override
- protected void onFinishInflate() {
- // Setup the tab host
- setup();
-
- final ViewGroup tabsContainer = (ViewGroup) findViewById(R.id.tabs_container);
- final TabWidget tabs = getTabWidget();
- final AppsCustomizePagedView appsCustomizePane = (AppsCustomizePagedView)
- findViewById(R.id.apps_customize_pane_content);
- mTabs = tabs;
- mTabsContainer = tabsContainer;
- mAppsCustomizePane = appsCustomizePane;
- mAnimationBuffer = (FrameLayout) findViewById(R.id.animation_buffer);
- mContent = (LinearLayout) findViewById(R.id.apps_customize_content);
- if (tabs == null || mAppsCustomizePane == null) throw new Resources.NotFoundException();
-
- // Configure the tabs content factory to return the same paged view (that we change the
- // content filter on)
- TabContentFactory contentFactory = new TabContentFactory() {
- public View createTabContent(String tag) {
- return appsCustomizePane;
- }
- };
-
- // Create the tabs
- TextView tabView;
- String label;
- label = getContext().getString(R.string.all_apps_button_label);
- tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
- tabView.setText(label);
- tabView.setContentDescription(label);
- addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
- label = getContext().getString(R.string.widgets_tab_label);
- tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
- tabView.setText(label);
- tabView.setContentDescription(label);
- addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
- setOnTabChangedListener(this);
-
- // Setup the key listener to jump between the last tab view and the market icon
- AppsCustomizeTabKeyEventListener keyListener = new AppsCustomizeTabKeyEventListener();
- View lastTab = tabs.getChildTabViewAt(tabs.getTabCount() - 1);
- lastTab.setOnKeyListener(keyListener);
- View shopButton = findViewById(R.id.market_button);
- shopButton.setOnKeyListener(keyListener);
-
- // Hide the tab bar until we measure
- mTabsContainer.setAlpha(0f);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- boolean remeasureTabWidth = (mTabs.getLayoutParams().width <= 0);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- // Set the width of the tab list to the content width
- if (remeasureTabWidth) {
- int contentWidth = mAppsCustomizePane.getPageContentWidth();
- if (contentWidth > 0 && mTabs.getLayoutParams().width != contentWidth) {
- // Set the width and show the tab bar
- mTabs.getLayoutParams().width = contentWidth;
- post(mRelayoutAndMakeVisible);
- }
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // If we are mid transitioning to the workspace, then intercept touch events here so we
- // can ignore them, otherwise we just let all apps handle the touch events.
- if (mInTransition && mTransitioningToWorkspace) {
- return true;
- }
- return super.onInterceptTouchEvent(ev);
- };
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Allow touch events to fall through to the workspace if we are transitioning there
- if (mInTransition && mTransitioningToWorkspace) {
- return super.onTouchEvent(event);
- }
-
- // Intercept all touch events up to the bottom of the AppsCustomizePane so they do not fall
- // through to the workspace and trigger showWorkspace()
- if (event.getY() < mAppsCustomizePane.getBottom()) {
- return true;
- }
- return super.onTouchEvent(event);
- }
-
- private void onTabChangedStart() {
- mAppsCustomizePane.hideScrollingIndicator(false);
- }
-
- private void reloadCurrentPage() {
- if (!LauncherApplication.isScreenLarge()) {
- mAppsCustomizePane.flashScrollingIndicator(true);
- }
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
- mAppsCustomizePane.requestFocus();
- }
-
- private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) {
- mAppsCustomizePane.setContentType(type);
- }
-
- @Override
- public void onTabChanged(String tabId) {
- final AppsCustomizePagedView.ContentType type = getContentTypeForTabTag(tabId);
- if (mSuppressContentCallback) {
- mSuppressContentCallback = false;
- return;
- }
-
- // Animate the changing of the tab content by fading pages in and out
- final Resources res = getResources();
- final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
-
- // We post a runnable here because there is a delay while the first page is loading and
- // the feedback from having changed the tab almost feels better than having it stick
- post(new Runnable() {
- @Override
- public void run() {
- if (mAppsCustomizePane.getMeasuredWidth() <= 0 ||
- mAppsCustomizePane.getMeasuredHeight() <= 0) {
- reloadCurrentPage();
- return;
- }
-
- // Take the visible pages and re-parent them temporarily to mAnimatorBuffer
- // and then cross fade to the new pages
- int[] visiblePageRange = new int[2];
- mAppsCustomizePane.getVisiblePages(visiblePageRange);
- if (visiblePageRange[0] == -1 && visiblePageRange[1] == -1) {
- // If we can't get the visible page ranges, then just skip the animation
- reloadCurrentPage();
- return;
- }
- ArrayList<View> visiblePages = new ArrayList<View>();
- for (int i = visiblePageRange[0]; i <= visiblePageRange[1]; i++) {
- visiblePages.add(mAppsCustomizePane.getPageAt(i));
- }
-
- // We want the pages to be rendered in exactly the same way as they were when
- // their parent was mAppsCustomizePane -- so set the scroll on mAnimationBuffer
- // to be exactly the same as mAppsCustomizePane, and below, set the left/top
- // parameters to be correct for each of the pages
- mAnimationBuffer.scrollTo(mAppsCustomizePane.getScrollX(), 0);
-
- // mAppsCustomizePane renders its children in reverse order, so
- // add the pages to mAnimationBuffer in reverse order to match that behavior
- for (int i = visiblePages.size() - 1; i >= 0; i--) {
- View child = visiblePages.get(i);
- if (child instanceof PagedViewCellLayout) {
- ((PagedViewCellLayout) child).resetChildrenOnKeyListeners();
- } else if (child instanceof PagedViewGridLayout) {
- ((PagedViewGridLayout) child).resetChildrenOnKeyListeners();
- }
- PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(false);
- mAppsCustomizePane.removeView(child);
- PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(true);
- mAnimationBuffer.setAlpha(1f);
- mAnimationBuffer.setVisibility(View.VISIBLE);
- LayoutParams p = new FrameLayout.LayoutParams(child.getMeasuredWidth(),
- child.getMeasuredHeight());
- p.setMargins((int) child.getLeft(), (int) child.getTop(), 0, 0);
- mAnimationBuffer.addView(child, p);
- }
-
- // Toggle the new content
- onTabChangedStart();
- onTabChangedEnd(type);
-
- // Animate the transition
- ObjectAnimator outAnim = ObjectAnimator.ofFloat(mAnimationBuffer, "alpha", 0f);
- outAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimationBuffer.setVisibility(View.GONE);
- mAnimationBuffer.removeAllViews();
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- mAnimationBuffer.setVisibility(View.GONE);
- mAnimationBuffer.removeAllViews();
- }
- });
- ObjectAnimator inAnim = ObjectAnimator.ofFloat(mAppsCustomizePane, "alpha", 1f);
- inAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- reloadCurrentPage();
- }
- });
- AnimatorSet animSet = new AnimatorSet();
- animSet.playTogether(outAnim, inAnim);
- animSet.setDuration(duration);
- animSet.start();
- }
- });
- }
-
- public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
- mSuppressContentCallback = true;
- setCurrentTabByTag(getTabTagForContentType(type));
- }
-
- /**
- * Returns the content type for the specified tab tag.
- */
- public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
- if (tag.equals(APPS_TAB_TAG)) {
- return AppsCustomizePagedView.ContentType.Applications;
- } else if (tag.equals(WIDGETS_TAB_TAG)) {
- return AppsCustomizePagedView.ContentType.Widgets;
- }
- return AppsCustomizePagedView.ContentType.Applications;
- }
-
- /**
- * Returns the tab tag for a given content type.
- */
- public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
- if (type == AppsCustomizePagedView.ContentType.Applications) {
- return APPS_TAB_TAG;
- } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
- return WIDGETS_TAB_TAG;
- }
- return APPS_TAB_TAG;
- }
-
- /**
- * Disable focus on anything under this view in the hierarchy if we are not visible.
- */
- @Override
- public int getDescendantFocusability() {
- if (getVisibility() != View.VISIBLE) {
- return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
- }
- return super.getDescendantFocusability();
- }
-
- void reset() {
- if (mInTransition) {
- // Defer to after the transition to reset
- mResetAfterTransition = true;
- } else {
- // Reset immediately
- mAppsCustomizePane.reset();
- }
- }
-
- private void enableAndBuildHardwareLayer() {
- // isHardwareAccelerated() checks if we're attached to a window and if that
- // window is HW accelerated-- we were sometimes not attached to a window
- // and buildLayer was throwing an IllegalStateException
- if (isHardwareAccelerated()) {
- // Turn on hardware layers for performance
- setLayerType(LAYER_TYPE_HARDWARE, null);
-
- // force building the layer, so you don't get a blip early in an animation
- // when the layer is created layer
- buildLayer();
-
- // Let the GC system know that now is a good time to do any garbage
- // collection; makes it less likely we'll get a GC during the all apps
- // to workspace animation
- System.gc();
- }
- }
-
- @Override
- public View getContent() {
- return mContent;
- }
-
- /* LauncherTransitionable overrides */
- @Override
- public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mAppsCustomizePane.onLauncherTransitionPrepare(l, animated, toWorkspace);
- mInTransition = true;
- mTransitioningToWorkspace = toWorkspace;
-
- if (toWorkspace) {
- // Going from All Apps -> Workspace
- setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
- // Stop the scrolling indicator - we don't want All Apps to be invalidating itself
- // during the transition, especially since it has a hardware layer set on it
- mAppsCustomizePane.cancelScrollingIndicatorAnimations();
- } else {
- // Going from Workspace -> All Apps
- mContent.setVisibility(VISIBLE);
-
- // Make sure the current page is loaded (we start loading the side pages after the
- // transition to prevent slowing down the animation)
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true);
-
- if (!LauncherApplication.isScreenLarge()) {
- mAppsCustomizePane.showScrollingIndicator(true);
- }
- }
-
- if (mResetAfterTransition) {
- mAppsCustomizePane.reset();
- mResetAfterTransition = false;
- }
- }
-
- @Override
- public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- if (animated) {
- enableAndBuildHardwareLayer();
- }
- }
-
- @Override
- public void onLauncherTransitionStep(Launcher l, float t) {
- // Do nothing
- }
-
- @Override
- public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mAppsCustomizePane.onLauncherTransitionEnd(l, animated, toWorkspace);
- mInTransition = false;
- if (animated) {
- setLayerType(LAYER_TYPE_NONE, null);
- }
-
- if (!toWorkspace) {
- // Going from Workspace -> All Apps
- setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
-
- // Dismiss the workspace cling and show the all apps cling (if not already shown)
- l.dismissWorkspaceCling(null);
- mAppsCustomizePane.showAllAppsCling();
- // Make sure adjacent pages are loaded (we wait until after the transition to
- // prevent slowing down the animation)
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
-
- if (!LauncherApplication.isScreenLarge()) {
- mAppsCustomizePane.hideScrollingIndicator(false);
- }
- }
- }
-
- private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
- ViewGroup parent = (ViewGroup) getParent();
- if (parent == null) return;
-
- final int count = parent.getChildCount();
- if (!isChildrenDrawingOrderEnabled()) {
- for (int i = 0; i < count; i++) {
- final View child = parent.getChildAt(i);
- if (child == this) {
- break;
- } else {
- if (child.getVisibility() == GONE) {
- continue;
- }
- child.setVisibility(visibility);
- }
- }
- } else {
- throw new RuntimeException("Failed; can't get z-order of views");
- }
- }
-
- public void onWindowVisible() {
- if (getVisibility() == VISIBLE) {
- mContent.setVisibility(VISIBLE);
- // We unload the widget previews when the UI is hidden, so need to reload pages
- // Load the current page synchronously, and the neighboring pages asynchronously
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true);
- mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage());
- }
- }
-
- public void onTrimMemory() {
- mContent.setVisibility(GONE);
- // Clear the widget pages of all their subviews - this will trigger the widget previews
- // to delete their bitmaps
- mAppsCustomizePane.clearAllWidgetPages();
- }
-
- boolean isTransitioning() {
- return mInTransition;
- }
-}
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
deleted file mode 100644
index ddc4b9fa0..000000000
--- a/src/com/android/launcher2/BubbleTextView.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.Region.Op;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.TextView;
-
-/**
- * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
- * because we want to make the bubble taller than the text and TextView's clip is
- * too aggressive.
- */
-public class BubbleTextView extends TextView {
- static final float CORNER_RADIUS = 4.0f;
- static final float SHADOW_LARGE_RADIUS = 4.0f;
- static final float SHADOW_SMALL_RADIUS = 1.75f;
- static final float SHADOW_Y_OFFSET = 2.0f;
- static final int SHADOW_LARGE_COLOUR = 0xDD000000;
- static final int SHADOW_SMALL_COLOUR = 0xCC000000;
- static final float PADDING_H = 8.0f;
- static final float PADDING_V = 3.0f;
-
- private int mPrevAlpha = -1;
-
- private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
- private final Canvas mTempCanvas = new Canvas();
- private final Rect mTempRect = new Rect();
- private boolean mDidInvalidateForPressedState;
- private Bitmap mPressedOrFocusedBackground;
- private int mFocusedOutlineColor;
- private int mFocusedGlowColor;
- private int mPressedOutlineColor;
- private int mPressedGlowColor;
-
- private boolean mBackgroundSizeChanged;
- private Drawable mBackground;
-
- private boolean mStayPressed;
- private CheckLongPressHelper mLongPressHelper;
-
- public BubbleTextView(Context context) {
- super(context);
- init();
- }
-
- public BubbleTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
-
- private void init() {
- mLongPressHelper = new CheckLongPressHelper(this);
- mBackground = getBackground();
-
- final Resources res = getContext().getResources();
- mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor =
- res.getColor(android.R.color.holo_blue_light);
-
- setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
- }
-
- public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
- Bitmap b = info.getIcon(iconCache);
-
- setCompoundDrawablesWithIntrinsicBounds(null,
- new FastBitmapDrawable(b),
- null, null);
- setText(info.title);
- setTag(info);
- }
-
- @Override
- protected boolean setFrame(int left, int top, int right, int bottom) {
- if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
- mBackgroundSizeChanged = true;
- }
- return super.setFrame(left, top, right, bottom);
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mBackground || super.verifyDrawable(who);
- }
-
- @Override
- protected void drawableStateChanged() {
- if (isPressed()) {
- // In this case, we have already created the pressed outline on ACTION_DOWN,
- // so we just need to do an invalidate to trigger draw
- if (!mDidInvalidateForPressedState) {
- setCellLayoutPressedOrFocusedIcon();
- }
- } else {
- // Otherwise, either clear the pressed/focused background, or create a background
- // for the focused state
- final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null;
- if (!mStayPressed) {
- mPressedOrFocusedBackground = null;
- }
- if (isFocused()) {
- if (getLayout() == null) {
- // In some cases, we get focus before we have been layed out. Set the
- // background to null so that it will get created when the view is drawn.
- mPressedOrFocusedBackground = null;
- } else {
- mPressedOrFocusedBackground = createGlowingOutline(
- mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
- }
- mStayPressed = false;
- setCellLayoutPressedOrFocusedIcon();
- }
- final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null;
- if (!backgroundEmptyBefore && backgroundEmptyNow) {
- setCellLayoutPressedOrFocusedIcon();
- }
- }
-
- Drawable d = mBackground;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- super.drawableStateChanged();
- }
-
- /**
- * Draw this BubbleTextView into the given Canvas.
- *
- * @param destCanvas the canvas to draw on
- * @param padding the horizontal and vertical padding to use when drawing
- */
- private void drawWithPadding(Canvas destCanvas, int padding) {
- final Rect clipRect = mTempRect;
- getDrawingRect(clipRect);
-
- // adjust the clip rect so that we don't include the text label
- clipRect.bottom =
- getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0);
-
- // Draw the View into the bitmap.
- // The translate of scrollX and scrollY is necessary when drawing TextViews, because
- // they set scrollX and scrollY to large values to achieve centered text
- destCanvas.save();
- destCanvas.scale(getScaleX(), getScaleY(),
- (getWidth() + padding) / 2, (getHeight() + padding) / 2);
- destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2);
- destCanvas.clipRect(clipRect, Op.REPLACE);
- draw(destCanvas);
- destCanvas.restore();
- }
-
- /**
- * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
- * Responsibility for the bitmap is transferred to the caller.
- */
- private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) {
- final int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
- final Bitmap b = Bitmap.createBitmap(
- getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888);
-
- canvas.setBitmap(b);
- drawWithPadding(canvas, padding);
- mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor);
- canvas.setBitmap(null);
-
- return b;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Call the superclass onTouchEvent first, because sometimes it changes the state to
- // isPressed() on an ACTION_UP
- boolean result = super.onTouchEvent(event);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // So that the pressed outline is visible immediately when isPressed() is true,
- // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
- // to create it)
- if (mPressedOrFocusedBackground == null) {
- mPressedOrFocusedBackground = createGlowingOutline(
- mTempCanvas, mPressedGlowColor, mPressedOutlineColor);
- }
- // Invalidate so the pressed state is visible, or set a flag so we know that we
- // have to call invalidate as soon as the state is "pressed"
- if (isPressed()) {
- mDidInvalidateForPressedState = true;
- setCellLayoutPressedOrFocusedIcon();
- } else {
- mDidInvalidateForPressedState = false;
- }
-
- mLongPressHelper.postCheckForLongPress();
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- // If we've touched down and up on an item, and it's still not "pressed", then
- // destroy the pressed outline
- if (!isPressed()) {
- mPressedOrFocusedBackground = null;
- }
-
- mLongPressHelper.cancelLongPress();
- break;
- }
- return result;
- }
-
- void setStayPressed(boolean stayPressed) {
- mStayPressed = stayPressed;
- if (!stayPressed) {
- mPressedOrFocusedBackground = null;
- }
- setCellLayoutPressedOrFocusedIcon();
- }
-
- void setCellLayoutPressedOrFocusedIcon() {
- if (getParent() instanceof ShortcutAndWidgetContainer) {
- ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent();
- if (parent != null) {
- CellLayout layout = (CellLayout) parent.getParent();
- layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null);
- }
- }
- }
-
- void clearPressedOrFocusedBackground() {
- mPressedOrFocusedBackground = null;
- setCellLayoutPressedOrFocusedIcon();
- }
-
- Bitmap getPressedOrFocusedBackground() {
- return mPressedOrFocusedBackground;
- }
-
- int getPressedOrFocusedBackgroundPadding() {
- return HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
- }
-
- @Override
- public void draw(Canvas canvas) {
- final Drawable background = mBackground;
- if (background != null) {
- final int scrollX = getScrollX();
- final int scrollY = getScrollY();
-
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
- mBackgroundSizeChanged = false;
- }
-
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
- }
-
- // If text is transparent, don't draw any shadow
- if (getCurrentTextColor() == getResources().getColor(android.R.color.transparent)) {
- getPaint().clearShadowLayer();
- super.draw(canvas);
- return;
- }
-
- // We enhance the shadow by drawing the shadow twice
- getPaint().setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
- super.draw(canvas);
- canvas.save(Canvas.CLIP_SAVE_FLAG);
- canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
- getScrollX() + getWidth(),
- getScrollY() + getHeight(), Region.Op.INTERSECT);
- getPaint().setShadowLayer(SHADOW_SMALL_RADIUS, 0.0f, 0.0f, SHADOW_SMALL_COLOUR);
- super.draw(canvas);
- canvas.restore();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mBackground != null) mBackground.setCallback(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (mBackground != null) mBackground.setCallback(null);
- }
-
- @Override
- protected boolean onSetAlpha(int alpha) {
- if (mPrevAlpha != alpha) {
- mPrevAlpha = alpha;
- super.onSetAlpha(alpha);
- }
- return true;
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- mLongPressHelper.cancelLongPress();
- }
-}
diff --git a/src/com/android/launcher2/ButtonDropTarget.java b/src/com/android/launcher2/ButtonDropTarget.java
deleted file mode 100644
index 1c9fa5f95..000000000
--- a/src/com/android/launcher2/ButtonDropTarget.java
+++ /dev/null
@@ -1,147 +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.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-
-/**
- * Implements a DropTarget.
- */
-public class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
-
- protected final int mTransitionDuration;
-
- protected Launcher mLauncher;
- private int mBottomDragPadding;
- protected TextView mText;
- protected SearchDropTargetBar mSearchDropTargetBar;
-
- /** Whether this drop target is active for the current drag */
- protected boolean mActive;
-
- /** The paint applied to the drag view on hover */
- protected int mHoverColor = 0;
-
- public ButtonDropTarget(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ButtonDropTarget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- Resources r = getResources();
- mTransitionDuration = r.getInteger(R.integer.config_dropTargetBgTransitionDuration);
- mBottomDragPadding = r.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
- }
-
- void setLauncher(Launcher launcher) {
- mLauncher = launcher;
- }
-
- public boolean acceptDrop(DragObject d) {
- return false;
- }
-
- public void setSearchDropTargetBar(SearchDropTargetBar searchDropTargetBar) {
- mSearchDropTargetBar = searchDropTargetBar;
- }
-
- protected Drawable getCurrentDrawable() {
- Drawable[] drawables = getCompoundDrawables();
- for (int i = 0; i < drawables.length; ++i) {
- if (drawables[i] != null) {
- return drawables[i];
- }
- }
- return null;
- }
-
- public void onDrop(DragObject d) {
- }
-
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
- // Do nothing
- }
-
- public void onDragEnter(DragObject d) {
- d.dragView.setColor(mHoverColor);
- }
-
- public void onDragOver(DragObject d) {
- // Do nothing
- }
-
- public void onDragExit(DragObject d) {
- d.dragView.setColor(0);
- }
-
- public void onDragStart(DragSource source, Object info, int dragAction) {
- // Do nothing
- }
-
- public boolean isDropEnabled() {
- return mActive;
- }
-
- public void onDragEnd() {
- // Do nothing
- }
-
- @Override
- public void getHitRect(android.graphics.Rect outRect) {
- super.getHitRect(outRect);
- outRect.bottom += mBottomDragPadding;
- }
-
- Rect getIconRect(int itemWidth, int itemHeight, int drawableWidth, int drawableHeight) {
- DragLayer dragLayer = mLauncher.getDragLayer();
-
- // Find the rect to animate to (the view is center aligned)
- Rect to = new Rect();
- dragLayer.getViewRectRelativeToSelf(this, to);
- int width = drawableWidth;
- int height = drawableHeight;
- int left = to.left + getPaddingLeft();
- int top = to.top + (getMeasuredHeight() - height) / 2;
- to.set(left, top, left + width, top + height);
-
- // Center the destination rect about the trash icon
- int xOffset = (int) -(itemWidth - width) / 2;
- int yOffset = (int) -(itemHeight - height) / 2;
- to.offset(xOffset, yOffset);
-
- return to;
- }
-
- @Override
- public DropTarget getDropTargetDelegate(DragObject d) {
- return null;
- }
-
- public void getLocationInDragLayer(int[] loc) {
- mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
- }
-}
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
deleted file mode 100644
index c028ff1dc..000000000
--- a/src/com/android/launcher2/CellLayout.java
+++ /dev/null
@@ -1,3022 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
-
-import com.android.launcher.R;
-import com.android.launcher2.FolderIcon.FolderRingAnimator;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Stack;
-
-public class CellLayout extends ViewGroup {
- static final String TAG = "CellLayout";
-
- private Launcher mLauncher;
- private int mCellWidth;
- private int mCellHeight;
-
- private int mCountX;
- private int mCountY;
-
- private int mOriginalWidthGap;
- private int mOriginalHeightGap;
- private int mWidthGap;
- private int mHeightGap;
- private int mMaxGap;
- private boolean mScrollingTransformsDirty = false;
-
- private final Rect mRect = new Rect();
- private final CellInfo mCellInfo = new CellInfo();
-
- // These are temporary variables to prevent having to allocate a new object just to
- // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
- private final int[] mTmpXY = new int[2];
- private final int[] mTmpPoint = new int[2];
- int[] mTempLocation = new int[2];
-
- boolean[][] mOccupied;
- boolean[][] mTmpOccupied;
- private boolean mLastDownOnOccupiedCell = false;
-
- private OnTouchListener mInterceptTouchListener;
-
- private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
- private int[] mFolderLeaveBehindCell = {-1, -1};
-
- private int mForegroundAlpha = 0;
- private float mBackgroundAlpha;
- private float mBackgroundAlphaMultiplier = 1.0f;
-
- private Drawable mNormalBackground;
- private Drawable mActiveGlowBackground;
- private Drawable mOverScrollForegroundDrawable;
- private Drawable mOverScrollLeft;
- private Drawable mOverScrollRight;
- private Rect mBackgroundRect;
- private Rect mForegroundRect;
- private int mForegroundPadding;
-
- // If we're actively dragging something over this screen, mIsDragOverlapping is true
- private boolean mIsDragOverlapping = false;
- private final Point mDragCenter = new Point();
-
- // These arrays are used to implement the drag visualization on x-large screens.
- // They are used as circular arrays, indexed by mDragOutlineCurrent.
- private Rect[] mDragOutlines = new Rect[4];
- private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
- private InterruptibleInOutAnimator[] mDragOutlineAnims =
- new InterruptibleInOutAnimator[mDragOutlines.length];
-
- // Used as an index into the above 3 arrays; indicates which is the most current value.
- private int mDragOutlineCurrent = 0;
- private final Paint mDragOutlinePaint = new Paint();
-
- private BubbleTextView mPressedOrFocusedIcon;
-
- private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
- HashMap<CellLayout.LayoutParams, Animator>();
- private HashMap<View, ReorderHintAnimation>
- mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
-
- private boolean mItemPlacementDirty = false;
-
- // When a drag operation is in progress, holds the nearest cell to the touch point
- private final int[] mDragCell = new int[2];
-
- private boolean mDragging = false;
-
- private TimeInterpolator mEaseOutInterpolator;
- private ShortcutAndWidgetContainer mShortcutsAndWidgets;
-
- private boolean mIsHotseat = false;
-
- public static final int MODE_DRAG_OVER = 0;
- public static final int MODE_ON_DROP = 1;
- public static final int MODE_ON_DROP_EXTERNAL = 2;
- public static final int MODE_ACCEPT_DROP = 3;
- private static final boolean DESTRUCTIVE_REORDER = false;
- private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
-
- static final int LANDSCAPE = 0;
- static final int PORTRAIT = 1;
-
- private static final float REORDER_HINT_MAGNITUDE = 0.12f;
- private static final int REORDER_ANIMATION_DURATION = 150;
- private float mReorderHintAnimationMagnitude;
-
- private ArrayList<View> mIntersectingViews = new ArrayList<View>();
- private Rect mOccupiedRect = new Rect();
- private int[] mDirectionVector = new int[2];
- int[] mPreviousReorderDirection = new int[2];
- private static final int INVALID_DIRECTION = -100;
- private DropTarget.DragEnforcer mDragEnforcer;
-
- private final static PorterDuffXfermode sAddBlendMode =
- new PorterDuffXfermode(PorterDuff.Mode.ADD);
-
- public CellLayout(Context context) {
- this(context, null);
- }
-
- public CellLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CellLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mDragEnforcer = new DropTarget.DragEnforcer(context);
-
- // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
- // the user where a dragged item will land when dropped.
- setWillNotDraw(false);
- mLauncher = (Launcher) context;
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
-
- mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
- mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
- mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
- mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
- mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
- mCountX = LauncherModel.getCellCountX();
- mCountY = LauncherModel.getCellCountY();
- mOccupied = new boolean[mCountX][mCountY];
- mTmpOccupied = new boolean[mCountX][mCountY];
- mPreviousReorderDirection[0] = INVALID_DIRECTION;
- mPreviousReorderDirection[1] = INVALID_DIRECTION;
-
- a.recycle();
-
- setAlwaysDrawnWithCacheEnabled(false);
-
- final Resources res = getResources();
-
- mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
- mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
-
- mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
- mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
- mForegroundPadding =
- res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
-
- mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
- res.getDimensionPixelSize(R.dimen.app_icon_size));
-
- mNormalBackground.setFilterBitmap(true);
- mActiveGlowBackground.setFilterBitmap(true);
-
- // Initialize the data structures used for the drag visualization.
-
- mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
-
-
- mDragCell[0] = mDragCell[1] = -1;
- for (int i = 0; i < mDragOutlines.length; i++) {
- mDragOutlines[i] = new Rect(-1, -1, -1, -1);
- }
-
- // When dragging things around the home screens, we show a green outline of
- // where the item will land. The outlines gradually fade out, leaving a trail
- // behind the drag path.
- // Set up all the animations that are used to implement this fading.
- final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
- final float fromAlphaValue = 0;
- final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
-
- Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
-
- for (int i = 0; i < mDragOutlineAnims.length; i++) {
- final InterruptibleInOutAnimator anim =
- new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
- anim.getAnimator().setInterpolator(mEaseOutInterpolator);
- final int thisIndex = i;
- anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final Bitmap outline = (Bitmap)anim.getTag();
-
- // If an animation is started and then stopped very quickly, we can still
- // get spurious updates we've cleared the tag. Guard against this.
- if (outline == null) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- Object val = animation.getAnimatedValue();
- Log.d(TAG, "anim " + thisIndex + " update: " + val +
- ", isStopped " + anim.isStopped());
- }
- // Try to prevent it from continuing to run
- animation.cancel();
- } else {
- mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
- CellLayout.this.invalidate(mDragOutlines[thisIndex]);
- }
- }
- });
- // The animation holds a reference to the drag outline bitmap as long is it's
- // running. This way the bitmap can be GCed when the animations are complete.
- anim.getAnimator().addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
- anim.setTag(null);
- }
- }
- });
- mDragOutlineAnims[i] = anim;
- }
-
- mBackgroundRect = new Rect();
- mForegroundRect = new Rect();
-
- mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
- mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
- addView(mShortcutsAndWidgets);
- }
-
- static int widthInPortrait(Resources r, int numCells) {
- // We use this method from Workspace to figure out how many rows/columns Launcher should
- // have. We ignore the left/right padding on CellLayout because it turns out in our design
- // the padding extends outside the visible screen size, but it looked fine anyway.
- int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
- int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
- r.getDimensionPixelSize(R.dimen.workspace_height_gap));
-
- return minGap * (numCells - 1) + cellWidth * numCells;
- }
-
- static int heightInLandscape(Resources r, int numCells) {
- // We use this method from Workspace to figure out how many rows/columns Launcher should
- // have. We ignore the left/right padding on CellLayout because it turns out in our design
- // the padding extends outside the visible screen size, but it looked fine anyway.
- int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
- int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
- r.getDimensionPixelSize(R.dimen.workspace_height_gap));
-
- return minGap * (numCells - 1) + cellHeight * numCells;
- }
-
- public void enableHardwareLayers() {
- mShortcutsAndWidgets.enableHardwareLayers();
- }
-
- public void setGridSize(int x, int y) {
- mCountX = x;
- mCountY = y;
- mOccupied = new boolean[mCountX][mCountY];
- mTmpOccupied = new boolean[mCountX][mCountY];
- mTempRectStack.clear();
- requestLayout();
- }
-
- private void invalidateBubbleTextView(BubbleTextView icon) {
- final int padding = icon.getPressedOrFocusedBackgroundPadding();
- invalidate(icon.getLeft() + getPaddingLeft() - padding,
- icon.getTop() + getPaddingTop() - padding,
- icon.getRight() + getPaddingLeft() + padding,
- icon.getBottom() + getPaddingTop() + padding);
- }
-
- void setOverScrollAmount(float r, boolean left) {
- if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
- mOverScrollForegroundDrawable = mOverScrollLeft;
- } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
- mOverScrollForegroundDrawable = mOverScrollRight;
- }
-
- mForegroundAlpha = (int) Math.round((r * 255));
- mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
- invalidate();
- }
-
- void setPressedOrFocusedIcon(BubbleTextView icon) {
- // We draw the pressed or focused BubbleTextView's background in CellLayout because it
- // requires an expanded clip rect (due to the glow's blur radius)
- BubbleTextView oldIcon = mPressedOrFocusedIcon;
- mPressedOrFocusedIcon = icon;
- if (oldIcon != null) {
- invalidateBubbleTextView(oldIcon);
- }
- if (mPressedOrFocusedIcon != null) {
- invalidateBubbleTextView(mPressedOrFocusedIcon);
- }
- }
-
- void setIsDragOverlapping(boolean isDragOverlapping) {
- if (mIsDragOverlapping != isDragOverlapping) {
- mIsDragOverlapping = isDragOverlapping;
- invalidate();
- }
- }
-
- boolean getIsDragOverlapping() {
- return mIsDragOverlapping;
- }
-
- protected void setOverscrollTransformsDirty(boolean dirty) {
- mScrollingTransformsDirty = dirty;
- }
-
- protected void resetOverscrollTransforms() {
- if (mScrollingTransformsDirty) {
- setOverscrollTransformsDirty(false);
- setTranslationX(0);
- setRotationY(0);
- // It doesn't matter if we pass true or false here, the important thing is that we
- // pass 0, which results in the overscroll drawable not being drawn any more.
- setOverScrollAmount(0, false);
- setPivotX(getMeasuredWidth() / 2);
- setPivotY(getMeasuredHeight() / 2);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
- // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
- // When we're small, we are either drawn normally or in the "accepts drops" state (during
- // a drag). However, we also drag the mini hover background *over* one of those two
- // backgrounds
- if (mBackgroundAlpha > 0.0f) {
- Drawable bg;
-
- if (mIsDragOverlapping) {
- // In the mini case, we draw the active_glow bg *over* the active background
- bg = mActiveGlowBackground;
- } else {
- bg = mNormalBackground;
- }
-
- bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
- bg.setBounds(mBackgroundRect);
- bg.draw(canvas);
- }
-
- final Paint paint = mDragOutlinePaint;
- for (int i = 0; i < mDragOutlines.length; i++) {
- final float alpha = mDragOutlineAlphas[i];
- if (alpha > 0) {
- final Rect r = mDragOutlines[i];
- final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
- paint.setAlpha((int)(alpha + .5f));
- canvas.drawBitmap(b, null, r, paint);
- }
- }
-
- // We draw the pressed or focused BubbleTextView's background in CellLayout because it
- // requires an expanded clip rect (due to the glow's blur radius)
- if (mPressedOrFocusedIcon != null) {
- final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
- final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
- if (b != null) {
- canvas.drawBitmap(b,
- mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
- mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
- null);
- }
- }
-
- if (DEBUG_VISUALIZE_OCCUPIED) {
- int[] pt = new int[2];
- ColorDrawable cd = new ColorDrawable(Color.RED);
- cd.setBounds(0, 0, mCellWidth, mCellHeight);
- for (int i = 0; i < mCountX; i++) {
- for (int j = 0; j < mCountY; j++) {
- if (mOccupied[i][j]) {
- cellToPoint(i, j, pt);
- canvas.save();
- canvas.translate(pt[0], pt[1]);
- cd.draw(canvas);
- canvas.restore();
- }
- }
- }
- }
-
- int previewOffset = FolderRingAnimator.sPreviewSize;
-
- // The folder outer / inner ring image(s)
- for (int i = 0; i < mFolderOuterRings.size(); i++) {
- FolderRingAnimator fra = mFolderOuterRings.get(i);
-
- // Draw outer ring
- Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
- int width = (int) fra.getOuterRingSize();
- int height = width;
- cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
-
- int centerX = mTempLocation[0] + mCellWidth / 2;
- int centerY = mTempLocation[1] + previewOffset / 2;
-
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - height / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
-
- // Draw inner ring
- d = FolderRingAnimator.sSharedInnerRingDrawable;
- width = (int) fra.getInnerRingSize();
- height = width;
- cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
-
- centerX = mTempLocation[0] + mCellWidth / 2;
- centerY = mTempLocation[1] + previewOffset / 2;
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - width / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
- }
-
- if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
- Drawable d = FolderIcon.sSharedFolderLeaveBehind;
- int width = d.getIntrinsicWidth();
- int height = d.getIntrinsicHeight();
-
- cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
- int centerX = mTempLocation[0] + mCellWidth / 2;
- int centerY = mTempLocation[1] + previewOffset / 2;
-
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - width / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (mForegroundAlpha > 0) {
- mOverScrollForegroundDrawable.setBounds(mForegroundRect);
- Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
- p.setXfermode(sAddBlendMode);
- mOverScrollForegroundDrawable.draw(canvas);
- p.setXfermode(null);
- }
- }
-
- public void showFolderAccept(FolderRingAnimator fra) {
- mFolderOuterRings.add(fra);
- }
-
- public void hideFolderAccept(FolderRingAnimator fra) {
- if (mFolderOuterRings.contains(fra)) {
- mFolderOuterRings.remove(fra);
- }
- invalidate();
- }
-
- public void setFolderLeaveBehindCell(int x, int y) {
- mFolderLeaveBehindCell[0] = x;
- mFolderLeaveBehindCell[1] = y;
- invalidate();
- }
-
- public void clearFolderLeaveBehind() {
- mFolderLeaveBehindCell[0] = -1;
- mFolderLeaveBehindCell[1] = -1;
- invalidate();
- }
-
- @Override
- public boolean shouldDelayChildPressedState() {
- return false;
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- // Cancel long press for all children
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- child.cancelLongPress();
- }
- }
-
- public void setOnInterceptTouchListener(View.OnTouchListener listener) {
- mInterceptTouchListener = listener;
- }
-
- int getCountX() {
- return mCountX;
- }
-
- int getCountY() {
- return mCountY;
- }
-
- public void setIsHotseat(boolean isHotseat) {
- mIsHotseat = isHotseat;
- }
-
- public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells) {
- final LayoutParams lp = params;
-
- // Hotseat icons - remove text
- if (child instanceof BubbleTextView) {
- BubbleTextView bubbleChild = (BubbleTextView) child;
-
- Resources res = getResources();
- if (mIsHotseat) {
- bubbleChild.setTextColor(res.getColor(android.R.color.transparent));
- } else {
- bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color));
- }
- }
-
- // Generate an id for each view, this assumes we have at most 256x256 cells
- // per workspace screen
- if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
- // If the horizontal or vertical span is set to -1, it is taken to
- // mean that it spans the extent of the CellLayout
- if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
- if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
-
- child.setId(childId);
-
- mShortcutsAndWidgets.addView(child, index, lp);
-
- if (markCells) markCellsAsOccupiedForView(child);
-
- return true;
- }
- return false;
- }
-
- @Override
- public void removeAllViews() {
- clearOccupiedCells();
- mShortcutsAndWidgets.removeAllViews();
- }
-
- @Override
- public void removeAllViewsInLayout() {
- if (mShortcutsAndWidgets.getChildCount() > 0) {
- clearOccupiedCells();
- mShortcutsAndWidgets.removeAllViewsInLayout();
- }
- }
-
- public void removeViewWithoutMarkingCells(View view) {
- mShortcutsAndWidgets.removeView(view);
- }
-
- @Override
- public void removeView(View view) {
- markCellsAsUnoccupiedForView(view);
- mShortcutsAndWidgets.removeView(view);
- }
-
- @Override
- public void removeViewAt(int index) {
- markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
- mShortcutsAndWidgets.removeViewAt(index);
- }
-
- @Override
- public void removeViewInLayout(View view) {
- markCellsAsUnoccupiedForView(view);
- mShortcutsAndWidgets.removeViewInLayout(view);
- }
-
- @Override
- public void removeViews(int start, int count) {
- for (int i = start; i < start + count; i++) {
- markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
- }
- mShortcutsAndWidgets.removeViews(start, count);
- }
-
- @Override
- public void removeViewsInLayout(int start, int count) {
- for (int i = start; i < start + count; i++) {
- markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
- }
- mShortcutsAndWidgets.removeViewsInLayout(start, count);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
- }
-
- public void setTagToCellInfoForPoint(int touchX, int touchY) {
- final CellInfo cellInfo = mCellInfo;
- Rect frame = mRect;
- final int x = touchX + getScrollX();
- final int y = touchY + getScrollY();
- final int count = mShortcutsAndWidgets.getChildCount();
-
- boolean found = false;
- for (int i = count - 1; i >= 0; i--) {
- final View child = mShortcutsAndWidgets.getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
- lp.isLockedToGrid) {
- child.getHitRect(frame);
-
- float scale = child.getScaleX();
- frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
- child.getBottom());
- // The child hit rect is relative to the CellLayoutChildren parent, so we need to
- // offset that by this CellLayout's padding to test an (x,y) point that is relative
- // to this view.
- frame.offset(getPaddingLeft(), getPaddingTop());
- frame.inset((int) (frame.width() * (1f - scale) / 2),
- (int) (frame.height() * (1f - scale) / 2));
-
- if (frame.contains(x, y)) {
- cellInfo.cell = child;
- cellInfo.cellX = lp.cellX;
- cellInfo.cellY = lp.cellY;
- cellInfo.spanX = lp.cellHSpan;
- cellInfo.spanY = lp.cellVSpan;
- found = true;
- break;
- }
- }
- }
-
- mLastDownOnOccupiedCell = found;
-
- if (!found) {
- final int cellXY[] = mTmpXY;
- pointToCellExact(x, y, cellXY);
-
- cellInfo.cell = null;
- cellInfo.cellX = cellXY[0];
- cellInfo.cellY = cellXY[1];
- cellInfo.spanX = 1;
- cellInfo.spanY = 1;
- }
- setTag(cellInfo);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // First we clear the tag to ensure that on every touch down we start with a fresh slate,
- // even in the case where we return early. Not clearing here was causing bugs whereby on
- // long-press we'd end up picking up an item from a previous drag operation.
- final int action = ev.getAction();
-
- if (action == MotionEvent.ACTION_DOWN) {
- clearTagCellInfo();
- }
-
- if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
- return true;
- }
-
- if (action == MotionEvent.ACTION_DOWN) {
- setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
- }
-
- return false;
- }
-
- private void clearTagCellInfo() {
- final CellInfo cellInfo = mCellInfo;
- cellInfo.cell = null;
- cellInfo.cellX = -1;
- cellInfo.cellY = -1;
- cellInfo.spanX = 0;
- cellInfo.spanY = 0;
- setTag(cellInfo);
- }
-
- public CellInfo getTag() {
- return (CellInfo) super.getTag();
- }
-
- /**
- * Given a point, return the cell that strictly encloses that point
- * @param x X coordinate of the point
- * @param y Y coordinate of the point
- * @param result Array of 2 ints to hold the x and y coordinate of the cell
- */
- void pointToCellExact(int x, int y, int[] result) {
- final int hStartPadding = getPaddingLeft();
- final int vStartPadding = getPaddingTop();
-
- result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
- result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
-
- final int xAxis = mCountX;
- final int yAxis = mCountY;
-
- if (result[0] < 0) result[0] = 0;
- if (result[0] >= xAxis) result[0] = xAxis - 1;
- if (result[1] < 0) result[1] = 0;
- if (result[1] >= yAxis) result[1] = yAxis - 1;
- }
-
- /**
- * Given a point, return the cell that most closely encloses that point
- * @param x X coordinate of the point
- * @param y Y coordinate of the point
- * @param result Array of 2 ints to hold the x and y coordinate of the cell
- */
- void pointToCellRounded(int x, int y, int[] result) {
- pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
- }
-
- /**
- * Given a cell coordinate, return the point that represents the upper left corner of that cell
- *
- * @param cellX X coordinate of the cell
- * @param cellY Y coordinate of the cell
- *
- * @param result Array of 2 ints to hold the x and y coordinate of the point
- */
- void cellToPoint(int cellX, int cellY, int[] result) {
- final int hStartPadding = getPaddingLeft();
- final int vStartPadding = getPaddingTop();
-
- result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
- result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
- }
-
- /**
- * Given a cell coordinate, return the point that represents the center of the cell
- *
- * @param cellX X coordinate of the cell
- * @param cellY Y coordinate of the cell
- *
- * @param result Array of 2 ints to hold the x and y coordinate of the point
- */
- void cellToCenterPoint(int cellX, int cellY, int[] result) {
- regionToCenterPoint(cellX, cellY, 1, 1, result);
- }
-
- /**
- * Given a cell coordinate and span return the point that represents the center of the regio
- *
- * @param cellX X coordinate of the cell
- * @param cellY Y coordinate of the cell
- *
- * @param result Array of 2 ints to hold the x and y coordinate of the point
- */
- void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
- final int hStartPadding = getPaddingLeft();
- final int vStartPadding = getPaddingTop();
- result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
- (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
- result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
- (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
- }
-
- /**
- * Given a cell coordinate and span fills out a corresponding pixel rect
- *
- * @param cellX X coordinate of the cell
- * @param cellY Y coordinate of the cell
- * @param result Rect in which to write the result
- */
- void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
- final int hStartPadding = getPaddingLeft();
- final int vStartPadding = getPaddingTop();
- final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
- final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
- result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
- top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
- }
-
- public float getDistanceFromCell(float x, float y, int[] cell) {
- cellToCenterPoint(cell[0], cell[1], mTmpPoint);
- float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
- Math.pow(y - mTmpPoint[1], 2));
- return distance;
- }
-
- int getCellWidth() {
- return mCellWidth;
- }
-
- int getCellHeight() {
- return mCellHeight;
- }
-
- int getWidthGap() {
- return mWidthGap;
- }
-
- int getHeightGap() {
- return mHeightGap;
- }
-
- Rect getContentRect(Rect r) {
- if (r == null) {
- r = new Rect();
- }
- int left = getPaddingLeft();
- int top = getPaddingTop();
- int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
- int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
- r.set(left, top, right, bottom);
- return r;
- }
-
- static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight,
- int countX, int countY, int orientation) {
- int numWidthGaps = countX - 1;
- int numHeightGaps = countY - 1;
-
- int widthGap;
- int heightGap;
- int cellWidth;
- int cellHeight;
- int paddingLeft;
- int paddingRight;
- int paddingTop;
- int paddingBottom;
-
- int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap);
- if (orientation == LANDSCAPE) {
- cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land);
- cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land);
- widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land);
- heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land);
- paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land);
- paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land);
- paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land);
- paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land);
- } else {
- // PORTRAIT
- cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port);
- cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port);
- widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port);
- heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port);
- paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port);
- paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port);
- paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port);
- paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port);
- }
-
- if (widthGap < 0 || heightGap < 0) {
- int hSpace = measureWidth - paddingLeft - paddingRight;
- int vSpace = measureHeight - paddingTop - paddingBottom;
- int hFreeSpace = hSpace - (countX * cellWidth);
- int vFreeSpace = vSpace - (countY * cellHeight);
- widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
- heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
- }
- metrics.set(cellWidth, cellHeight, widthGap, heightGap);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
- }
-
- int numWidthGaps = mCountX - 1;
- int numHeightGaps = mCountY - 1;
-
- if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
- int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
- int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
- int hFreeSpace = hSpace - (mCountX * mCellWidth);
- int vFreeSpace = vSpace - (mCountY * mCellHeight);
- mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
- mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
- mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
- } else {
- mWidthGap = mOriginalWidthGap;
- mHeightGap = mOriginalHeightGap;
- }
-
- // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
- int newWidth = widthSpecSize;
- int newHeight = heightSpecSize;
- if (widthSpecMode == MeasureSpec.AT_MOST) {
- newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
- ((mCountX - 1) * mWidthGap);
- newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
- ((mCountY - 1) * mHeightGap);
- setMeasuredDimension(newWidth, newHeight);
- }
-
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
- getPaddingRight(), MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
- getPaddingBottom(), MeasureSpec.EXACTLY);
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
- setMeasuredDimension(newWidth, newHeight);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- child.layout(getPaddingLeft(), getPaddingTop(),
- r - l - getPaddingRight(), b - t - getPaddingBottom());
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mBackgroundRect.set(0, 0, w, h);
- mForegroundRect.set(mForegroundPadding, mForegroundPadding,
- w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
- }
-
- @Override
- protected void setChildrenDrawingCacheEnabled(boolean enabled) {
- mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
- }
-
- @Override
- protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
- mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
- }
-
- public float getBackgroundAlpha() {
- return mBackgroundAlpha;
- }
-
- public void setBackgroundAlphaMultiplier(float multiplier) {
- if (mBackgroundAlphaMultiplier != multiplier) {
- mBackgroundAlphaMultiplier = multiplier;
- invalidate();
- }
- }
-
- public float getBackgroundAlphaMultiplier() {
- return mBackgroundAlphaMultiplier;
- }
-
- public void setBackgroundAlpha(float alpha) {
- if (mBackgroundAlpha != alpha) {
- mBackgroundAlpha = alpha;
- invalidate();
- }
- }
-
- public void setShortcutAndWidgetAlpha(float alpha) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- getChildAt(i).setAlpha(alpha);
- }
- }
-
- public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
- if (getChildCount() > 0) {
- return (ShortcutAndWidgetContainer) getChildAt(0);
- }
- return null;
- }
-
- public View getChildAt(int x, int y) {
- return mShortcutsAndWidgets.getChildAt(x, y);
- }
-
- public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
- int delay, boolean permanent, boolean adjustOccupied) {
- ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
- boolean[][] occupied = mOccupied;
- if (!permanent) {
- occupied = mTmpOccupied;
- }
-
- if (clc.indexOfChild(child) != -1) {
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final ItemInfo info = (ItemInfo) child.getTag();
-
- // We cancel any existing animations
- if (mReorderAnimators.containsKey(lp)) {
- mReorderAnimators.get(lp).cancel();
- mReorderAnimators.remove(lp);
- }
-
- final int oldX = lp.x;
- final int oldY = lp.y;
- if (adjustOccupied) {
- occupied[lp.cellX][lp.cellY] = false;
- occupied[cellX][cellY] = true;
- }
- lp.isLockedToGrid = true;
- if (permanent) {
- lp.cellX = info.cellX = cellX;
- lp.cellY = info.cellY = cellY;
- } else {
- lp.tmpCellX = cellX;
- lp.tmpCellY = cellY;
- }
- clc.setupLp(lp);
- lp.isLockedToGrid = false;
- final int newX = lp.x;
- final int newY = lp.y;
-
- lp.x = oldX;
- lp.y = oldY;
-
- // Exit early if we're not actually moving the view
- if (oldX == newX && oldY == newY) {
- lp.isLockedToGrid = true;
- return true;
- }
-
- ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- va.setDuration(duration);
- mReorderAnimators.put(lp, va);
-
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float r = ((Float) animation.getAnimatedValue()).floatValue();
- lp.x = (int) ((1 - r) * oldX + r * newX);
- lp.y = (int) ((1 - r) * oldY + r * newY);
- child.requestLayout();
- }
- });
- va.addListener(new AnimatorListenerAdapter() {
- boolean cancelled = false;
- public void onAnimationEnd(Animator animation) {
- // If the animation was cancelled, it means that another animation
- // has interrupted this one, and we don't want to lock the item into
- // place just yet.
- if (!cancelled) {
- lp.isLockedToGrid = true;
- child.requestLayout();
- }
- if (mReorderAnimators.containsKey(lp)) {
- mReorderAnimators.remove(lp);
- }
- }
- public void onAnimationCancel(Animator animation) {
- cancelled = true;
- }
- });
- va.setStartDelay(delay);
- va.start();
- return true;
- }
- return false;
- }
-
- /**
- * Estimate where the top left cell of the dragged item will land if it is dropped.
- *
- * @param originX The X value of the top left corner of the item
- * @param originY The Y value of the top left corner of the item
- * @param spanX The number of horizontal cells that the item spans
- * @param spanY The number of vertical cells that the item spans
- * @param result The estimated drop cell X and Y.
- */
- void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
- final int countX = mCountX;
- final int countY = mCountY;
-
- // pointToCellRounded takes the top left of a cell but will pad that with
- // cellWidth/2 and cellHeight/2 when finding the matching cell
- pointToCellRounded(originX, originY, result);
-
- // If the item isn't fully on this screen, snap to the edges
- int rightOverhang = result[0] + spanX - countX;
- if (rightOverhang > 0) {
- result[0] -= rightOverhang; // Snap to right
- }
- result[0] = Math.max(0, result[0]); // Snap to left
- int bottomOverhang = result[1] + spanY - countY;
- if (bottomOverhang > 0) {
- result[1] -= bottomOverhang; // Snap to bottom
- }
- result[1] = Math.max(0, result[1]); // Snap to top
- }
-
- void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
- int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
- final int oldDragCellX = mDragCell[0];
- final int oldDragCellY = mDragCell[1];
-
- if (v != null && dragOffset == null) {
- mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
- } else {
- mDragCenter.set(originX, originY);
- }
-
- if (dragOutline == null && v == null) {
- return;
- }
-
- if (cellX != oldDragCellX || cellY != oldDragCellY) {
- mDragCell[0] = cellX;
- mDragCell[1] = cellY;
- // Find the top left corner of the rect the object will occupy
- final int[] topLeft = mTmpPoint;
- cellToPoint(cellX, cellY, topLeft);
-
- int left = topLeft[0];
- int top = topLeft[1];
-
- if (v != null && dragOffset == null) {
- // When drawing the drag outline, it did not account for margin offsets
- // added by the view's parent.
- MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
- left += lp.leftMargin;
- top += lp.topMargin;
-
- // Offsets due to the size difference between the View and the dragOutline.
- // There is a size difference to account for the outer blur, which may lie
- // outside the bounds of the view.
- top += (v.getHeight() - dragOutline.getHeight()) / 2;
- // We center about the x axis
- left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
- - dragOutline.getWidth()) / 2;
- } else {
- if (dragOffset != null && dragRegion != null) {
- // Center the drag region *horizontally* in the cell and apply a drag
- // outline offset
- left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
- - dragRegion.width()) / 2;
- top += dragOffset.y;
- } else {
- // Center the drag outline in the cell
- left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
- - dragOutline.getWidth()) / 2;
- top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
- - dragOutline.getHeight()) / 2;
- }
- }
- final int oldIndex = mDragOutlineCurrent;
- mDragOutlineAnims[oldIndex].animateOut();
- mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
- Rect r = mDragOutlines[mDragOutlineCurrent];
- r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
- if (resize) {
- cellToRect(cellX, cellY, spanX, spanY, r);
- }
-
- mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
- mDragOutlineAnims[mDragOutlineCurrent].animateIn();
- }
- }
-
- public void clearDragOutlines() {
- final int oldIndex = mDragOutlineCurrent;
- mDragOutlineAnims[oldIndex].animateOut();
- mDragCell[0] = mDragCell[1] = -1;
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
- int[] result) {
- return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param minSpanX The minimum horizontal span required
- * @param minSpanY The minimum vertical span required
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
- int spanY, int[] result, int[] resultSpan) {
- return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
- result, resultSpan);
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreOccupied If true, the result can be an occupied cell
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
- boolean ignoreOccupied, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY,
- spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
- }
-
- private final Stack<Rect> mTempRectStack = new Stack<Rect>();
- private void lazyInitTempRectStack() {
- if (mTempRectStack.isEmpty()) {
- for (int i = 0; i < mCountX * mCountY; i++) {
- mTempRectStack.push(new Rect());
- }
- }
- }
-
- private void recycleTempRects(Stack<Rect> used) {
- while (!used.isEmpty()) {
- mTempRectStack.push(used.pop());
- }
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param minSpanX The minimum horizontal span required
- * @param minSpanY The minimum vertical span required
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreOccupied If true, the result can be an occupied cell
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
- View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
- boolean[][] occupied) {
- lazyInitTempRectStack();
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
-
- // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
- // to the center of the item, but we are searching based on the top-left cell, so
- // we translate the point over to correspond to the top-left.
- pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
- pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
-
- // Keep track of best-scoring drop area
- final int[] bestXY = result != null ? result : new int[2];
- double bestDistance = Double.MAX_VALUE;
- final Rect bestRect = new Rect(-1, -1, -1, -1);
- final Stack<Rect> validRegions = new Stack<Rect>();
-
- final int countX = mCountX;
- final int countY = mCountY;
-
- if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
- spanX < minSpanX || spanY < minSpanY) {
- return bestXY;
- }
-
- for (int y = 0; y < countY - (minSpanY - 1); y++) {
- inner:
- for (int x = 0; x < countX - (minSpanX - 1); x++) {
- int ySize = -1;
- int xSize = -1;
- if (ignoreOccupied) {
- // First, let's see if this thing fits anywhere
- for (int i = 0; i < minSpanX; i++) {
- for (int j = 0; j < minSpanY; j++) {
- if (occupied[x + i][y + j]) {
- continue inner;
- }
- }
- }
- xSize = minSpanX;
- ySize = minSpanY;
-
- // We know that the item will fit at _some_ acceptable size, now let's see
- // how big we can make it. We'll alternate between incrementing x and y spans
- // until we hit a limit.
- boolean incX = true;
- boolean hitMaxX = xSize >= spanX;
- boolean hitMaxY = ySize >= spanY;
- while (!(hitMaxX && hitMaxY)) {
- if (incX && !hitMaxX) {
- for (int j = 0; j < ySize; j++) {
- if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
- // We can't move out horizontally
- hitMaxX = true;
- }
- }
- if (!hitMaxX) {
- xSize++;
- }
- } else if (!hitMaxY) {
- for (int i = 0; i < xSize; i++) {
- if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
- // We can't move out vertically
- hitMaxY = true;
- }
- }
- if (!hitMaxY) {
- ySize++;
- }
- }
- hitMaxX |= xSize >= spanX;
- hitMaxY |= ySize >= spanY;
- incX = !incX;
- }
- incX = true;
- hitMaxX = xSize >= spanX;
- hitMaxY = ySize >= spanY;
- }
- final int[] cellXY = mTmpXY;
- cellToCenterPoint(x, y, cellXY);
-
- // We verify that the current rect is not a sub-rect of any of our previous
- // candidates. In this case, the current rect is disqualified in favour of the
- // containing rect.
- Rect currentRect = mTempRectStack.pop();
- currentRect.set(x, y, x + xSize, y + ySize);
- boolean contained = false;
- for (Rect r : validRegions) {
- if (r.contains(currentRect)) {
- contained = true;
- break;
- }
- }
- validRegions.push(currentRect);
- double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
- + Math.pow(cellXY[1] - pixelY, 2));
-
- if ((distance <= bestDistance && !contained) ||
- currentRect.contains(bestRect)) {
- bestDistance = distance;
- bestXY[0] = x;
- bestXY[1] = y;
- if (resultSpan != null) {
- resultSpan[0] = xSize;
- resultSpan[1] = ySize;
- }
- bestRect.set(currentRect);
- }
- }
- }
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
-
- // Return -1, -1 if no suitable location found
- if (bestDistance == Double.MAX_VALUE) {
- bestXY[0] = -1;
- bestXY[1] = -1;
- }
- recycleTempRects(validRegions);
- return bestXY;
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location, and will also weigh in a suggested direction vector of the
- * desired location. This method computers distance based on unit grid distances,
- * not pixel distances.
- *
- * @param cellX The X cell nearest to which you want to search for a vacant area.
- * @param cellY The Y cell nearest which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param direction The favored direction in which the views should move from x, y
- * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
- * matches exactly. Otherwise we find the best matching direction.
- * @param occoupied The array which represents which cells in the CellLayout are occupied
- * @param blockOccupied The array which represents which cells in the specified block (cellX,
- * cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
- boolean[][] occupied, boolean blockOccupied[][], int[] result) {
- // Keep track of best-scoring drop area
- final int[] bestXY = result != null ? result : new int[2];
- float bestDistance = Float.MAX_VALUE;
- int bestDirectionScore = Integer.MIN_VALUE;
-
- final int countX = mCountX;
- final int countY = mCountY;
-
- for (int y = 0; y < countY - (spanY - 1); y++) {
- inner:
- for (int x = 0; x < countX - (spanX - 1); x++) {
- // First, let's see if this thing fits anywhere
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
- continue inner;
- }
- }
- }
-
- float distance = (float)
- Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
- int[] curDirection = mTmpPoint;
- computeDirectionVector(x - cellX, y - cellY, curDirection);
- // The direction score is just the dot product of the two candidate direction
- // and that passed in.
- int curDirectionScore = direction[0] * curDirection[0] +
- direction[1] * curDirection[1];
- boolean exactDirectionOnly = false;
- boolean directionMatches = direction[0] == curDirection[0] &&
- direction[0] == curDirection[0];
- if ((directionMatches || !exactDirectionOnly) &&
- Float.compare(distance, bestDistance) < 0 || (Float.compare(distance,
- bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
- bestDistance = distance;
- bestDirectionScore = curDirectionScore;
- bestXY[0] = x;
- bestXY[1] = y;
- }
- }
- }
-
- // Return -1, -1 if no suitable location found
- if (bestDistance == Float.MAX_VALUE) {
- bestXY[0] = -1;
- bestXY[1] = -1;
- }
- return bestXY;
- }
-
- private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
- int[] direction,boolean[][] occupied,
- boolean blockOccupied[][], int[] result) {
- // Keep track of best-scoring drop area
- final int[] bestXY = result != null ? result : new int[2];
- bestXY[0] = -1;
- bestXY[1] = -1;
- float bestDistance = Float.MAX_VALUE;
-
- // We use this to march in a single direction
- if ((direction[0] != 0 && direction[1] != 0) ||
- (direction[0] == 0 && direction[1] == 0)) {
- return bestXY;
- }
-
- // This will only incrememnet one of x or y based on the assertion above
- int x = cellX + direction[0];
- int y = cellY + direction[1];
- while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
-
- boolean fail = false;
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
- fail = true;
- }
- }
- }
- if (!fail) {
- float distance = (float)
- Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
- if (Float.compare(distance, bestDistance) < 0) {
- bestDistance = distance;
- bestXY[0] = x;
- bestXY[1] = y;
- }
- }
- x += direction[0];
- y += direction[1];
- }
- return bestXY;
- }
-
- private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
- int[] direction, ItemConfiguration currentState) {
- CellAndSpan c = currentState.map.get(v);
- boolean success = false;
- markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
- markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
-
- findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
-
- if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
- c.x = mTempLocation[0];
- c.y = mTempLocation[1];
- success = true;
-
- }
- markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
- return success;
- }
-
- // This method looks in the specified direction to see if there is an additional view
- // immediately adjecent in that direction
- private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
- boolean[][] occupied, View dragView, ItemConfiguration currentState) {
- boolean found = false;
-
- int childCount = mShortcutsAndWidgets.getChildCount();
- Rect r0 = new Rect(boundingRect);
- Rect r1 = new Rect();
-
- int deltaX = 0;
- int deltaY = 0;
- if (direction[1] < 0) {
- r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
- deltaY = -1;
- } else if (direction[1] > 0) {
- r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
- deltaY = 1;
- } else if (direction[0] < 0) {
- r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
- deltaX = -1;
- } else if (direction[0] > 0) {
- r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
- deltaX = 1;
- }
-
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- if (views.contains(child) || child == dragView) continue;
- CellAndSpan c = currentState.map.get(child);
-
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
- if (Rect.intersects(r0, r1)) {
- if (!lp.canReorder) {
- return false;
- }
- boolean pushed = false;
- for (int x = c.x; x < c.x + c.spanX; x++) {
- for (int y = c.y; y < c.y + c.spanY; y++) {
- boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
- && y - deltaY >= 0 && y - deltaY < mCountY;
- if (inBounds && occupied[x - deltaX][y - deltaY]) {
- pushed = true;
- }
- }
- }
- if (pushed) {
- views.add(child);
- boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
- found = true;
- }
- }
- }
- return found;
- }
-
- private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
- int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
- if (views.size() == 0) return true;
-
- boolean success = false;
- Rect boundingRect = null;
- // We construct a rect which represents the entire group of views passed in
- for (View v: views) {
- CellAndSpan c = currentState.map.get(v);
- if (boundingRect == null) {
- boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
- } else {
- boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
- }
- }
-
- @SuppressWarnings("unchecked")
- ArrayList<View> dup = (ArrayList<View>) views.clone();
- // We try and expand the group of views in the direction vector passed, based on
- // whether they are physically adjacent, ie. based on "push mechanics".
- while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
- currentState)) {
- }
-
- // Mark the occupied state as false for the group of views we want to move.
- for (View v: dup) {
- CellAndSpan c = currentState.map.get(v);
- markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
- }
-
- boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
- int top = boundingRect.top;
- int left = boundingRect.left;
- // We mark more precisely which parts of the bounding rect are truly occupied, allowing
- // for tetris-style interlocking.
- for (View v: dup) {
- CellAndSpan c = currentState.map.get(v);
- markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
- }
-
- markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
-
- if (push) {
- findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
- boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
- } else {
- findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
- boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
- }
-
- // If we successfuly found a location by pushing the block of views, we commit it
- if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
- int deltaX = mTempLocation[0] - boundingRect.left;
- int deltaY = mTempLocation[1] - boundingRect.top;
- for (View v: dup) {
- CellAndSpan c = currentState.map.get(v);
- c.x += deltaX;
- c.y += deltaY;
- }
- success = true;
- }
-
- // In either case, we set the occupied array as marked for the location of the views
- for (View v: dup) {
- CellAndSpan c = currentState.map.get(v);
- markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
- }
- return success;
- }
-
- private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
- markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
- }
-
- // This method tries to find a reordering solution which satisfies the push mechanic by trying
- // to push items in each of the cardinal directions, in an order based on the direction vector
- // passed.
- private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied,
- int[] direction, View ignoreView, ItemConfiguration solution) {
- if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) {
- // If the direction vector has two non-zero components, we try pushing
- // separately in each of the components.
- int temp = direction[1];
- direction[1] = 0;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
- direction[1] = temp;
- temp = direction[0];
- direction[0] = 0;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
- // Revert the direction
- direction[0] = temp;
-
- // Now we try pushing in each component of the opposite direction
- direction[0] *= -1;
- direction[1] *= -1;
- temp = direction[1];
- direction[1] = 0;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
-
- direction[1] = temp;
- temp = direction[0];
- direction[0] = 0;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
- // revert the direction
- direction[0] = temp;
- direction[0] *= -1;
- direction[1] *= -1;
-
- } else {
- // If the direction vector has a single non-zero component, we push first in the
- // direction of the vector
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
-
- // Then we try the opposite direction
- direction[0] *= -1;
- direction[1] *= -1;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
- // Switch the direction back
- direction[0] *= -1;
- direction[1] *= -1;
-
- // If we have failed to find a push solution with the above, then we try
- // to find a solution by pushing along the perpendicular axis.
-
- // Swap the components
- int temp = direction[1];
- direction[1] = direction[0];
- direction[0] = temp;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
-
- // Then we try the opposite direction
- direction[0] *= -1;
- direction[1] *= -1;
- if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
- ignoreView, solution)) {
- return true;
- }
- // Switch the direction back
- direction[0] *= -1;
- direction[1] *= -1;
-
- // Swap the components back
- temp = direction[1];
- direction[1] = direction[0];
- direction[0] = temp;
- }
- return false;
- }
-
- private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
- View ignoreView, ItemConfiguration solution) {
- // Return early if get invalid cell positions
- if (cellX < 0 || cellY < 0) return false;
-
- mIntersectingViews.clear();
- mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
-
- // Mark the desired location of the view currently being dragged.
- if (ignoreView != null) {
- CellAndSpan c = solution.map.get(ignoreView);
- if (c != null) {
- c.x = cellX;
- c.y = cellY;
- }
- }
- Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
- Rect r1 = new Rect();
- for (View child: solution.map.keySet()) {
- if (child == ignoreView) continue;
- CellAndSpan c = solution.map.get(child);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
- if (Rect.intersects(r0, r1)) {
- if (!lp.canReorder) {
- return false;
- }
- mIntersectingViews.add(child);
- }
- }
-
- // First we try to find a solution which respects the push mechanic. That is,
- // we try to find a solution such that no displaced item travels through another item
- // without also displacing that item.
- if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView,
- solution)) {
- return true;
- }
-
- // Next we try moving the views as a block, but without requiring the push mechanic.
- if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
- solution)) {
- return true;
- }
-
- // Ok, they couldn't move as a block, let's move them individually
- for (View v : mIntersectingViews) {
- if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
- return false;
- }
- }
- return true;
- }
-
- /*
- * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
- * the provided point and the provided cell
- */
- private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
- double angle = Math.atan(((float) deltaY) / deltaX);
-
- result[0] = 0;
- result[1] = 0;
- if (Math.abs(Math.cos(angle)) > 0.5f) {
- result[0] = (int) Math.signum(deltaX);
- }
- if (Math.abs(Math.sin(angle)) > 0.5f) {
- result[1] = (int) Math.signum(deltaY);
- }
- }
-
- private void copyOccupiedArray(boolean[][] occupied) {
- for (int i = 0; i < mCountX; i++) {
- for (int j = 0; j < mCountY; j++) {
- occupied[i][j] = mOccupied[i][j];
- }
- }
- }
-
- ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
- int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
- // Copy the current state into the solution. This solution will be manipulated as necessary.
- copyCurrentStateToSolution(solution, false);
- // Copy the current occupied array into the temporary occupied array. This array will be
- // manipulated as necessary to find a solution.
- copyOccupiedArray(mTmpOccupied);
-
- // We find the nearest cell into which we would place the dragged item, assuming there's
- // nothing in its way.
- int result[] = new int[2];
- result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
-
- boolean success = false;
- // First we try the exact nearest position of the item being dragged,
- // we will then want to try to move this around to other neighbouring positions
- success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
- solution);
-
- if (!success) {
- // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
- // x, then 1 in y etc.
- if (spanX > minSpanX && (minSpanY == spanY || decX)) {
- return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
- dragView, false, solution);
- } else if (spanY > minSpanY) {
- return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
- dragView, true, solution);
- }
- solution.isSolution = false;
- } else {
- solution.isSolution = true;
- solution.dragViewX = result[0];
- solution.dragViewY = result[1];
- solution.dragViewSpanX = spanX;
- solution.dragViewSpanY = spanY;
- }
- return solution;
- }
-
- private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- CellAndSpan c;
- if (temp) {
- c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
- } else {
- c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
- }
- solution.map.put(child, c);
- }
- }
-
- private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
- for (int i = 0; i < mCountX; i++) {
- for (int j = 0; j < mCountY; j++) {
- mTmpOccupied[i][j] = false;
- }
- }
-
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- if (child == dragView) continue;
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- CellAndSpan c = solution.map.get(child);
- if (c != null) {
- lp.tmpCellX = c.x;
- lp.tmpCellY = c.y;
- lp.cellHSpan = c.spanX;
- lp.cellVSpan = c.spanY;
- markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
- }
- }
- markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
- solution.dragViewSpanY, mTmpOccupied, true);
- }
-
- private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
- commitDragView) {
-
- boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
- for (int i = 0; i < mCountX; i++) {
- for (int j = 0; j < mCountY; j++) {
- occupied[i][j] = false;
- }
- }
-
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- if (child == dragView) continue;
- CellAndSpan c = solution.map.get(child);
- if (c != null) {
- animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
- DESTRUCTIVE_REORDER, false);
- markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
- }
- }
- if (commitDragView) {
- markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
- solution.dragViewSpanY, occupied, true);
- }
- }
-
- // This method starts or changes the reorder hint animations
- private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- if (child == dragView) continue;
- CellAndSpan c = solution.map.get(child);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (c != null) {
- ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
- c.x, c.y, c.spanX, c.spanY);
- rha.animate();
- }
- }
- }
-
- // Class which represents the reorder hint animations. These animations show that an item is
- // in a temporary state, and hint at where the item will return to.
- class ReorderHintAnimation {
- View child;
- float finalDeltaX;
- float finalDeltaY;
- float initDeltaX;
- float initDeltaY;
- float finalScale;
- float initScale;
- private static final int DURATION = 300;
- Animator a;
-
- public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
- int spanX, int spanY) {
- regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
- final int x0 = mTmpPoint[0];
- final int y0 = mTmpPoint[1];
- regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
- final int x1 = mTmpPoint[0];
- final int y1 = mTmpPoint[1];
- final int dX = x1 - x0;
- final int dY = y1 - y0;
- finalDeltaX = 0;
- finalDeltaY = 0;
- if (dX == dY && dX == 0) {
- } else {
- if (dY == 0) {
- finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude;
- } else if (dX == 0) {
- finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude;
- } else {
- double angle = Math.atan( (float) (dY) / dX);
- finalDeltaX = (int) (- Math.signum(dX) *
- Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude));
- finalDeltaY = (int) (- Math.signum(dY) *
- Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude));
- }
- }
- initDeltaX = child.getTranslationX();
- initDeltaY = child.getTranslationY();
- finalScale = 1.0f - 4.0f / child.getWidth();
- initScale = child.getScaleX();
-
- child.setPivotY(child.getMeasuredHeight() * 0.5f);
- child.setPivotX(child.getMeasuredWidth() * 0.5f);
- this.child = child;
- }
-
- void animate() {
- if (mShakeAnimators.containsKey(child)) {
- ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
- oldAnimation.cancel();
- mShakeAnimators.remove(child);
- if (finalDeltaX == 0 && finalDeltaY == 0) {
- completeAnimationImmediately();
- return;
- }
- }
- if (finalDeltaX == 0 && finalDeltaY == 0) {
- return;
- }
- ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- a = va;
- va.setRepeatMode(ValueAnimator.REVERSE);
- va.setRepeatCount(ValueAnimator.INFINITE);
- va.setDuration(DURATION);
- va.setStartDelay((int) (Math.random() * 60));
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float r = ((Float) animation.getAnimatedValue()).floatValue();
- float x = r * finalDeltaX + (1 - r) * initDeltaX;
- float y = r * finalDeltaY + (1 - r) * initDeltaY;
- child.setTranslationX(x);
- child.setTranslationY(y);
- float s = r * finalScale + (1 - r) * initScale;
- child.setScaleX(s);
- child.setScaleY(s);
- }
- });
- va.addListener(new AnimatorListenerAdapter() {
- public void onAnimationRepeat(Animator animation) {
- // We make sure to end only after a full period
- initDeltaX = 0;
- initDeltaY = 0;
- initScale = 1.0f;
- }
- });
- mShakeAnimators.put(child, this);
- va.start();
- }
-
- private void cancel() {
- if (a != null) {
- a.cancel();
- }
- }
-
- private void completeAnimationImmediately() {
- if (a != null) {
- a.cancel();
- }
-
- AnimatorSet s = new AnimatorSet();
- a = s;
- s.playTogether(
- ObjectAnimator.ofFloat(child, "scaleX", 1f),
- ObjectAnimator.ofFloat(child, "scaleY", 1f),
- ObjectAnimator.ofFloat(child, "translationX", 0f),
- ObjectAnimator.ofFloat(child, "translationY", 0f)
- );
- s.setDuration(REORDER_ANIMATION_DURATION);
- s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
- s.start();
- }
- }
-
- private void completeAndClearReorderHintAnimations() {
- for (ReorderHintAnimation a: mShakeAnimators.values()) {
- a.completeAnimationImmediately();
- }
- mShakeAnimators.clear();
- }
-
- private void commitTempPlacement() {
- for (int i = 0; i < mCountX; i++) {
- for (int j = 0; j < mCountY; j++) {
- mOccupied[i][j] = mTmpOccupied[i][j];
- }
- }
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- ItemInfo info = (ItemInfo) child.getTag();
- // We do a null check here because the item info can be null in the case of the
- // AllApps button in the hotseat.
- if (info != null) {
- info.cellX = lp.cellX = lp.tmpCellX;
- info.cellY = lp.cellY = lp.tmpCellY;
- info.spanX = lp.cellHSpan;
- info.spanY = lp.cellVSpan;
- }
- }
- mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
- }
-
- public void setUseTempCoords(boolean useTempCoords) {
- int childCount = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < childCount; i++) {
- LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
- lp.useTmpCoords = useTempCoords;
- }
- }
-
- ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
- int spanX, int spanY, View dragView, ItemConfiguration solution) {
- int[] result = new int[2];
- int[] resultSpan = new int[2];
- findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
- resultSpan);
- if (result[0] >= 0 && result[1] >= 0) {
- copyCurrentStateToSolution(solution, false);
- solution.dragViewX = result[0];
- solution.dragViewY = result[1];
- solution.dragViewSpanX = resultSpan[0];
- solution.dragViewSpanY = resultSpan[1];
- solution.isSolution = true;
- } else {
- solution.isSolution = false;
- }
- return solution;
- }
-
- public void prepareChildForDrag(View child) {
- markCellsAsUnoccupiedForView(child);
- }
-
- /* This seems like it should be obvious and straight-forward, but when the direction vector
- needs to match with the notion of the dragView pushing other views, we have to employ
- a slightly more subtle notion of the direction vector. The question is what two points is
- the vector between? The center of the dragView and its desired destination? Not quite, as
- this doesn't necessarily coincide with the interaction of the dragView and items occupying
- those cells. Instead we use some heuristics to often lock the vector to up, down, left
- or right, which helps make pushing feel right.
- */
- private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
- int spanY, View dragView, int[] resultDirection) {
- int[] targetDestination = new int[2];
-
- findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
- Rect dragRect = new Rect();
- regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
- dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
-
- Rect dropRegionRect = new Rect();
- getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
- dragView, dropRegionRect, mIntersectingViews);
-
- int dropRegionSpanX = dropRegionRect.width();
- int dropRegionSpanY = dropRegionRect.height();
-
- regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
- dropRegionRect.height(), dropRegionRect);
-
- int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
- int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
-
- if (dropRegionSpanX == mCountX || spanX == mCountX) {
- deltaX = 0;
- }
- if (dropRegionSpanY == mCountY || spanY == mCountY) {
- deltaY = 0;
- }
-
- if (deltaX == 0 && deltaY == 0) {
- // No idea what to do, give a random direction.
- resultDirection[0] = 1;
- resultDirection[1] = 0;
- } else {
- computeDirectionVector(deltaX, deltaY, resultDirection);
- }
- }
-
- // For a given cell and span, fetch the set of views intersecting the region.
- private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
- View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
- if (boundingRect != null) {
- boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
- }
- intersectingViews.clear();
- Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
- Rect r1 = new Rect();
- final int count = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- if (child == dragView) continue;
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
- if (Rect.intersects(r0, r1)) {
- mIntersectingViews.add(child);
- if (boundingRect != null) {
- boundingRect.union(r1);
- }
- }
- }
- }
-
- boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
- View dragView, int[] result) {
- result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
- getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
- mIntersectingViews);
- return !mIntersectingViews.isEmpty();
- }
-
- void revertTempState() {
- if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
- final int count = mShortcutsAndWidgets.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = mShortcutsAndWidgets.getChildAt(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
- lp.tmpCellX = lp.cellX;
- lp.tmpCellY = lp.cellY;
- animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
- 0, false, false);
- }
- }
- completeAndClearReorderHintAnimations();
- setItemPlacementDirty(false);
- }
-
- boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
- View dragView, int[] direction, boolean commit) {
- int[] pixelXY = new int[2];
- regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
-
- // First we determine if things have moved enough to cause a different layout
- ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
- spanX, spanY, direction, dragView, true, new ItemConfiguration());
-
- setUseTempCoords(true);
- if (swapSolution != null && swapSolution.isSolution) {
- // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
- // committing anything or animating anything as we just want to determine if a solution
- // exists
- copySolutionToTempState(swapSolution, dragView);
- setItemPlacementDirty(true);
- animateItemsToSolution(swapSolution, dragView, commit);
-
- if (commit) {
- commitTempPlacement();
- completeAndClearReorderHintAnimations();
- setItemPlacementDirty(false);
- } else {
- beginOrAdjustHintAnimations(swapSolution, dragView,
- REORDER_ANIMATION_DURATION);
- }
- mShortcutsAndWidgets.requestLayout();
- }
- return swapSolution.isSolution;
- }
-
- int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
- View dragView, int[] result, int resultSpan[], int mode) {
- // First we determine if things have moved enough to cause a different layout
- result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
-
- if (resultSpan == null) {
- resultSpan = new int[2];
- }
-
- // When we are checking drop validity or actually dropping, we don't recompute the
- // direction vector, since we want the solution to match the preview, and it's possible
- // that the exact position of the item has changed to result in a new reordering outcome.
- if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
- && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
- mDirectionVector[0] = mPreviousReorderDirection[0];
- mDirectionVector[1] = mPreviousReorderDirection[1];
- // We reset this vector after drop
- if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
- mPreviousReorderDirection[0] = INVALID_DIRECTION;
- mPreviousReorderDirection[1] = INVALID_DIRECTION;
- }
- } else {
- getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
- mPreviousReorderDirection[0] = mDirectionVector[0];
- mPreviousReorderDirection[1] = mDirectionVector[1];
- }
-
- ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
- spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration());
-
- // We attempt the approach which doesn't shuffle views at all
- ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
- minSpanY, spanX, spanY, dragView, new ItemConfiguration());
-
- ItemConfiguration finalSolution = null;
- if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
- finalSolution = swapSolution;
- } else if (noShuffleSolution.isSolution) {
- finalSolution = noShuffleSolution;
- }
-
- boolean foundSolution = true;
- if (!DESTRUCTIVE_REORDER) {
- setUseTempCoords(true);
- }
-
- if (finalSolution != null) {
- result[0] = finalSolution.dragViewX;
- result[1] = finalSolution.dragViewY;
- resultSpan[0] = finalSolution.dragViewSpanX;
- resultSpan[1] = finalSolution.dragViewSpanY;
-
- // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
- // committing anything or animating anything as we just want to determine if a solution
- // exists
- if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
- if (!DESTRUCTIVE_REORDER) {
- copySolutionToTempState(finalSolution, dragView);
- }
- setItemPlacementDirty(true);
- animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
-
- if (!DESTRUCTIVE_REORDER &&
- (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
- commitTempPlacement();
- completeAndClearReorderHintAnimations();
- setItemPlacementDirty(false);
- } else {
- beginOrAdjustHintAnimations(finalSolution, dragView,
- REORDER_ANIMATION_DURATION);
- }
- }
- } else {
- foundSolution = false;
- result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
- }
-
- if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
- setUseTempCoords(false);
- }
-
- mShortcutsAndWidgets.requestLayout();
- return result;
- }
-
- void setItemPlacementDirty(boolean dirty) {
- mItemPlacementDirty = dirty;
- }
- boolean isItemPlacementDirty() {
- return mItemPlacementDirty;
- }
-
- private class ItemConfiguration {
- HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
- boolean isSolution = false;
- int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
-
- int area() {
- return dragViewSpanX * dragViewSpanY;
- }
- }
-
- private class CellAndSpan {
- int x, y;
- int spanX, spanY;
-
- public CellAndSpan(int x, int y, int spanX, int spanY) {
- this.x = x;
- this.y = y;
- this.spanX = spanX;
- this.spanY = spanY;
- }
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(
- int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param minSpanX The minimum horizontal span required
- * @param minSpanY The minimum vertical span required
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
- int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
- return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
- result, resultSpan, mOccupied);
- }
-
- /**
- * Find a starting cell position that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestArea(
- int pixelX, int pixelY, int spanX, int spanY, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
- }
-
- boolean existsEmptyCell() {
- return findCellForSpan(null, 1, 1);
- }
-
- /**
- * Finds the upper-left coordinate of the first rectangle in the grid that can
- * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
- * then this method will only return coordinates for rectangles that contain the cell
- * (intersectX, intersectY)
- *
- * @param cellXY The array that will contain the position of a vacant cell if such a cell
- * can be found.
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- *
- * @return True if a vacant cell of the specified dimension was found, false otherwise.
- */
- boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
- }
-
- /**
- * Like above, but ignores any cells occupied by the item "ignoreView"
- *
- * @param cellXY The array that will contain the position of a vacant cell if such a cell
- * can be found.
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @return
- */
- boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
- ignoreView, mOccupied);
- }
-
- /**
- * Like above, but if intersectX and intersectY are not -1, then this method will try to
- * return coordinates for rectangles that contain the cell [intersectX, intersectY]
- *
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @param intersectX The X coordinate of the cell that we should try to overlap
- * @param intersectX The Y coordinate of the cell that we should try to overlap
- *
- * @return True if a vacant cell of the specified dimension was found, false otherwise.
- */
- boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY) {
- return findCellForSpanThatIntersectsIgnoring(
- cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
- }
-
- /**
- * The superset of the above two methods
- */
- boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
-
- boolean foundCell = false;
- while (true) {
- int startX = 0;
- if (intersectX >= 0) {
- startX = Math.max(startX, intersectX - (spanX - 1));
- }
- int endX = mCountX - (spanX - 1);
- if (intersectX >= 0) {
- endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
- }
- int startY = 0;
- if (intersectY >= 0) {
- startY = Math.max(startY, intersectY - (spanY - 1));
- }
- int endY = mCountY - (spanY - 1);
- if (intersectY >= 0) {
- endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
- }
-
- for (int y = startY; y < endY && !foundCell; y++) {
- inner:
- for (int x = startX; x < endX; x++) {
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j]) {
- // small optimization: we can skip to after the column we just found
- // an occupied cell
- x += i;
- continue inner;
- }
- }
- }
- if (cellXY != null) {
- cellXY[0] = x;
- cellXY[1] = y;
- }
- foundCell = true;
- break;
- }
- }
- if (intersectX == -1 && intersectY == -1) {
- break;
- } else {
- // if we failed to find anything, try again but without any requirements of
- // intersecting
- intersectX = -1;
- intersectY = -1;
- continue;
- }
- }
-
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
- return foundCell;
- }
-
- /**
- * A drag event has begun over this layout.
- * It may have begun over this layout (in which case onDragChild is called first),
- * or it may have begun on another layout.
- */
- void onDragEnter() {
- mDragEnforcer.onDragEnter();
- mDragging = true;
- }
-
- /**
- * Called when drag has left this CellLayout or has been completed (successfully or not)
- */
- void onDragExit() {
- mDragEnforcer.onDragExit();
- // This can actually be called when we aren't in a drag, e.g. when adding a new
- // item to this layout via the customize drawer.
- // Guard against that case.
- if (mDragging) {
- mDragging = false;
- }
-
- // Invalidate the drag data
- mDragCell[0] = mDragCell[1] = -1;
- mDragOutlineAnims[mDragOutlineCurrent].animateOut();
- mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
- revertTempState();
- setIsDragOverlapping(false);
- }
-
- /**
- * Mark a child as having been dropped.
- * At the beginning of the drag operation, the child may have been on another
- * screen, but it is re-parented before this method is called.
- *
- * @param child The child that is being dropped
- */
- void onDropChild(View child) {
- if (child != null) {
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.dropped = true;
- child.requestLayout();
- }
- }
-
- /**
- * Computes a bounding rectangle for a range of cells
- *
- * @param cellX X coordinate of upper left corner expressed as a cell position
- * @param cellY Y coordinate of upper left corner expressed as a cell position
- * @param cellHSpan Width in cells
- * @param cellVSpan Height in cells
- * @param resultRect Rect into which to put the results
- */
- public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
- final int widthGap = mWidthGap;
- final int heightGap = mHeightGap;
-
- final int hStartPadding = getPaddingLeft();
- final int vStartPadding = getPaddingTop();
-
- int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
- int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
-
- int x = hStartPadding + cellX * (cellWidth + widthGap);
- int y = vStartPadding + cellY * (cellHeight + heightGap);
-
- resultRect.set(x, y, x + width, y + height);
- }
-
- /**
- * Computes the required horizontal and vertical cell spans to always
- * fit the given rectangle.
- *
- * @param width Width in pixels
- * @param height Height in pixels
- * @param result An array of length 2 in which to store the result (may be null).
- */
- public int[] rectToCell(int width, int height, int[] result) {
- return rectToCell(getResources(), width, height, result);
- }
-
- public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
- // Always assume we're working with the smallest span to make sure we
- // reserve enough space in both orientations.
- int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
- int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
- int smallerSize = Math.min(actualWidth, actualHeight);
-
- // Always round up to next largest cell
- int spanX = (int) Math.ceil(width / (float) smallerSize);
- int spanY = (int) Math.ceil(height / (float) smallerSize);
-
- if (result == null) {
- return new int[] { spanX, spanY };
- }
- result[0] = spanX;
- result[1] = spanY;
- return result;
- }
-
- public int[] cellSpansToSize(int hSpans, int vSpans) {
- int[] size = new int[2];
- size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
- size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
- return size;
- }
-
- /**
- * Calculate the grid spans needed to fit given item
- */
- public void calculateSpans(ItemInfo info) {
- final int minWidth;
- final int minHeight;
-
- if (info instanceof LauncherAppWidgetInfo) {
- minWidth = ((LauncherAppWidgetInfo) info).minWidth;
- minHeight = ((LauncherAppWidgetInfo) info).minHeight;
- } else if (info instanceof PendingAddWidgetInfo) {
- minWidth = ((PendingAddWidgetInfo) info).minWidth;
- minHeight = ((PendingAddWidgetInfo) info).minHeight;
- } else {
- // It's not a widget, so it must be 1x1
- info.spanX = info.spanY = 1;
- return;
- }
- int[] spans = rectToCell(minWidth, minHeight, null);
- info.spanX = spans[0];
- info.spanY = spans[1];
- }
-
- /**
- * Find the first vacant cell, if there is one.
- *
- * @param vacant Holds the x and y coordinate of the vacant cell
- * @param spanX Horizontal cell span.
- * @param spanY Vertical cell span.
- *
- * @return True if a vacant cell was found
- */
- public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
-
- return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
- }
-
- static boolean findVacantCell(int[] vacant, int spanX, int spanY,
- int xCount, int yCount, boolean[][] occupied) {
-
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- boolean available = !occupied[x][y];
-out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
- for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
- available = available && !occupied[i][j];
- if (!available) break out;
- }
- }
-
- if (available) {
- vacant[0] = x;
- vacant[1] = y;
- return true;
- }
- }
- }
-
- return false;
- }
-
- private void clearOccupiedCells() {
- for (int x = 0; x < mCountX; x++) {
- for (int y = 0; y < mCountY; y++) {
- mOccupied[x][y] = false;
- }
- }
- }
-
- public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
- markCellsAsUnoccupiedForView(view);
- markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
- }
-
- public void markCellsAsOccupiedForView(View view) {
- markCellsAsOccupiedForView(view, mOccupied);
- }
- public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
- if (view == null || view.getParent() != mShortcutsAndWidgets) return;
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
- }
-
- public void markCellsAsUnoccupiedForView(View view) {
- markCellsAsUnoccupiedForView(view, mOccupied);
- }
- public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
- if (view == null || view.getParent() != mShortcutsAndWidgets) return;
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
- }
-
- private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
- boolean value) {
- if (cellX < 0 || cellY < 0) return;
- for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
- for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
- occupied[x][y] = value;
- }
- }
- }
-
- public int getDesiredWidth() {
- return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
- (Math.max((mCountX - 1), 0) * mWidthGap);
- }
-
- public int getDesiredHeight() {
- return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
- (Math.max((mCountY - 1), 0) * mHeightGap);
- }
-
- public boolean isOccupied(int x, int y) {
- if (x < mCountX && y < mCountY) {
- return mOccupied[x][y];
- } else {
- throw new RuntimeException("Position exceeds the bound of this CellLayout");
- }
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new CellLayout.LayoutParams(getContext(), attrs);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof CellLayout.LayoutParams;
- }
-
- @Override
- protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
- return new CellLayout.LayoutParams(p);
- }
-
- public static class CellLayoutAnimationController extends LayoutAnimationController {
- public CellLayoutAnimationController(Animation animation, float delay) {
- super(animation, delay);
- }
-
- @Override
- protected long getDelayForView(View view) {
- return (int) (Math.random() * 150);
- }
- }
-
- public static class LayoutParams extends ViewGroup.MarginLayoutParams {
- /**
- * Horizontal location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellX;
-
- /**
- * Vertical location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellY;
-
- /**
- * Temporary horizontal location of the item in the grid during reorder
- */
- public int tmpCellX;
-
- /**
- * Temporary vertical location of the item in the grid during reorder
- */
- public int tmpCellY;
-
- /**
- * Indicates that the temporary coordinates should be used to layout the items
- */
- public boolean useTmpCoords;
-
- /**
- * Number of cells spanned horizontally by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellHSpan;
-
- /**
- * Number of cells spanned vertically by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellVSpan;
-
- /**
- * Indicates whether the item will set its x, y, width and height parameters freely,
- * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
- */
- public boolean isLockedToGrid = true;
-
- /**
- * Indicates whether this item can be reordered. Always true except in the case of the
- * the AllApps button.
- */
- public boolean canReorder = true;
-
- // X coordinate of the view in the layout.
- @ViewDebug.ExportedProperty
- int x;
- // Y coordinate of the view in the layout.
- @ViewDebug.ExportedProperty
- int y;
-
- boolean dropped;
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
- cellHSpan = 1;
- cellVSpan = 1;
- }
-
- public LayoutParams(ViewGroup.LayoutParams source) {
- super(source);
- cellHSpan = 1;
- cellVSpan = 1;
- }
-
- public LayoutParams(LayoutParams source) {
- super(source);
- this.cellX = source.cellX;
- this.cellY = source.cellY;
- this.cellHSpan = source.cellHSpan;
- this.cellVSpan = source.cellVSpan;
- }
-
- public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
- super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- this.cellX = cellX;
- this.cellY = cellY;
- this.cellHSpan = cellHSpan;
- this.cellVSpan = cellVSpan;
- }
-
- public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
- if (isLockedToGrid) {
- final int myCellHSpan = cellHSpan;
- final int myCellVSpan = cellVSpan;
- final int myCellX = useTmpCoords ? tmpCellX : cellX;
- final int myCellY = useTmpCoords ? tmpCellY : cellY;
-
- width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
- leftMargin - rightMargin;
- height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
- topMargin - bottomMargin;
- x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
- y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
- }
- }
-
- public String toString() {
- return "(" + this.cellX + ", " + this.cellY + ")";
- }
-
- public void setWidth(int width) {
- this.width = width;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setHeight(int height) {
- this.height = height;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getX() {
- return x;
- }
-
- public void setY(int y) {
- this.y = y;
- }
-
- public int getY() {
- return y;
- }
- }
-
- // This class stores info for two purposes:
- // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
- // its spanX, spanY, and the screen it is on
- // 2. When long clicking on an empty cell in a CellLayout, we save information about the
- // cellX and cellY coordinates and which page was clicked. We then set this as a tag on
- // the CellLayout that was long clicked
- static final class CellInfo {
- View cell;
- int cellX = -1;
- int cellY = -1;
- int spanX;
- int spanY;
- int screen;
- long container;
-
- @Override
- public String toString() {
- return "Cell[view=" + (cell == null ? "null" : cell.getClass())
- + ", x=" + cellX + ", y=" + cellY + "]";
- }
- }
-
- public boolean lastDownOnOccupiedCell() {
- return mLastDownOnOccupiedCell;
- }
-}
diff --git a/src/com/android/launcher2/CheckLongPressHelper.java b/src/com/android/launcher2/CheckLongPressHelper.java
deleted file mode 100644
index 5c3752ad6..000000000
--- a/src/com/android/launcher2/CheckLongPressHelper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2012 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.view.View;
-
-public class CheckLongPressHelper {
- private View mView;
- private boolean mHasPerformedLongPress;
- private CheckForLongPress mPendingCheckForLongPress;
-
- class CheckForLongPress implements Runnable {
- public void run() {
- if ((mView.getParent() != null) && mView.hasWindowFocus()
- && !mHasPerformedLongPress) {
- if (mView.performLongClick()) {
- mView.setPressed(false);
- mHasPerformedLongPress = true;
- }
- }
- }
- }
-
- public CheckLongPressHelper(View v) {
- mView = v;
- }
-
- public void postCheckForLongPress() {
- mHasPerformedLongPress = false;
-
- if (mPendingCheckForLongPress == null) {
- mPendingCheckForLongPress = new CheckForLongPress();
- }
- mView.postDelayed(mPendingCheckForLongPress, LauncherApplication.getLongPressTimeout());
- }
-
- public void cancelLongPress() {
- mHasPerformedLongPress = false;
- if (mPendingCheckForLongPress != null) {
- mView.removeCallbacks(mPendingCheckForLongPress);
- mPendingCheckForLongPress = null;
- }
- }
-
- public boolean hasPerformedLongPress() {
- return mHasPerformedLongPress;
- }
-}
diff --git a/src/com/android/launcher2/Cling.java b/src/com/android/launcher2/Cling.java
deleted file mode 100644
index 646c54e90..000000000
--- a/src/com/android/launcher2/Cling.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.FocusFinder;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.FrameLayout;
-
-import com.android.launcher.R;
-
-public class Cling extends FrameLayout {
-
- static final String WORKSPACE_CLING_DISMISSED_KEY = "cling.workspace.dismissed";
- static final String ALLAPPS_CLING_DISMISSED_KEY = "cling.allapps.dismissed";
- static final String FOLDER_CLING_DISMISSED_KEY = "cling.folder.dismissed";
-
- private static String WORKSPACE_PORTRAIT = "workspace_portrait";
- private static String WORKSPACE_LANDSCAPE = "workspace_landscape";
- private static String WORKSPACE_LARGE = "workspace_large";
- private static String WORKSPACE_CUSTOM = "workspace_custom";
-
- private static String ALLAPPS_PORTRAIT = "all_apps_portrait";
- private static String ALLAPPS_LANDSCAPE = "all_apps_landscape";
- private static String ALLAPPS_LARGE = "all_apps_large";
-
- private static String FOLDER_PORTRAIT = "folder_portrait";
- private static String FOLDER_LANDSCAPE = "folder_landscape";
- private static String FOLDER_LARGE = "folder_large";
-
- private Launcher mLauncher;
- private boolean mIsInitialized;
- private String mDrawIdentifier;
- private Drawable mBackground;
- private Drawable mPunchThroughGraphic;
- private Drawable mHandTouchGraphic;
- private int mPunchThroughGraphicCenterRadius;
- private int mAppIconSize;
- private int mButtonBarHeight;
- private float mRevealRadius;
- private int[] mPositionData;
-
- private Paint mErasePaint;
-
- public Cling(Context context) {
- this(context, null, 0);
- }
-
- public Cling(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public Cling(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0);
- mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier);
- a.recycle();
- }
-
- void init(Launcher l, int[] positionData) {
- if (!mIsInitialized) {
- mLauncher = l;
- mPositionData = positionData;
-
- Resources r = getContext().getResources();
-
- mPunchThroughGraphic = r.getDrawable(R.drawable.cling);
- mPunchThroughGraphicCenterRadius =
- r.getDimensionPixelSize(R.dimen.clingPunchThroughGraphicCenterRadius);
- mAppIconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
- mRevealRadius = r.getDimensionPixelSize(R.dimen.reveal_radius) * 1f;
- mButtonBarHeight = r.getDimensionPixelSize(R.dimen.button_bar_height);
-
- mErasePaint = new Paint();
- mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
- mErasePaint.setColor(0xFFFFFF);
- mErasePaint.setAlpha(0);
-
- mIsInitialized = true;
- }
- }
-
- void cleanup() {
- mBackground = null;
- mPunchThroughGraphic = null;
- mHandTouchGraphic = null;
- mIsInitialized = false;
- }
-
- public String getDrawIdentifier() {
- return mDrawIdentifier;
- }
-
- private int[] getPunchThroughPositions() {
- if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT)) {
- return new int[]{getMeasuredWidth() / 2, getMeasuredHeight() - (mButtonBarHeight / 2)};
- } else if (mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)) {
- return new int[]{getMeasuredWidth() - (mButtonBarHeight / 2), getMeasuredHeight() / 2};
- } else if (mDrawIdentifier.equals(WORKSPACE_LARGE)) {
- final float scale = LauncherApplication.getScreenDensity();
- final int cornerXOffset = (int) (scale * 15);
- final int cornerYOffset = (int) (scale * 10);
- return new int[]{getMeasuredWidth() - cornerXOffset, cornerYOffset};
- } else if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) ||
- mDrawIdentifier.equals(ALLAPPS_LANDSCAPE) ||
- mDrawIdentifier.equals(ALLAPPS_LARGE)) {
- return mPositionData;
- }
- return new int[]{-1, -1};
- }
-
- @Override
- public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) {
- if (descendant.includeForAccessibility()) {
- return descendant;
- }
- return null;
- }
-
- @Override
- public View focusSearch(int direction) {
- return this.focusSearch(null, direction);
- }
-
- @Override
- public View focusSearch(View focused, int direction) {
- return FocusFinder.getInstance().findNextFocus(this, focused, direction);
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- return (mDrawIdentifier.equals(WORKSPACE_PORTRAIT)
- || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE)
- || mDrawIdentifier.equals(WORKSPACE_LARGE)
- || mDrawIdentifier.equals(ALLAPPS_PORTRAIT)
- || mDrawIdentifier.equals(ALLAPPS_LANDSCAPE)
- || mDrawIdentifier.equals(ALLAPPS_LARGE)
- || mDrawIdentifier.equals(WORKSPACE_CUSTOM));
- }
-
- @Override
- public boolean onTouchEvent(android.view.MotionEvent event) {
- if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
- mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
- mDrawIdentifier.equals(WORKSPACE_LARGE) ||
- mDrawIdentifier.equals(ALLAPPS_PORTRAIT) ||
- mDrawIdentifier.equals(ALLAPPS_LANDSCAPE) ||
- mDrawIdentifier.equals(ALLAPPS_LARGE)) {
-
- int[] positions = getPunchThroughPositions();
- for (int i = 0; i < positions.length; i += 2) {
- double diff = Math.sqrt(Math.pow(event.getX() - positions[i], 2) +
- Math.pow(event.getY() - positions[i + 1], 2));
- if (diff < mRevealRadius) {
- return false;
- }
- }
- } else if (mDrawIdentifier.equals(FOLDER_PORTRAIT) ||
- mDrawIdentifier.equals(FOLDER_LANDSCAPE) ||
- mDrawIdentifier.equals(FOLDER_LARGE)) {
- Folder f = mLauncher.getWorkspace().getOpenFolder();
- if (f != null) {
- Rect r = new Rect();
- f.getHitRect(r);
- if (r.contains((int) event.getX(), (int) event.getY())) {
- return false;
- }
- }
- }
- return true;
- };
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- if (mIsInitialized) {
- DisplayMetrics metrics = new DisplayMetrics();
- mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
- // Initialize the draw buffer (to allow punching through)
- Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
-
- // Draw the background
- if (mBackground == null) {
- if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) ||
- mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) ||
- mDrawIdentifier.equals(WORKSPACE_LARGE)) {
- mBackground = getResources().getDrawable(R.drawable.bg_cling1);
- } else if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) ||
- mDrawIdentifier.equals(ALLAPPS_LANDSCAPE) ||
- mDrawIdentifier.equals(ALLAPPS_LARGE)) {
- mBackground = getResources().getDrawable(R.drawable.bg_cling2);
- } else if (mDrawIdentifier.equals(FOLDER_PORTRAIT) ||
- mDrawIdentifier.equals(FOLDER_LANDSCAPE)) {
- mBackground = getResources().getDrawable(R.drawable.bg_cling3);
- } else if (mDrawIdentifier.equals(FOLDER_LARGE)) {
- mBackground = getResources().getDrawable(R.drawable.bg_cling4);
- } else if (mDrawIdentifier.equals(WORKSPACE_CUSTOM)) {
- mBackground = getResources().getDrawable(R.drawable.bg_cling5);
- }
- }
- if (mBackground != null) {
- mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
- mBackground.draw(c);
- } else {
- c.drawColor(0x99000000);
- }
-
- int cx = -1;
- int cy = -1;
- float scale = mRevealRadius / mPunchThroughGraphicCenterRadius;
- int dw = (int) (scale * mPunchThroughGraphic.getIntrinsicWidth());
- int dh = (int) (scale * mPunchThroughGraphic.getIntrinsicHeight());
-
- // Determine where to draw the punch through graphic
- int[] positions = getPunchThroughPositions();
- for (int i = 0; i < positions.length; i += 2) {
- cx = positions[i];
- cy = positions[i + 1];
- if (cx > -1 && cy > -1) {
- c.drawCircle(cx, cy, mRevealRadius, mErasePaint);
- mPunchThroughGraphic.setBounds(cx - dw/2, cy - dh/2, cx + dw/2, cy + dh/2);
- mPunchThroughGraphic.draw(c);
- }
- }
-
- // Draw the hand graphic in All Apps
- if (mDrawIdentifier.equals(ALLAPPS_PORTRAIT) ||
- mDrawIdentifier.equals(ALLAPPS_LANDSCAPE) ||
- mDrawIdentifier.equals(ALLAPPS_LARGE)) {
- if (mHandTouchGraphic == null) {
- mHandTouchGraphic = getResources().getDrawable(R.drawable.hand);
- }
- int offset = mAppIconSize / 4;
- mHandTouchGraphic.setBounds(cx + offset, cy + offset,
- cx + mHandTouchGraphic.getIntrinsicWidth() + offset,
- cy + mHandTouchGraphic.getIntrinsicHeight() + offset);
- mHandTouchGraphic.draw(c);
- }
-
- canvas.drawBitmap(b, 0, 0, null);
- c.setBitmap(null);
- b = null;
- }
-
- // Draw the rest of the cling
- super.dispatchDraw(canvas);
- };
-}
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
deleted file mode 100644
index 930da56aa..000000000
--- a/src/com/android/launcher2/DeferredHandler.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2008 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.LinkedList;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue;
-
-/**
- * Queue of things to run on a looper thread. Items posted with {@link #post} will not
- * be actually enqued on the handler until after the last one has run, to keep from
- * starving the thread.
- *
- * This class is fifo.
- */
-public class DeferredHandler {
- private LinkedList<Runnable> mQueue = new LinkedList<Runnable>();
- private MessageQueue mMessageQueue = Looper.myQueue();
- private Impl mHandler = new Impl();
-
- private class Impl extends Handler implements MessageQueue.IdleHandler {
- public void handleMessage(Message msg) {
- Runnable r;
- synchronized (mQueue) {
- if (mQueue.size() == 0) {
- return;
- }
- r = mQueue.removeFirst();
- }
- r.run();
- synchronized (mQueue) {
- scheduleNextLocked();
- }
- }
-
- public boolean queueIdle() {
- handleMessage(null);
- return false;
- }
- }
-
- private class IdleRunnable implements Runnable {
- Runnable mRunnable;
-
- IdleRunnable(Runnable r) {
- mRunnable = r;
- }
-
- public void run() {
- mRunnable.run();
- }
- }
-
- public DeferredHandler() {
- }
-
- /** Schedule runnable to run after everything that's on the queue right now. */
- public void post(Runnable runnable) {
- synchronized (mQueue) {
- mQueue.add(runnable);
- if (mQueue.size() == 1) {
- scheduleNextLocked();
- }
- }
- }
-
- /** Schedule runnable to run when the queue goes idle. */
- public void postIdle(final Runnable runnable) {
- post(new IdleRunnable(runnable));
- }
-
- public void cancelRunnable(Runnable runnable) {
- synchronized (mQueue) {
- while (mQueue.remove(runnable)) { }
- }
- }
-
- public void cancel() {
- synchronized (mQueue) {
- mQueue.clear();
- }
- }
-
- void scheduleNextLocked() {
- if (mQueue.size() > 0) {
- Runnable peek = mQueue.getFirst();
- if (peek instanceof IdleRunnable) {
- mMessageQueue.addIdleHandler(mHandler);
- } else {
- mHandler.sendEmptyMessage(1);
- }
- }
- }
-}
-
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
deleted file mode 100644
index 949c035ea..000000000
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LinearInterpolator;
-
-import com.android.launcher.R;
-
-public class DeleteDropTarget extends ButtonDropTarget {
- private static int DELETE_ANIMATION_DURATION = 285;
- private static int FLING_DELETE_ANIMATION_DURATION = 350;
- private static float FLING_TO_DELETE_FRICTION = 0.035f;
- private static int MODE_FLING_DELETE_TO_TRASH = 0;
- private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
-
- private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR;
-
- private ColorStateList mOriginalTextColor;
- private TransitionDrawable mUninstallDrawable;
- private TransitionDrawable mRemoveDrawable;
- private TransitionDrawable mCurrentDrawable;
-
- public DeleteDropTarget(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- // Get the drawable
- mOriginalTextColor = getTextColors();
-
- // Get the hover color
- Resources r = getResources();
- mHoverColor = r.getColor(R.color.delete_target_hover_tint);
- mUninstallDrawable = (TransitionDrawable)
- r.getDrawable(R.drawable.uninstall_target_selector);
- mRemoveDrawable = (TransitionDrawable) r.getDrawable(R.drawable.remove_target_selector);
-
- mRemoveDrawable.setCrossFadeEnabled(true);
- mUninstallDrawable.setCrossFadeEnabled(true);
-
- // The current drawable is set to either the remove drawable or the uninstall drawable
- // and is initially set to the remove drawable, as set in the layout xml.
- mCurrentDrawable = (TransitionDrawable) getCurrentDrawable();
-
- // Remove the text in the Phone UI in landscape
- int orientation = getResources().getConfiguration().orientation;
- if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- if (!LauncherApplication.isScreenLarge()) {
- setText("");
- }
- }
- }
-
- private boolean isAllAppsApplication(DragSource source, Object info) {
- return (source instanceof AppsCustomizePagedView) && (info instanceof ApplicationInfo);
- }
- private boolean isAllAppsWidget(DragSource source, Object info) {
- if (source instanceof AppsCustomizePagedView) {
- if (info instanceof PendingAddItemInfo) {
- PendingAddItemInfo addInfo = (PendingAddItemInfo) info;
- switch (addInfo.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- return true;
- }
- }
- }
- return false;
- }
- private boolean isDragSourceWorkspaceOrFolder(DragObject d) {
- return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder);
- }
- private boolean isWorkspaceOrFolderApplication(DragObject d) {
- return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
- }
- private boolean isWorkspaceOrFolderWidget(DragObject d) {
- return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof LauncherAppWidgetInfo);
- }
- private boolean isWorkspaceFolder(DragObject d) {
- return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo);
- }
-
- private void setHoverColor() {
- mCurrentDrawable.startTransition(mTransitionDuration);
- setTextColor(mHoverColor);
- }
- private void resetHoverColor() {
- mCurrentDrawable.resetTransition();
- setTextColor(mOriginalTextColor);
- }
-
- @Override
- public boolean acceptDrop(DragObject d) {
- // We can remove everything including App shortcuts, folders, widgets, etc.
- return true;
- }
-
- @Override
- public void onDragStart(DragSource source, Object info, int dragAction) {
- boolean isVisible = true;
- boolean isUninstall = false;
-
- // If we are dragging a widget from AppsCustomize, hide the delete target
- if (isAllAppsWidget(source, info)) {
- isVisible = false;
- }
-
- // If we are dragging an application from AppsCustomize, only show the control if we can
- // delete the app (it was downloaded), and rename the string to "uninstall" in such a case
- if (isAllAppsApplication(source, info)) {
- ApplicationInfo appInfo = (ApplicationInfo) info;
- if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) {
- isUninstall = true;
- } else {
- isVisible = false;
- }
- }
-
- if (isUninstall) {
- setCompoundDrawablesWithIntrinsicBounds(mUninstallDrawable, null, null, null);
- } else {
- setCompoundDrawablesWithIntrinsicBounds(mRemoveDrawable, null, null, null);
- }
- mCurrentDrawable = (TransitionDrawable) getCurrentDrawable();
-
- mActive = isVisible;
- resetHoverColor();
- ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE);
- if (getText().length() > 0) {
- setText(isUninstall ? R.string.delete_target_uninstall_label
- : R.string.delete_target_label);
- }
- }
-
- @Override
- public void onDragEnd() {
- super.onDragEnd();
- mActive = false;
- }
-
- public void onDragEnter(DragObject d) {
- super.onDragEnter(d);
-
- setHoverColor();
- }
-
- public void onDragExit(DragObject d) {
- super.onDragExit(d);
-
- if (!d.dragComplete) {
- resetHoverColor();
- } else {
- // Restore the hover color if we are deleting
- d.dragView.setColor(mHoverColor);
- }
- }
-
- private void animateToTrashAndCompleteDrop(final DragObject d) {
- DragLayer dragLayer = mLauncher.getDragLayer();
- Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
- Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
- mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight());
- float scale = (float) to.width() / from.width();
-
- mSearchDropTargetBar.deferOnDragEnd();
- Runnable onAnimationEndRunnable = new Runnable() {
- @Override
- public void run() {
- mSearchDropTargetBar.onDragEnd();
- mLauncher.exitSpringLoadedDragMode();
- completeDrop(d);
- }
- };
- dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
- DELETE_ANIMATION_DURATION, new DecelerateInterpolator(2),
- new LinearInterpolator(), onAnimationEndRunnable,
- DragLayer.ANIMATION_END_DISAPPEAR, null);
- }
-
- private void completeDrop(DragObject d) {
- ItemInfo item = (ItemInfo) d.dragInfo;
-
- if (isAllAppsApplication(d.dragSource, item)) {
- // Uninstall the application if it is being dragged from AppsCustomize
- mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
- } else if (isWorkspaceOrFolderApplication(d)) {
- LauncherModel.deleteItemFromDatabase(mLauncher, item);
- } else if (isWorkspaceFolder(d)) {
- // Remove the folder from the workspace and delete the contents from launcher model
- FolderInfo folderInfo = (FolderInfo) item;
- mLauncher.removeFolder(folderInfo);
- LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
- } else if (isWorkspaceOrFolderWidget(d)) {
- // Remove the widget from the workspace
- mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
- LauncherModel.deleteItemFromDatabase(mLauncher, item);
-
- final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
- final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
- if (appWidgetHost != null) {
- // Deleting an app widget ID is a void call but writes to disk before returning
- // to the caller...
- new Thread("deleteAppWidgetId") {
- public void run() {
- appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);
- }
- }.start();
- }
- }
- }
-
- public void onDrop(DragObject d) {
- animateToTrashAndCompleteDrop(d);
- }
-
- /**
- * Creates an animation from the current drag view to the delete trash icon.
- */
- private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer,
- DragObject d, PointF vel, ViewConfiguration config) {
- final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
- mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight());
- final Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
- // Calculate how far along the velocity vector we should put the intermediate point on
- // the bezier curve
- float velocity = Math.abs(vel.length());
- float vp = Math.min(1f, velocity / (config.getScaledMaximumFlingVelocity() / 2f));
- int offsetY = (int) (-from.top * vp);
- int offsetX = (int) (offsetY / (vel.y / vel.x));
- final float y2 = from.top + offsetY; // intermediate t/l
- final float x2 = from.left + offsetX;
- final float x1 = from.left; // drag view t/l
- final float y1 = from.top;
- final float x3 = to.left; // delete target t/l
- final float y3 = to.top;
-
- final TimeInterpolator scaleAlphaInterpolator = new TimeInterpolator() {
- @Override
- public float getInterpolation(float t) {
- return t * t * t * t * t * t * t * t;
- }
- };
- return new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final DragView dragView = (DragView) dragLayer.getAnimatedView();
- float t = ((Float) animation.getAnimatedValue()).floatValue();
- float tp = scaleAlphaInterpolator.getInterpolation(t);
- float initialScale = dragView.getInitialScale();
- float finalAlpha = 0.5f;
- float scale = dragView.getScaleX();
- float x1o = ((1f - scale) * dragView.getMeasuredWidth()) / 2f;
- float y1o = ((1f - scale) * dragView.getMeasuredHeight()) / 2f;
- float x = (1f - t) * (1f - t) * (x1 - x1o) + 2 * (1f - t) * t * (x2 - x1o) +
- (t * t) * x3;
- float y = (1f - t) * (1f - t) * (y1 - y1o) + 2 * (1f - t) * t * (y2 - x1o) +
- (t * t) * y3;
-
- dragView.setTranslationX(x);
- dragView.setTranslationY(y);
- dragView.setScaleX(initialScale * (1f - tp));
- dragView.setScaleY(initialScale * (1f - tp));
- dragView.setAlpha(finalAlpha + (1f - finalAlpha) * (1f - tp));
- }
- };
- }
-
- /**
- * Creates an animation from the current drag view along its current velocity vector.
- * For this animation, the alpha runs for a fixed duration and we update the position
- * progressively.
- */
- private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
- private DragLayer mDragLayer;
- private PointF mVelocity;
- private Rect mFrom;
- private long mPrevTime;
- private boolean mHasOffsetForScale;
- private float mFriction;
-
- private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
- public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
- long startTime, float friction) {
- mDragLayer = dragLayer;
- mVelocity = vel;
- mFrom = from;
- mPrevTime = startTime;
- mFriction = 1f - (dragLayer.getResources().getDisplayMetrics().density * friction);
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final DragView dragView = (DragView) mDragLayer.getAnimatedView();
- float t = ((Float) animation.getAnimatedValue()).floatValue();
- long curTime = AnimationUtils.currentAnimationTimeMillis();
-
- if (!mHasOffsetForScale) {
- mHasOffsetForScale = true;
- float scale = dragView.getScaleX();
- float xOffset = ((scale - 1f) * dragView.getMeasuredWidth()) / 2f;
- float yOffset = ((scale - 1f) * dragView.getMeasuredHeight()) / 2f;
-
- mFrom.left += xOffset;
- mFrom.top += yOffset;
- }
-
- mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
- mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
- dragView.setTranslationX(mFrom.left);
- dragView.setTranslationY(mFrom.top);
- dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
- mVelocity.x *= mFriction;
- mVelocity.y *= mFriction;
- mPrevTime = curTime;
- }
- };
- private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer,
- DragObject d, PointF vel, final long startTime, final int duration,
- ViewConfiguration config) {
- final Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
- return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime,
- FLING_TO_DELETE_FRICTION);
- }
-
- public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
- final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView;
-
- // Don't highlight the icon as it's animating
- d.dragView.setColor(0);
- d.dragView.updateInitialScaleToCurrentScale();
- // Don't highlight the target if we are flinging from AllApps
- if (isAllApps) {
- resetHoverColor();
- }
-
- if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
- // Defer animating out the drop target if we are animating to it
- mSearchDropTargetBar.deferOnDragEnd();
- mSearchDropTargetBar.finishAnimations();
- }
-
- final ViewConfiguration config = ViewConfiguration.get(mLauncher);
- final DragLayer dragLayer = mLauncher.getDragLayer();
- final int duration = FLING_DELETE_ANIMATION_DURATION;
- final long startTime = AnimationUtils.currentAnimationTimeMillis();
-
- // NOTE: Because it takes time for the first frame of animation to actually be
- // called and we expect the animation to be a continuation of the fling, we have
- // to account for the time that has elapsed since the fling finished. And since
- // we don't have a startDelay, we will always get call to update when we call
- // start() (which we want to ignore).
- final TimeInterpolator tInterpolator = new TimeInterpolator() {
- private int mCount = -1;
- private float mOffset = 0f;
-
- @Override
- public float getInterpolation(float t) {
- if (mCount < 0) {
- mCount++;
- } else if (mCount == 0) {
- mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
- startTime) / duration);
- mCount++;
- }
- return Math.min(1f, mOffset + t);
- }
- };
- AnimatorUpdateListener updateCb = null;
- if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
- updateCb = createFlingToTrashAnimatorListener(dragLayer, d, vel, config);
- } else if (mFlingDeleteMode == MODE_FLING_DELETE_ALONG_VECTOR) {
- updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime,
- duration, config);
- }
- Runnable onAnimationEndRunnable = new Runnable() {
- @Override
- public void run() {
- mSearchDropTargetBar.onDragEnd();
-
- // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
- // itself, otherwise, complete the drop to initiate the deletion process
- if (!isAllApps) {
- mLauncher.exitSpringLoadedDragMode();
- completeDrop(d);
- }
- mLauncher.getDragController().onDeferredEndFling(d);
- }
- };
- dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
- DragLayer.ANIMATION_END_DISAPPEAR, null);
- }
-}
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
deleted file mode 100644
index 84f151581..000000000
--- a/src/com/android/launcher2/DragController.java
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-
-/**
- * Class for initiating a drag within a view or across multiple views.
- */
-public class DragController {
- private static final String TAG = "Launcher.DragController";
-
- /** Indicates the drag is a move. */
- public static int DRAG_ACTION_MOVE = 0;
-
- /** Indicates the drag is a copy. */
- public static int DRAG_ACTION_COPY = 1;
-
- private static final int SCROLL_DELAY = 500;
- private static final int RESCROLL_DELAY = 750;
- private static final int VIBRATE_DURATION = 15;
-
- private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
-
- private static final int SCROLL_OUTSIDE_ZONE = 0;
- private static final int SCROLL_WAITING_IN_ZONE = 1;
-
- static final int SCROLL_NONE = -1;
- static final int SCROLL_LEFT = 0;
- static final int SCROLL_RIGHT = 1;
-
- private static final float MAX_FLING_DEGREES = 35f;
-
- private Launcher mLauncher;
- private Handler mHandler;
- private final Vibrator mVibrator;
-
- // temporaries to avoid gc thrash
- private Rect mRectTemp = new Rect();
- private final int[] mCoordinatesTemp = new int[2];
-
- /** Whether or not we're dragging. */
- private boolean mDragging;
-
- /** X coordinate of the down event. */
- private int mMotionDownX;
-
- /** Y coordinate of the down event. */
- private int mMotionDownY;
-
- /** the area at the edge of the screen that makes the workspace go left
- * or right while you're dragging.
- */
- private int mScrollZone;
-
- private DropTarget.DragObject mDragObject;
-
- /** Who can receive drop events */
- private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
- private ArrayList<DragListener> mListeners = new ArrayList<DragListener>();
- private DropTarget mFlingToDeleteDropTarget;
-
- /** The window token used as the parent for the DragView. */
- private IBinder mWindowToken;
-
- /** The view that will be scrolled when dragging to the left and right edges of the screen. */
- private View mScrollView;
-
- private View mMoveTarget;
-
- private DragScroller mDragScroller;
- private int mScrollState = SCROLL_OUTSIDE_ZONE;
- private ScrollRunnable mScrollRunnable = new ScrollRunnable();
-
- private DropTarget mLastDropTarget;
-
- private InputMethodManager mInputMethodManager;
-
- private int mLastTouch[] = new int[2];
- private long mLastTouchUpTime = -1;
- private int mDistanceSinceScroll = 0;
-
- private int mTmpPoint[] = new int[2];
- private Rect mDragLayerRect = new Rect();
-
- protected int mFlingToDeleteThresholdVelocity;
- private VelocityTracker mVelocityTracker;
-
- /**
- * Interface to receive notifications when a drag starts or stops
- */
- interface DragListener {
-
- /**
- * A drag has begun
- *
- * @param source An object representing where the drag originated
- * @param info The data associated with the object that is being dragged
- * @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
- * or {@link DragController#DRAG_ACTION_COPY}
- */
- void onDragStart(DragSource source, Object info, int dragAction);
-
- /**
- * The drag has ended
- */
- void onDragEnd();
- }
-
- /**
- * Used to create a new DragLayer from XML.
- *
- * @param context The application's context.
- */
- public DragController(Launcher launcher) {
- Resources r = launcher.getResources();
- mLauncher = launcher;
- mHandler = new Handler();
- mScrollZone = r.getDimensionPixelSize(R.dimen.scroll_zone);
- mVelocityTracker = VelocityTracker.obtain();
- mVibrator = (Vibrator) launcher.getSystemService(Context.VIBRATOR_SERVICE);
-
- float density = r.getDisplayMetrics().density;
- mFlingToDeleteThresholdVelocity =
- (int) (r.getInteger(R.integer.config_flingToDeleteMinVelocity) * density);
- }
-
- public boolean dragging() {
- return mDragging;
- }
-
- /**
- * Starts a drag.
- *
- * @param v The view that is being dragged
- * @param bmp The bitmap that represents the view being dragged
- * @param source An object representing where the drag originated
- * @param dragInfo The data associated with the object that is being dragged
- * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
- * {@link #DRAG_ACTION_COPY}
- * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
- * Makes dragging feel more precise, e.g. you can clip out a transparent border
- */
- public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
- Rect dragRegion, float initialDragViewScale) {
- int[] loc = mCoordinatesTemp;
- mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
- int dragLayerX = loc[0] + v.getPaddingLeft() +
- (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
- int dragLayerY = loc[1] + v.getPaddingTop() +
- (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
-
- startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, dragRegion,
- initialDragViewScale);
-
- if (dragAction == DRAG_ACTION_MOVE) {
- v.setVisibility(View.GONE);
- }
- }
-
- /**
- * Starts a drag.
- *
- * @param b The bitmap to display as the drag image. It will be re-scaled to the
- * enlarged size.
- * @param dragLayerX The x position in the DragLayer of the left-top of the bitmap.
- * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
- * @param source An object representing where the drag originated
- * @param dragInfo The data associated with the object that is being dragged
- * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
- * {@link #DRAG_ACTION_COPY}
- * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
- * Makes dragging feel more precise, e.g. you can clip out a transparent border
- */
- public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
- DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
- float initialDragViewScale) {
- if (PROFILE_DRAWING_DURING_DRAG) {
- android.os.Debug.startMethodTracing("Launcher");
- }
-
- // Hide soft keyboard, if visible
- if (mInputMethodManager == null) {
- mInputMethodManager = (InputMethodManager)
- mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE);
- }
- mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
-
- for (DragListener listener : mListeners) {
- listener.onDragStart(source, dragInfo, dragAction);
- }
-
- final int registrationX = mMotionDownX - dragLayerX;
- final int registrationY = mMotionDownY - dragLayerY;
-
- final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
- final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
-
- mDragging = true;
-
- mDragObject = new DropTarget.DragObject();
-
- mDragObject.dragComplete = false;
- mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
- mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
- mDragObject.dragSource = source;
- mDragObject.dragInfo = dragInfo;
-
- mVibrator.vibrate(VIBRATE_DURATION);
-
- final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
- registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale);
-
- if (dragOffset != null) {
- dragView.setDragVisualizeOffset(new Point(dragOffset));
- }
- if (dragRegion != null) {
- dragView.setDragRegion(new Rect(dragRegion));
- }
-
- dragView.show(mMotionDownX, mMotionDownY);
- handleMoveEvent(mMotionDownX, mMotionDownY);
- }
-
- /**
- * Draw the view into a bitmap.
- */
- Bitmap getViewBitmap(View v) {
- v.clearFocus();
- v.setPressed(false);
-
- boolean willNotCache = v.willNotCacheDrawing();
- v.setWillNotCacheDrawing(false);
-
- // Reset the drawing cache background color to fully transparent
- // for the duration of this operation
- int color = v.getDrawingCacheBackgroundColor();
- v.setDrawingCacheBackgroundColor(0);
- float alpha = v.getAlpha();
- v.setAlpha(1.0f);
-
- if (color != 0) {
- v.destroyDrawingCache();
- }
- v.buildDrawingCache();
- Bitmap cacheBitmap = v.getDrawingCache();
- if (cacheBitmap == null) {
- Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
- return null;
- }
-
- Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
-
- // Restore the view
- v.destroyDrawingCache();
- v.setAlpha(alpha);
- v.setWillNotCacheDrawing(willNotCache);
- v.setDrawingCacheBackgroundColor(color);
-
- return bitmap;
- }
-
- /**
- * Call this from a drag source view like this:
- *
- * <pre>
- * @Override
- * public boolean dispatchKeyEvent(KeyEvent event) {
- * return mDragController.dispatchKeyEvent(this, event)
- * || super.dispatchKeyEvent(event);
- * </pre>
- */
- public boolean dispatchKeyEvent(KeyEvent event) {
- return mDragging;
- }
-
- public boolean isDragging() {
- return mDragging;
- }
-
- /**
- * Stop dragging without dropping.
- */
- public void cancelDrag() {
- if (mDragging) {
- if (mLastDropTarget != null) {
- mLastDropTarget.onDragExit(mDragObject);
- }
- mDragObject.deferDragViewCleanupPostAnimation = false;
- mDragObject.cancelled = true;
- mDragObject.dragComplete = true;
- mDragObject.dragSource.onDropCompleted(null, mDragObject, false, false);
- }
- endDrag();
- }
- public void onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context) {
- // Cancel the current drag if we are removing an app that we are dragging
- if (mDragObject != null) {
- Object rawDragInfo = mDragObject.dragInfo;
- if (rawDragInfo instanceof ShortcutInfo) {
- ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo;
- for (ApplicationInfo info : apps) {
- // Added null checks to prevent NPE we've seen in the wild
- if (dragInfo != null &&
- dragInfo.intent != null &&
- info.intent != null) {
- boolean isSamePackage = dragInfo.getPackageName().equals(
- info.getPackageName());
- if (isSamePackage) {
- cancelDrag();
- return;
- }
- }
- }
- }
- }
- }
-
- private void endDrag() {
- if (mDragging) {
- mDragging = false;
- clearScrollRunnable();
- boolean isDeferred = false;
- if (mDragObject.dragView != null) {
- isDeferred = mDragObject.deferDragViewCleanupPostAnimation;
- if (!isDeferred) {
- mDragObject.dragView.remove();
- }
- mDragObject.dragView = null;
- }
-
- // Only end the drag if we are not deferred
- if (!isDeferred) {
- for (DragListener listener : mListeners) {
- listener.onDragEnd();
- }
- }
- }
-
- releaseVelocityTracker();
- }
-
- /**
- * This only gets called as a result of drag view cleanup being deferred in endDrag();
- */
- void onDeferredEndDrag(DragView dragView) {
- dragView.remove();
-
- // If we skipped calling onDragEnd() before, do it now
- for (DragListener listener : mListeners) {
- listener.onDragEnd();
- }
- }
-
- void onDeferredEndFling(DropTarget.DragObject d) {
- d.dragSource.onFlingToDeleteCompleted();
- }
-
- /**
- * Clamps the position to the drag layer bounds.
- */
- private int[] getClampedDragLayerPos(float x, float y) {
- mLauncher.getDragLayer().getLocalVisibleRect(mDragLayerRect);
- mTmpPoint[0] = (int) Math.max(mDragLayerRect.left, Math.min(x, mDragLayerRect.right - 1));
- mTmpPoint[1] = (int) Math.max(mDragLayerRect.top, Math.min(y, mDragLayerRect.bottom - 1));
- return mTmpPoint;
- }
-
- long getLastGestureUpTime() {
- if (mDragging) {
- return System.currentTimeMillis();
- } else {
- return mLastTouchUpTime;
- }
- }
-
- void resetLastGestureUpTime() {
- mLastTouchUpTime = -1;
- }
-
- /**
- * Call this from a drag source view.
- */
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
- + mDragging);
- }
-
- // Update the velocity tracker
- acquireVelocityTrackerAndAddMovement(ev);
-
- final int action = ev.getAction();
- final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
- final int dragLayerX = dragLayerPos[0];
- final int dragLayerY = dragLayerPos[1];
-
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- break;
- case MotionEvent.ACTION_DOWN:
- // Remember location of down touch
- mMotionDownX = dragLayerX;
- mMotionDownY = dragLayerY;
- mLastDropTarget = null;
- break;
- case MotionEvent.ACTION_UP:
- mLastTouchUpTime = System.currentTimeMillis();
- if (mDragging) {
- PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (vec != null) {
- dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
- } else {
- drop(dragLayerX, dragLayerY);
- }
- }
- endDrag();
- break;
- case MotionEvent.ACTION_CANCEL:
- cancelDrag();
- break;
- }
-
- return mDragging;
- }
-
- /**
- * Sets the view that should handle move events.
- */
- void setMoveTarget(View view) {
- mMoveTarget = view;
- }
-
- public boolean dispatchUnhandledMove(View focused, int direction) {
- return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
- }
-
- private void clearScrollRunnable() {
- mHandler.removeCallbacks(mScrollRunnable);
- if (mScrollState == SCROLL_WAITING_IN_ZONE) {
- mScrollState = SCROLL_OUTSIDE_ZONE;
- mScrollRunnable.setDirection(SCROLL_RIGHT);
- mDragScroller.onExitScrollArea();
- mLauncher.getDragLayer().onExitScrollArea();
- }
- }
-
- private void handleMoveEvent(int x, int y) {
- mDragObject.dragView.move(x, y);
-
- // Drop on someone?
- final int[] coordinates = mCoordinatesTemp;
- DropTarget dropTarget = findDropTarget(x, y, coordinates);
- mDragObject.x = coordinates[0];
- mDragObject.y = coordinates[1];
- if (dropTarget != null) {
- DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
- if (delegate != null) {
- dropTarget = delegate;
- }
-
- if (mLastDropTarget != dropTarget) {
- if (mLastDropTarget != null) {
- mLastDropTarget.onDragExit(mDragObject);
- }
- dropTarget.onDragEnter(mDragObject);
- }
- dropTarget.onDragOver(mDragObject);
- } else {
- if (mLastDropTarget != null) {
- mLastDropTarget.onDragExit(mDragObject);
- }
- }
- mLastDropTarget = dropTarget;
-
- // After a scroll, the touch point will still be in the scroll region.
- // Rather than scrolling immediately, require a bit of twiddling to scroll again
- final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
- mDistanceSinceScroll +=
- Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
- mLastTouch[0] = x;
- mLastTouch[1] = y;
- final int delay = mDistanceSinceScroll < slop ? RESCROLL_DELAY : SCROLL_DELAY;
-
- if (x < mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- if (mDragScroller.onEnterScrollArea(x, y, SCROLL_LEFT)) {
- mLauncher.getDragLayer().onEnterScrollArea(SCROLL_LEFT);
- mScrollRunnable.setDirection(SCROLL_LEFT);
- mHandler.postDelayed(mScrollRunnable, delay);
- }
- }
- } else if (x > mScrollView.getWidth() - mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- if (mDragScroller.onEnterScrollArea(x, y, SCROLL_RIGHT)) {
- mLauncher.getDragLayer().onEnterScrollArea(SCROLL_RIGHT);
- mScrollRunnable.setDirection(SCROLL_RIGHT);
- mHandler.postDelayed(mScrollRunnable, delay);
- }
- }
- } else {
- clearScrollRunnable();
- }
- }
-
- public void forceMoveEvent() {
- if (mDragging) {
- handleMoveEvent(mDragObject.x, mDragObject.y);
- }
- }
-
- /**
- * Call this from a drag source view.
- */
- public boolean onTouchEvent(MotionEvent ev) {
- if (!mDragging) {
- return false;
- }
-
- // Update the velocity tracker
- acquireVelocityTrackerAndAddMovement(ev);
-
- final int action = ev.getAction();
- final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
- final int dragLayerX = dragLayerPos[0];
- final int dragLayerY = dragLayerPos[1];
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- // Remember where the motion event started
- mMotionDownX = dragLayerX;
- mMotionDownY = dragLayerY;
-
- if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
- } else {
- mScrollState = SCROLL_OUTSIDE_ZONE;
- }
- break;
- case MotionEvent.ACTION_MOVE:
- handleMoveEvent(dragLayerX, dragLayerY);
- break;
- case MotionEvent.ACTION_UP:
- // Ensure that we've processed a move event at the current pointer location.
- handleMoveEvent(dragLayerX, dragLayerY);
- mHandler.removeCallbacks(mScrollRunnable);
-
- if (mDragging) {
- PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (vec != null) {
- dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
- } else {
- drop(dragLayerX, dragLayerY);
- }
- }
- endDrag();
- break;
- case MotionEvent.ACTION_CANCEL:
- mHandler.removeCallbacks(mScrollRunnable);
- cancelDrag();
- break;
- }
-
- return true;
- }
-
- /**
- * Determines whether the user flung the current item to delete it.
- *
- * @return the vector at which the item was flung, or null if no fling was detected.
- */
- private PointF isFlingingToDelete(DragSource source) {
- if (mFlingToDeleteDropTarget == null) return null;
- if (!source.supportsFlingToDelete()) return null;
-
- ViewConfiguration config = ViewConfiguration.get(mLauncher);
- mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
-
- if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
- // Do a quick dot product test to ensure that we are flinging upwards
- PointF vel = new PointF(mVelocityTracker.getXVelocity(),
- mVelocityTracker.getYVelocity());
- PointF upVec = new PointF(0f, -1f);
- float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
- (vel.length() * upVec.length()));
- if (theta <= Math.toRadians(MAX_FLING_DEGREES)) {
- return vel;
- }
- }
- return null;
- }
-
- private void dropOnFlingToDeleteTarget(float x, float y, PointF vel) {
- final int[] coordinates = mCoordinatesTemp;
-
- mDragObject.x = coordinates[0];
- mDragObject.y = coordinates[1];
-
- // Clean up dragging on the target if it's not the current fling delete target otherwise,
- // start dragging to it.
- if (mLastDropTarget != null && mFlingToDeleteDropTarget != mLastDropTarget) {
- mLastDropTarget.onDragExit(mDragObject);
- }
-
- // Drop onto the fling-to-delete target
- boolean accepted = false;
- mFlingToDeleteDropTarget.onDragEnter(mDragObject);
- // We must set dragComplete to true _only_ after we "enter" the fling-to-delete target for
- // "drop"
- mDragObject.dragComplete = true;
- mFlingToDeleteDropTarget.onDragExit(mDragObject);
- if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
- mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y,
- vel);
- accepted = true;
- }
- mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
- accepted);
- }
-
- private void drop(float x, float y) {
- final int[] coordinates = mCoordinatesTemp;
- final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
-
- mDragObject.x = coordinates[0];
- mDragObject.y = coordinates[1];
- boolean accepted = false;
- if (dropTarget != null) {
- mDragObject.dragComplete = true;
- dropTarget.onDragExit(mDragObject);
- if (dropTarget.acceptDrop(mDragObject)) {
- dropTarget.onDrop(mDragObject);
- accepted = true;
- }
- }
- mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, false, accepted);
- }
-
- private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
- final Rect r = mRectTemp;
-
- final ArrayList<DropTarget> dropTargets = mDropTargets;
- final int count = dropTargets.size();
- for (int i=count-1; i>=0; i--) {
- DropTarget target = dropTargets.get(i);
- if (!target.isDropEnabled())
- continue;
-
- target.getHitRect(r);
-
- // Convert the hit rect to DragLayer coordinates
- target.getLocationInDragLayer(dropCoordinates);
- r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
-
- mDragObject.x = x;
- mDragObject.y = y;
- if (r.contains(x, y)) {
- DropTarget delegate = target.getDropTargetDelegate(mDragObject);
- if (delegate != null) {
- target = delegate;
- target.getLocationInDragLayer(dropCoordinates);
- }
-
- // Make dropCoordinates relative to the DropTarget
- dropCoordinates[0] = x - dropCoordinates[0];
- dropCoordinates[1] = y - dropCoordinates[1];
-
- return target;
- }
- }
- return null;
- }
-
- public void setDragScoller(DragScroller scroller) {
- mDragScroller = scroller;
- }
-
- public void setWindowToken(IBinder token) {
- mWindowToken = token;
- }
-
- /**
- * Sets the drag listner which will be notified when a drag starts or ends.
- */
- public void addDragListener(DragListener l) {
- mListeners.add(l);
- }
-
- /**
- * Remove a previously installed drag listener.
- */
- public void removeDragListener(DragListener l) {
- mListeners.remove(l);
- }
-
- /**
- * Add a DropTarget to the list of potential places to receive drop events.
- */
- public void addDropTarget(DropTarget target) {
- mDropTargets.add(target);
- }
-
- /**
- * Don't send drop events to <em>target</em> any more.
- */
- public void removeDropTarget(DropTarget target) {
- mDropTargets.remove(target);
- }
-
- /**
- * Sets the current fling-to-delete drop target.
- */
- public void setFlingToDeleteDropTarget(DropTarget target) {
- mFlingToDeleteDropTarget = target;
- }
-
- private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- }
-
- private void releaseVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- /**
- * Set which view scrolls for touch events near the edge of the screen.
- */
- public void setScrollView(View v) {
- mScrollView = v;
- }
-
- DragView getDragView() {
- return mDragObject.dragView;
- }
-
- private class ScrollRunnable implements Runnable {
- private int mDirection;
-
- ScrollRunnable() {
- }
-
- public void run() {
- if (mDragScroller != null) {
- if (mDirection == SCROLL_LEFT) {
- mDragScroller.scrollLeft();
- } else {
- mDragScroller.scrollRight();
- }
- mScrollState = SCROLL_OUTSIDE_ZONE;
- mDistanceSinceScroll = 0;
- mDragScroller.onExitScrollArea();
- mLauncher.getDragLayer().onExitScrollArea();
-
- if (isDragging()) {
- // Force an update so that we can requeue the scroller if necessary
- forceMoveEvent();
- }
- }
- }
-
- void setDirection(int direction) {
- mDirection = direction;
- }
- }
-}
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
deleted file mode 100644
index 4be1914e0..000000000
--- a/src/com/android/launcher2/DragLayer.java
+++ /dev/null
@@ -1,766 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-
-/**
- * A ViewGroup that coordinates dragging across its descendants
- */
-public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChangeListener {
- private DragController mDragController;
- private int[] mTmpXY = new int[2];
-
- private int mXDown, mYDown;
- private Launcher mLauncher;
-
- // Variables relating to resizing widgets
- private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
- new ArrayList<AppWidgetResizeFrame>();
- private AppWidgetResizeFrame mCurrentResizeFrame;
-
- // Variables relating to animation of views after drop
- private ValueAnimator mDropAnim = null;
- private ValueAnimator mFadeOutAnim = null;
- private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
- private DragView mDropView = null;
- private int mAnchorViewInitialScrollX = 0;
- private View mAnchorView = null;
-
- private boolean mHoverPointClosesFolder = false;
- private Rect mHitRect = new Rect();
- private int mWorkspaceIndex = -1;
- private int mQsbIndex = -1;
- public static final int ANIMATION_END_DISAPPEAR = 0;
- public static final int ANIMATION_END_FADE_OUT = 1;
- public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
-
- /**
- * Used to create a new DragLayer from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- */
- public DragLayer(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- // Disable multitouch across the workspace/all apps/customize tray
- setMotionEventSplittingEnabled(false);
- setChildrenDrawingOrderEnabled(true);
- setOnHierarchyChangeListener(this);
-
- mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo);
- mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo);
- }
-
- public void setup(Launcher launcher, DragController controller) {
- mLauncher = launcher;
- mDragController = controller;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
- }
-
- private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
- getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
- if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
- return true;
- }
- return false;
- }
-
- private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
- getDescendantRectRelativeToSelf(folder, mHitRect);
- if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
- return true;
- }
- return false;
- }
-
- private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
- Rect hitRect = new Rect();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- for (AppWidgetResizeFrame child: mResizeFrames) {
- child.getHitRect(hitRect);
- if (hitRect.contains(x, y)) {
- if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
- mCurrentResizeFrame = child;
- mXDown = x;
- mYDown = y;
- requestDisallowInterceptTouchEvent(true);
- return true;
- }
- }
- }
-
- Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
- if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) {
- if (currentFolder.isEditingName()) {
- if (!isEventOverFolderTextRegion(currentFolder, ev)) {
- currentFolder.dismissEditingName();
- return true;
- }
- }
-
- getDescendantRectRelativeToSelf(currentFolder, hitRect);
- if (!isEventOverFolder(currentFolder, ev)) {
- mLauncher.closeFolder();
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (handleTouchDown(ev, true)) {
- return true;
- }
- }
- clearAllResizeFrames();
- return mDragController.onInterceptTouchEvent(ev);
- }
-
- @Override
- public boolean onInterceptHoverEvent(MotionEvent ev) {
- Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
- if (currentFolder == null) {
- return false;
- } else {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isTouchExplorationEnabled()) {
- final int action = ev.getAction();
- boolean isOverFolder;
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER:
- isOverFolder = isEventOverFolder(currentFolder, ev);
- if (!isOverFolder) {
- sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
- mHoverPointClosesFolder = true;
- return true;
- } else if (isOverFolder) {
- mHoverPointClosesFolder = false;
- } else {
- return true;
- }
- case MotionEvent.ACTION_HOVER_MOVE:
- isOverFolder = isEventOverFolder(currentFolder, ev);
- if (!isOverFolder && !mHoverPointClosesFolder) {
- sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
- mHoverPointClosesFolder = true;
- return true;
- } else if (isOverFolder) {
- mHoverPointClosesFolder = false;
- } else {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isEnabled()) {
- int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_VIEW_FOCUSED);
- onInitializeAccessibilityEvent(event);
- event.getText().add(getContext().getString(stringId));
- accessibilityManager.sendAccessibilityEvent(event);
- }
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent ev) {
- // If we've received this, we've already done the necessary handling
- // in onInterceptHoverEvent. Return true to consume the event.
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean handled = false;
- int action = ev.getAction();
-
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (handleTouchDown(ev, false)) {
- return true;
- }
- }
- }
-
- if (mCurrentResizeFrame != null) {
- handled = true;
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
- mCurrentResizeFrame.onTouchUp();
- mCurrentResizeFrame = null;
- }
- }
- if (handled) return true;
- return mDragController.onTouchEvent(ev);
- }
-
- /**
- * Determine the rect of the descendant in this DragLayer's coordinates
- *
- * @param descendant The descendant whose coordinates we want to find.
- * @param r The rect into which to place the results.
- * @return The factor by which this descendant is scaled relative to this DragLayer.
- */
- public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
- mTmpXY[0] = 0;
- mTmpXY[1] = 0;
- float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
- r.set(mTmpXY[0], mTmpXY[1],
- mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
- return scale;
- }
-
- public void getLocationInDragLayer(View child, int[] loc) {
- loc[0] = 0;
- loc[1] = 0;
- getDescendantCoordRelativeToSelf(child, loc);
- }
-
- /**
- * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
- * coordinates.
- *
- * @param descendant The descendant to which the passed coordinate is relative.
- * @param coord The coordinate that we want mapped.
- * @return The factor by which this descendant is scaled relative to this DragLayer.
- */
- public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
- float scale = 1.0f;
- float[] pt = {coord[0], coord[1]};
- descendant.getMatrix().mapPoints(pt);
- scale *= descendant.getScaleX();
- pt[0] += descendant.getLeft();
- pt[1] += descendant.getTop();
- ViewParent viewParent = descendant.getParent();
- while (viewParent instanceof View && viewParent != this) {
- final View view = (View)viewParent;
- view.getMatrix().mapPoints(pt);
- scale *= view.getScaleX();
- pt[0] += view.getLeft() - view.getScrollX();
- pt[1] += view.getTop() - view.getScrollY();
- viewParent = view.getParent();
- }
- coord[0] = (int) Math.round(pt[0]);
- coord[1] = (int) Math.round(pt[1]);
- return scale;
- }
-
- public void getViewRectRelativeToSelf(View v, Rect r) {
- int[] loc = new int[2];
- getLocationInWindow(loc);
- int x = loc[0];
- int y = loc[1];
-
- v.getLocationInWindow(loc);
- int vX = loc[0];
- int vY = loc[1];
-
- int left = vX - x;
- int top = vY - y;
- r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
- }
-
- @Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- return mDragController.dispatchUnhandledMove(focused, direction);
- }
-
- public static class LayoutParams extends FrameLayout.LayoutParams {
- public int x, y;
- public boolean customPosition = false;
-
- /**
- * {@inheritDoc}
- */
- public LayoutParams(int width, int height) {
- super(width, height);
- }
-
- public void setWidth(int width) {
- this.width = width;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setHeight(int height) {
- this.height = height;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getX() {
- return x;
- }
-
- public void setY(int y) {
- this.y = y;
- }
-
- public int getY() {
- return y;
- }
- }
-
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
- if (flp instanceof LayoutParams) {
- final LayoutParams lp = (LayoutParams) flp;
- if (lp.customPosition) {
- child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
- }
- }
- }
- }
-
- public void clearAllResizeFrames() {
- if (mResizeFrames.size() > 0) {
- for (AppWidgetResizeFrame frame: mResizeFrames) {
- frame.commitResize();
- removeView(frame);
- }
- mResizeFrames.clear();
- }
- }
-
- public boolean hasResizeFrames() {
- return mResizeFrames.size() > 0;
- }
-
- public boolean isWidgetBeingResized() {
- return mCurrentResizeFrame != null;
- }
-
- public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
- CellLayout cellLayout) {
- AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
- widget, cellLayout, this);
-
- LayoutParams lp = new LayoutParams(-1, -1);
- lp.customPosition = true;
-
- addView(resizeFrame, lp);
- mResizeFrames.add(resizeFrame);
-
- resizeFrame.snapToWidget(false);
- }
-
- public void animateViewIntoPosition(DragView dragView, final View child) {
- animateViewIntoPosition(dragView, child, null);
- }
-
- public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
- float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
- int duration) {
- Rect r = new Rect();
- getViewRectRelativeToSelf(dragView, r);
- final int fromX = r.left;
- final int fromY = r.top;
-
- animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
- onFinishRunnable, animationEndStyle, duration, null);
- }
-
- public void animateViewIntoPosition(DragView dragView, final View child,
- final Runnable onFinishAnimationRunnable) {
- animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable, null);
- }
-
- public void animateViewIntoPosition(DragView dragView, final View child, int duration,
- final Runnable onFinishAnimationRunnable, View anchorView) {
- ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
- CellLayout parent = (CellLayout) (CellLayout) parentChildren.getParent();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- parentChildren.measureChild(child);
-
- Rect r = new Rect();
- getViewRectRelativeToSelf(dragView, r);
-
- int coord[] = new int[2];
- coord[0] = lp.x;
- coord[1] = lp.y;
-
- // Since the child hasn't necessarily been laid out, we force the lp to be updated with
- // the correct coordinates (above) and use these to determine the final location
- float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
- int toX = coord[0];
- int toY = coord[1];
- if (child instanceof TextView) {
- TextView tv = (TextView) child;
-
- // The child may be scaled (always about the center of the view) so to account for it,
- // we have to offset the position by the scaled size. Once we do that, we can center
- // the drag view about the scaled child view.
- toY += Math.round(scale * tv.getPaddingTop());
- toY -= dragView.getMeasuredHeight() * (1 - scale) / 2;
- toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
- } else if (child instanceof FolderIcon) {
- // Account for holographic blur padding on the drag view
- toY -= Workspace.DRAG_BITMAP_PADDING / 2;
- // Center in the x coordinate about the target's drawable
- toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
- } else {
- toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
- toX -= (Math.round(scale * (dragView.getMeasuredWidth()
- - child.getMeasuredWidth()))) / 2;
- }
-
- final int fromX = r.left;
- final int fromY = r.top;
- child.setVisibility(INVISIBLE);
- Runnable onCompleteRunnable = new Runnable() {
- public void run() {
- child.setVisibility(VISIBLE);
- if (onFinishAnimationRunnable != null) {
- onFinishAnimationRunnable.run();
- }
- }
- };
- animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, scale, scale,
- onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
- }
-
- public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
- final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
- float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
- int animationEndStyle, int duration, View anchorView) {
- Rect from = new Rect(fromX, fromY, fromX +
- view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
- Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
- animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
- null, null, onCompleteRunnable, animationEndStyle, anchorView);
- }
-
- /**
- * This method animates a view at the end of a drag and drop animation.
- *
- * @param view The view to be animated. This view is drawn directly into DragLayer, and so
- * doesn't need to be a child of DragLayer.
- * @param from The initial location of the view. Only the left and top parameters are used.
- * @param to The final location of the view. Only the left and top parameters are used. This
- * location doesn't account for scaling, and so should be centered about the desired
- * final location (including scaling).
- * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
- * @param finalScale The final scale of the view. The view is scaled about its center.
- * @param duration The duration of the animation.
- * @param motionInterpolator The interpolator to use for the location of the view.
- * @param alphaInterpolator The interpolator to use for the alpha of the view.
- * @param onCompleteRunnable Optional runnable to run on animation completion.
- * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
- * the runnable will execute after the view is faded out.
- * @param anchorView If not null, this represents the view which the animated view stays
- * anchored to in case scrolling is currently taking place. Note: currently this is
- * only used for the X dimension for the case of the workspace.
- */
- public void animateView(final DragView view, final Rect from, final Rect to,
- final float finalAlpha, final float initScaleX, final float initScaleY,
- final float finalScaleX, final float finalScaleY, int duration,
- final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
- final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
-
- // Calculate the duration of the animation based on the object's distance
- final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
- Math.pow(to.top - from.top, 2));
- final Resources res = getResources();
- final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
-
- // If duration < 0, this is a cue to compute the duration based on the distance
- if (duration < 0) {
- duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
- if (dist < maxDist) {
- duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
- }
- duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
- }
-
- // Fall back to cubic ease out interpolator for the animation if none is specified
- TimeInterpolator interpolator = null;
- if (alphaInterpolator == null || motionInterpolator == null) {
- interpolator = mCubicEaseOutInterpolator;
- }
-
- // Animate the view
- final float initAlpha = view.getAlpha();
- final float dropViewScale = view.getScaleX();
- AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
- final int width = view.getMeasuredWidth();
- final int height = view.getMeasuredHeight();
-
- float alphaPercent = alphaInterpolator == null ? percent :
- alphaInterpolator.getInterpolation(percent);
- float motionPercent = motionInterpolator == null ? percent :
- motionInterpolator.getInterpolation(percent);
-
- float initialScaleX = initScaleX * dropViewScale;
- float initialScaleY = initScaleY * dropViewScale;
- float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
- float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
- float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
-
- float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
- float fromTop = from.top + (initialScaleY - 1f) * height / 2;
-
- int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
- int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
-
- int xPos = x - mDropView.getScrollX() + (mAnchorView != null
- ? (mAnchorViewInitialScrollX - mAnchorView.getScrollX()) : 0);
- int yPos = y - mDropView.getScrollY();
-
- mDropView.setTranslationX(xPos);
- mDropView.setTranslationY(yPos);
- mDropView.setScaleX(scaleX);
- mDropView.setScaleY(scaleY);
- mDropView.setAlpha(alpha);
- }
- };
- animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
- anchorView);
- }
-
- public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
- TimeInterpolator interpolator, final Runnable onCompleteRunnable,
- final int animationEndStyle, View anchorView) {
- // Clean up the previous animations
- if (mDropAnim != null) mDropAnim.cancel();
- if (mFadeOutAnim != null) mFadeOutAnim.cancel();
-
- // Show the drop view if it was previously hidden
- mDropView = view;
- mDropView.cancelAnimation();
- mDropView.resetLayoutParams();
-
- // Set the anchor view if the page is scrolling
- if (anchorView != null) {
- mAnchorViewInitialScrollX = anchorView.getScrollX();
- }
- mAnchorView = anchorView;
-
- // Create and start the animation
- mDropAnim = new ValueAnimator();
- mDropAnim.setInterpolator(interpolator);
- mDropAnim.setDuration(duration);
- mDropAnim.setFloatValues(0f, 1f);
- mDropAnim.addUpdateListener(updateCb);
- mDropAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- switch (animationEndStyle) {
- case ANIMATION_END_DISAPPEAR:
- clearAnimatedView();
- break;
- case ANIMATION_END_FADE_OUT:
- fadeOutDragView();
- break;
- case ANIMATION_END_REMAIN_VISIBLE:
- break;
- }
- }
- });
- mDropAnim.start();
- }
-
- public void clearAnimatedView() {
- if (mDropAnim != null) {
- mDropAnim.cancel();
- }
- if (mDropView != null) {
- mDragController.onDeferredEndDrag(mDropView);
- }
- mDropView = null;
- invalidate();
- }
-
- public View getAnimatedView() {
- return mDropView;
- }
-
- private void fadeOutDragView() {
- mFadeOutAnim = new ValueAnimator();
- mFadeOutAnim.setDuration(150);
- mFadeOutAnim.setFloatValues(0f, 1f);
- mFadeOutAnim.removeAllUpdateListeners();
- mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
-
- float alpha = 1 - percent;
- mDropView.setAlpha(alpha);
- }
- });
- mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- if (mDropView != null) {
- mDragController.onDeferredEndDrag(mDropView);
- }
- mDropView = null;
- invalidate();
- }
- });
- mFadeOutAnim.start();
- }
-
- @Override
- public void onChildViewAdded(View parent, View child) {
- updateChildIndices();
- }
-
- @Override
- public void onChildViewRemoved(View parent, View child) {
- updateChildIndices();
- }
-
- private void updateChildIndices() {
- if (mLauncher != null) {
- mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace());
- mQsbIndex = indexOfChild(mLauncher.getSearchBar());
- }
- }
-
- @Override
- protected int getChildDrawingOrder(int childCount, int i) {
- // We don't want to prioritize the workspace drawing on top of the other children in
- // landscape for the overscroll event.
- if (LauncherApplication.isScreenLandscape(getContext())) {
- return super.getChildDrawingOrder(childCount, i);
- }
-
- if (mWorkspaceIndex == -1 || mQsbIndex == -1 ||
- mLauncher.getWorkspace().isDrawingBackgroundGradient()) {
- return i;
- }
-
- // This ensures that the workspace is drawn above the hotseat and qsb,
- // except when the workspace is drawing a background gradient, in which
- // case we want the workspace to stay behind these elements.
- if (i == mQsbIndex) {
- return mWorkspaceIndex;
- } else if (i == mWorkspaceIndex) {
- return mQsbIndex;
- } else {
- return i;
- }
- }
-
- private boolean mInScrollArea;
- private Drawable mLeftHoverDrawable;
- private Drawable mRightHoverDrawable;
-
- void onEnterScrollArea(int direction) {
- mInScrollArea = true;
- invalidate();
- }
-
- void onExitScrollArea() {
- mInScrollArea = false;
- invalidate();
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
-
- if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
- Workspace workspace = mLauncher.getWorkspace();
- int width = workspace.getWidth();
- Rect childRect = new Rect();
- getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
-
- int page = workspace.getNextPage();
- CellLayout leftPage = (CellLayout) workspace.getChildAt(page - 1);
- CellLayout rightPage = (CellLayout) workspace.getChildAt(page + 1);
-
- if (leftPage != null && leftPage.getIsDragOverlapping()) {
- mLeftHoverDrawable.setBounds(0, childRect.top,
- mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
- mLeftHoverDrawable.draw(canvas);
- } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
- mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
- childRect.top, width, childRect.bottom);
- mRightHoverDrawable.draw(canvas);
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/DragScroller.java b/src/com/android/launcher2/DragScroller.java
deleted file mode 100644
index a3ee6c237..000000000
--- a/src/com/android/launcher2/DragScroller.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-/**
- * Handles scrolling while dragging
- *
- */
-public interface DragScroller {
- void scrollLeft();
- void scrollRight();
-
- /**
- * The touch point has entered the scroll area; a scroll is imminent.
- * This event will only occur while a drag is active.
- *
- * @param direction The scroll direction
- */
- boolean onEnterScrollArea(int x, int y, int direction);
-
- /**
- * The touch point has left the scroll area.
- * NOTE: This may not be called, if a drop occurs inside the scroll area.
- */
- boolean onExitScrollArea();
-}
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
deleted file mode 100644
index 54404770a..000000000
--- a/src/com/android/launcher2/DragSource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2008 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.view.View;
-
-import com.android.launcher2.DropTarget.DragObject;
-
-/**
- * Interface defining an object that can originate a drag.
- *
- */
-public interface DragSource {
- /**
- * @return whether items dragged from this source supports
- */
- boolean supportsFlingToDelete();
-
- /**
- * A callback specifically made back to the source after an item from this source has been flung
- * to be deleted on a DropTarget. In such a situation, this method will be called after
- * onDropCompleted, and more importantly, after the fling animation has completed.
- */
- void onFlingToDeleteCompleted();
-
- /**
- * A callback made back to the source after an item from this source has been dropped on a
- * DropTarget.
- */
- void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success);
-}
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
deleted file mode 100644
index b6645e102..000000000
--- a/src/com/android/launcher2/DragView.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.animation.DecelerateInterpolator;
-
-import com.android.launcher.R;
-
-public class DragView extends View {
- private static float sDragAlpha = 1f;
-
- private Bitmap mBitmap;
- private Bitmap mCrossFadeBitmap;
- private Paint mPaint;
- private int mRegistrationX;
- private int mRegistrationY;
-
- private Point mDragVisualizeOffset = null;
- private Rect mDragRegion = null;
- private DragLayer mDragLayer = null;
- private boolean mHasDrawn = false;
- private float mCrossFadeProgress = 0f;
-
- ValueAnimator mAnim;
- private float mOffsetX = 0.0f;
- private float mOffsetY = 0.0f;
- private float mInitialScale = 1f;
-
- /**
- * Construct the drag view.
- * <p>
- * The registration point is the point inside our view that the touch events should
- * be centered upon.
- *
- * @param launcher The Launcher instance
- * @param bitmap The view that we're dragging around. We scale it up when we draw it.
- * @param registrationX The x coordinate of the registration point.
- * @param registrationY The y coordinate of the registration point.
- */
- public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
- int left, int top, int width, int height, final float initialScale) {
- super(launcher);
- mDragLayer = launcher.getDragLayer();
- mInitialScale = initialScale;
-
- final Resources res = getResources();
- final float offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
- final float offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
- final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale);
- final float scale = (width + scaleDps) / width;
-
- // Animate the view into the correct position
- mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
- mAnim.setDuration(150);
- mAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float value = (Float) animation.getAnimatedValue();
-
- final int deltaX = (int) ((value * offsetX) - mOffsetX);
- final int deltaY = (int) ((value * offsetY) - mOffsetY);
-
- mOffsetX += deltaX;
- mOffsetY += deltaY;
- setScaleX(initialScale + (value * (scale - initialScale)));
- setScaleY(initialScale + (value * (scale - initialScale)));
- if (sDragAlpha != 1f) {
- setAlpha(sDragAlpha * value + (1f - value));
- }
-
- if (getParent() == null) {
- animation.cancel();
- } else {
- setTranslationX(getTranslationX() + deltaX);
- setTranslationY(getTranslationY() + deltaY);
- }
- }
- });
-
- mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
- setDragRegion(new Rect(0, 0, width, height));
-
- // The point in our scaled bitmap that the touch events are located
- mRegistrationX = registrationX;
- mRegistrationY = registrationY;
-
- // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
- int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- measure(ms, ms);
- mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
- }
-
- public float getOffsetY() {
- return mOffsetY;
- }
-
- public int getDragRegionLeft() {
- return mDragRegion.left;
- }
-
- public int getDragRegionTop() {
- return mDragRegion.top;
- }
-
- public int getDragRegionWidth() {
- return mDragRegion.width();
- }
-
- public int getDragRegionHeight() {
- return mDragRegion.height();
- }
-
- public void setDragVisualizeOffset(Point p) {
- mDragVisualizeOffset = p;
- }
-
- public Point getDragVisualizeOffset() {
- return mDragVisualizeOffset;
- }
-
- public void setDragRegion(Rect r) {
- mDragRegion = r;
- }
-
- public Rect getDragRegion() {
- return mDragRegion;
- }
-
- public float getInitialScale() {
- return mInitialScale;
- }
-
- public void updateInitialScaleToCurrentScale() {
- mInitialScale = getScaleX();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- Paint p = new Paint();
- p.setStyle(Paint.Style.FILL);
- p.setColor(0x66ffffff);
- canvas.drawRect(0, 0, getWidth(), getHeight(), p);
- }
-
- mHasDrawn = true;
- boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
- if (crossFade) {
- int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
- mPaint.setAlpha(alpha);
- }
- canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
- if (crossFade) {
- mPaint.setAlpha((int) (255 * mCrossFadeProgress));
- canvas.save();
- float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
- float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
- canvas.scale(sX, sY);
- canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
- canvas.restore();
- }
- }
-
- public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
- mCrossFadeBitmap = crossFadeBitmap;
- }
-
- public void crossFade(int duration) {
- ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- va.setDuration(duration);
- va.setInterpolator(new DecelerateInterpolator(1.5f));
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mCrossFadeProgress = animation.getAnimatedFraction();
- }
- });
- va.start();
- }
-
- public void setColor(int color) {
- if (mPaint == null) {
- mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
- }
- if (color != 0) {
- mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
- } else {
- mPaint.setColorFilter(null);
- }
- invalidate();
- }
-
- public boolean hasDrawn() {
- return mHasDrawn;
- }
-
- @Override
- public void setAlpha(float alpha) {
- super.setAlpha(alpha);
- mPaint.setAlpha((int) (255 * alpha));
- invalidate();
- }
-
- /**
- * Create a window containing this view and show it.
- *
- * @param windowToken obtained from v.getWindowToken() from one of your views
- * @param touchX the x coordinate the user touched in DragLayer coordinates
- * @param touchY the y coordinate the user touched in DragLayer coordinates
- */
- public void show(int touchX, int touchY) {
- mDragLayer.addView(this);
-
- // Enable hw-layers on this view
- setLayerType(View.LAYER_TYPE_HARDWARE, null);
-
- // Start the pick-up animation
- DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
- lp.width = mBitmap.getWidth();
- lp.height = mBitmap.getHeight();
- lp.customPosition = true;
- setLayoutParams(lp);
- setTranslationX(touchX - mRegistrationX);
- setTranslationY(touchY - mRegistrationY);
- mAnim.start();
- }
-
- public void cancelAnimation() {
- if (mAnim != null && mAnim.isRunning()) {
- mAnim.cancel();
- }
- }
-
- public void resetLayoutParams() {
- mOffsetX = mOffsetY = 0;
- requestLayout();
- }
-
- /**
- * Move the window containing this view.
- *
- * @param touchX the x coordinate the user touched in DragLayer coordinates
- * @param touchY the y coordinate the user touched in DragLayer coordinates
- */
- void move(int touchX, int touchY) {
- setTranslationX(touchX - mRegistrationX + (int) mOffsetX);
- setTranslationY(touchY - mRegistrationY + (int) mOffsetY);
- }
-
- void remove() {
- if (getParent() != null) {
- // Disable hw-layers on this view
- setLayerType(View.LAYER_TYPE_NONE, null);
-
- mDragLayer.removeView(DragView.this);
- }
- }
-}
-
diff --git a/src/com/android/launcher2/DrawableStateProxyView.java b/src/com/android/launcher2/DrawableStateProxyView.java
deleted file mode 100644
index 5d2f6e0a2..000000000
--- a/src/com/android/launcher2/DrawableStateProxyView.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 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.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.launcher.R;
-
-public class DrawableStateProxyView extends LinearLayout {
-
- private View mView;
- private int mViewId;
-
- public DrawableStateProxyView(Context context) {
- this(context, null);
- }
-
- public DrawableStateProxyView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
-
- public DrawableStateProxyView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DrawableStateProxyView,
- defStyle, 0);
- mViewId = a.getResourceId(R.styleable.DrawableStateProxyView_sourceViewId, -1);
- a.recycle();
-
- setFocusable(false);
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
-
- if (mView == null) {
- View parent = (View) getParent();
- mView = parent.findViewById(mViewId);
- }
- mView.setPressed(isPressed());
- mView.setHovered(isHovered());
- }
-
- @Override
- public boolean onHoverEvent(MotionEvent event) {
- return false;
- }
-}
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
deleted file mode 100644
index d627a4c2e..000000000
--- a/src/com/android/launcher2/DropTarget.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.PointF;
-import android.graphics.Rect;
-import android.util.Log;
-
-/**
- * Interface defining an object that can receive a drag.
- *
- */
-public interface DropTarget {
-
- public static final String TAG = "DropTarget";
-
- class DragObject {
- public int x = -1;
- public int y = -1;
-
- /** X offset from the upper-left corner of the cell to where we touched. */
- public int xOffset = -1;
-
- /** Y offset from the upper-left corner of the cell to where we touched. */
- public int yOffset = -1;
-
- /** This indicates whether a drag is in final stages, either drop or cancel. It
- * differentiates onDragExit, since this is called when the drag is ending, above
- * the current drag target, or when the drag moves off the current drag object.
- */
- public boolean dragComplete = false;
-
- /** The view that moves around while you drag. */
- public DragView dragView = null;
-
- /** The data associated with the object being dragged */
- public Object dragInfo = null;
-
- /** Where the drag originated */
- public DragSource dragSource = null;
-
- /** Post drag animation runnable */
- public Runnable postAnimationRunnable = null;
-
- /** Indicates that the drag operation was cancelled */
- public boolean cancelled = false;
-
- /** Defers removing the DragView from the DragLayer until after the drop animation. */
- public boolean deferDragViewCleanupPostAnimation = true;
-
- public DragObject() {
- }
- }
-
- public static class DragEnforcer implements DragController.DragListener {
- int dragParity = 0;
-
- public DragEnforcer(Context context) {
- Launcher launcher = (Launcher) context;
- launcher.getDragController().addDragListener(this);
- }
-
- void onDragEnter() {
- dragParity++;
- if (dragParity != 1) {
- Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
- }
- }
-
- void onDragExit() {
- dragParity--;
- if (dragParity != 0) {
- Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
- }
- }
-
- @Override
- public void onDragStart(DragSource source, Object info, int dragAction) {
- if (dragParity != 0) {
- Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
- }
- }
-
- @Override
- public void onDragEnd() {
- if (dragParity != 0) {
- Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
- }
- }
- }
-
- /**
- * Used to temporarily disable certain drop targets
- *
- * @return boolean specifying whether this drop target is currently enabled
- */
- boolean isDropEnabled();
-
- /**
- * Handle an object being dropped on the DropTarget
- *
- * @param source DragSource where the drag started
- * @param x X coordinate of the drop location
- * @param y Y coordinate of the drop location
- * @param xOffset Horizontal offset with the object being dragged where the original
- * touch happened
- * @param yOffset Vertical offset with the object being dragged where the original
- * touch happened
- * @param dragView The DragView that's being dragged around on screen.
- * @param dragInfo Data associated with the object being dragged
- *
- */
- void onDrop(DragObject dragObject);
-
- void onDragEnter(DragObject dragObject);
-
- void onDragOver(DragObject dragObject);
-
- void onDragExit(DragObject dragObject);
-
- /**
- * Handle an object being dropped as a result of flinging to delete and will be called in place
- * of onDrop(). (This is only called on objects that are set as the DragController's
- * fling-to-delete target.
- */
- void onFlingToDelete(DragObject dragObject, int x, int y, PointF vec);
-
- /**
- * Allows a DropTarget to delegate drag and drop events to another object.
- *
- * Most subclasses will should just return null from this method.
- *
- * @param source DragSource where the drag started
- * @param x X coordinate of the drop location
- * @param y Y coordinate of the drop location
- * @param xOffset Horizontal offset with the object being dragged where the original
- * touch happened
- * @param yOffset Vertical offset with the object being dragged where the original
- * touch happened
- * @param dragView The DragView that's being dragged around on screen.
- * @param dragInfo Data associated with the object being dragged
- *
- * @return The DropTarget to delegate to, or null to not delegate to another object.
- */
- DropTarget getDropTargetDelegate(DragObject dragObject);
-
- /**
- * Check if a drop action can occur at, or near, the requested location.
- * This will be called just before onDrop.
- *
- * @param source DragSource where the drag started
- * @param x X coordinate of the drop location
- * @param y Y coordinate of the drop location
- * @param xOffset Horizontal offset with the object being dragged where the
- * original touch happened
- * @param yOffset Vertical offset with the object being dragged where the
- * original touch happened
- * @param dragView The DragView that's being dragged around on screen.
- * @param dragInfo Data associated with the object being dragged
- * @return True if the drop will be accepted, false otherwise.
- */
- boolean acceptDrop(DragObject dragObject);
-
- // These methods are implemented in Views
- void getHitRect(Rect outRect);
- void getLocationInDragLayer(int[] loc);
- int getLeft();
- int getTop();
-}
diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java
deleted file mode 100644
index d317d3302..000000000
--- a/src/com/android/launcher2/FastBitmapDrawable.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-
-class FastBitmapDrawable extends Drawable {
- private Bitmap mBitmap;
- private int mAlpha;
- private int mWidth;
- private int mHeight;
- private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-
- FastBitmapDrawable(Bitmap b) {
- mAlpha = 255;
- mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- final Rect r = getBounds();
- canvas.drawBitmap(mBitmap, r.left, r.top, mPaint);
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- mPaint.setColorFilter(cf);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- mAlpha = alpha;
- mPaint.setAlpha(alpha);
- }
-
- public void setFilterBitmap(boolean filterBitmap) {
- mPaint.setFilterBitmap(filterBitmap);
- }
-
- public int getAlpha() {
- return mAlpha;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mWidth;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mHeight;
- }
-
- @Override
- public int getMinimumWidth() {
- return mWidth;
- }
-
- @Override
- public int getMinimumHeight() {
- return mHeight;
- }
-
- public void setBitmap(Bitmap b) {
- mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
- }
-
- public Bitmap getBitmap() {
- return mBitmap;
- }
-}
diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java
deleted file mode 100644
index e9f986d76..000000000
--- a/src/com/android/launcher2/FocusHelper.java
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.res.Configuration;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-/**
- * A keyboard listener we set on all the workspace icons.
- */
-class IconKeyEventListener implements View.OnKeyListener {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleIconKeyEvent(v, keyCode, event);
- }
-}
-
-/**
- * A keyboard listener we set on all the workspace icons.
- */
-class FolderKeyEventListener implements View.OnKeyListener {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
- }
-}
-
-/**
- * A keyboard listener we set on all the hotseat buttons.
- */
-class HotseatIconKeyEventListener implements View.OnKeyListener {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- final Configuration configuration = v.getResources().getConfiguration();
- return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation);
- }
-}
-
-/**
- * A keyboard listener we set on the last tab button in AppsCustomize to jump to then
- * market icon and vice versa.
- */
-class AppsCustomizeTabKeyEventListener implements View.OnKeyListener {
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleAppsCustomizeTabKeyEvent(v, keyCode, event);
- }
-}
-
-public class FocusHelper {
- /**
- * Private helper to get the parent TabHost in the view hiearchy.
- */
- private static TabHost findTabHostParent(View v) {
- ViewParent p = v.getParent();
- while (p != null && !(p instanceof TabHost)) {
- p = p.getParent();
- }
- return (TabHost) p;
- }
-
- /**
- * Handles key events in a AppsCustomize tab between the last tab view and the shop button.
- */
- static boolean handleAppsCustomizeTabKeyEvent(View v, int keyCode, KeyEvent e) {
- final TabHost tabHost = findTabHostParent(v);
- final ViewGroup contents = tabHost.getTabContentView();
- final View shop = tabHost.findViewById(R.id.market_button);
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the shop button if we aren't on it
- if (v != shop) {
- shop.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the content view (down is handled by the tab key handler otherwise)
- if (v == shop) {
- contents.requestFocus();
- wasHandled = true;
- }
- }
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Returns the Viewgroup containing page contents for the page at the index specified.
- */
- private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
- ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index);
- if (page instanceof PagedViewCellLayout) {
- // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
- page = (ViewGroup) page.getChildAt(0);
- }
- return page;
- }
-
- /**
- * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
- */
- static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
- KeyEvent e) {
-
- final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
- final PagedView container = (PagedView) parent.getParent();
- final TabHost tabHost = findTabHostParent(container);
- final TabWidget tabs = tabHost.getTabWidget();
- final int widgetIndex = parent.indexOfChild(w);
- final int widgetCount = parent.getChildCount();
- final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent));
- final int pageCount = container.getChildCount();
- final int cellCountX = parent.getCellCountX();
- final int cellCountY = parent.getCellCountY();
- final int x = widgetIndex % cellCountX;
- final int y = widgetIndex / cellCountX;
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- ViewGroup newParent = null;
- // Now that we load items in the bg asynchronously, we can't just focus
- // child siblings willy-nilly
- View child = null;
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous widget or the last widget on the previous page
- if (widgetIndex > 0) {
- parent.getChildAt(widgetIndex - 1).requestFocus();
- } else {
- if (pageIndex > 0) {
- newParent = getAppsCustomizePage(container, pageIndex - 1);
- if (newParent != null) {
- child = newParent.getChildAt(newParent.getChildCount() - 1);
- if (child != null) child.requestFocus();
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next widget or the first widget on the next page
- if (widgetIndex < (widgetCount - 1)) {
- parent.getChildAt(widgetIndex + 1).requestFocus();
- } else {
- if (pageIndex < (pageCount - 1)) {
- newParent = getAppsCustomizePage(container, pageIndex + 1);
- if (newParent != null) {
- child = newParent.getChildAt(0);
- if (child != null) child.requestFocus();
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (handleKeyEvent) {
- // Select the closest icon in the previous row, otherwise select the tab bar
- if (y > 0) {
- int newWidgetIndex = ((y - 1) * cellCountX) + x;
- child = parent.getChildAt(newWidgetIndex);
- if (child != null) child.requestFocus();
- } else {
- tabs.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the closest icon in the previous row, otherwise do nothing
- if (y < (cellCountY - 1)) {
- int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
- child = parent.getChildAt(newWidgetIndex);
- if (child != null) child.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (handleKeyEvent) {
- // Simulate a click on the widget
- View.OnClickListener clickListener = (View.OnClickListener) container;
- clickListener.onClick(w);
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_PAGE_UP:
- if (handleKeyEvent) {
- // Select the first item on the previous page, or the first item on this page
- // if there is no previous page
- if (pageIndex > 0) {
- newParent = getAppsCustomizePage(container, pageIndex - 1);
- if (newParent != null) {
- child = newParent.getChildAt(0);
- }
- } else {
- child = parent.getChildAt(0);
- }
- if (child != null) child.requestFocus();
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_PAGE_DOWN:
- if (handleKeyEvent) {
- // Select the first item on the next page, or the last item on this page
- // if there is no next page
- if (pageIndex < (pageCount - 1)) {
- newParent = getAppsCustomizePage(container, pageIndex + 1);
- if (newParent != null) {
- child = newParent.getChildAt(0);
- }
- } else {
- child = parent.getChildAt(widgetCount - 1);
- }
- if (child != null) child.requestFocus();
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- if (handleKeyEvent) {
- // Select the first item on this page
- child = parent.getChildAt(0);
- if (child != null) child.requestFocus();
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_END:
- if (handleKeyEvent) {
- // Select the last item on this page
- parent.getChildAt(widgetCount - 1).requestFocus();
- }
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Handles key events in a PageViewCellLayout containing PagedViewIcons.
- */
- static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
- ViewGroup parentLayout;
- ViewGroup itemContainer;
- int countX;
- int countY;
- if (v.getParent() instanceof PagedViewCellLayoutChildren) {
- itemContainer = (ViewGroup) v.getParent();
- parentLayout = (ViewGroup) itemContainer.getParent();
- countX = ((PagedViewCellLayout) parentLayout).getCellCountX();
- countY = ((PagedViewCellLayout) parentLayout).getCellCountY();
- } else {
- itemContainer = parentLayout = (ViewGroup) v.getParent();
- countX = ((PagedViewGridLayout) parentLayout).getCellCountX();
- countY = ((PagedViewGridLayout) parentLayout).getCellCountY();
- }
-
- // Note we have an extra parent because of the
- // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
- final PagedView container = (PagedView) parentLayout.getParent();
- final TabHost tabHost = findTabHostParent(container);
- final TabWidget tabs = tabHost.getTabWidget();
- final int iconIndex = itemContainer.indexOfChild(v);
- final int itemCount = itemContainer.getChildCount();
- final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
- final int pageCount = container.getChildCount();
-
- final int x = iconIndex % countX;
- final int y = iconIndex / countX;
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- ViewGroup newParent = null;
- // Side pages do not always load synchronously, so check before focusing child siblings
- // willy-nilly
- View child = null;
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous icon or the last icon on the previous page
- if (iconIndex > 0) {
- itemContainer.getChildAt(iconIndex - 1).requestFocus();
- } else {
- if (pageIndex > 0) {
- newParent = getAppsCustomizePage(container, pageIndex - 1);
- if (newParent != null) {
- container.snapToPage(pageIndex - 1);
- child = newParent.getChildAt(newParent.getChildCount() - 1);
- if (child != null) child.requestFocus();
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next icon or the first icon on the next page
- if (iconIndex < (itemCount - 1)) {
- itemContainer.getChildAt(iconIndex + 1).requestFocus();
- } else {
- if (pageIndex < (pageCount - 1)) {
- newParent = getAppsCustomizePage(container, pageIndex + 1);
- if (newParent != null) {
- container.snapToPage(pageIndex + 1);
- child = newParent.getChildAt(0);
- if (child != null) child.requestFocus();
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (handleKeyEvent) {
- // Select the closest icon in the previous row, otherwise select the tab bar
- if (y > 0) {
- int newiconIndex = ((y - 1) * countX) + x;
- itemContainer.getChildAt(newiconIndex).requestFocus();
- } else {
- tabs.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the closest icon in the previous row, otherwise do nothing
- if (y < (countY - 1)) {
- int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x);
- itemContainer.getChildAt(newiconIndex).requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (handleKeyEvent) {
- // Simulate a click on the icon
- View.OnClickListener clickListener = (View.OnClickListener) container;
- clickListener.onClick(v);
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_PAGE_UP:
- if (handleKeyEvent) {
- // Select the first icon on the previous page, or the first icon on this page
- // if there is no previous page
- if (pageIndex > 0) {
- newParent = getAppsCustomizePage(container, pageIndex - 1);
- if (newParent != null) {
- container.snapToPage(pageIndex - 1);
- child = newParent.getChildAt(0);
- if (child != null) child.requestFocus();
- }
- } else {
- itemContainer.getChildAt(0).requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_PAGE_DOWN:
- if (handleKeyEvent) {
- // Select the first icon on the next page, or the last icon on this page
- // if there is no next page
- if (pageIndex < (pageCount - 1)) {
- newParent = getAppsCustomizePage(container, pageIndex + 1);
- if (newParent != null) {
- container.snapToPage(pageIndex + 1);
- child = newParent.getChildAt(0);
- if (child != null) child.requestFocus();
- }
- } else {
- itemContainer.getChildAt(itemCount - 1).requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- if (handleKeyEvent) {
- // Select the first icon on this page
- itemContainer.getChildAt(0).requestFocus();
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_END:
- if (handleKeyEvent) {
- // Select the last icon on this page
- itemContainer.getChildAt(itemCount - 1).requestFocus();
- }
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Handles key events in the tab widget.
- */
- static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
- if (!LauncherApplication.isScreenLarge()) return false;
-
- final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
- final TabHost tabHost = findTabHostParent(parent);
- final ViewGroup contents = tabHost.getTabContentView();
- final int tabCount = parent.getTabCount();
- final int tabIndex = parent.getChildTabIndex(v);
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous tab
- if (tabIndex > 0) {
- parent.getChildTabViewAt(tabIndex - 1).requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next tab, or if the last tab has a focus right id, select that
- if (tabIndex < (tabCount - 1)) {
- parent.getChildTabViewAt(tabIndex + 1).requestFocus();
- } else {
- if (v.getNextFocusRightId() != View.NO_ID) {
- tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- // Do nothing
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the content view
- contents.requestFocus();
- }
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Handles key events in the workspace hotseat (bottom of the screen).
- */
- static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
- final ViewGroup parent = (ViewGroup) v.getParent();
- final ViewGroup launcher = (ViewGroup) parent.getParent();
- final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
- final int buttonIndex = parent.indexOfChild(v);
- final int buttonCount = parent.getChildCount();
- final int pageIndex = workspace.getCurrentPage();
-
- // NOTE: currently we don't special case for the phone UI in different
- // orientations, even though the hotseat is on the side in landscape mode. This
- // is to ensure that accessibility consistency is maintained across rotations.
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous button, otherwise snap to the previous page
- if (buttonIndex > 0) {
- parent.getChildAt(buttonIndex - 1).requestFocus();
- } else {
- workspace.snapToPage(pageIndex - 1);
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next button, otherwise snap to the next page
- if (buttonIndex < (buttonCount - 1)) {
- parent.getChildAt(buttonIndex + 1).requestFocus();
- } else {
- workspace.snapToPage(pageIndex + 1);
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (handleKeyEvent) {
- // Select the first bubble text view in the current page of the workspace
- final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
- final ShortcutAndWidgetContainer children = layout.getShortcutsAndWidgets();
- final View newIcon = getIconInDirection(layout, children, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- workspace.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- // Do nothing
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Private helper method to get the CellLayoutChildren given a CellLayout index.
- */
- private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
- ViewGroup container, int i) {
- ViewGroup parent = (ViewGroup) container.getChildAt(i);
- return (ShortcutAndWidgetContainer) parent.getChildAt(0);
- }
-
- /**
- * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
- * from top left to bottom right.
- */
- private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
- ViewGroup parent) {
- // First we order each the CellLayout children by their x,y coordinates
- final int cellCountX = layout.getCountX();
- final int count = parent.getChildCount();
- ArrayList<View> views = new ArrayList<View>();
- for (int j = 0; j < count; ++j) {
- views.add(parent.getChildAt(j));
- }
- Collections.sort(views, new Comparator<View>() {
- @Override
- public int compare(View lhs, View rhs) {
- CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
- CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
- int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
- int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
- return lvIndex - rvIndex;
- }
- });
- return views;
- }
- /**
- * Private helper method to find the index of the next BubbleTextView or FolderIcon in the
- * direction delta.
- *
- * @param delta either -1 or 1 depending on the direction we want to search
- */
- private static View findIndexOfIcon(ArrayList<View> views, int i, int delta) {
- // Then we find the next BubbleTextView offset by delta from i
- final int count = views.size();
- int newI = i + delta;
- while (0 <= newI && newI < count) {
- View newV = views.get(newI);
- if (newV instanceof BubbleTextView || newV instanceof FolderIcon) {
- return newV;
- }
- newI += delta;
- }
- return null;
- }
- private static View getIconInDirection(CellLayout layout, ViewGroup parent, int i,
- int delta) {
- final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
- return findIndexOfIcon(views, i, delta);
- }
- private static View getIconInDirection(CellLayout layout, ViewGroup parent, View v,
- int delta) {
- final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
- return findIndexOfIcon(views, views.indexOf(v), delta);
- }
- /**
- * Private helper method to find the next closest BubbleTextView or FolderIcon in the direction
- * delta on the next line.
- *
- * @param delta either -1 or 1 depending on the line and direction we want to search
- */
- private static View getClosestIconOnLine(CellLayout layout, ViewGroup parent, View v,
- int lineDelta) {
- final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
- final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
- final int cellCountY = layout.getCountY();
- final int row = lp.cellY;
- final int newRow = row + lineDelta;
- if (0 <= newRow && newRow < cellCountY) {
- float closestDistance = Float.MAX_VALUE;
- int closestIndex = -1;
- int index = views.indexOf(v);
- int endIndex = (lineDelta < 0) ? -1 : views.size();
- while (index != endIndex) {
- View newV = views.get(index);
- CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
- boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
- if (satisfiesRow &&
- (newV instanceof BubbleTextView || newV instanceof FolderIcon)) {
- float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
- Math.pow(tmpLp.cellY - lp.cellY, 2));
- if (tmpDistance < closestDistance) {
- closestIndex = index;
- closestDistance = tmpDistance;
- }
- }
- if (index <= endIndex) {
- ++index;
- } else {
- --index;
- }
- }
- if (closestIndex > -1) {
- return views.get(closestIndex);
- }
- }
- return null;
- }
-
- /**
- * Handles key events in a Workspace containing.
- */
- static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
- ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
- final CellLayout layout = (CellLayout) parent.getParent();
- final Workspace workspace = (Workspace) layout.getParent();
- final ViewGroup launcher = (ViewGroup) workspace.getParent();
- final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.qsb_bar);
- final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat);
- int pageIndex = workspace.indexOfChild(layout);
- int pageCount = workspace.getChildCount();
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous icon or the last icon on the previous page if possible
- View newIcon = getIconInDirection(layout, parent, v, -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- if (pageIndex > 0) {
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
- newIcon = getIconInDirection(layout, parent,
- parent.getChildCount(), -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- // Snap to the previous page
- workspace.snapToPage(pageIndex - 1);
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next icon or the first icon on the next page if possible
- View newIcon = getIconInDirection(layout, parent, v, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- if (pageIndex < (pageCount - 1)) {
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
- newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- // Snap to the next page
- workspace.snapToPage(pageIndex + 1);
- }
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (handleKeyEvent) {
- // Select the closest icon in the previous line, otherwise select the tab bar
- View newIcon = getClosestIconOnLine(layout, parent, v, -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- wasHandled = true;
- } else {
- tabs.requestFocus();
- }
- }
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the closest icon in the next line, otherwise select the button bar
- View newIcon = getClosestIconOnLine(layout, parent, v, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- wasHandled = true;
- } else if (hotseat != null) {
- hotseat.requestFocus();
- }
- }
- break;
- case KeyEvent.KEYCODE_PAGE_UP:
- if (handleKeyEvent) {
- // Select the first icon on the previous page or the first icon on this page
- // if there is no previous page
- if (pageIndex > 0) {
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
- View newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- // Snap to the previous page
- workspace.snapToPage(pageIndex - 1);
- }
- } else {
- View newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_PAGE_DOWN:
- if (handleKeyEvent) {
- // Select the first icon on the next page or the last icon on this page
- // if there is no previous page
- if (pageIndex < (pageCount - 1)) {
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
- View newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- // Snap to the next page
- workspace.snapToPage(pageIndex + 1);
- }
- } else {
- View newIcon = getIconInDirection(layout, parent,
- parent.getChildCount(), -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- if (handleKeyEvent) {
- // Select the first icon on this page
- View newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_END:
- if (handleKeyEvent) {
- // Select the last icon on this page
- View newIcon = getIconInDirection(layout, parent,
- parent.getChildCount(), -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-
- /**
- * Handles key events for items in a Folder.
- */
- static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
- ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
- final CellLayout layout = (CellLayout) parent.getParent();
- final Folder folder = (Folder) layout.getParent();
- View title = folder.mFolderName;
-
- final int action = e.getAction();
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- boolean wasHandled = false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (handleKeyEvent) {
- // Select the previous icon
- View newIcon = getIconInDirection(layout, parent, v, -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (handleKeyEvent) {
- // Select the next icon
- View newIcon = getIconInDirection(layout, parent, v, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- title.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (handleKeyEvent) {
- // Select the closest icon in the previous line
- View newIcon = getClosestIconOnLine(layout, parent, v, -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (handleKeyEvent) {
- // Select the closest icon in the next line
- View newIcon = getClosestIconOnLine(layout, parent, v, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- } else {
- title.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- if (handleKeyEvent) {
- // Select the first icon on this page
- View newIcon = getIconInDirection(layout, parent, -1, 1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- case KeyEvent.KEYCODE_MOVE_END:
- if (handleKeyEvent) {
- // Select the last icon on this page
- View newIcon = getIconInDirection(layout, parent,
- parent.getChildCount(), -1);
- if (newIcon != null) {
- newIcon.requestFocus();
- }
- }
- wasHandled = true;
- break;
- default: break;
- }
- return wasHandled;
- }
-}
diff --git a/src/com/android/launcher2/FocusOnlyTabWidget.java b/src/com/android/launcher2/FocusOnlyTabWidget.java
deleted file mode 100644
index 8e9f58c61..000000000
--- a/src/com/android/launcher2/FocusOnlyTabWidget.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TabWidget;
-
-public class FocusOnlyTabWidget extends TabWidget {
- public FocusOnlyTabWidget(Context context) {
- super(context);
- }
-
- public FocusOnlyTabWidget(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public FocusOnlyTabWidget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public View getSelectedTab() {
- final int count = getTabCount();
- for (int i = 0; i < count; ++i) {
- View v = getChildTabViewAt(i);
- if (v.isSelected()) {
- return v;
- }
- }
- return null;
- }
-
- public int getChildTabIndex(View v) {
- final int tabCount = getTabCount();
- for (int i = 0; i < tabCount; ++i) {
- if (getChildTabViewAt(i) == v) {
- return i;
- }
- }
- return -1;
- }
-
- public void setCurrentTabToFocusedTab() {
- View tab = null;
- int index = -1;
- final int count = getTabCount();
- for (int i = 0; i < count; ++i) {
- View v = getChildTabViewAt(i);
- if (v.hasFocus()) {
- tab = v;
- index = i;
- break;
- }
- }
- if (index > -1) {
- super.setCurrentTab(index);
- super.onFocusChange(tab, true);
- }
- }
- public void superOnFocusChange(View v, boolean hasFocus) {
- super.onFocusChange(v, hasFocus);
- }
-
- @Override
- public void onFocusChange(android.view.View v, boolean hasFocus) {
- if (v == this && hasFocus && getTabCount() > 0) {
- getSelectedTab().requestFocus();
- return;
- }
- }
-}
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
deleted file mode 100644
index de2e4359a..000000000
--- a/src/com/android/launcher2/Folder.java
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.InputType;
-import android.text.Selection;
-import android.text.Spannable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-import com.android.launcher2.FolderInfo.FolderListener;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-/**
- * Represents a set of icons chosen by the user or generated by the system.
- */
-public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
- View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
- View.OnFocusChangeListener {
-
- @SuppressWarnings("unused")
- private static final String TAG = "Launcher.Folder";
-
- protected DragController mDragController;
- protected Launcher mLauncher;
- protected FolderInfo mInfo;
-
- static final int STATE_NONE = -1;
- static final int STATE_SMALL = 0;
- static final int STATE_ANIMATING = 1;
- static final int STATE_OPEN = 2;
-
- private int mExpandDuration;
- protected CellLayout mContent;
- private final LayoutInflater mInflater;
- private final IconCache mIconCache;
- private int mState = STATE_NONE;
- private static final int REORDER_ANIMATION_DURATION = 230;
- private static final int ON_EXIT_CLOSE_DELAY = 800;
- private boolean mRearrangeOnClose = false;
- private FolderIcon mFolderIcon;
- private int mMaxCountX;
- private int mMaxCountY;
- private int mMaxNumItems;
- private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
- private Drawable mIconDrawable;
- boolean mItemsInvalidated = false;
- private ShortcutInfo mCurrentDragInfo;
- private View mCurrentDragView;
- boolean mSuppressOnAdd = false;
- private int[] mTargetCell = new int[2];
- private int[] mPreviousTargetCell = new int[2];
- private int[] mEmptyCell = new int[2];
- private Alarm mReorderAlarm = new Alarm();
- private Alarm mOnExitAlarm = new Alarm();
- private int mFolderNameHeight;
- private Rect mTempRect = new Rect();
- private boolean mDragInProgress = false;
- private boolean mDeleteFolderOnDropCompleted = false;
- private boolean mSuppressFolderDeletion = false;
- private boolean mItemAddedBackToSelfViaIcon = false;
- FolderEditText mFolderName;
- private float mFolderIconPivotX;
- private float mFolderIconPivotY;
-
- private boolean mIsEditingName = false;
- private InputMethodManager mInputMethodManager;
-
- private static String sDefaultFolderName;
- private static String sHintText;
- private ObjectAnimator mOpenCloseAnimator;
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attribtues set containing the Workspace's customization values.
- */
- public Folder(Context context, AttributeSet attrs) {
- super(context, attrs);
- setAlwaysDrawnWithCacheEnabled(false);
- mInflater = LayoutInflater.from(context);
- mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
-
- Resources res = getResources();
- mMaxCountX = res.getInteger(R.integer.folder_max_count_x);
- mMaxCountY = res.getInteger(R.integer.folder_max_count_y);
- mMaxNumItems = res.getInteger(R.integer.folder_max_num_items);
- if (mMaxCountX < 0 || mMaxCountY < 0 || mMaxNumItems < 0) {
- mMaxCountX = LauncherModel.getCellCountX();
- mMaxCountY = LauncherModel.getCellCountY();
- mMaxNumItems = mMaxCountX * mMaxCountY;
- }
-
- mInputMethodManager = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-
- mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration);
-
- if (sDefaultFolderName == null) {
- sDefaultFolderName = res.getString(R.string.folder_name);
- }
- if (sHintText == null) {
- sHintText = res.getString(R.string.folder_hint_text);
- }
- mLauncher = (Launcher) context;
- // We need this view to be focusable in touch mode so that when text editing of the folder
- // name is complete, we have something to focus on, thus hiding the cursor and giving
- // reliable behvior when clicking the text field (since it will always gain focus on click).
- setFocusableInTouchMode(true);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mContent = (CellLayout) findViewById(R.id.folder_content);
- mContent.setGridSize(0, 0);
- mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
- mFolderName = (FolderEditText) findViewById(R.id.folder_name);
- mFolderName.setFolder(this);
- mFolderName.setOnFocusChangeListener(this);
-
- // We find out how tall the text view wants to be (it is set to wrap_content), so that
- // we can allocate the appropriate amount of space for it.
- int measureSpec = MeasureSpec.UNSPECIFIED;
- mFolderName.measure(measureSpec, measureSpec);
- mFolderNameHeight = mFolderName.getMeasuredHeight();
-
- // We disable action mode for now since it messes up the view on phones
- mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback);
- mFolderName.setOnEditorActionListener(this);
- mFolderName.setSelectAllOnFocus(true);
- mFolderName.setInputType(mFolderName.getInputType() |
- InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
- }
-
- private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- return false;
- }
-
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- return false;
- }
-
- public void onDestroyActionMode(ActionMode mode) {
- }
-
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return false;
- }
- };
-
- public void onClick(View v) {
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- // refactor this code from Folder
- ShortcutInfo item = (ShortcutInfo) tag;
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- item.intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
-
- mLauncher.startActivitySafely(v, item.intent, item);
- }
- }
-
- public boolean onLongClick(View v) {
- // Return if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return true;
-
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- ShortcutInfo item = (ShortcutInfo) tag;
- if (!v.isInTouchMode()) {
- return false;
- }
-
- mLauncher.dismissFolderCling(null);
-
- mLauncher.getWorkspace().onDragStartedWithItem(v);
- mLauncher.getWorkspace().beginDragShared(v, this);
- mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
-
- mCurrentDragInfo = item;
- mEmptyCell[0] = item.cellX;
- mEmptyCell[1] = item.cellY;
- mCurrentDragView = v;
-
- mContent.removeView(mCurrentDragView);
- mInfo.remove(mCurrentDragInfo);
- mDragInProgress = true;
- mItemAddedBackToSelfViaIcon = false;
- }
- return true;
- }
-
- public boolean isEditingName() {
- return mIsEditingName;
- }
-
- public void startEditingFolderName() {
- mFolderName.setHint("");
- mIsEditingName = true;
- }
-
- public void dismissEditingName() {
- mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
- doneEditingFolderName(true);
- }
-
- public void doneEditingFolderName(boolean commit) {
- mFolderName.setHint(sHintText);
- // Convert to a string here to ensure that no other state associated with the text field
- // gets saved.
- String newTitle = mFolderName.getText().toString();
- mInfo.setTitle(newTitle);
- LauncherModel.updateItemInDatabase(mLauncher, mInfo);
-
- if (commit) {
- sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- String.format(getContext().getString(R.string.folder_renamed), newTitle));
- }
- // In order to clear the focus from the text field, we set the focus on ourself. This
- // ensures that every time the field is clicked, focus is gained, giving reliable behavior.
- requestFocus();
-
- Selection.setSelection((Spannable) mFolderName.getText(), 0, 0);
- mIsEditingName = false;
- }
-
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- dismissEditingName();
- return true;
- }
- return false;
- }
-
- public View getEditTextRegion() {
- return mFolderName;
- }
-
- public Drawable getDragDrawable() {
- return mIconDrawable;
- }
-
- /**
- * We need to handle touch events to prevent them from falling through to the workspace below.
- */
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return true;
- }
-
- public void setDragController(DragController dragController) {
- mDragController = dragController;
- }
-
- void setFolderIcon(FolderIcon icon) {
- mFolderIcon = icon;
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // When the folder gets focus, we don't want to announce the list of items.
- return true;
- }
-
- /**
- * @return the FolderInfo object associated with this folder
- */
- FolderInfo getInfo() {
- return mInfo;
- }
-
- private class GridComparator implements Comparator<ShortcutInfo> {
- int mNumCols;
- public GridComparator(int numCols) {
- mNumCols = numCols;
- }
-
- @Override
- public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
- int lhIndex = lhs.cellY * mNumCols + lhs.cellX;
- int rhIndex = rhs.cellY * mNumCols + rhs.cellX;
- return (lhIndex - rhIndex);
- }
- }
-
- private void placeInReadingOrder(ArrayList<ShortcutInfo> items) {
- int maxX = 0;
- int count = items.size();
- for (int i = 0; i < count; i++) {
- ShortcutInfo item = items.get(i);
- if (item.cellX > maxX) {
- maxX = item.cellX;
- }
- }
-
- GridComparator gridComparator = new GridComparator(maxX + 1);
- Collections.sort(items, gridComparator);
- final int countX = mContent.getCountX();
- for (int i = 0; i < count; i++) {
- int x = i % countX;
- int y = i / countX;
- ShortcutInfo item = items.get(i);
- item.cellX = x;
- item.cellY = y;
- }
- }
-
- void bind(FolderInfo info) {
- mInfo = info;
- ArrayList<ShortcutInfo> children = info.contents;
- ArrayList<ShortcutInfo> overflow = new ArrayList<ShortcutInfo>();
- setupContentForNumItems(children.size());
- placeInReadingOrder(children);
- int count = 0;
- for (int i = 0; i < children.size(); i++) {
- ShortcutInfo child = (ShortcutInfo) children.get(i);
- if (!createAndAddShortcut(child)) {
- overflow.add(child);
- } else {
- count++;
- }
- }
-
- // We rearrange the items in case there are any empty gaps
- setupContentForNumItems(count);
-
- // If our folder has too many items we prune them from the list. This is an issue
- // when upgrading from the old Folders implementation which could contain an unlimited
- // number of items.
- for (ShortcutInfo item: overflow) {
- mInfo.remove(item);
- LauncherModel.deleteItemFromDatabase(mLauncher, item);
- }
-
- mItemsInvalidated = true;
- updateTextViewFocus();
- mInfo.addListener(this);
-
- if (!sDefaultFolderName.contentEquals(mInfo.title)) {
- mFolderName.setText(mInfo.title);
- } else {
- mFolderName.setText("");
- }
- updateItemLocationsInDatabase();
- }
-
- /**
- * Creates a new UserFolder, inflated from R.layout.user_folder.
- *
- * @param context The application's context.
- *
- * @return A new UserFolder.
- */
- static Folder fromXml(Context context) {
- return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
- }
-
- /**
- * This method is intended to make the UserFolder to be visually identical in size and position
- * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
- */
- private void positionAndSizeAsIcon() {
- if (!(getParent() instanceof DragLayer)) return;
- setScaleX(0.8f);
- setScaleY(0.8f);
- setAlpha(0f);
- mState = STATE_SMALL;
- }
-
- public void animateOpen() {
- positionAndSizeAsIcon();
-
- if (!(getParent() instanceof DragLayer)) return;
- centerAboutIcon();
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
- PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
- PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
- final ObjectAnimator oa = mOpenCloseAnimator =
- ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
-
- oa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- String.format(getContext().getString(R.string.folder_opened),
- mContent.getCountX(), mContent.getCountY()));
- mState = STATE_ANIMATING;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mState = STATE_OPEN;
- setLayerType(LAYER_TYPE_NONE, null);
- Cling cling = mLauncher.showFirstRunFoldersCling();
- if (cling != null) {
- cling.bringToFront();
- }
- setFocusOnFirstChild();
- }
- });
- oa.setDuration(mExpandDuration);
- setLayerType(LAYER_TYPE_HARDWARE, null);
- buildLayer();
- post(new Runnable() {
- public void run() {
- // Check if the animator changed in the meantime
- if (oa != mOpenCloseAnimator)
- return;
- oa.start();
- }
- });
- }
-
- private void sendCustomAccessibilityEvent(int type, String text) {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isEnabled()) {
- AccessibilityEvent event = AccessibilityEvent.obtain(type);
- onInitializeAccessibilityEvent(event);
- event.getText().add(text);
- accessibilityManager.sendAccessibilityEvent(event);
- }
- }
-
- private void setFocusOnFirstChild() {
- View firstChild = mContent.getChildAt(0, 0);
- if (firstChild != null) {
- firstChild.requestFocus();
- }
- }
-
- public void animateClosed() {
- if (!(getParent() instanceof DragLayer)) return;
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
- PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
- PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
- final ObjectAnimator oa = mOpenCloseAnimator =
- ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
-
- oa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- onCloseComplete();
- setLayerType(LAYER_TYPE_NONE, null);
- mState = STATE_SMALL;
- }
- @Override
- public void onAnimationStart(Animator animation) {
- sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- getContext().getString(R.string.folder_closed));
- mState = STATE_ANIMATING;
- }
- });
- oa.setDuration(mExpandDuration);
- setLayerType(LAYER_TYPE_HARDWARE, null);
- buildLayer();
- post(new Runnable() {
- public void run() {
- // Check if the animator changed in the meantime
- if (oa != mOpenCloseAnimator)
- return;
- oa.start();
- }
- });
- }
-
- void notifyDataSetChanged() {
- // recreate all the children if the data set changes under us. We may want to do this more
- // intelligently (ie just removing the views that should no longer exist)
- mContent.removeAllViewsInLayout();
- bind(mInfo);
- }
-
- public boolean acceptDrop(DragObject d) {
- final ItemInfo item = (ItemInfo) d.dragInfo;
- final int itemType = item.itemType;
- return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
- !isFull());
- }
-
- protected boolean findAndSetEmptyCells(ShortcutInfo item) {
- int[] emptyCell = new int[2];
- if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
- item.cellX = emptyCell[0];
- item.cellY = emptyCell[1];
- return true;
- } else {
- return false;
- }
- }
-
- protected boolean createAndAddShortcut(ShortcutInfo item) {
- final TextView textView =
- (TextView) mInflater.inflate(R.layout.application, this, false);
- textView.setCompoundDrawablesWithIntrinsicBounds(null,
- new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
- textView.setText(item.title);
- textView.setTag(item);
-
- textView.setOnClickListener(this);
- textView.setOnLongClickListener(this);
-
- // We need to check here to verify that the given item's location isn't already occupied
- // by another item.
- if (mContent.getChildAt(item.cellX, item.cellY) != null || item.cellX < 0 || item.cellY < 0
- || item.cellX >= mContent.getCountX() || item.cellY >= mContent.getCountY()) {
- // This shouldn't happen, log it.
- Log.e(TAG, "Folder order not properly persisted during bind");
- if (!findAndSetEmptyCells(item)) {
- return false;
- }
- }
-
- CellLayout.LayoutParams lp =
- new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
- boolean insert = false;
- textView.setOnKeyListener(new FolderKeyEventListener());
- mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
- return true;
- }
-
- public void onDragEnter(DragObject d) {
- mPreviousTargetCell[0] = -1;
- mPreviousTargetCell[1] = -1;
- mOnExitAlarm.cancelAlarm();
- }
-
- OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
- public void onAlarm(Alarm alarm) {
- realTimeReorder(mEmptyCell, mTargetCell);
- }
- };
-
- boolean readingOrderGreaterThan(int[] v1, int[] v2) {
- if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) {
- return true;
- } else {
- return false;
- }
- }
-
- private void realTimeReorder(int[] empty, int[] target) {
- boolean wrap;
- int startX;
- int endX;
- int startY;
- int delay = 0;
- float delayAmount = 30;
- if (readingOrderGreaterThan(target, empty)) {
- wrap = empty[0] >= mContent.getCountX() - 1;
- startY = wrap ? empty[1] + 1 : empty[1];
- for (int y = startY; y <= target[1]; y++) {
- startX = y == empty[1] ? empty[0] + 1 : 0;
- endX = y < target[1] ? mContent.getCountX() - 1 : target[0];
- for (int x = startX; x <= endX; x++) {
- View v = mContent.getChildAt(x,y);
- if (mContent.animateChildToPosition(v, empty[0], empty[1],
- REORDER_ANIMATION_DURATION, delay, true, true)) {
- empty[0] = x;
- empty[1] = y;
- delay += delayAmount;
- delayAmount *= 0.9;
- }
- }
- }
- } else {
- wrap = empty[0] == 0;
- startY = wrap ? empty[1] - 1 : empty[1];
- for (int y = startY; y >= target[1]; y--) {
- startX = y == empty[1] ? empty[0] - 1 : mContent.getCountX() - 1;
- endX = y > target[1] ? 0 : target[0];
- for (int x = startX; x >= endX; x--) {
- View v = mContent.getChildAt(x,y);
- if (mContent.animateChildToPosition(v, empty[0], empty[1],
- REORDER_ANIMATION_DURATION, delay, true, true)) {
- empty[0] = x;
- empty[1] = y;
- delay += delayAmount;
- delayAmount *= 0.9;
- }
- }
- }
- }
- }
-
- public void onDragOver(DragObject d) {
- float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, null);
- mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1], 1, 1, mTargetCell);
-
- if (mTargetCell[0] != mPreviousTargetCell[0] || mTargetCell[1] != mPreviousTargetCell[1]) {
- mReorderAlarm.cancelAlarm();
- mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
- mReorderAlarm.setAlarm(150);
- mPreviousTargetCell[0] = mTargetCell[0];
- mPreviousTargetCell[1] = mTargetCell[1];
- }
- }
-
- // This is used to compute the visual center of the dragView. The idea is that
- // the visual center represents the user's interpretation of where the item is, and hence
- // is the appropriate point to use when determining drop location.
- private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
- DragView dragView, float[] recycle) {
- float res[];
- if (recycle == null) {
- res = new float[2];
- } else {
- res = recycle;
- }
-
- // These represent the visual top and left of drag view if a dragRect was provided.
- // If a dragRect was not provided, then they correspond to the actual view left and
- // top, as the dragRect is in that case taken to be the entire dragView.
- // R.dimen.dragViewOffsetY.
- int left = x - xOffset;
- int top = y - yOffset;
-
- // In order to find the visual center, we shift by half the dragRect
- res[0] = left + dragView.getDragRegion().width() / 2;
- res[1] = top + dragView.getDragRegion().height() / 2;
-
- return res;
- }
-
- OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
- public void onAlarm(Alarm alarm) {
- completeDragExit();
- }
- };
-
- public void completeDragExit() {
- mLauncher.closeFolder();
- mCurrentDragInfo = null;
- mCurrentDragView = null;
- mSuppressOnAdd = false;
- mRearrangeOnClose = true;
- }
-
- public void onDragExit(DragObject d) {
- // We only close the folder if this is a true drag exit, ie. not because a drop
- // has occurred above the folder.
- if (!d.dragComplete) {
- mOnExitAlarm.setOnAlarmListener(mOnExitAlarmListener);
- mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
- }
- mReorderAlarm.cancelAlarm();
- }
-
- public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
- boolean success) {
- if (success) {
- if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
- replaceFolderWithFinalItem();
- }
- } else {
- // The drag failed, we need to return the item to the folder
- mFolderIcon.onDrop(d);
-
- // We're going to trigger a "closeFolder" which may occur before this item has
- // been added back to the folder -- this could cause the folder to be deleted
- if (mOnExitAlarm.alarmPending()) {
- mSuppressFolderDeletion = true;
- }
- }
-
- if (target != this) {
- if (mOnExitAlarm.alarmPending()) {
- mOnExitAlarm.cancelAlarm();
- completeDragExit();
- }
- }
- mDeleteFolderOnDropCompleted = false;
- mDragInProgress = false;
- mItemAddedBackToSelfViaIcon = false;
- mCurrentDragInfo = null;
- mCurrentDragView = null;
- mSuppressOnAdd = false;
-
- // Reordering may have occured, and we need to save the new item locations. We do this once
- // at the end to prevent unnecessary database operations.
- updateItemLocationsInDatabase();
- }
-
- @Override
- public boolean supportsFlingToDelete() {
- return true;
- }
-
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
- // Do nothing
- }
-
- @Override
- public void onFlingToDeleteCompleted() {
- // Do nothing
- }
-
- private void updateItemLocationsInDatabase() {
- ArrayList<View> list = getItemsInReadingOrder();
- for (int i = 0; i < list.size(); i++) {
- View v = list.get(i);
- ItemInfo info = (ItemInfo) v.getTag();
- LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0,
- info.cellX, info.cellY);
- }
- }
-
- public void notifyDrop() {
- if (mDragInProgress) {
- mItemAddedBackToSelfViaIcon = true;
- }
- }
-
- public boolean isDropEnabled() {
- return true;
- }
-
- public DropTarget getDropTargetDelegate(DragObject d) {
- return null;
- }
-
- private void setupContentDimensions(int count) {
- ArrayList<View> list = getItemsInReadingOrder();
-
- int countX = mContent.getCountX();
- int countY = mContent.getCountY();
- boolean done = false;
-
- while (!done) {
- int oldCountX = countX;
- int oldCountY = countY;
- if (countX * countY < count) {
- // Current grid is too small, expand it
- if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
- countX++;
- } else if (countY < mMaxCountY) {
- countY++;
- }
- if (countY == 0) countY++;
- } else if ((countY - 1) * countX >= count && countY >= countX) {
- countY = Math.max(0, countY - 1);
- } else if ((countX - 1) * countY >= count) {
- countX = Math.max(0, countX - 1);
- }
- done = countX == oldCountX && countY == oldCountY;
- }
- mContent.setGridSize(countX, countY);
- arrangeChildren(list);
- }
-
- public boolean isFull() {
- return getItemCount() >= mMaxNumItems;
- }
-
- private void centerAboutIcon() {
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-
- int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
- int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight()
- + mFolderNameHeight;
- DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
-
- parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect);
-
- int centerX = mTempRect.centerX();
- int centerY = mTempRect.centerY();
- int centeredLeft = centerX - width / 2;
- int centeredTop = centerY - height / 2;
-
- int currentPage = mLauncher.getWorkspace().getCurrentPage();
- // In case the workspace is scrolling, we need to use the final scroll to compute
- // the folders bounds.
- mLauncher.getWorkspace().setFinalScrollForPageChange(currentPage);
- // We first fetch the currently visible CellLayoutChildren
- CellLayout currentLayout = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPage);
- ShortcutAndWidgetContainer boundingLayout = currentLayout.getShortcutsAndWidgets();
- Rect bounds = new Rect();
- parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
- // We reset the workspaces scroll
- mLauncher.getWorkspace().resetFinalScrollForPageChange(currentPage);
-
- // We need to bound the folder to the currently visible CellLayoutChildren
- int left = Math.min(Math.max(bounds.left, centeredLeft),
- bounds.left + bounds.width() - width);
- int top = Math.min(Math.max(bounds.top, centeredTop),
- bounds.top + bounds.height() - height);
- // If the folder doesn't fit within the bounds, center it about the desired bounds
- if (width >= bounds.width()) {
- left = bounds.left + (bounds.width() - width) / 2;
- }
- if (height >= bounds.height()) {
- top = bounds.top + (bounds.height() - height) / 2;
- }
-
- int folderPivotX = width / 2 + (centeredLeft - left);
- int folderPivotY = height / 2 + (centeredTop - top);
- setPivotX(folderPivotX);
- setPivotY(folderPivotY);
- mFolderIconPivotX = (int) (mFolderIcon.getMeasuredWidth() *
- (1.0f * folderPivotX / width));
- mFolderIconPivotY = (int) (mFolderIcon.getMeasuredHeight() *
- (1.0f * folderPivotY / height));
-
- lp.width = width;
- lp.height = height;
- lp.x = left;
- lp.y = top;
- }
-
- float getPivotXForIconAnimation() {
- return mFolderIconPivotX;
- }
- float getPivotYForIconAnimation() {
- return mFolderIconPivotY;
- }
-
- private void setupContentForNumItems(int count) {
- setupContentDimensions(count);
-
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- if (lp == null) {
- lp = new DragLayer.LayoutParams(0, 0);
- lp.customPosition = true;
- setLayoutParams(lp);
- }
- centerAboutIcon();
- }
-
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
- int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight()
- + mFolderNameHeight;
-
- int contentWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
- MeasureSpec.EXACTLY);
- int contentHeightSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredHeight(),
- MeasureSpec.EXACTLY);
- mContent.measure(contentWidthSpec, contentHeightSpec);
-
- mFolderName.measure(contentWidthSpec,
- MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
- setMeasuredDimension(width, height);
- }
-
- private void arrangeChildren(ArrayList<View> list) {
- int[] vacant = new int[2];
- if (list == null) {
- list = getItemsInReadingOrder();
- }
- mContent.removeAllViews();
-
- for (int i = 0; i < list.size(); i++) {
- View v = list.get(i);
- mContent.getVacantCell(vacant, 1, 1);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
- lp.cellX = vacant[0];
- lp.cellY = vacant[1];
- ItemInfo info = (ItemInfo) v.getTag();
- if (info.cellX != vacant[0] || info.cellY != vacant[1]) {
- info.cellX = vacant[0];
- info.cellY = vacant[1];
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
- info.cellX, info.cellY);
- }
- boolean insert = false;
- mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
- }
- mItemsInvalidated = true;
- }
-
- public int getItemCount() {
- return mContent.getShortcutsAndWidgets().getChildCount();
- }
-
- public View getItemAt(int index) {
- return mContent.getShortcutsAndWidgets().getChildAt(index);
- }
-
- private void onCloseComplete() {
- DragLayer parent = (DragLayer) getParent();
- if (parent != null) {
- parent.removeView(this);
- }
- mDragController.removeDropTarget((DropTarget) this);
- clearFocus();
- mFolderIcon.requestFocus();
-
- if (mRearrangeOnClose) {
- setupContentForNumItems(getItemCount());
- mRearrangeOnClose = false;
- }
- if (getItemCount() <= 1) {
- if (!mDragInProgress && !mSuppressFolderDeletion) {
- replaceFolderWithFinalItem();
- } else if (mDragInProgress) {
- mDeleteFolderOnDropCompleted = true;
- }
- }
- mSuppressFolderDeletion = false;
- }
-
- private void replaceFolderWithFinalItem() {
- ItemInfo finalItem = null;
-
- if (getItemCount() == 1) {
- finalItem = mInfo.contents.get(0);
- }
-
- // Remove the folder completely
- CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen);
- cellLayout.removeView(mFolderIcon);
- if (mFolderIcon instanceof DropTarget) {
- mDragController.removeDropTarget((DropTarget) mFolderIcon);
- }
- mLauncher.removeFolder(mInfo);
-
- if (finalItem != null) {
- LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
- mInfo.screen, mInfo.cellX, mInfo.cellY);
- }
- LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
-
- // Add the last remaining child to the workspace in place of the folder
- if (finalItem != null) {
- View child = mLauncher.createShortcut(R.layout.application, cellLayout,
- (ShortcutInfo) finalItem);
-
- mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, mInfo.cellX,
- mInfo.cellY, mInfo.spanX, mInfo.spanY);
- }
- }
-
- // This method keeps track of the last item in the folder for the purposes
- // of keyboard focus
- private void updateTextViewFocus() {
- View lastChild = getItemAt(getItemCount() - 1);
- getItemAt(getItemCount() - 1);
- if (lastChild != null) {
- mFolderName.setNextFocusDownId(lastChild.getId());
- mFolderName.setNextFocusRightId(lastChild.getId());
- mFolderName.setNextFocusLeftId(lastChild.getId());
- mFolderName.setNextFocusUpId(lastChild.getId());
- }
- }
-
- public void onDrop(DragObject d) {
- ShortcutInfo item;
- if (d.dragInfo instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- item = ((ApplicationInfo) d.dragInfo).makeShortcut();
- item.spanX = 1;
- item.spanY = 1;
- } else {
- item = (ShortcutInfo) d.dragInfo;
- }
- // Dragged from self onto self, currently this is the only path possible, however
- // we keep this as a distinct code path.
- if (item == mCurrentDragInfo) {
- ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
- si.cellX = lp.cellX = mEmptyCell[0];
- si.cellX = lp.cellY = mEmptyCell[1];
- mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
- if (d.dragView.hasDrawn()) {
- mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView);
- } else {
- d.deferDragViewCleanupPostAnimation = false;
- mCurrentDragView.setVisibility(VISIBLE);
- }
- mItemsInvalidated = true;
- setupContentDimensions(getItemCount());
- mSuppressOnAdd = true;
- }
- mInfo.add(item);
- }
-
- public void onAdd(ShortcutInfo item) {
- mItemsInvalidated = true;
- // If the item was dropped onto this open folder, we have done the work associated
- // with adding the item to the folder, as indicated by mSuppressOnAdd being set
- if (mSuppressOnAdd) return;
- if (!findAndSetEmptyCells(item)) {
- // The current layout is full, can we expand it?
- setupContentForNumItems(getItemCount() + 1);
- findAndSetEmptyCells(item);
- }
- createAndAddShortcut(item);
- LauncherModel.addOrMoveItemInDatabase(
- mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
- }
-
- public void onRemove(ShortcutInfo item) {
- mItemsInvalidated = true;
- // If this item is being dragged from this open folder, we have already handled
- // the work associated with removing the item, so we don't have to do anything here.
- if (item == mCurrentDragInfo) return;
- View v = getViewForInfo(item);
- mContent.removeView(v);
- if (mState == STATE_ANIMATING) {
- mRearrangeOnClose = true;
- } else {
- setupContentForNumItems(getItemCount());
- }
- if (getItemCount() <= 1) {
- replaceFolderWithFinalItem();
- }
- }
-
- private View getViewForInfo(ShortcutInfo item) {
- for (int j = 0; j < mContent.getCountY(); j++) {
- for (int i = 0; i < mContent.getCountX(); i++) {
- View v = mContent.getChildAt(i, j);
- if (v.getTag() == item) {
- return v;
- }
- }
- }
- return null;
- }
-
- public void onItemsChanged() {
- updateTextViewFocus();
- }
-
- public void onTitleChanged(CharSequence title) {
- }
-
- public ArrayList<View> getItemsInReadingOrder() {
- return getItemsInReadingOrder(true);
- }
-
- public ArrayList<View> getItemsInReadingOrder(boolean includeCurrentDragItem) {
- if (mItemsInvalidated) {
- mItemsInReadingOrder.clear();
- for (int j = 0; j < mContent.getCountY(); j++) {
- for (int i = 0; i < mContent.getCountX(); i++) {
- View v = mContent.getChildAt(i, j);
- if (v != null) {
- ShortcutInfo info = (ShortcutInfo) v.getTag();
- if (info != mCurrentDragInfo || includeCurrentDragItem) {
- mItemsInReadingOrder.add(v);
- }
- }
- }
- }
- mItemsInvalidated = false;
- }
- return mItemsInReadingOrder;
- }
-
- public void getLocationInDragLayer(int[] loc) {
- mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
- }
-
- public void onFocusChange(View v, boolean hasFocus) {
- if (v == mFolderName && hasFocus) {
- startEditingFolderName();
- }
- }
-}
diff --git a/src/com/android/launcher2/FolderEditText.java b/src/com/android/launcher2/FolderEditText.java
deleted file mode 100644
index 13169bd51..000000000
--- a/src/com/android/launcher2/FolderEditText.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.EditText;
-
-public class FolderEditText extends EditText {
-
- private Folder mFolder;
-
- public FolderEditText(Context context) {
- super(context);
- }
-
- public FolderEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public FolderEditText(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public void setFolder(Folder folder) {
- mFolder = folder;
- }
-
- @Override
- public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- // Catch the back button on the soft keyboard so that we can just close the activity
- if (event.getKeyCode() == android.view.KeyEvent.KEYCODE_BACK) {
- mFolder.doneEditingFolderName(true);
- }
- return super.onKeyPreIme(keyCode, event);
- }
-}
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
deleted file mode 100644
index 4919b57f0..000000000
--- a/src/com/android/launcher2/FolderIcon.java
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
-import com.android.launcher2.FolderInfo.FolderListener;
-
-import java.util.ArrayList;
-
-/**
- * An icon that can appear on in the workspace representing an {@link UserFolder}.
- */
-public class FolderIcon extends LinearLayout implements FolderListener {
- private Launcher mLauncher;
- Folder mFolder;
- FolderInfo mInfo;
- private static boolean sStaticValuesDirty = true;
-
- private CheckLongPressHelper mLongPressHelper;
-
- // The number of icons to display in the
- private static final int NUM_ITEMS_IN_PREVIEW = 3;
- private static final int CONSUMPTION_ANIMATION_DURATION = 100;
- private static final int DROP_IN_ANIMATION_DURATION = 400;
- private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
-
- // The degree to which the inner ring grows when accepting drop
- private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
-
- // The degree to which the outer ring is scaled in its natural state
- private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
-
- // The amount of vertical spread between items in the stack [0...1]
- private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f;
-
- // The degree to which the item in the back of the stack is scaled [0...1]
- // (0 means it's not scaled at all, 1 means it's scaled to nothing)
- private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f;
-
- public static Drawable sSharedFolderLeaveBehind = null;
-
- private ImageView mPreviewBackground;
- private BubbleTextView mFolderName;
-
- FolderRingAnimator mFolderRingAnimator = null;
-
- // These variables are all associated with the drawing of the preview; they are stored
- // as member variables for shared usage and to avoid computation on each frame
- private int mIntrinsicIconSize;
- private float mBaselineIconScale;
- private int mBaselineIconSize;
- private int mAvailableSpaceInPreview;
- private int mTotalWidth = -1;
- private int mPreviewOffsetX;
- private int mPreviewOffsetY;
- private float mMaxPerspectiveShift;
- boolean mAnimating = false;
- private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
- private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-
- public FolderIcon(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public FolderIcon(Context context) {
- super(context);
- init();
- }
-
- private void init() {
- mLongPressHelper = new CheckLongPressHelper(this);
- }
-
- public boolean isDropEnabled() {
- final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
- final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
- final Workspace workspace = (Workspace) cellLayout.getParent();
- return !workspace.isSmall();
- }
-
- static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
- FolderInfo folderInfo, IconCache iconCache) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION;
- if (error) {
- throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
- "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
- "is dependent on this");
- }
-
- FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
-
- icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
- icon.mFolderName.setText(folderInfo.title);
- icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
-
- icon.setTag(folderInfo);
- icon.setOnClickListener(launcher);
- icon.mInfo = folderInfo;
- icon.mLauncher = launcher;
- icon.setContentDescription(String.format(launcher.getString(R.string.folder_name_format),
- folderInfo.title));
- Folder folder = Folder.fromXml(launcher);
- folder.setDragController(launcher.getDragController());
- folder.setFolderIcon(icon);
- folder.bind(folderInfo);
- icon.mFolder = folder;
-
- icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
- folderInfo.addListener(icon);
-
- return icon;
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- sStaticValuesDirty = true;
- return super.onSaveInstanceState();
- }
-
- public static class FolderRingAnimator {
- public int mCellX;
- public int mCellY;
- private CellLayout mCellLayout;
- public float mOuterRingSize;
- public float mInnerRingSize;
- public FolderIcon mFolderIcon = null;
- public Drawable mOuterRingDrawable = null;
- public Drawable mInnerRingDrawable = null;
- public static Drawable sSharedOuterRingDrawable = null;
- public static Drawable sSharedInnerRingDrawable = null;
- public static int sPreviewSize = -1;
- public static int sPreviewPadding = -1;
-
- private ValueAnimator mAcceptAnimator;
- private ValueAnimator mNeutralAnimator;
-
- public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
- mFolderIcon = folderIcon;
- Resources res = launcher.getResources();
- mOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
- mInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
-
- // We need to reload the static values when configuration changes in case they are
- // different in another configuration
- if (sStaticValuesDirty) {
- sPreviewSize = res.getDimensionPixelSize(R.dimen.folder_preview_size);
- sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
- sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
- sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo);
- sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
- sStaticValuesDirty = false;
- }
- }
-
- public void animateToAcceptState() {
- if (mNeutralAnimator != null) {
- mNeutralAnimator.cancel();
- }
- mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f);
- mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
-
- final int previewSize = sPreviewSize;
- mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
- mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * previewSize;
- mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * previewSize;
- if (mCellLayout != null) {
- mCellLayout.invalidate();
- }
- }
- });
- mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (mFolderIcon != null) {
- mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE);
- }
- }
- });
- mAcceptAnimator.start();
- }
-
- public void animateToNaturalState() {
- if (mAcceptAnimator != null) {
- mAcceptAnimator.cancel();
- }
- mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f);
- mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
-
- final int previewSize = sPreviewSize;
- mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
- mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * previewSize;
- mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * previewSize;
- if (mCellLayout != null) {
- mCellLayout.invalidate();
- }
- }
- });
- mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCellLayout != null) {
- mCellLayout.hideFolderAccept(FolderRingAnimator.this);
- }
- if (mFolderIcon != null) {
- mFolderIcon.mPreviewBackground.setVisibility(VISIBLE);
- }
- }
- });
- mNeutralAnimator.start();
- }
-
- // Location is expressed in window coordinates
- public void getCell(int[] loc) {
- loc[0] = mCellX;
- loc[1] = mCellY;
- }
-
- // Location is expressed in window coordinates
- public void setCell(int x, int y) {
- mCellX = x;
- mCellY = y;
- }
-
- public void setCellLayout(CellLayout layout) {
- mCellLayout = layout;
- }
-
- public float getOuterRingSize() {
- return mOuterRingSize;
- }
-
- public float getInnerRingSize() {
- return mInnerRingSize;
- }
- }
-
- private boolean willAcceptItem(ItemInfo item) {
- final int itemType = item.itemType;
- return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
- !mFolder.isFull() && item != mInfo && !mInfo.opened);
- }
-
- public boolean acceptDrop(Object dragInfo) {
- final ItemInfo item = (ItemInfo) dragInfo;
- return willAcceptItem(item);
- }
-
- public void addItem(ShortcutInfo item) {
- mInfo.add(item);
- LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
- }
-
- public void onDragEnter(Object dragInfo) {
- if (!willAcceptItem((ItemInfo) dragInfo)) return;
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
- CellLayout layout = (CellLayout) getParent().getParent();
- mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
- mFolderRingAnimator.setCellLayout(layout);
- mFolderRingAnimator.animateToAcceptState();
- layout.showFolderAccept(mFolderRingAnimator);
- }
-
- public void onDragOver(Object dragInfo) {
- }
-
- public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
- final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
- float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
-
- Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
- computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
-
- // This will animate the dragView (srcView) into the new folder
- onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null);
-
- // This will animate the first item from it's position as an icon into its
- // position as the first item in the preview
- animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION);
- addItem(destInfo);
- }
-
- public void onDragExit(Object dragInfo) {
- onDragExit();
- }
-
- public void onDragExit() {
- mFolderRingAnimator.animateToNaturalState();
- }
-
- private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
- float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable,
- DragObject d) {
- item.cellX = -1;
- item.cellY = -1;
-
- // Typically, the animateView corresponds to the DragView; however, if this is being done
- // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we
- // will not have a view to animate
- if (animateView != null) {
- DragLayer dragLayer = mLauncher.getDragLayer();
- Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(animateView, from);
- Rect to = finalRect;
- if (to == null) {
- to = new Rect();
- Workspace workspace = mLauncher.getWorkspace();
- // Set cellLayout and this to it's final state to compute final animation locations
- workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
- float scaleX = getScaleX();
- float scaleY = getScaleY();
- setScaleX(1.0f);
- setScaleY(1.0f);
- scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
- // Finished computing final animation locations, restore current state
- setScaleX(scaleX);
- setScaleY(scaleY);
- workspace.resetTransitionTransform((CellLayout) getParent().getParent());
- }
-
- int[] center = new int[2];
- float scale = getLocalCenterForIndex(index, center);
- center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
- center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
-
- to.offset(center[0] - animateView.getMeasuredWidth() / 2,
- center[1] - animateView.getMeasuredHeight() / 2);
-
- float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
-
- float finalScale = scale * scaleRelativeToDragLayer;
- dragLayer.animateView(animateView, from, to, finalAlpha,
- 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
- new DecelerateInterpolator(2), new AccelerateInterpolator(2),
- postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
- postDelayed(new Runnable() {
- public void run() {
- addItem(item);
- }
- }, DROP_IN_ANIMATION_DURATION);
- } else {
- addItem(item);
- }
- }
-
- public void onDrop(DragObject d) {
- ShortcutInfo item;
- if (d.dragInfo instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- item = ((ApplicationInfo) d.dragInfo).makeShortcut();
- } else {
- item = (ShortcutInfo) d.dragInfo;
- }
- mFolder.notifyDrop();
- onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d);
- }
-
- public DropTarget getDropTargetDelegate(DragObject d) {
- return null;
- }
-
- private void computePreviewDrawingParams(int drawableSize, int totalSize) {
- if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) {
- mIntrinsicIconSize = drawableSize;
- mTotalWidth = totalSize;
-
- final int previewSize = FolderRingAnimator.sPreviewSize;
- final int previewPadding = FolderRingAnimator.sPreviewPadding;
-
- mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
- // cos(45) = 0.707 + ~= 0.1) = 0.8f
- int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f));
-
- int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR));
- mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight);
-
- mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale);
- mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR;
-
- mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
- mPreviewOffsetY = previewPadding;
- }
- }
-
- private void computePreviewDrawingParams(Drawable d) {
- computePreviewDrawingParams(d.getIntrinsicWidth(), getMeasuredWidth());
- }
-
- class PreviewItemDrawingParams {
- PreviewItemDrawingParams(float transX, float transY, float scale, int overlayAlpha) {
- this.transX = transX;
- this.transY = transY;
- this.scale = scale;
- this.overlayAlpha = overlayAlpha;
- }
- float transX;
- float transY;
- float scale;
- int overlayAlpha;
- Drawable drawable;
- }
-
- private float getLocalCenterForIndex(int index, int[] center) {
- mParams = computePreviewItemDrawingParams(Math.min(NUM_ITEMS_IN_PREVIEW, index), mParams);
-
- mParams.transX += mPreviewOffsetX;
- mParams.transY += mPreviewOffsetY;
- float offsetX = mParams.transX + (mParams.scale * mIntrinsicIconSize) / 2;
- float offsetY = mParams.transY + (mParams.scale * mIntrinsicIconSize) / 2;
-
- center[0] = (int) Math.round(offsetX);
- center[1] = (int) Math.round(offsetY);
- return mParams.scale;
- }
-
- private PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
- PreviewItemDrawingParams params) {
- index = NUM_ITEMS_IN_PREVIEW - index - 1;
- float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
- float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
-
- float offset = (1 - r) * mMaxPerspectiveShift;
- float scaledSize = scale * mBaselineIconSize;
- float scaleOffsetCorrection = (1 - scale) * mBaselineIconSize;
-
- // We want to imagine our coordinates from the bottom left, growing up and to the
- // right. This is natural for the x-axis, but for the y-axis, we have to invert things.
- float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection);
- float transX = offset + scaleOffsetCorrection;
- float totalScale = mBaselineIconScale * scale;
- final int overlayAlpha = (int) (80 * (1 - r));
-
- if (params == null) {
- params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
- } else {
- params.transX = transX;
- params.transY = transY;
- params.scale = totalScale;
- params.overlayAlpha = overlayAlpha;
- }
- return params;
- }
-
- private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
- canvas.save();
- canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY);
- canvas.scale(params.scale, params.scale);
- Drawable d = params.drawable;
-
- if (d != null) {
- d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
- d.setFilterBitmap(true);
- d.setColorFilter(Color.argb(params.overlayAlpha, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);
- d.draw(canvas);
- d.clearColorFilter();
- d.setFilterBitmap(false);
- }
- canvas.restore();
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
-
- if (mFolder == null) return;
- if (mFolder.getItemCount() == 0 && !mAnimating) return;
-
- ArrayList<View> items = mFolder.getItemsInReadingOrder(false);
- Drawable d;
- TextView v;
-
- // Update our drawing parameters if necessary
- if (mAnimating) {
- computePreviewDrawingParams(mAnimParams.drawable);
- } else {
- v = (TextView) items.get(0);
- d = v.getCompoundDrawables()[1];
- computePreviewDrawingParams(d);
- }
-
- int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
- if (!mAnimating) {
- for (int i = nItemsInPreview - 1; i >= 0; i--) {
- v = (TextView) items.get(i);
- d = v.getCompoundDrawables()[1];
-
- mParams = computePreviewItemDrawingParams(i, mParams);
- mParams.drawable = d;
- drawPreviewItem(canvas, mParams);
- }
- } else {
- drawPreviewItem(canvas, mAnimParams);
- }
- }
-
- private void animateFirstItem(final Drawable d, int duration) {
- computePreviewDrawingParams(d);
- final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
-
- final float scale0 = 1.0f;
- final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
- final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2;
- mAnimParams.drawable = d;
-
- ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f);
- va.addUpdateListener(new AnimatorUpdateListener(){
- public void onAnimationUpdate(ValueAnimator animation) {
- float progress = (Float) animation.getAnimatedValue();
-
- mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0);
- mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0);
- mAnimParams.scale = scale0 + progress * (finalParams.scale - scale0);
- invalidate();
- }
- });
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mAnimating = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- }
- });
- va.setDuration(duration);
- va.start();
- }
-
- public void setTextVisible(boolean visible) {
- if (visible) {
- mFolderName.setVisibility(VISIBLE);
- } else {
- mFolderName.setVisibility(INVISIBLE);
- }
- }
-
- public boolean getTextVisible() {
- return mFolderName.getVisibility() == VISIBLE;
- }
-
- public void onItemsChanged() {
- invalidate();
- requestLayout();
- }
-
- public void onAdd(ShortcutInfo item) {
- invalidate();
- requestLayout();
- }
-
- public void onRemove(ShortcutInfo item) {
- invalidate();
- requestLayout();
- }
-
- public void onTitleChanged(CharSequence title) {
- mFolderName.setText(title.toString());
- setContentDescription(String.format(getContext().getString(R.string.folder_name_format),
- title));
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Call the superclass onTouchEvent first, because sometimes it changes the state to
- // isPressed() on an ACTION_UP
- boolean result = super.onTouchEvent(event);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mLongPressHelper.postCheckForLongPress();
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- mLongPressHelper.cancelLongPress();
- break;
- }
- return result;
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- mLongPressHelper.cancelLongPress();
- }
-}
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
deleted file mode 100644
index f59707671..000000000
--- a/src/com/android/launcher2/FolderInfo.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2008 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 android.content.ContentValues;
-
-/**
- * Represents a folder containing shortcuts or apps.
- */
-class FolderInfo extends ItemInfo {
-
- /**
- * Whether this folder has been opened
- */
- boolean opened;
-
- /**
- * The folder name.
- */
- CharSequence title;
-
- /**
- * The apps and shortcuts
- */
- ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
-
- ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
-
- FolderInfo() {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
- }
-
- /**
- * Add an app or shortcut
- *
- * @param item
- */
- public void add(ShortcutInfo item) {
- contents.add(item);
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).onAdd(item);
- }
- itemsChanged();
- }
-
- /**
- * Remove an app or shortcut. Does not change the DB.
- *
- * @param item
- */
- public void remove(ShortcutInfo item) {
- contents.remove(item);
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).onRemove(item);
- }
- itemsChanged();
- }
-
- public void setTitle(CharSequence title) {
- this.title = title;
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).onTitleChanged(title);
- }
- }
-
- @Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
- values.put(LauncherSettings.Favorites.TITLE, title.toString());
- }
-
- void addListener(FolderListener listener) {
- listeners.add(listener);
- }
-
- void removeListener(FolderListener listener) {
- if (listeners.contains(listener)) {
- listeners.remove(listener);
- }
- }
-
- void itemsChanged() {
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).onItemsChanged();
- }
- }
-
- @Override
- void unbind() {
- super.unbind();
- listeners.clear();
- }
-
- interface FolderListener {
- public void onAdd(ShortcutInfo item);
- public void onRemove(ShortcutInfo item);
- public void onTitleChanged(CharSequence title);
- public void onItemsChanged();
- }
-}
diff --git a/src/com/android/launcher2/HandleView.java b/src/com/android/launcher2/HandleView.java
deleted file mode 100644
index d77138b0a..000000000
--- a/src/com/android/launcher2/HandleView.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.launcher.R;
-
-public class HandleView extends ImageView {
- private static final int ORIENTATION_HORIZONTAL = 1;
-
- private Launcher mLauncher;
- private int mOrientation = ORIENTATION_HORIZONTAL;
-
- public HandleView(Context context) {
- super(context);
- }
-
- public HandleView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public HandleView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HandleView, defStyle, 0);
- mOrientation = a.getInt(R.styleable.HandleView_direction, ORIENTATION_HORIZONTAL);
- a.recycle();
-
- setContentDescription(context.getString(R.string.all_apps_button_label));
- }
-
- @Override
- public View focusSearch(int direction) {
- View newFocus = super.focusSearch(direction);
- if (newFocus == null && !mLauncher.isAllAppsVisible()) {
- final Workspace workspace = mLauncher.getWorkspace();
- workspace.dispatchUnhandledMove(null, direction);
- return (mOrientation == ORIENTATION_HORIZONTAL && direction == FOCUS_DOWN) ?
- this : workspace;
- }
- return newFocus;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN && mLauncher.isAllAppsVisible()) {
- return false;
- }
- return super.onTouchEvent(ev);
- }
-
- void setLauncher(Launcher launcher) {
- mLauncher = launcher;
- }
-}
diff --git a/src/com/android/launcher2/HolographicImageView.java b/src/com/android/launcher2/HolographicImageView.java
deleted file mode 100644
index 9e551e047..000000000
--- a/src/com/android/launcher2/HolographicImageView.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-public class HolographicImageView extends ImageView {
-
- private final HolographicViewHelper mHolographicHelper;
-
- public HolographicImageView(Context context) {
- this(context, null);
- }
-
- public HolographicImageView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public HolographicImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mHolographicHelper = new HolographicViewHelper(context);
- }
-
- void invalidatePressedFocusedStates() {
- mHolographicHelper.invalidatePressedFocusedStates(this);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- // One time call to generate the pressed/focused state -- must be called after
- // measure/layout
- mHolographicHelper.generatePressedFocusedStates(this);
- }
-}
diff --git a/src/com/android/launcher2/HolographicLinearLayout.java b/src/com/android/launcher2/HolographicLinearLayout.java
deleted file mode 100644
index 0f997d5fa..000000000
--- a/src/com/android/launcher2/HolographicLinearLayout.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.launcher.R;
-
-public class HolographicLinearLayout extends LinearLayout {
-
- private final HolographicViewHelper mHolographicHelper;
- private ImageView mImageView;
- private int mImageViewId;
-
- public HolographicLinearLayout(Context context) {
- this(context, null);
- }
-
- public HolographicLinearLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public HolographicLinearLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HolographicLinearLayout,
- defStyle, 0);
- mImageViewId = a.getResourceId(R.styleable.HolographicLinearLayout_sourceImageViewId, -1);
- a.recycle();
-
- setWillNotDraw(false);
- mHolographicHelper = new HolographicViewHelper(context);
- }
-
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
-
- if (mImageView != null) {
- Drawable d = mImageView.getDrawable();
- if (d instanceof StateListDrawable) {
- StateListDrawable sld = (StateListDrawable) d;
- sld.setState(getDrawableState());
- }
- }
- }
-
- void invalidatePressedFocusedStates() {
- mHolographicHelper.invalidatePressedFocusedStates(mImageView);
- invalidate();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- // One time call to generate the pressed/focused state -- must be called after
- // measure/layout
- if (mImageView == null) {
- mImageView = (ImageView) findViewById(mImageViewId);
- }
- mHolographicHelper.generatePressedFocusedStates(mImageView);
- }
-}
diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
deleted file mode 100644
index 56d194d4e..000000000
--- a/src/com/android/launcher2/HolographicOutlineHelper.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2008 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.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.MaskFilter;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.TableMaskFilter;
-
-public class HolographicOutlineHelper {
- private final Paint mHolographicPaint = new Paint();
- private final Paint mBlurPaint = new Paint();
- private final Paint mErasePaint = new Paint();
- private final Paint mAlphaClipPaint = new Paint();
-
- public static final int MAX_OUTER_BLUR_RADIUS;
- public static final int MIN_OUTER_BLUR_RADIUS;
-
- private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
- private static final BlurMaskFilter sThickOuterBlurMaskFilter;
- private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
- private static final BlurMaskFilter sThinOuterBlurMaskFilter;
- private static final BlurMaskFilter sThickInnerBlurMaskFilter;
- private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
- private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
-
- private static final int THICK = 0;
- private static final int MEDIUM = 1;
- private static final int EXTRA_THICK = 2;
-
- static {
- final float scale = LauncherApplication.getScreenDensity();
-
- MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
- MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
-
- sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
- sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
- sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
- sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
- sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
- sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
- sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
- }
-
- private int[] mTempOffset = new int[2];
-
- HolographicOutlineHelper() {
- mHolographicPaint.setFilterBitmap(true);
- mHolographicPaint.setAntiAlias(true);
- mBlurPaint.setFilterBitmap(true);
- mBlurPaint.setAntiAlias(true);
- mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
- mErasePaint.setFilterBitmap(true);
- mErasePaint.setAntiAlias(true);
- MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(180, 255);
- mAlphaClipPaint.setMaskFilter(alphaClipTable);
- }
-
- /**
- * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
- * pages.
- */
- public static float highlightAlphaInterpolator(float r) {
- float maxAlpha = 0.6f;
- return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
- }
-
- /**
- * Returns the interpolated view alpha for the effect we want when scrolling pages.
- */
- public static float viewAlphaInterpolator(float r) {
- final float pivot = 0.95f;
- if (r < pivot) {
- return (float) Math.pow(r / pivot, 1.5f);
- } else {
- return 1.0f;
- }
- }
-
- /**
- * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
- * bitmap.
- */
- void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, int thickness) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, mAlphaClipPaint,
- thickness);
- }
- void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, Paint alphaClipPaint, int thickness) {
-
- // We start by removing most of the alpha channel so as to ignore shadows, and
- // other types of partial transparency when defining the shape of the object
- if (alphaClipPaint == null) {
- alphaClipPaint = mAlphaClipPaint;
- }
- Bitmap glowShape = srcDst.extractAlpha(alphaClipPaint, mTempOffset);
-
- // calculate the outer blur first
- BlurMaskFilter outerBlurMaskFilter;
- switch (thickness) {
- case EXTRA_THICK:
- outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
- break;
- case THICK:
- outerBlurMaskFilter = sThickOuterBlurMaskFilter;
- break;
- case MEDIUM:
- outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
- break;
- default:
- throw new RuntimeException("Invalid blur thickness");
- }
- mBlurPaint.setMaskFilter(outerBlurMaskFilter);
- int[] outerBlurOffset = new int[2];
- Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
- if (thickness == EXTRA_THICK) {
- mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
- } else {
- mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
- }
-
- int[] brightOutlineOffset = new int[2];
- Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
-
- // calculate the inner blur
- srcDstCanvas.setBitmap(glowShape);
- srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
- BlurMaskFilter innerBlurMaskFilter;
- switch (thickness) {
- case EXTRA_THICK:
- innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
- break;
- case THICK:
- innerBlurMaskFilter = sThickInnerBlurMaskFilter;
- break;
- case MEDIUM:
- innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
- break;
- default:
- throw new RuntimeException("Invalid blur thickness");
- }
- mBlurPaint.setMaskFilter(innerBlurMaskFilter);
- int[] thickInnerBlurOffset = new int[2];
- Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
-
- // mask out the inner blur
- srcDstCanvas.setBitmap(thickInnerBlur);
- srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
- -thickInnerBlurOffset[1], mErasePaint);
- srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
- mErasePaint);
- srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
- mErasePaint);
-
- // draw the inner and outer blur
- srcDstCanvas.setBitmap(srcDst);
- srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
- mHolographicPaint.setColor(color);
- srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
- mHolographicPaint);
- srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
- mHolographicPaint);
-
- // draw the bright outline
- mHolographicPaint.setColor(outlineColor);
- srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
- mHolographicPaint);
-
- // cleanup
- srcDstCanvas.setBitmap(null);
- brightOutline.recycle();
- thickOuterBlur.recycle();
- thickInnerBlur.recycle();
- glowShape.recycle();
- }
-
- void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
- }
-
- void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
- }
-
- void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, Paint alphaClipPaint) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, alphaClipPaint,
- MEDIUM);
- }
-
- void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
- }
-
-}
diff --git a/src/com/android/launcher2/HolographicViewHelper.java b/src/com/android/launcher2/HolographicViewHelper.java
deleted file mode 100644
index fd499082f..000000000
--- a/src/com/android/launcher2/HolographicViewHelper.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.StateListDrawable;
-import android.widget.ImageView;
-
-public class HolographicViewHelper {
-
- private final Canvas mTempCanvas = new Canvas();
-
- private boolean mStatesUpdated;
- private int mHighlightColor;
-
- public HolographicViewHelper(Context context) {
- Resources res = context.getResources();
- mHighlightColor = res.getColor(android.R.color.holo_blue_light);
- }
-
- /**
- * Generate the pressed/focused states if necessary.
- */
- void generatePressedFocusedStates(ImageView v) {
- if (!mStatesUpdated && v != null) {
- mStatesUpdated = true;
- Bitmap outline = createPressImage(v, mTempCanvas);
- FastBitmapDrawable d = new FastBitmapDrawable(outline);
-
- StateListDrawable states = new StateListDrawable();
- states.addState(new int[] {android.R.attr.state_pressed}, d);
- states.addState(new int[] {android.R.attr.state_focused}, d);
- states.addState(new int[] {}, v.getDrawable());
- v.setImageDrawable(states);
- }
- }
-
- /**
- * Invalidates the pressed/focused states.
- */
- void invalidatePressedFocusedStates(ImageView v) {
- mStatesUpdated = false;
- if (v != null) {
- v.invalidate();
- }
- }
-
- /**
- * Creates a new press state image which is the old image with a blue overlay.
- * Responsibility for the bitmap is transferred to the caller.
- */
- private Bitmap createPressImage(ImageView v, Canvas canvas) {
- final int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
- final Bitmap b = Bitmap.createBitmap(
- v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
-
- canvas.setBitmap(b);
- canvas.save();
- v.getDrawable().draw(canvas);
- canvas.restore();
- canvas.drawColor(mHighlightColor, PorterDuff.Mode.SRC_IN);
- canvas.setBitmap(null);
-
- return b;
- }
-}
diff --git a/src/com/android/launcher2/Hotseat.java b/src/com/android/launcher2/Hotseat.java
deleted file mode 100644
index 15d606d8f..000000000
--- a/src/com/android/launcher2/Hotseat.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.launcher.R;
-
-public class Hotseat extends FrameLayout {
- @SuppressWarnings("unused")
- private static final String TAG = "Hotseat";
-
- private Launcher mLauncher;
- private CellLayout mContent;
-
- private int mCellCountX;
- private int mCellCountY;
- private int mAllAppsButtonRank;
- private boolean mIsLandscape;
-
- public Hotseat(Context context) {
- this(context, null);
- }
-
- public Hotseat(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public Hotseat(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.Hotseat, defStyle, 0);
- mCellCountX = a.getInt(R.styleable.Hotseat_cellCountX, -1);
- mCellCountY = a.getInt(R.styleable.Hotseat_cellCountY, -1);
- mAllAppsButtonRank = context.getResources().getInteger(R.integer.hotseat_all_apps_index);
- mIsLandscape = context.getResources().getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE;
- }
-
- public void setup(Launcher launcher) {
- mLauncher = launcher;
- setOnKeyListener(new HotseatIconKeyEventListener());
- }
-
- CellLayout getLayout() {
- return mContent;
- }
-
- /* Get the orientation invariant order of the item in the hotseat for persistence. */
- int getOrderInHotseat(int x, int y) {
- return mIsLandscape ? (mContent.getCountY() - y - 1) : x;
- }
- /* Get the orientation specific coordinates given an invariant order in the hotseat. */
- int getCellXFromOrder(int rank) {
- return mIsLandscape ? 0 : rank;
- }
- int getCellYFromOrder(int rank) {
- return mIsLandscape ? (mContent.getCountY() - (rank + 1)) : 0;
- }
- public boolean isAllAppsButtonRank(int rank) {
- return rank == mAllAppsButtonRank;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (mCellCountX < 0) mCellCountX = LauncherModel.getCellCountX();
- if (mCellCountY < 0) mCellCountY = LauncherModel.getCellCountY();
- mContent = (CellLayout) findViewById(R.id.layout);
- mContent.setGridSize(mCellCountX, mCellCountY);
- mContent.setIsHotseat(true);
-
- resetLayout();
- }
-
- void resetLayout() {
- mContent.removeAllViewsInLayout();
-
- // Add the Apps button
- Context context = getContext();
- LayoutInflater inflater = LayoutInflater.from(context);
- BubbleTextView allAppsButton = (BubbleTextView)
- inflater.inflate(R.layout.application, mContent, false);
- allAppsButton.setCompoundDrawablesWithIntrinsicBounds(null,
- context.getResources().getDrawable(R.drawable.all_apps_button_icon), null, null);
- allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
- allAppsButton.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (mLauncher != null &&
- (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
- mLauncher.onTouchDownAllAppsButton(v);
- }
- return false;
- }
- });
-
- allAppsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(android.view.View v) {
- if (mLauncher != null) {
- mLauncher.onClickAllAppsButton(v);
- }
- }
- });
-
- // Note: We do this to ensure that the hotseat is always laid out in the orientation of
- // the hotseat in order regardless of which orientation they were added
- int x = getCellXFromOrder(mAllAppsButtonRank);
- int y = getCellYFromOrder(mAllAppsButtonRank);
- CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
- lp.canReorder = false;
- mContent.addViewToCellLayout(allAppsButton, -1, 0, lp, true);
- }
-}
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
deleted file mode 100644
index aa19545bd..000000000
--- a/src/com/android/launcher2/IconCache.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-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.drawable.Drawable;
-
-import java.util.HashMap;
-
-/**
- * Cache of application icons. Icons can be made from any thread.
- */
-public class IconCache {
- @SuppressWarnings("unused")
- private static final String TAG = "Launcher.IconCache";
-
- private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
-
- private static class CacheEntry {
- public Bitmap icon;
- public String title;
- }
-
- private final Bitmap mDefaultIcon;
- private final LauncherApplication mContext;
- private final PackageManager mPackageManager;
- private final HashMap<ComponentName, CacheEntry> mCache =
- new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
- private int mIconDpi;
-
- public IconCache(LauncherApplication context) {
- ActivityManager activityManager =
- (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-
- mContext = context;
- mPackageManager = context.getPackageManager();
- mIconDpi = activityManager.getLauncherLargeIconDensity();
-
- // need to set mIconDpi before getting default icon
- mDefaultIcon = makeDefaultIcon();
- }
-
- public Drawable getFullResDefaultActivityIcon() {
- return getFullResIcon(Resources.getSystem(),
- android.R.mipmap.sym_def_app_icon);
- }
-
- public Drawable getFullResIcon(Resources resources, int iconId) {
- Drawable d;
- try {
- d = resources.getDrawableForDensity(iconId, mIconDpi);
- } catch (Resources.NotFoundException e) {
- d = null;
- }
-
- return (d != null) ? d : getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(String packageName, int iconId) {
- Resources resources;
- try {
- resources = mPackageManager.getResourcesForApplication(packageName);
- } catch (PackageManager.NameNotFoundException e) {
- resources = null;
- }
- if (resources != null) {
- if (iconId != 0) {
- return getFullResIcon(resources, iconId);
- }
- }
- return getFullResDefaultActivityIcon();
- }
-
- public Drawable getFullResIcon(ResolveInfo info) {
- return getFullResIcon(info.activityInfo);
- }
-
- public Drawable getFullResIcon(ActivityInfo info) {
-
- Resources resources;
- try {
- resources = mPackageManager.getResourcesForApplication(
- info.applicationInfo);
- } catch (PackageManager.NameNotFoundException e) {
- resources = null;
- }
- if (resources != null) {
- int iconId = info.getIconResource();
- if (iconId != 0) {
- return getFullResIcon(resources, iconId);
- }
- }
- return getFullResDefaultActivityIcon();
- }
-
- private Bitmap makeDefaultIcon() {
- Drawable d = getFullResDefaultActivityIcon();
- Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
- Math.max(d.getIntrinsicHeight(), 1),
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
- d.setBounds(0, 0, b.getWidth(), b.getHeight());
- d.draw(c);
- c.setBitmap(null);
- return b;
- }
-
- /**
- * Remove any records for the supplied ComponentName.
- */
- public void remove(ComponentName componentName) {
- synchronized (mCache) {
- mCache.remove(componentName);
- }
- }
-
- /**
- * Empty out the cache.
- */
- public void flush() {
- synchronized (mCache) {
- mCache.clear();
- }
- }
-
- /**
- * Fill in "application" with the icon and label for "info."
- */
- public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info,
- HashMap<Object, CharSequence> labelCache) {
- synchronized (mCache) {
- CacheEntry entry = cacheLocked(application.componentName, info, labelCache);
-
- application.title = entry.title;
- application.iconBitmap = entry.icon;
- }
- }
-
- public Bitmap getIcon(Intent intent) {
- synchronized (mCache) {
- final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
- ComponentName component = intent.getComponent();
-
- if (resolveInfo == null || component == null) {
- return mDefaultIcon;
- }
-
- CacheEntry entry = cacheLocked(component, resolveInfo, null);
- return entry.icon;
- }
- }
-
- public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo,
- HashMap<Object, CharSequence> labelCache) {
- synchronized (mCache) {
- if (resolveInfo == null || component == null) {
- return null;
- }
-
- CacheEntry entry = cacheLocked(component, resolveInfo, labelCache);
- return entry.icon;
- }
- }
-
- public boolean isDefaultIcon(Bitmap icon) {
- return mDefaultIcon == icon;
- }
-
- private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,
- HashMap<Object, CharSequence> labelCache) {
- CacheEntry entry = mCache.get(componentName);
- if (entry == null) {
- entry = new CacheEntry();
-
- mCache.put(componentName, entry);
-
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
- if (labelCache != null && labelCache.containsKey(key)) {
- entry.title = labelCache.get(key).toString();
- } else {
- entry.title = info.loadLabel(mPackageManager).toString();
- if (labelCache != null) {
- labelCache.put(key, entry.title);
- }
- }
- if (entry.title == null) {
- entry.title = info.activityInfo.name;
- }
-
- entry.icon = Utilities.createIconBitmap(
- getFullResIcon(info), mContext);
- }
- return entry;
- }
-
- public HashMap<ComponentName,Bitmap> getAllIcons() {
- synchronized (mCache) {
- HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
- for (ComponentName cn : mCache.keySet()) {
- final CacheEntry e = mCache.get(cn);
- set.put(cn, e.icon);
- }
- return set;
- }
- }
-}
diff --git a/src/com/android/launcher2/InfoDropTarget.java b/src/com/android/launcher2/InfoDropTarget.java
deleted file mode 100644
index d6bf5f2cc..000000000
--- a/src/com/android/launcher2/InfoDropTarget.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.drawable.TransitionDrawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher.R;
-
-public class InfoDropTarget extends ButtonDropTarget {
-
- private ColorStateList mOriginalTextColor;
- private TransitionDrawable mDrawable;
-
- public InfoDropTarget(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public InfoDropTarget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mOriginalTextColor = getTextColors();
-
- // Get the hover color
- Resources r = getResources();
- mHoverColor = r.getColor(R.color.info_target_hover_tint);
- mDrawable = (TransitionDrawable) getCurrentDrawable();
- mDrawable.setCrossFadeEnabled(true);
-
- // Remove the text in the Phone UI in landscape
- int orientation = getResources().getConfiguration().orientation;
- if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- if (!LauncherApplication.isScreenLarge()) {
- setText("");
- }
- }
- }
-
- private boolean isFromAllApps(DragSource source) {
- return (source instanceof AppsCustomizePagedView);
- }
-
- @Override
- public boolean acceptDrop(DragObject d) {
- // acceptDrop is called just before onDrop. We do the work here, rather than
- // in onDrop, because it allows us to reject the drop (by returning false)
- // so that the object being dragged isn't removed from the drag source.
- ComponentName componentName = null;
- if (d.dragInfo instanceof ApplicationInfo) {
- componentName = ((ApplicationInfo) d.dragInfo).componentName;
- } else if (d.dragInfo instanceof ShortcutInfo) {
- componentName = ((ShortcutInfo) d.dragInfo).intent.getComponent();
- } else if (d.dragInfo instanceof PendingAddItemInfo) {
- componentName = ((PendingAddItemInfo) d.dragInfo).componentName;
- }
- if (componentName != null) {
- mLauncher.startApplicationDetailsActivity(componentName);
- }
-
- // There is no post-drop animation, so clean up the DragView now
- d.deferDragViewCleanupPostAnimation = false;
- return false;
- }
-
- @Override
- public void onDragStart(DragSource source, Object info, int dragAction) {
- boolean isVisible = true;
-
- // Hide this button unless we are dragging something from AllApps
- if (!isFromAllApps(source)) {
- isVisible = false;
- }
-
- mActive = isVisible;
- mDrawable.resetTransition();
- setTextColor(mOriginalTextColor);
- ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE);
- }
-
- @Override
- public void onDragEnd() {
- super.onDragEnd();
- mActive = false;
- }
-
- public void onDragEnter(DragObject d) {
- super.onDragEnter(d);
-
- mDrawable.startTransition(mTransitionDuration);
- setTextColor(mHoverColor);
- }
-
- public void onDragExit(DragObject d) {
- super.onDragExit(d);
-
- if (!d.dragComplete) {
- mDrawable.resetTransition();
- setTextColor(mOriginalTextColor);
- }
- }
-}
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
deleted file mode 100644
index a525d00ee..000000000
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2008 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.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.os.Debug;
-import android.widget.Toast;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-public class InstallShortcutReceiver extends BroadcastReceiver {
- public static final String ACTION_INSTALL_SHORTCUT =
- "com.android.launcher.action.INSTALL_SHORTCUT";
- public static final String NEW_APPS_PAGE_KEY = "apps.new.page";
- public static final String NEW_APPS_LIST_KEY = "apps.new.list";
-
- public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
- public static final int NEW_SHORTCUT_STAGGER_DELAY = 75;
-
- private static final int INSTALL_SHORTCUT_SUCCESSFUL = 0;
- private static final int INSTALL_SHORTCUT_IS_DUPLICATE = -1;
- private static final int INSTALL_SHORTCUT_NO_SPACE = -2;
-
- // A mime-type representing shortcut data
- public static final String SHORTCUT_MIMETYPE =
- "com.android.launcher/shortcut";
-
- // The set of shortcuts that are pending install
- private static ArrayList<PendingInstallShortcutInfo> mInstallQueue =
- new ArrayList<PendingInstallShortcutInfo>();
-
- // Determines whether to defer installing shortcuts immediately until
- // processAllPendingInstalls() is called.
- private static boolean mUseInstallQueue = false;
-
- private static class PendingInstallShortcutInfo {
- Intent data;
- Intent launchIntent;
- String name;
-
- public PendingInstallShortcutInfo(Intent rawData, String shortcutName,
- Intent shortcutIntent) {
- data = rawData;
- name = shortcutName;
- launchIntent = shortcutIntent;
- }
- }
-
- public void onReceive(Context context, Intent data) {
- if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {
- return;
- }
-
- Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- if (intent == null) {
- return;
- }
- // This name is only used for comparisons and notifications, so fall back to activity name
- // if not supplied
- String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- if (name == null) {
- try {
- PackageManager pm = context.getPackageManager();
- ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0);
- name = info.loadLabel(pm).toString();
- } catch (PackageManager.NameNotFoundException nnfe) {
- return;
- }
- }
- // Queue the item up for adding if launcher has not loaded properly yet
- boolean launcherNotLoaded = LauncherModel.getCellCountX() <= 0 ||
- LauncherModel.getCellCountY() <= 0;
-
- PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, name, intent);
- if (mUseInstallQueue || launcherNotLoaded) {
- mInstallQueue.add(info);
- } else {
- processInstallShortcut(context, info);
- }
- }
-
- static void enableInstallQueue() {
- mUseInstallQueue = true;
- }
- static void disableAndFlushInstallQueue(Context context) {
- mUseInstallQueue = false;
- flushInstallQueue(context);
- }
- static void flushInstallQueue(Context context) {
- Iterator<PendingInstallShortcutInfo> iter = mInstallQueue.iterator();
- while (iter.hasNext()) {
- processInstallShortcut(context, iter.next());
- iter.remove();
- }
- }
-
- private static void processInstallShortcut(Context context,
- PendingInstallShortcutInfo pendingInfo) {
- String spKey = LauncherApplication.getSharedPreferencesKey();
- SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
-
- final Intent data = pendingInfo.data;
- final Intent intent = pendingInfo.launchIntent;
- final String name = pendingInfo.name;
-
- // Lock on the app so that we don't try and get the items while apps are being added
- LauncherApplication app = (LauncherApplication) context.getApplicationContext();
- final int[] result = {INSTALL_SHORTCUT_SUCCESSFUL};
- boolean found = false;
- synchronized (app) {
- final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
- final boolean exists = LauncherModel.shortcutExists(context, name, intent);
-
- // Try adding to the workspace screens incrementally, starting at the default or center
- // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
- final int screen = Launcher.DEFAULT_SCREEN;
- for (int i = 0; i < (2 * Launcher.SCREEN_COUNT) + 1 && !found; ++i) {
- int si = screen + (int) ((i / 2f) + 0.5f) * ((i % 2 == 1) ? 1 : -1);
- if (0 <= si && si < Launcher.SCREEN_COUNT) {
- found = installShortcut(context, data, items, name, intent, si, exists, sp,
- result);
- }
- }
- }
-
- // We only report error messages (duplicate shortcut or out of space) as the add-animation
- // will provide feedback otherwise
- if (!found) {
- if (result[0] == INSTALL_SHORTCUT_NO_SPACE) {
- Toast.makeText(context, context.getString(R.string.completely_out_of_space),
- Toast.LENGTH_SHORT).show();
- } else if (result[0] == INSTALL_SHORTCUT_IS_DUPLICATE) {
- Toast.makeText(context, context.getString(R.string.shortcut_duplicate, name),
- Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- private static boolean installShortcut(Context context, Intent data, ArrayList<ItemInfo> items,
- String name, Intent intent, final int screen, boolean shortcutExists,
- final SharedPreferences sharedPrefs, int[] result) {
- int[] tmpCoordinates = new int[2];
- if (findEmptyCell(context, items, tmpCoordinates, screen)) {
- if (intent != null) {
- if (intent.getAction() == null) {
- intent.setAction(Intent.ACTION_VIEW);
- } else if (intent.getAction().equals(Intent.ACTION_MAIN) &&
- intent.getCategories() != null &&
- intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
-
- // By default, we allow for duplicate entries (located in
- // different places)
- boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
- if (duplicate || !shortcutExists) {
- // If the new app is going to fall into the same page as before, then just
- // continue adding to the current page
- int newAppsScreen = sharedPrefs.getInt(NEW_APPS_PAGE_KEY, screen);
- Set<String> newApps = new HashSet<String>();
- if (newAppsScreen == screen) {
- newApps = sharedPrefs.getStringSet(NEW_APPS_LIST_KEY, newApps);
- }
- synchronized (newApps) {
- newApps.add(intent.toUri(0).toString());
- }
- final Set<String> savedNewApps = newApps;
- new Thread("setNewAppsThread") {
- public void run() {
- synchronized (savedNewApps) {
- sharedPrefs.edit()
- .putInt(NEW_APPS_PAGE_KEY, screen)
- .putStringSet(NEW_APPS_LIST_KEY, savedNewApps)
- .commit();
- }
- }
- }.start();
-
- // Update the Launcher db
- LauncherApplication app = (LauncherApplication) context.getApplicationContext();
- ShortcutInfo info = app.getModel().addShortcut(context, data,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
- tmpCoordinates[0], tmpCoordinates[1], true);
- if (info == null) {
- return false;
- }
- } else {
- result[0] = INSTALL_SHORTCUT_IS_DUPLICATE;
- }
-
- return true;
- }
- } else {
- result[0] = INSTALL_SHORTCUT_NO_SPACE;
- }
-
- return false;
- }
-
- private static boolean findEmptyCell(Context context, ArrayList<ItemInfo> items, int[] xy,
- int screen) {
- final int xCount = LauncherModel.getCellCountX();
- final int yCount = LauncherModel.getCellCountY();
- boolean[][] occupied = new boolean[xCount][yCount];
-
- ItemInfo item = null;
- int cellX, cellY, spanX, spanY;
- for (int i = 0; i < items.size(); ++i) {
- item = items.get(i);
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (item.screen == screen) {
- cellX = item.cellX;
- cellY = item.cellY;
- spanX = item.spanX;
- spanY = item.spanY;
- for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {
- for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {
- occupied[x][y] = true;
- }
- }
- }
- }
- }
-
- return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
- }
-}
diff --git a/src/com/android/launcher2/InstallWidgetReceiver.java b/src/com/android/launcher2/InstallWidgetReceiver.java
deleted file mode 100644
index a1e9b1187..000000000
--- a/src/com/android/launcher2/InstallWidgetReceiver.java
+++ /dev/null
@@ -1,195 +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 java.util.List;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ClipData;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.database.DataSetObserver;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-
-/**
- * We will likely flesh this out later, to handle allow external apps to place widgets, but for now,
- * we just want to expose the action around for checking elsewhere.
- */
-public class InstallWidgetReceiver {
- public static final String ACTION_INSTALL_WIDGET =
- "com.android.launcher.action.INSTALL_WIDGET";
- public static final String ACTION_SUPPORTS_CLIPDATA_MIMETYPE =
- "com.android.launcher.action.SUPPORTS_CLIPDATA_MIMETYPE";
-
- // Currently not exposed. Put into Intent when we want to make it public.
- // TEMP: Should we call this "EXTRA_APPWIDGET_PROVIDER"?
- public static final String EXTRA_APPWIDGET_COMPONENT =
- "com.android.launcher.extra.widget.COMPONENT";
- public static final String EXTRA_APPWIDGET_CONFIGURATION_DATA_MIME_TYPE =
- "com.android.launcher.extra.widget.CONFIGURATION_DATA_MIME_TYPE";
- public static final String EXTRA_APPWIDGET_CONFIGURATION_DATA =
- "com.android.launcher.extra.widget.CONFIGURATION_DATA";
-
- /**
- * A simple data class that contains per-item information that the adapter below can reference.
- */
- public static class WidgetMimeTypeHandlerData {
- public ResolveInfo resolveInfo;
- public AppWidgetProviderInfo widgetInfo;
-
- public WidgetMimeTypeHandlerData(ResolveInfo rInfo, AppWidgetProviderInfo wInfo) {
- resolveInfo = rInfo;
- widgetInfo = wInfo;
- }
- }
-
- /**
- * The ListAdapter which presents all the valid widgets that can be created for a given drop.
- */
- public static class WidgetListAdapter implements ListAdapter, DialogInterface.OnClickListener {
- private LayoutInflater mInflater;
- private Launcher mLauncher;
- private String mMimeType;
- private ClipData mClipData;
- private List<WidgetMimeTypeHandlerData> mActivities;
- private CellLayout mTargetLayout;
- private int mTargetLayoutScreen;
- private int[] mTargetLayoutPos;
-
- public WidgetListAdapter(Launcher l, String mimeType, ClipData data,
- List<WidgetMimeTypeHandlerData> list, CellLayout target,
- int targetScreen, int[] targetPos) {
- mLauncher = l;
- mMimeType = mimeType;
- mClipData = data;
- mActivities = list;
- mTargetLayout = target;
- mTargetLayoutScreen = targetScreen;
- mTargetLayoutPos = targetPos;
- }
-
- @Override
- public void registerDataSetObserver(DataSetObserver observer) {
- }
-
- @Override
- public void unregisterDataSetObserver(DataSetObserver observer) {
- }
-
- @Override
- public int getCount() {
- return mActivities.size();
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
- final PackageManager packageManager = context.getPackageManager();
-
- // Lazy-create inflater
- if (mInflater == null) {
- mInflater = LayoutInflater.from(context);
- }
-
- // Use the convert-view where possible
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.external_widget_drop_list_item, parent,
- false);
- }
-
- final WidgetMimeTypeHandlerData data = mActivities.get(position);
- final ResolveInfo resolveInfo = data.resolveInfo;
- final AppWidgetProviderInfo widgetInfo = data.widgetInfo;
-
- // Set the icon
- Drawable d = resolveInfo.loadIcon(packageManager);
- ImageView i = (ImageView) convertView.findViewById(R.id.provider_icon);
- i.setImageDrawable(d);
-
- // Set the text
- final CharSequence component = resolveInfo.loadLabel(packageManager);
- final int[] widgetSpan = new int[2];
- mTargetLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, widgetSpan);
- TextView t = (TextView) convertView.findViewById(R.id.provider);
- t.setText(context.getString(R.string.external_drop_widget_pick_format,
- component, widgetSpan[0], widgetSpan[1]));
-
- return convertView;
- }
-
- @Override
- public int getItemViewType(int position) {
- return 0;
- }
-
- @Override
- public int getViewTypeCount() {
- return 1;
- }
-
- @Override
- public boolean isEmpty() {
- return mActivities.isEmpty();
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return true;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final AppWidgetProviderInfo widgetInfo = mActivities.get(which).widgetInfo;
-
- final PendingAddWidgetInfo createInfo = new PendingAddWidgetInfo(widgetInfo, mMimeType,
- mClipData);
- mLauncher.addAppWidgetFromDrop(createInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP,
- mTargetLayoutScreen, null, null, mTargetLayoutPos);
- }
- }
-}
diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java
deleted file mode 100644
index 135fa3996..000000000
--- a/src/com/android/launcher2/InterruptibleInOutAnimator.java
+++ /dev/null
@@ -1,130 +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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-
-/**
- * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
- * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
- * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will
- * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the
- * interpolator in the same direction.
- */
-public class InterruptibleInOutAnimator {
- private long mOriginalDuration;
- private float mOriginalFromValue;
- private float mOriginalToValue;
- private ValueAnimator mAnimator;
-
- private boolean mFirstRun = true;
-
- private Object mTag = null;
-
- private static final int STOPPED = 0;
- private static final int IN = 1;
- private static final int OUT = 2;
-
- // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
- private int mDirection = STOPPED;
-
- public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
- mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration);
- mOriginalDuration = duration;
- mOriginalFromValue = fromValue;
- mOriginalToValue = toValue;
-
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mDirection = STOPPED;
- }
- });
- }
-
- private void animate(int direction) {
- final long currentPlayTime = mAnimator.getCurrentPlayTime();
- final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
- final float startValue = mFirstRun ? mOriginalFromValue :
- ((Float) mAnimator.getAnimatedValue()).floatValue();
-
- // Make sure it's stopped before we modify any values
- cancel();
-
- // TODO: We don't really need to do the animation if startValue == toValue, but
- // somehow that doesn't seem to work, possibly a quirk of the animation framework
- mDirection = direction;
-
- // Ensure we don't calculate a non-sensical duration
- long duration = mOriginalDuration - currentPlayTime;
- mAnimator.setDuration(Math.max(0, Math.min(duration, mOriginalDuration)));
-
- mAnimator.setFloatValues(startValue, toValue);
- mAnimator.start();
- mFirstRun = false;
- }
-
- public void cancel() {
- mAnimator.cancel();
- mDirection = STOPPED;
- }
-
- public void end() {
- mAnimator.end();
- mDirection = STOPPED;
- }
-
- /**
- * Return true when the animation is not running and it hasn't even been started.
- */
- public boolean isStopped() {
- return mDirection == STOPPED;
- }
-
- /**
- * This is the equivalent of calling Animator.start(), except that it can be called when
- * the animation is running in the opposite direction, in which case we reverse
- * direction and animate for a correspondingly shorter duration.
- */
- public void animateIn() {
- animate(IN);
- }
-
- /**
- * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the
- * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(),
- * if the animation is currently running in the opposite direction, we reverse
- * direction and animate for a correspondingly shorter duration.
- */
- public void animateOut() {
- animate(OUT);
- }
-
- public void setTag(Object tag) {
- mTag = tag;
- }
-
- public Object getTag() {
- return mTag;
- }
-
- public ValueAnimator getAnimator() {
- return mAnimator;
- }
-}
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
deleted file mode 100644
index dedc0f4f3..000000000
--- a/src/com/android/launcher2/ItemInfo.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2008 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.ContentValues;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * Represents an item in the launcher.
- */
-class ItemInfo {
-
- static final int NO_ID = -1;
-
- /**
- * The id in the settings database for this item
- */
- long id = NO_ID;
-
- /**
- * One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
- * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
- * {@link LauncherSettings.Favorites#ITEM_TYPE_FOLDER}, or
- * {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}.
- */
- int itemType;
-
- /**
- * The id of the container that holds this item. For the desktop, this will be
- * {@link LauncherSettings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it
- * will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders
- * it will be the id of the folder.
- */
- long container = NO_ID;
-
- /**
- * Iindicates the screen in which the shortcut appears.
- */
- int screen = -1;
-
- /**
- * Indicates the X position of the associated cell.
- */
- int cellX = -1;
-
- /**
- * Indicates the Y position of the associated cell.
- */
- int cellY = -1;
-
- /**
- * Indicates the X cell span.
- */
- int spanX = 1;
-
- /**
- * Indicates the Y cell span.
- */
- int spanY = 1;
-
- /**
- * Indicates the minimum X cell span.
- */
- int minSpanX = 1;
-
- /**
- * Indicates the minimum Y cell span.
- */
- int minSpanY = 1;
- /**
- * Indicates whether the item is a gesture.
- */
- boolean isGesture = false;
-
- /**
- * The position of the item in a drag-and-drop operation.
- */
- int[] dropPos = null;
-
- ItemInfo() {
- }
-
- ItemInfo(ItemInfo info) {
- id = info.id;
- cellX = info.cellX;
- cellY = info.cellY;
- spanX = info.spanX;
- spanY = info.spanY;
- screen = info.screen;
- itemType = info.itemType;
- container = info.container;
- }
-
- /** Returns the package name that the intent will resolve to, or an empty string if
- * none exists. */
- static String getPackageName(Intent intent) {
- if (intent != null) {
- String packageName = intent.getPackage();
- if (packageName == null && intent.getComponent() != null) {
- packageName = intent.getComponent().getPackageName();
- }
- if (packageName != null) {
- return packageName;
- }
- }
- return "";
- }
-
- /**
- * Write the fields of this item to the DB
- *
- * @param values
- */
- void onAddToDatabase(ContentValues values) {
- values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
- if (!isGesture) {
- values.put(LauncherSettings.Favorites.CONTAINER, container);
- values.put(LauncherSettings.Favorites.SCREEN, screen);
- values.put(LauncherSettings.Favorites.CELLX, cellX);
- values.put(LauncherSettings.Favorites.CELLY, cellY);
- values.put(LauncherSettings.Favorites.SPANX, spanX);
- values.put(LauncherSettings.Favorites.SPANY, spanY);
- }
- }
-
- void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
- values.put(LauncherSettings.Favorites.CELLX, cellX);
- values.put(LauncherSettings.Favorites.CELLY, cellY);
- }
-
- static byte[] flattenBitmap(Bitmap bitmap) {
- // Try go guesstimate how much space the icon will take when serialized
- // to avoid unnecessary allocations/copies during the write.
- int size = bitmap.getWidth() * bitmap.getHeight() * 4;
- ByteArrayOutputStream out = new ByteArrayOutputStream(size);
- try {
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- out.flush();
- out.close();
- return out.toByteArray();
- } catch (IOException e) {
- Log.w("Favorite", "Could not write icon");
- return null;
- }
- }
-
- static void writeBitmap(ContentValues values, Bitmap bitmap) {
- if (bitmap != null) {
- byte[] data = flattenBitmap(bitmap);
- values.put(LauncherSettings.Favorites.ICON, data);
- }
- }
-
- /**
- * It is very important that sub-classes implement this if they contain any references
- * to the activity (anything in the view hierarchy etc.). If not, leaks can result since
- * ItemInfo objects persist across rotation and can hence leak by holding stale references
- * to the old view hierarchy / activity.
- */
- void unbind() {
- }
-
- @Override
- public String toString() {
- return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
- + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
- + " spanY=" + spanY + " isGesture=" + isGesture + " dropPos=" + dropPos + ")";
- }
-}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
deleted file mode 100644
index f4180cd00..000000000
--- a/src/com/android/launcher2/Launcher.java
+++ /dev/null
@@ -1,3710 +0,0 @@
-
-/*
- * Copyright (C) 2008 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.accounts.Account;
-import android.accounts.AccountManager;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.SearchManager;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks2;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.text.Selection;
-import android.text.SpannableStringBuilder;
-import android.text.method.TextKeyListener;
-import android.util.Log;
-import android.view.Display;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Advanceable;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.common.Search;
-import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Default launcher application.
- */
-public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- AllAppsView.Watcher, View.OnTouchListener {
- static final String TAG = "Launcher";
- static final boolean LOGD = false;
-
- static final boolean PROFILE_STARTUP = false;
- static final boolean DEBUG_WIDGETS = false;
- static final boolean DEBUG_STRICT_MODE = false;
-
- private static final int MENU_GROUP_WALLPAPER = 1;
- private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
- private static final int MENU_MANAGE_APPS = MENU_WALLPAPER_SETTINGS + 1;
- private static final int MENU_SYSTEM_SETTINGS = MENU_MANAGE_APPS + 1;
- private static final int MENU_HELP = MENU_SYSTEM_SETTINGS + 1;
-
- private static final int REQUEST_CREATE_SHORTCUT = 1;
- private static final int REQUEST_CREATE_APPWIDGET = 5;
- private static final int REQUEST_PICK_APPLICATION = 6;
- private static final int REQUEST_PICK_SHORTCUT = 7;
- private static final int REQUEST_PICK_APPWIDGET = 9;
- private static final int REQUEST_PICK_WALLPAPER = 10;
-
- private static final int REQUEST_BIND_APPWIDGET = 11;
-
- static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
-
- static final int SCREEN_COUNT = 5;
- static final int DEFAULT_SCREEN = 2;
-
- private static final String PREFERENCES = "launcher.preferences";
- static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher.force_enable_rotation";
-
- // The Intent extra that defines whether to ignore the launch animation
- static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
- "com.android.launcher.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
-
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
- // Type: int
- private static final String RUNTIME_STATE = "launcher.state";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CONTAINER = "launcher.add_container";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cell_x";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cell_y";
- // Type: boolean
- private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
- // Type: long
- private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_span_x";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
- // Type: parcelable
- private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
-
- private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
- private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
- "com.android.launcher.toolbar_search_icon";
- private static final String TOOLBAR_VOICE_SEARCH_ICON_METADATA_NAME =
- "com.android.launcher.toolbar_voice_search_icon";
-
- /** The different states that Launcher can be in. */
- private enum State { WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED };
- private State mState = State.WORKSPACE;
- private AnimatorSet mStateAnimation;
- private AnimatorSet mDividerAnimator;
-
- static final int APPWIDGET_HOST_ID = 1024;
- private static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
- private static final int EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT = 600;
- private static final int SHOW_CLING_DURATION = 550;
- private static final int DISMISS_CLING_DURATION = 250;
-
- private static final Object sLock = new Object();
- private static int sScreen = DEFAULT_SCREEN;
-
- // How long to wait before the new-shortcut animation automatically pans the workspace
- private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10;
-
- private final BroadcastReceiver mCloseSystemDialogsReceiver
- = new CloseSystemDialogsIntentReceiver();
- private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
-
- private LayoutInflater mInflater;
-
- private Workspace mWorkspace;
- private View mQsbDivider;
- private View mDockDivider;
- private DragLayer mDragLayer;
- private DragController mDragController;
-
- private AppWidgetManager mAppWidgetManager;
- private LauncherAppWidgetHost mAppWidgetHost;
-
- private ItemInfo mPendingAddInfo = new ItemInfo();
- private AppWidgetProviderInfo mPendingAddWidgetInfo;
-
- private int[] mTmpAddItemCellCoordinates = new int[2];
-
- private FolderInfo mFolderInfo;
-
- private Hotseat mHotseat;
- private View mAllAppsButton;
-
- private SearchDropTargetBar mSearchDropTargetBar;
- private AppsCustomizeTabHost mAppsCustomizeTabHost;
- private AppsCustomizePagedView mAppsCustomizeContent;
- private boolean mAutoAdvanceRunning = false;
-
- private Bundle mSavedState;
-
- private SpannableStringBuilder mDefaultKeySsb = null;
-
- private boolean mWorkspaceLoading = true;
-
- private boolean mPaused = true;
- private boolean mRestoring;
- private boolean mWaitingForResult;
- private boolean mOnResumeNeedsLoad;
-
- private Bundle mSavedInstanceState;
-
- private LauncherModel mModel;
- private IconCache mIconCache;
- private boolean mUserPresent = true;
- private boolean mVisible = false;
- private boolean mAttached = false;
-
- private static LocaleConfiguration sLocaleConfiguration = null;
-
- private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
-
- private Intent mAppMarketIntent = null;
-
- // Related to the auto-advancing of widgets
- private final int ADVANCE_MSG = 1;
- private final int mAdvanceInterval = 20000;
- private final int mAdvanceStagger = 250;
- private long mAutoAdvanceSentTime;
- private long mAutoAdvanceTimeLeft = -1;
- private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
- new HashMap<View, AppWidgetProviderInfo>();
-
- // Determines how long to wait after a rotation before restoring the screen orientation to
- // match the sensor state.
- private final int mRestoreScreenOrientationDelay = 500;
-
- // External icons saved in case of resource changes, orientation, etc.
- private static Drawable.ConstantState[] sGlobalSearchIcon = new Drawable.ConstantState[2];
- private static Drawable.ConstantState[] sVoiceSearchIcon = new Drawable.ConstantState[2];
- private static Drawable.ConstantState[] sAppMarketIcon = new Drawable.ConstantState[2];
-
- static final ArrayList<String> sDumpLogs = new ArrayList<String>();
-
- // We only want to get the SharedPreferences once since it does an FS stat each time we get
- // it from the context.
- private SharedPreferences mSharedPrefs;
-
- // Holds the page that we need to animate to, and the icon views that we need to animate up
- // when we scroll to that page on resume.
- private int mNewShortcutAnimatePage = -1;
- private ArrayList<View> mNewShortcutAnimateViews = new ArrayList<View>();
- private ImageView mFolderIconImageView;
- private Bitmap mFolderIconBitmap;
- private Canvas mFolderIconCanvas;
- private Rect mRectForFolderAnimation = new Rect();
-
- private BubbleTextView mWaitingForResume;
-
- private Runnable mBuildLayersRunnable = new Runnable() {
- public void run() {
- if (mWorkspace != null) {
- mWorkspace.buildPageHardwareLayers();
- }
- }
- };
-
- private static ArrayList<PendingAddArguments> sPendingAddList
- = new ArrayList<PendingAddArguments>();
-
- private static class PendingAddArguments {
- int requestCode;
- Intent intent;
- long container;
- int screen;
- int cellX;
- int cellY;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (DEBUG_STRICT_MODE) {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectDiskReads()
- .detectDiskWrites()
- .detectNetwork() // or .detectAll() for all detectable problems
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .detectLeakedClosableObjects()
- .penaltyLog()
- .penaltyDeath()
- .build());
- }
-
- super.onCreate(savedInstanceState);
- LauncherApplication app = ((LauncherApplication)getApplication());
- mSharedPrefs = getSharedPreferences(LauncherApplication.getSharedPreferencesKey(),
- Context.MODE_PRIVATE);
- mModel = app.setLauncher(this);
- mIconCache = app.getIconCache();
- mDragController = new DragController(this);
- mInflater = getLayoutInflater();
-
- mAppWidgetManager = AppWidgetManager.getInstance(this);
- mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
- mAppWidgetHost.startListening();
-
- if (PROFILE_STARTUP) {
- android.os.Debug.startMethodTracing(
- Environment.getExternalStorageDirectory() + "/launcher");
- }
-
- checkForLocaleChange();
- setContentView(R.layout.launcher);
- setupViews();
- showFirstRunWorkspaceCling();
-
- registerContentObservers();
-
- lockAllApps();
-
- mSavedState = savedInstanceState;
- restoreState(mSavedState);
-
- // Update customization drawer _after_ restoring the states
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.onPackagesUpdated();
- }
-
- if (PROFILE_STARTUP) {
- android.os.Debug.stopMethodTracing();
- }
-
- if (!mRestoring) {
- mModel.startLoader(true);
- }
-
- if (!mModel.isAllAppsLoaded()) {
- ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent();
- mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent);
- }
-
- // For handling default keys
- mDefaultKeySsb = new SpannableStringBuilder();
- Selection.setSelection(mDefaultKeySsb, 0);
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- registerReceiver(mCloseSystemDialogsReceiver, filter);
-
- updateGlobalIcons();
-
- // On large interfaces, we want the screen to auto-rotate based on the current orientation
- unlockScreenOrientation(true);
- }
-
- private void updateGlobalIcons() {
- boolean searchVisible = false;
- boolean voiceVisible = false;
- // If we have a saved version of these external icons, we load them up immediately
- int coi = getCurrentOrientationIndexForGlobalIcons();
- if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null ||
- sAppMarketIcon[coi] == null) {
- updateAppMarketIcon();
- searchVisible = updateGlobalSearchIcon();
- voiceVisible = updateVoiceSearchIcon(searchVisible);
- }
- if (sGlobalSearchIcon[coi] != null) {
- updateGlobalSearchIcon(sGlobalSearchIcon[coi]);
- searchVisible = true;
- }
- if (sVoiceSearchIcon[coi] != null) {
- updateVoiceSearchIcon(sVoiceSearchIcon[coi]);
- voiceVisible = true;
- }
- if (sAppMarketIcon[coi] != null) {
- updateAppMarketIcon(sAppMarketIcon[coi]);
- }
- mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
- }
-
- private void checkForLocaleChange() {
- if (sLocaleConfiguration == null) {
- new AsyncTask<Void, Void, LocaleConfiguration>() {
- @Override
- protected LocaleConfiguration doInBackground(Void... unused) {
- LocaleConfiguration localeConfiguration = new LocaleConfiguration();
- readConfiguration(Launcher.this, localeConfiguration);
- return localeConfiguration;
- }
-
- @Override
- protected void onPostExecute(LocaleConfiguration result) {
- sLocaleConfiguration = result;
- checkForLocaleChange(); // recursive, but now with a locale configuration
- }
- }.execute();
- return;
- }
-
- final Configuration configuration = getResources().getConfiguration();
-
- final String previousLocale = sLocaleConfiguration.locale;
- final String locale = configuration.locale.toString();
-
- final int previousMcc = sLocaleConfiguration.mcc;
- final int mcc = configuration.mcc;
-
- final int previousMnc = sLocaleConfiguration.mnc;
- final int mnc = configuration.mnc;
-
- boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
-
- if (localeChanged) {
- sLocaleConfiguration.locale = locale;
- sLocaleConfiguration.mcc = mcc;
- sLocaleConfiguration.mnc = mnc;
-
- mIconCache.flush();
-
- final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
- new Thread("WriteLocaleConfiguration") {
- @Override
- public void run() {
- writeConfiguration(Launcher.this, localeConfiguration);
- }
- }.start();
- }
- }
-
- private static class LocaleConfiguration {
- public String locale;
- public int mcc = -1;
- public int mnc = -1;
- }
-
- private static void readConfiguration(Context context, LocaleConfiguration configuration) {
- DataInputStream in = null;
- try {
- in = new DataInputStream(context.openFileInput(PREFERENCES));
- configuration.locale = in.readUTF();
- configuration.mcc = in.readInt();
- configuration.mnc = in.readInt();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- // Ignore
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- private static void writeConfiguration(Context context, LocaleConfiguration configuration) {
- DataOutputStream out = null;
- try {
- out = new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE));
- out.writeUTF(configuration.locale);
- out.writeInt(configuration.mcc);
- out.writeInt(configuration.mnc);
- out.flush();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- //noinspection ResultOfMethodCallIgnored
- context.getFileStreamPath(PREFERENCES).delete();
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- public DragLayer getDragLayer() {
- return mDragLayer;
- }
-
- boolean isDraggingEnabled() {
- // We prevent dragging when we are loading the workspace as it is possible to pick up a view
- // that is subsequently removed from the workspace in startBinding().
- return !mModel.isLoadingWorkspace();
- }
-
- static int getScreen() {
- synchronized (sLock) {
- return sScreen;
- }
- }
-
- static void setScreen(int screen) {
- synchronized (sLock) {
- sScreen = screen;
- }
- }
-
- /**
- * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
- * a configuration step, this allows the proper animations to run after other transitions.
- */
- private boolean completeAdd(PendingAddArguments args) {
- boolean result = false;
- switch (args.requestCode) {
- case REQUEST_PICK_APPLICATION:
- completeAddApplication(args.intent, args.container, args.screen, args.cellX,
- args.cellY);
- break;
- case REQUEST_PICK_SHORTCUT:
- processShortcut(args.intent);
- break;
- case REQUEST_CREATE_SHORTCUT:
- completeAddShortcut(args.intent, args.container, args.screen, args.cellX,
- args.cellY);
- result = true;
- break;
- case REQUEST_CREATE_APPWIDGET:
- int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- completeAddAppWidget(appWidgetId, args.container, args.screen, null, null);
- result = true;
- break;
- case REQUEST_PICK_WALLPAPER:
- // We just wanted the activity result here so we can clear mWaitingForResult
- break;
- }
- // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
- // if you turned the screen off and then back while in All Apps, Launcher would not
- // return to the workspace. Clearing mAddInfo.container here fixes this issue
- resetAddInfo();
- return result;
- }
-
- @Override
- protected void onActivityResult(
- final int requestCode, final int resultCode, final Intent data) {
- if (requestCode == REQUEST_BIND_APPWIDGET) {
- int appWidgetId = data != null ?
- data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
- if (resultCode == RESULT_CANCELED) {
- completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
- } else if (resultCode == RESULT_OK) {
- addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, mPendingAddWidgetInfo);
- }
- return;
- }
- boolean delayExitSpringLoadedMode = false;
- boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
- requestCode == REQUEST_CREATE_APPWIDGET);
- mWaitingForResult = false;
-
- // We have special handling for widgets
- if (isWidgetDrop) {
- int appWidgetId = data != null ?
- data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
- if (appWidgetId < 0) {
- Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not returned from the \\" +
- "widget configuration activity.");
- completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
- } else {
- completeTwoStageWidgetDrop(resultCode, appWidgetId);
- }
- return;
- }
-
- // The pattern used here is that a user PICKs a specific application,
- // which, depending on the target, might need to CREATE the actual target.
-
- // For example, the user would PICK_SHORTCUT for "Music playlist", and we
- // launch over to the Music app to actually CREATE_SHORTCUT.
- if (resultCode == RESULT_OK && mPendingAddInfo.container != ItemInfo.NO_ID) {
- final PendingAddArguments args = new PendingAddArguments();
- args.requestCode = requestCode;
- args.intent = data;
- args.container = mPendingAddInfo.container;
- args.screen = mPendingAddInfo.screen;
- args.cellX = mPendingAddInfo.cellX;
- args.cellY = mPendingAddInfo.cellY;
- if (isWorkspaceLocked()) {
- sPendingAddList.add(args);
- } else {
- delayExitSpringLoadedMode = completeAdd(args);
- }
- }
- mDragLayer.clearAnimatedView();
- // Exit spring loaded mode if necessary after cancelling the configuration of a widget
- exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), delayExitSpringLoadedMode,
- null);
- }
-
- private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
- CellLayout cellLayout =
- (CellLayout) mWorkspace.getChildAt(mPendingAddInfo.screen);
- Runnable onCompleteRunnable = null;
- int animationType = 0;
-
- AppWidgetHostView boundWidget = null;
- if (resultCode == RESULT_OK) {
- animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
- final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
- mPendingAddWidgetInfo);
- boundWidget = layout;
- onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- completeAddAppWidget(appWidgetId, mPendingAddInfo.container,
- mPendingAddInfo.screen, layout, null);
- exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false,
- null);
- }
- };
- } else if (resultCode == RESULT_CANCELED) {
- animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
- onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false,
- null);
- }
- };
- }
- if (mDragLayer.getAnimatedView() != null) {
- mWorkspace.animateWidgetDrop(mPendingAddInfo, cellLayout,
- (DragView) mDragLayer.getAnimatedView(), onCompleteRunnable,
- animationType, boundWidget, true);
- } else {
- // The animated view may be null in the case of a rotation during widget configuration
- onCompleteRunnable.run();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- // Process any items that were added while Launcher was away
- InstallShortcutReceiver.flushInstallQueue(this);
-
- mPaused = false;
- if (mRestoring || mOnResumeNeedsLoad) {
- mWorkspaceLoading = true;
- mModel.startLoader(true);
- mRestoring = false;
- mOnResumeNeedsLoad = false;
- }
-
- // Reset the pressed state of icons that were locked in the press state while activities
- // were launching
- if (mWaitingForResume != null) {
- // Resets the previous workspace icon press state
- mWaitingForResume.setStayPressed(false);
- }
- if (mAppsCustomizeContent != null) {
- // Resets the previous all apps icon press state
- mAppsCustomizeContent.resetDrawableState();
- }
- // It is possible that widgets can receive updates while launcher is not in the foreground.
- // Consequently, the widgets will be inflated in the orientation of the foreground activity
- // (framework issue). On resuming, we ensure that any widgets are inflated for the current
- // orientation.
- getWorkspace().reinflateWidgetsIfNecessary();
-
- // Again, as with the above scenario, it's possible that one or more of the global icons
- // were updated in the wrong orientation.
- updateGlobalIcons();
- }
-
- @Override
- protected void onPause() {
- // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
- // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
- // when Launcher resumes and we are still in AllApps.
- updateWallpaperVisibility(true);
-
- super.onPause();
- mPaused = true;
- mDragController.cancelDrag();
- mDragController.resetLastGestureUpTime();
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- // Flag the loader to stop early before switching
- mModel.stopLoader();
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.surrender();
- }
- return Boolean.TRUE;
- }
-
- // We can't hide the IME if it was forced open. So don't bother
- /*
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
-
- if (hasFocus) {
- final InputMethodManager inputManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- WindowManager.LayoutParams lp = getWindow().getAttributes();
- inputManager.hideSoftInputFromWindow(lp.token, 0, new android.os.ResultReceiver(new
- android.os.Handler()) {
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- Log.d(TAG, "ResultReceiver got resultCode=" + resultCode);
- }
- });
- Log.d(TAG, "called hideSoftInputFromWindow from onWindowFocusChanged");
- }
- }
- */
-
- private boolean acceptFilter() {
- final InputMethodManager inputManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- return !inputManager.isFullscreenMode();
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- final int uniChar = event.getUnicodeChar();
- final boolean handled = super.onKeyDown(keyCode, event);
- final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
- if (!handled && acceptFilter() && isKeyNotWhitespace) {
- boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
- keyCode, event);
- if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
- // something usable has been typed - start a search
- // the typed text will be retrieved and cleared by
- // showSearchDialog()
- // If there are multiple keystrokes before the search dialog takes focus,
- // onSearchRequested() will be called for every keystroke,
- // but it is idempotent, so it's fine.
- return onSearchRequested();
- }
- }
-
- // Eat the long press event so the keyboard doesn't come up.
- if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) {
- return true;
- }
-
- return handled;
- }
-
- private String getTypedText() {
- return mDefaultKeySsb.toString();
- }
-
- private void clearTypedText() {
- mDefaultKeySsb.clear();
- mDefaultKeySsb.clearSpans();
- Selection.setSelection(mDefaultKeySsb, 0);
- }
-
- /**
- * Given the integer (ordinal) value of a State enum instance, convert it to a variable of type
- * State
- */
- private static State intToState(int stateOrdinal) {
- State state = State.WORKSPACE;
- final State[] stateValues = State.values();
- for (int i = 0; i < stateValues.length; i++) {
- if (stateValues[i].ordinal() == stateOrdinal) {
- state = stateValues[i];
- break;
- }
- }
- return state;
- }
-
- /**
- * Restores the previous state, if it exists.
- *
- * @param savedState The previous state.
- */
- private void restoreState(Bundle savedState) {
- if (savedState == null) {
- return;
- }
-
- State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
- if (state == State.APPS_CUSTOMIZE) {
- showAllApps(false);
- }
-
- int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
- if (currentScreen > -1) {
- mWorkspace.setCurrentPage(currentScreen);
- }
-
- final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1);
- final int pendingAddScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
-
- if (pendingAddContainer != ItemInfo.NO_ID && pendingAddScreen > -1) {
- mPendingAddInfo.container = pendingAddContainer;
- mPendingAddInfo.screen = pendingAddScreen;
- mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
- mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
- mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
- mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
- mPendingAddWidgetInfo = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
- mWaitingForResult = true;
- mRestoring = true;
- }
-
-
- boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false);
- if (renameFolder) {
- long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID);
- mFolderInfo = mModel.getFolderById(this, sFolders, id);
- mRestoring = true;
- }
-
-
- // Restore the AppsCustomize tab
- if (mAppsCustomizeTabHost != null) {
- String curTab = savedState.getString("apps_customize_currentTab");
- if (curTab != null) {
- // We set this directly so that there is no delay before the tab is set
- mAppsCustomizeContent.setContentType(
- mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
- mAppsCustomizeTabHost.setCurrentTabByTag(curTab);
- mAppsCustomizeContent.loadAssociatedPages(
- mAppsCustomizeContent.getCurrentPage());
- }
-
- int currentIndex = savedState.getInt("apps_customize_currentIndex");
- mAppsCustomizeContent.restorePageForIndex(currentIndex);
- }
- }
-
- /**
- * Finds all the views we need and configure them properly.
- */
- private void setupViews() {
- final DragController dragController = mDragController;
-
- mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
- mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
- mQsbDivider = (ImageView) findViewById(R.id.qsb_divider);
- mDockDivider = (ImageView) findViewById(R.id.dock_divider);
-
- // Setup the drag layer
- mDragLayer.setup(this, dragController);
-
- // Setup the hotseat
- mHotseat = (Hotseat) findViewById(R.id.hotseat);
- if (mHotseat != null) {
- mHotseat.setup(this);
- }
-
- // Setup the workspace
- mWorkspace.setHapticFeedbackEnabled(false);
- mWorkspace.setOnLongClickListener(this);
- mWorkspace.setup(dragController);
- dragController.addDragListener(mWorkspace);
-
- // Get the search/delete bar
- mSearchDropTargetBar = (SearchDropTargetBar) mDragLayer.findViewById(R.id.qsb_bar);
-
- // Setup AppsCustomize
- mAppsCustomizeTabHost = (AppsCustomizeTabHost)
- findViewById(R.id.apps_customize_pane);
- mAppsCustomizeContent = (AppsCustomizePagedView)
- mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
- mAppsCustomizeTabHost.setup(this);
- mAppsCustomizeContent.setup(this, dragController);
-
- // Get the all apps button
- mAllAppsButton = findViewById(R.id.all_apps_button);
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
- onTouchDownAllAppsButton(v);
- }
- return false;
- }
- });
- }
- // Setup the drag controller (drop targets have to be added in reverse order in priority)
- dragController.setDragScoller(mWorkspace);
- dragController.setScrollView(mDragLayer);
- dragController.setMoveTarget(mWorkspace);
- dragController.addDropTarget(mWorkspace);
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.setup(this, dragController);
- }
- }
-
- /**
- * Creates a view representing a shortcut.
- *
- * @param info The data structure describing the shortcut.
- *
- * @return A View inflated from R.layout.application.
- */
- View createShortcut(ShortcutInfo info) {
- return createShortcut(R.layout.application,
- (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
- }
-
- /**
- * Creates a view representing a shortcut inflated from the specified resource.
- *
- * @param layoutResId The id of the XML layout used to create the shortcut.
- * @param parent The group the shortcut belongs to.
- * @param info The data structure describing the shortcut.
- *
- * @return A View inflated from layoutResId.
- */
- View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
- BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
- favorite.applyFromShortcutInfo(info, mIconCache);
- favorite.setOnClickListener(this);
- return favorite;
- }
-
- /**
- * Add an application shortcut to the workspace.
- *
- * @param data The intent describing the application.
- * @param cellInfo The position on screen where to create the shortcut.
- */
- void completeAddApplication(Intent data, long container, int screen, int cellX, int cellY) {
- final int[] cellXY = mTmpAddItemCellCoordinates;
- final CellLayout layout = getCellLayout(container, screen);
-
- // First we check if we already know the exact location where we want to add this item.
- if (cellX >= 0 && cellY >= 0) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- } else if (!layout.findCellForSpan(cellXY, 1, 1)) {
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
-
- final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
-
- if (info != null) {
- info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- info.container = ItemInfo.NO_ID;
- mWorkspace.addApplicationShortcut(info, layout, container, screen, cellXY[0], cellXY[1],
- isWorkspaceLocked(), cellX, cellY);
- } else {
- Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
- }
- }
-
- /**
- * Add a shortcut to the workspace.
- *
- * @param data The intent describing the shortcut.
- * @param cellInfo The position on screen where to create the shortcut.
- */
- private void completeAddShortcut(Intent data, long container, int screen, int cellX,
- int cellY) {
- int[] cellXY = mTmpAddItemCellCoordinates;
- int[] touchXY = mPendingAddInfo.dropPos;
- CellLayout layout = getCellLayout(container, screen);
-
- boolean foundCellSpan = false;
-
- ShortcutInfo info = mModel.infoFromShortcutIntent(this, data, null);
- if (info == null) {
- return;
- }
- final View view = createShortcut(info);
-
- // First we check if we already know the exact location where we want to add this item.
- if (cellX >= 0 && cellY >= 0) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- foundCellSpan = true;
-
- // If appropriate, either create a folder or add to an existing folder
- if (mWorkspace.createUserFolderIfNecessary(view, container, layout, cellXY, 0,
- true, null,null)) {
- return;
- }
- DragObject dragObject = new DragObject();
- dragObject.dragInfo = info;
- if (mWorkspace.addToExistingFolderIfNecessary(view, layout, cellXY, 0, dragObject,
- true)) {
- return;
- }
- } else if (touchXY != null) {
- // when dragging and dropping, just find the closest free spot
- int[] result = layout.findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, cellXY);
- foundCellSpan = (result != null);
- } else {
- foundCellSpan = layout.findCellForSpan(cellXY, 1, 1);
- }
-
- if (!foundCellSpan) {
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
-
- LauncherModel.addItemToDatabase(this, info, container, screen, cellXY[0], cellXY[1], false);
-
- if (!mRestoring) {
- mWorkspace.addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1,
- isWorkspaceLocked());
- }
- }
-
- static int[] getSpanForWidget(Context context, ComponentName component, int minWidth,
- int minHeight) {
- Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context, component, null);
- // We want to account for the extra amount of padding that we are adding to the widget
- // to ensure that it gets the full amount of space that it has requested
- int requiredWidth = minWidth + padding.left + padding.right;
- int requiredHeight = minHeight + padding.top + padding.bottom;
- return CellLayout.rectToCell(context.getResources(), requiredWidth, requiredHeight, null);
- }
-
- static int[] getSpanForWidget(Context context, AppWidgetProviderInfo info) {
- return getSpanForWidget(context, info.provider, info.minWidth, info.minHeight);
- }
-
- static int[] getMinSpanForWidget(Context context, AppWidgetProviderInfo info) {
- return getSpanForWidget(context, info.provider, info.minResizeWidth, info.minResizeHeight);
- }
-
- static int[] getSpanForWidget(Context context, PendingAddWidgetInfo info) {
- return getSpanForWidget(context, info.componentName, info.minWidth, info.minHeight);
- }
-
- static int[] getMinSpanForWidget(Context context, PendingAddWidgetInfo info) {
- return getSpanForWidget(context, info.componentName, info.minResizeWidth,
- info.minResizeHeight);
- }
-
- /**
- * Add a widget to the workspace.
- *
- * @param appWidgetId The app widget id
- * @param cellInfo The position on screen where to create the widget.
- */
- private void completeAddAppWidget(final int appWidgetId, long container, int screen,
- AppWidgetHostView hostView, AppWidgetProviderInfo appWidgetInfo) {
- if (appWidgetInfo == null) {
- appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- }
-
- // Calculate the grid spans needed to fit this widget
- CellLayout layout = getCellLayout(container, screen);
-
- int[] minSpanXY = getMinSpanForWidget(this, appWidgetInfo);
- int[] spanXY = getSpanForWidget(this, appWidgetInfo);
-
- // Try finding open space on Launcher screen
- // We have saved the position to which the widget was dragged-- this really only matters
- // if we are placing widgets on a "spring-loaded" screen
- int[] cellXY = mTmpAddItemCellCoordinates;
- int[] touchXY = mPendingAddInfo.dropPos;
- int[] finalSpan = new int[2];
- boolean foundCellSpan = false;
- if (mPendingAddInfo.cellX >= 0 && mPendingAddInfo.cellY >= 0) {
- cellXY[0] = mPendingAddInfo.cellX;
- cellXY[1] = mPendingAddInfo.cellY;
- spanXY[0] = mPendingAddInfo.spanX;
- spanXY[1] = mPendingAddInfo.spanY;
- foundCellSpan = true;
- } else if (touchXY != null) {
- // when dragging and dropping, just find the closest free spot
- int[] result = layout.findNearestVacantArea(
- touchXY[0], touchXY[1], minSpanXY[0], minSpanXY[1], spanXY[0],
- spanXY[1], cellXY, finalSpan);
- spanXY[0] = finalSpan[0];
- spanXY[1] = finalSpan[1];
- foundCellSpan = (result != null);
- } else {
- foundCellSpan = layout.findCellForSpan(cellXY, minSpanXY[0], minSpanXY[1]);
- }
-
- if (!foundCellSpan) {
- if (appWidgetId != -1) {
- // Deleting an app widget ID is a void call but writes to disk before returning
- // to the caller...
- new Thread("deleteAppWidgetId") {
- public void run() {
- mAppWidgetHost.deleteAppWidgetId(appWidgetId);
- }
- }.start();
- }
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
-
- // Build Launcher-specific widget info and save to database
- LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId,
- appWidgetInfo.provider);
- launcherInfo.spanX = spanXY[0];
- launcherInfo.spanY = spanXY[1];
- launcherInfo.minSpanX = mPendingAddInfo.minSpanX;
- launcherInfo.minSpanY = mPendingAddInfo.minSpanY;
-
- LauncherModel.addItemToDatabase(this, launcherInfo,
- container, screen, cellXY[0], cellXY[1], false);
-
- if (!mRestoring) {
- if (hostView == null) {
- // Perform actual inflation because we're live
- launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
- launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
- } else {
- // The AppWidgetHostView has already been inflated and instantiated
- launcherInfo.hostView = hostView;
- }
-
- launcherInfo.hostView.setTag(launcherInfo);
- launcherInfo.hostView.setVisibility(View.VISIBLE);
- launcherInfo.notifyWidgetSizeChanged(this);
- mWorkspace.addInScreen(launcherInfo.hostView, container, screen, cellXY[0], cellXY[1],
- launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
-
- addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo);
- }
- resetAddInfo();
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- mUserPresent = false;
- mDragLayer.clearAllResizeFrames();
- updateRunning();
-
- // Reset AllApps to its initial state only if we are not in the middle of
- // processing a multi-step drop
- if (mAppsCustomizeTabHost != null && mPendingAddInfo.container == ItemInfo.NO_ID) {
- mAppsCustomizeTabHost.reset();
- showWorkspace(false);
- }
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- mUserPresent = true;
- updateRunning();
- }
- }
- };
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // Listen for broadcasts related to user-presence
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_USER_PRESENT);
- registerReceiver(mReceiver, filter);
-
- mAttached = true;
- mVisible = true;
- }
-
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mVisible = false;
-
- if (mAttached) {
- unregisterReceiver(mReceiver);
- mAttached = false;
- }
- updateRunning();
- }
-
- public void onWindowVisibilityChanged(int visibility) {
- mVisible = visibility == View.VISIBLE;
- updateRunning();
- // The following code used to be in onResume, but it turns out onResume is called when
- // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
- // is a more appropriate event to handle
- if (mVisible) {
- mAppsCustomizeTabHost.onWindowVisible();
- if (!mWorkspaceLoading) {
- final ViewTreeObserver observer = mWorkspace.getViewTreeObserver();
- // We want to let Launcher draw itself at least once before we force it to build
- // layers on all the workspace pages, so that transitioning to Launcher from other
- // apps is nice and speedy. Usually the first call to preDraw doesn't correspond to
- // a true draw so we wait until the second preDraw call to be safe
- observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- public boolean onPreDraw() {
- // We delay the layer building a bit in order to give
- // other message processing a time to run. In particular
- // this avoids a delay in hiding the IME if it was
- // currently shown, because doing that may involve
- // some communication back with the app.
- mWorkspace.postDelayed(mBuildLayersRunnable, 500);
-
- observer.removeOnPreDrawListener(this);
- return true;
- }
- });
- }
- // When Launcher comes back to foreground, a different Activity might be responsible for
- // the app market intent, so refresh the icon
- updateAppMarketIcon();
- clearTypedText();
- }
- }
-
- private void sendAdvanceMessage(long delay) {
- mHandler.removeMessages(ADVANCE_MSG);
- Message msg = mHandler.obtainMessage(ADVANCE_MSG);
- mHandler.sendMessageDelayed(msg, delay);
- mAutoAdvanceSentTime = System.currentTimeMillis();
- }
-
- private void updateRunning() {
- boolean autoAdvanceRunning = mVisible && mUserPresent && !mWidgetsToAdvance.isEmpty();
- if (autoAdvanceRunning != mAutoAdvanceRunning) {
- mAutoAdvanceRunning = autoAdvanceRunning;
- if (autoAdvanceRunning) {
- long delay = mAutoAdvanceTimeLeft == -1 ? mAdvanceInterval : mAutoAdvanceTimeLeft;
- sendAdvanceMessage(delay);
- } else {
- if (!mWidgetsToAdvance.isEmpty()) {
- mAutoAdvanceTimeLeft = Math.max(0, mAdvanceInterval -
- (System.currentTimeMillis() - mAutoAdvanceSentTime));
- }
- mHandler.removeMessages(ADVANCE_MSG);
- mHandler.removeMessages(0); // Remove messages sent using postDelayed()
- }
- }
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == ADVANCE_MSG) {
- int i = 0;
- for (View key: mWidgetsToAdvance.keySet()) {
- final View v = key.findViewById(mWidgetsToAdvance.get(key).autoAdvanceViewId);
- final int delay = mAdvanceStagger * i;
- if (v instanceof Advanceable) {
- postDelayed(new Runnable() {
- public void run() {
- ((Advanceable) v).advance();
- }
- }, delay);
- }
- i++;
- }
- sendAdvanceMessage(mAdvanceInterval);
- }
- }
- };
-
- void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
- if (appWidgetInfo == null || appWidgetInfo.autoAdvanceViewId == -1) return;
- View v = hostView.findViewById(appWidgetInfo.autoAdvanceViewId);
- if (v instanceof Advanceable) {
- mWidgetsToAdvance.put(hostView, appWidgetInfo);
- ((Advanceable) v).fyiWillBeAdvancedByHostKThx();
- updateRunning();
- }
- }
-
- void removeWidgetToAutoAdvance(View hostView) {
- if (mWidgetsToAdvance.containsKey(hostView)) {
- mWidgetsToAdvance.remove(hostView);
- updateRunning();
- }
- }
-
- public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) {
- removeWidgetToAutoAdvance(launcherInfo.hostView);
- launcherInfo.hostView = null;
- }
-
- void showOutOfSpaceMessage(boolean isHotseatLayout) {
- int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
- Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
- }
-
- public LauncherAppWidgetHost getAppWidgetHost() {
- return mAppWidgetHost;
- }
-
- public LauncherModel getModel() {
- return mModel;
- }
-
- void closeSystemDialogs() {
- getWindow().closeAllPanels();
-
- // Whatever we were doing is hereby canceled.
- mWaitingForResult = false;
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
- // Close the menu
- if (Intent.ACTION_MAIN.equals(intent.getAction())) {
- // also will cancel mWaitingForResult.
- closeSystemDialogs();
-
- boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
- != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-
- Folder openFolder = mWorkspace.getOpenFolder();
- // In all these cases, only animate if we're already on home
- mWorkspace.exitWidgetResizeMode();
- if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
- openFolder == null) {
- mWorkspace.moveToDefaultScreen(true);
- }
-
- closeFolder();
- exitSpringLoadedDragMode();
- showWorkspace(alreadyOnHome);
-
- final View v = getWindow().peekDecorView();
- if (v != null && v.getWindowToken() != null) {
- InputMethodManager imm = (InputMethodManager)getSystemService(
- INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
- }
-
- // Reset AllApps to its initial state
- if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
- mAppsCustomizeTabHost.reset();
- }
- }
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- // Do not call super here
- mSavedInstanceState = savedInstanceState;
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentPage());
- super.onSaveInstanceState(outState);
-
- outState.putInt(RUNTIME_STATE, mState.ordinal());
- // We close any open folder since it will not be re-opened, and we need to make sure
- // this state is reflected.
- closeFolder();
-
- if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screen > -1 &&
- mWaitingForResult) {
- outState.putLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, mPendingAddInfo.container);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mPendingAddInfo.screen);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, mPendingAddInfo.cellX);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, mPendingAddInfo.cellY);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_X, mPendingAddInfo.spanX);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y, mPendingAddInfo.spanY);
- outState.putParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO, mPendingAddWidgetInfo);
- }
-
- if (mFolderInfo != null && mWaitingForResult) {
- outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true);
- outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
- }
-
- // Save the current AppsCustomize tab
- if (mAppsCustomizeTabHost != null) {
- String currentTabTag = mAppsCustomizeTabHost.getCurrentTabTag();
- if (currentTabTag != null) {
- outState.putString("apps_customize_currentTab", currentTabTag);
- }
- int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
- outState.putInt("apps_customize_currentIndex", currentIndex);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- // Remove all pending runnables
- mHandler.removeMessages(ADVANCE_MSG);
- mHandler.removeMessages(0);
- mWorkspace.removeCallbacks(mBuildLayersRunnable);
-
- // Stop callbacks from LauncherModel
- LauncherApplication app = ((LauncherApplication) getApplication());
- mModel.stopLoader();
- app.setLauncher(null);
-
- try {
- mAppWidgetHost.stopListening();
- } catch (NullPointerException ex) {
- Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
- }
- mAppWidgetHost = null;
-
- mWidgetsToAdvance.clear();
-
- TextKeyListener.getInstance().release();
-
-
- unbindWorkspaceAndHotseatItems();
-
- getContentResolver().unregisterContentObserver(mWidgetObserver);
- unregisterReceiver(mCloseSystemDialogsReceiver);
-
- mDragLayer.clearAllResizeFrames();
- ((ViewGroup) mWorkspace.getParent()).removeAllViews();
- mWorkspace.removeAllViews();
- mWorkspace = null;
- mDragController = null;
-
- ValueAnimator.clearAllAnimations();
- }
-
- public DragController getDragController() {
- return mDragController;
- }
-
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- if (requestCode >= 0) mWaitingForResult = true;
- super.startActivityForResult(intent, requestCode);
- }
-
- /**
- * Indicates that we want global search for this activity by setting the globalSearch
- * argument for {@link #startSearch} to true.
- */
- @Override
- public void startSearch(String initialQuery, boolean selectInitialQuery,
- Bundle appSearchData, boolean globalSearch) {
-
- showWorkspace(true);
-
- if (initialQuery == null) {
- // Use any text typed in the launcher as the initial query
- initialQuery = getTypedText();
- }
- if (appSearchData == null) {
- appSearchData = new Bundle();
- appSearchData.putString(Search.SOURCE, "launcher-search");
- }
- Rect sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
-
- final SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- searchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(),
- appSearchData, globalSearch, sourceBounds);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- if (isWorkspaceLocked()) {
- return false;
- }
-
- super.onCreateOptionsMenu(menu);
-
- Intent manageApps = new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS);
- manageApps.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- Intent settings = new Intent(android.provider.Settings.ACTION_SETTINGS);
- settings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- String helpUrl = getString(R.string.help_url);
- Intent help = new Intent(Intent.ACTION_VIEW, Uri.parse(helpUrl));
- help.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
- menu.add(MENU_GROUP_WALLPAPER, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper)
- .setIcon(android.R.drawable.ic_menu_gallery)
- .setAlphabeticShortcut('W');
- menu.add(0, MENU_MANAGE_APPS, 0, R.string.menu_manage_apps)
- .setIcon(android.R.drawable.ic_menu_manage)
- .setIntent(manageApps)
- .setAlphabeticShortcut('M');
- menu.add(0, MENU_SYSTEM_SETTINGS, 0, R.string.menu_settings)
- .setIcon(android.R.drawable.ic_menu_preferences)
- .setIntent(settings)
- .setAlphabeticShortcut('P');
- if (!helpUrl.isEmpty()) {
- menu.add(0, MENU_HELP, 0, R.string.menu_help)
- .setIcon(android.R.drawable.ic_menu_help)
- .setIntent(help)
- .setAlphabeticShortcut('H');
- }
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
-
- if (mAppsCustomizeTabHost.isTransitioning()) {
- return false;
- }
- boolean allAppsVisible = (mAppsCustomizeTabHost.getVisibility() == View.VISIBLE);
- menu.setGroupVisible(MENU_GROUP_WALLPAPER, !allAppsVisible);
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_WALLPAPER_SETTINGS:
- startWallpaper();
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onSearchRequested() {
- startSearch(null, false, null, true);
- // Use a custom animation for launching search
- overridePendingTransition(R.anim.fade_in_fast, R.anim.fade_out_fast);
- return true;
- }
-
- public boolean isWorkspaceLocked() {
- return mWorkspaceLoading || mWaitingForResult;
- }
-
- private void resetAddInfo() {
- mPendingAddInfo.container = ItemInfo.NO_ID;
- mPendingAddInfo.screen = -1;
- mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1;
- mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1;
- mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = -1;
- mPendingAddInfo.dropPos = null;
- }
-
- void addAppWidgetImpl(final int appWidgetId, ItemInfo info, AppWidgetHostView boundWidget,
- AppWidgetProviderInfo appWidgetInfo) {
- if (appWidgetInfo.configure != null) {
- mPendingAddWidgetInfo = appWidgetInfo;
-
- // Launch over to configure widget, if needed
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
- intent.setComponent(appWidgetInfo.configure);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
- } else {
- // Otherwise just add it
- completeAddAppWidget(appWidgetId, info.container, info.screen, boundWidget,
- appWidgetInfo);
- // Exit spring loaded mode if necessary after adding the widget
- exitSpringLoadedDragModeDelayed(true, false, null);
- }
- }
-
- /**
- * Process a shortcut drop.
- *
- * @param componentName The name of the component
- * @param screen The screen where it should be added
- * @param cell The cell it should be added to, optional
- * @param position The location on the screen where it was dropped, optional
- */
- void processShortcutFromDrop(ComponentName componentName, long container, int screen,
- int[] cell, int[] loc) {
- resetAddInfo();
- mPendingAddInfo.container = container;
- mPendingAddInfo.screen = screen;
- mPendingAddInfo.dropPos = loc;
-
- if (cell != null) {
- mPendingAddInfo.cellX = cell[0];
- mPendingAddInfo.cellY = cell[1];
- }
-
- Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
- createShortcutIntent.setComponent(componentName);
- processShortcut(createShortcutIntent);
- }
-
- /**
- * Process a widget drop.
- *
- * @param info The PendingAppWidgetInfo of the widget being added.
- * @param screen The screen where it should be added
- * @param cell The cell it should be added to, optional
- * @param position The location on the screen where it was dropped, optional
- */
- void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, int screen,
- int[] cell, int[] span, int[] loc) {
- resetAddInfo();
- mPendingAddInfo.container = info.container = container;
- mPendingAddInfo.screen = info.screen = screen;
- mPendingAddInfo.dropPos = loc;
- mPendingAddInfo.minSpanX = info.minSpanX;
- mPendingAddInfo.minSpanY = info.minSpanY;
-
- if (cell != null) {
- mPendingAddInfo.cellX = cell[0];
- mPendingAddInfo.cellY = cell[1];
- }
- if (span != null) {
- mPendingAddInfo.spanX = span[0];
- mPendingAddInfo.spanY = span[1];
- }
-
- AppWidgetHostView hostView = info.boundWidget;
- int appWidgetId;
- if (hostView != null) {
- appWidgetId = hostView.getAppWidgetId();
- addAppWidgetImpl(appWidgetId, info, hostView, info.info);
- } else {
- // In this case, we either need to start an activity to get permission to bind
- // the widget, or we need to start an activity to configure the widget, or both.
- appWidgetId = getAppWidgetHost().allocateAppWidgetId();
- if (mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.componentName)) {
- addAppWidgetImpl(appWidgetId, info, null, info.info);
- } else {
- mPendingAddWidgetInfo = info.info;
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
- startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
- }
- }
- }
-
- void processShortcut(Intent intent) {
- // Handle case where user selected "Applications"
- String applicationName = getResources().getString(R.string.group_applications);
- String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-
- if (applicationName != null && applicationName.equals(shortcutName)) {
- Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
- pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_application));
- startActivityForResultSafely(pickIntent, REQUEST_PICK_APPLICATION);
- } else {
- startActivityForResultSafely(intent, REQUEST_CREATE_SHORTCUT);
- }
- }
-
- void processWallpaper(Intent intent) {
- startActivityForResult(intent, REQUEST_PICK_WALLPAPER);
- }
-
- FolderIcon addFolder(CellLayout layout, long container, final int screen, int cellX,
- int cellY) {
- final FolderInfo folderInfo = new FolderInfo();
- folderInfo.title = getText(R.string.folder_name);
-
- // Update the model
- LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screen, cellX, cellY,
- false);
- sFolders.put(folderInfo.id, folderInfo);
-
- // Create the view
- FolderIcon newFolder =
- FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo, mIconCache);
- mWorkspace.addInScreen(newFolder, container, screen, cellX, cellY, 1, 1,
- isWorkspaceLocked());
- return newFolder;
- }
-
- void removeFolder(FolderInfo folder) {
- sFolders.remove(folder.id);
- }
-
- private void startWallpaper() {
- showWorkspace(true);
- final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
- Intent chooser = Intent.createChooser(pickWallpaper,
- getText(R.string.chooser_wallpaper));
- // NOTE: Adds a configure option to the chooser if the wallpaper supports it
- // Removed in Eclair MR1
-// WallpaperManager wm = (WallpaperManager)
-// getSystemService(Context.WALLPAPER_SERVICE);
-// WallpaperInfo wi = wm.getWallpaperInfo();
-// if (wi != null && wi.getSettingsActivity() != null) {
-// LabeledIntent li = new LabeledIntent(getPackageName(),
-// R.string.configure_wallpaper, 0);
-// li.setClassName(wi.getPackageName(), wi.getSettingsActivity());
-// chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { li });
-// }
- startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);
- }
-
- /**
- * Registers various content observers. The current implementation registers
- * only a favorites observer to keep track of the favorites applications.
- */
- private void registerContentObservers() {
- ContentResolver resolver = getContentResolver();
- resolver.registerContentObserver(LauncherProvider.CONTENT_APPWIDGET_RESET_URI,
- true, mWidgetObserver);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_HOME:
- return true;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- if (SystemProperties.getInt("debug.launcher2.dumpstate", 0) != 0) {
- dumpState();
- return true;
- }
- break;
- }
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_HOME:
- return true;
- }
- }
-
- return super.dispatchKeyEvent(event);
- }
-
- @Override
- public void onBackPressed() {
- if (mState == State.APPS_CUSTOMIZE) {
- showWorkspace(true);
- } else if (mWorkspace.getOpenFolder() != null) {
- Folder openFolder = mWorkspace.getOpenFolder();
- if (openFolder.isEditingName()) {
- openFolder.dismissEditingName();
- } else {
- closeFolder();
- }
- } else {
- mWorkspace.exitWidgetResizeMode();
-
- // Back button is a no-op here, but give at least some feedback for the button press
- mWorkspace.showOutlinesTemporarily();
- }
- }
-
- /**
- * Re-listen when widgets are reset.
- */
- private void onAppWidgetReset() {
- if (mAppWidgetHost != null) {
- mAppWidgetHost.startListening();
- }
- }
-
- /**
- * Go through the and disconnect any of the callbacks in the drawables and the views or we
- * leak the previous Home screen on orientation change.
- */
- private void unbindWorkspaceAndHotseatItems() {
- if (mModel != null) {
- mModel.unbindWorkspaceItems();
- }
- }
-
- /**
- * Launches the intent referred by the clicked shortcut.
- *
- * @param v The view representing the clicked shortcut.
- */
- public void onClick(View v) {
- // Make sure that rogue clicks don't get through while allapps is launching, or after the
- // view has detached (it's possible for this to happen if the view is removed mid touch).
- if (v.getWindowToken() == null) {
- return;
- }
-
- if (!mWorkspace.isFinishedSwitchingState()) {
- return;
- }
-
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- // Open shortcut
- final Intent intent = ((ShortcutInfo) tag).intent;
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
-
- boolean success = startActivitySafely(v, intent, tag);
-
- if (success && v instanceof BubbleTextView) {
- mWaitingForResume = (BubbleTextView) v;
- mWaitingForResume.setStayPressed(true);
- }
- } else if (tag instanceof FolderInfo) {
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- handleFolderClick(fi);
- }
- } else if (v == mAllAppsButton) {
- if (mState == State.APPS_CUSTOMIZE) {
- showWorkspace(true);
- } else {
- onClickAllAppsButton(v);
- }
- }
- }
-
- public boolean onTouch(View v, MotionEvent event) {
- // this is an intercepted event being forwarded from mWorkspace;
- // clicking anywhere on the workspace causes the customization drawer to slide down
- showWorkspace(true);
- return false;
- }
-
- /**
- * Event handler for the search button
- *
- * @param v The view that was clicked.
- */
- public void onClickSearchButton(View v) {
- v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-
- onSearchRequested();
- }
-
- /**
- * Event handler for the voice button
- *
- * @param v The view that was clicked.
- */
- public void onClickVoiceButton(View v) {
- v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-
- try {
- final SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- ComponentName activityName = searchManager.getGlobalSearchActivity();
- Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (activityName != null) {
- intent.setPackage(activityName.getPackageName());
- }
- startActivity(null, intent, "onClickVoiceButton");
- overridePendingTransition(R.anim.fade_in_fast, R.anim.fade_out_fast);
- } catch (ActivityNotFoundException e) {
- Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivitySafely(null, intent, "onClickVoiceButton");
- }
- }
-
- /**
- * Event handler for the "grid" button that appears on the home screen, which
- * enters all apps mode.
- *
- * @param v The view that was clicked.
- */
- public void onClickAllAppsButton(View v) {
- showAllApps(true);
- }
-
- public void onTouchDownAllAppsButton(View v) {
- // Provide the same haptic feedback that the system offers for virtual keys.
- v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
- }
-
- public void onClickAppMarketButton(View v) {
- if (mAppMarketIntent != null) {
- startActivitySafely(v, mAppMarketIntent, "app market");
- } else {
- Log.e(TAG, "Invalid app market intent.");
- }
- }
-
- void startApplicationDetailsActivity(ComponentName componentName) {
- String packageName = componentName.getPackageName();
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
- Uri.fromParts("package", packageName, null));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- startActivitySafely(null, intent, "startApplicationDetailsActivity");
- }
-
- void startApplicationUninstallActivity(ApplicationInfo appInfo) {
- if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) == 0) {
- // System applications cannot be installed. For now, show a toast explaining that.
- // We may give them the option of disabling apps this way.
- int messageId = R.string.uninstall_system_app_text;
- Toast.makeText(this, messageId, Toast.LENGTH_SHORT).show();
- } else {
- String packageName = appInfo.componentName.getPackageName();
- String className = appInfo.componentName.getClassName();
- Intent intent = new Intent(
- Intent.ACTION_DELETE, Uri.fromParts("package", packageName, className));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- startActivity(intent);
- }
- }
-
- boolean startActivity(View v, Intent intent, Object tag) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- try {
- // Only launch using the new animation if the shortcut has not opted out (this is a
- // private contract between launcher and may be ignored in the future).
- boolean useLaunchAnimation = (v != null) &&
- !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
- if (useLaunchAnimation) {
- ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
- v.getMeasuredWidth(), v.getMeasuredHeight());
-
- startActivity(intent, opts.toBundle());
- } else {
- startActivity(intent);
- }
- return true;
- } catch (SecurityException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Launcher does not have the permission to launch " + intent +
- ". Make sure to create a MAIN intent-filter for the corresponding activity " +
- "or use the exported attribute for this activity. "
- + "tag="+ tag + " intent=" + intent, e);
- }
- return false;
- }
-
- boolean startActivitySafely(View v, Intent intent, Object tag) {
- boolean success = false;
- try {
- success = startActivity(v, intent, tag);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
- }
- return success;
- }
-
- void startActivityForResultSafely(Intent intent, int requestCode) {
- try {
- startActivityForResult(intent, requestCode);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- } catch (SecurityException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Launcher does not have the permission to launch " + intent +
- ". Make sure to create a MAIN intent-filter for the corresponding activity " +
- "or use the exported attribute for this activity.", e);
- }
- }
-
- private void handleFolderClick(FolderIcon folderIcon) {
- final FolderInfo info = folderIcon.mInfo;
- Folder openFolder = mWorkspace.getFolderForTag(info);
-
- // If the folder info reports that the associated folder is open, then verify that
- // it is actually opened. There have been a few instances where this gets out of sync.
- if (info.opened && openFolder == null) {
- Log.d(TAG, "Folder info marked as open, but associated folder is not open. Screen: "
- + info.screen + " (" + info.cellX + ", " + info.cellY + ")");
- info.opened = false;
- }
-
- if (!info.opened) {
- // Close any open folder
- closeFolder();
- // Open the requested folder
- openFolder(folderIcon);
- } else {
- // Find the open folder...
- int folderScreen;
- if (openFolder != null) {
- folderScreen = mWorkspace.getPageForView(openFolder);
- // .. and close it
- closeFolder(openFolder);
- if (folderScreen != mWorkspace.getCurrentPage()) {
- // Close any folder open on the current screen
- closeFolder();
- // Pull the folder onto this screen
- openFolder(folderIcon);
- }
- }
- }
- }
-
- /**
- * This method draws the FolderIcon to an ImageView and then adds and positions that ImageView
- * in the DragLayer in the exact absolute location of the original FolderIcon.
- */
- private void copyFolderIconToImage(FolderIcon fi) {
- final int width = fi.getMeasuredWidth();
- final int height = fi.getMeasuredHeight();
-
- // Lazy load ImageView, Bitmap and Canvas
- if (mFolderIconImageView == null) {
- mFolderIconImageView = new ImageView(this);
- }
- if (mFolderIconBitmap == null || mFolderIconBitmap.getWidth() != width ||
- mFolderIconBitmap.getHeight() != height) {
- mFolderIconBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mFolderIconCanvas = new Canvas(mFolderIconBitmap);
- }
-
- DragLayer.LayoutParams lp;
- if (mFolderIconImageView.getLayoutParams() instanceof DragLayer.LayoutParams) {
- lp = (DragLayer.LayoutParams) mFolderIconImageView.getLayoutParams();
- } else {
- lp = new DragLayer.LayoutParams(width, height);
- }
-
- mDragLayer.getViewRectRelativeToSelf(fi, mRectForFolderAnimation);
- lp.customPosition = true;
- lp.x = mRectForFolderAnimation.left;
- lp.y = mRectForFolderAnimation.top;
- lp.width = width;
- lp.height = height;
-
- mFolderIconCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
- fi.draw(mFolderIconCanvas);
- mFolderIconImageView.setImageBitmap(mFolderIconBitmap);
- if (fi.mFolder != null) {
- mFolderIconImageView.setPivotX(fi.mFolder.getPivotXForIconAnimation());
- mFolderIconImageView.setPivotY(fi.mFolder.getPivotYForIconAnimation());
- }
- // Just in case this image view is still in the drag layer from a previous animation,
- // we remove it and re-add it.
- if (mDragLayer.indexOfChild(mFolderIconImageView) != -1) {
- mDragLayer.removeView(mFolderIconImageView);
- }
- mDragLayer.addView(mFolderIconImageView, lp);
- if (fi.mFolder != null) {
- fi.mFolder.bringToFront();
- }
- }
-
- private void growAndFadeOutFolderIcon(FolderIcon fi) {
- if (fi == null) return;
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
- PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.5f);
- PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.5f);
-
- FolderInfo info = (FolderInfo) fi.getTag();
- if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- CellLayout cl = (CellLayout) fi.getParent().getParent();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) fi.getLayoutParams();
- cl.setFolderLeaveBehindCell(lp.cellX, lp.cellY);
- }
-
- // Push an ImageView copy of the FolderIcon into the DragLayer and hide the original
- copyFolderIconToImage(fi);
- fi.setVisibility(View.INVISIBLE);
-
- ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha,
- scaleX, scaleY);
- oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
- oa.start();
- }
-
- private void shrinkAndFadeInFolderIcon(final FolderIcon fi) {
- if (fi == null) return;
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f);
- PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
- PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
-
- final CellLayout cl = (CellLayout) fi.getParent().getParent();
-
- // We remove and re-draw the FolderIcon in-case it has changed
- mDragLayer.removeView(mFolderIconImageView);
- copyFolderIconToImage(fi);
- ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha,
- scaleX, scaleY);
- oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
- oa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (cl != null) {
- cl.clearFolderLeaveBehind();
- // Remove the ImageView copy of the FolderIcon and make the original visible.
- mDragLayer.removeView(mFolderIconImageView);
- fi.setVisibility(View.VISIBLE);
- }
- }
- });
- oa.start();
- }
-
- /**
- * Opens the user folder described by the specified tag. The opening of the folder
- * is animated relative to the specified View. If the View is null, no animation
- * is played.
- *
- * @param folderInfo The FolderInfo describing the folder to open.
- */
- public void openFolder(FolderIcon folderIcon) {
- Folder folder = folderIcon.mFolder;
- FolderInfo info = folder.mInfo;
-
- info.opened = true;
-
- // Just verify that the folder hasn't already been added to the DragLayer.
- // There was a one-off crash where the folder had a parent already.
- if (folder.getParent() == null) {
- mDragLayer.addView(folder);
- mDragController.addDropTarget((DropTarget) folder);
- } else {
- Log.w(TAG, "Opening folder (" + folder + ") which already has a parent (" +
- folder.getParent() + ").");
- }
- folder.animateOpen();
- growAndFadeOutFolderIcon(folderIcon);
- }
-
- public void closeFolder() {
- Folder folder = mWorkspace.getOpenFolder();
- if (folder != null) {
- if (folder.isEditingName()) {
- folder.dismissEditingName();
- }
- closeFolder(folder);
-
- // Dismiss the folder cling
- dismissFolderCling(null);
- }
- }
-
- void closeFolder(Folder folder) {
- folder.getInfo().opened = false;
-
- ViewGroup parent = (ViewGroup) folder.getParent().getParent();
- if (parent != null) {
- FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo);
- shrinkAndFadeInFolderIcon(fi);
- }
- folder.animateClosed();
- }
-
- public boolean onLongClick(View v) {
- if (!isDraggingEnabled()) return false;
- if (isWorkspaceLocked()) return false;
- if (mState != State.WORKSPACE) return false;
-
- if (!(v instanceof CellLayout)) {
- v = (View) v.getParent().getParent();
- }
-
- resetAddInfo();
- CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
- // This happens when long clicking an item with the dpad/trackball
- if (longClickCellInfo == null) {
- return true;
- }
-
- // The hotseat touch handling does not go through Workspace, and we always allow long press
- // on hotseat items.
- final View itemUnderLongClick = longClickCellInfo.cell;
- boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
- if (allowLongPress && !mDragController.isDragging()) {
- if (itemUnderLongClick == null) {
- // User long pressed on empty space
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- startWallpaper();
- } else {
- if (!(itemUnderLongClick instanceof Folder)) {
- // User long pressed on an item
- mWorkspace.startDrag(longClickCellInfo);
- }
- }
- }
- return true;
- }
-
- boolean isHotseatLayout(View layout) {
- return mHotseat != null && layout != null &&
- (layout instanceof CellLayout) && (layout == mHotseat.getLayout());
- }
- Hotseat getHotseat() {
- return mHotseat;
- }
- SearchDropTargetBar getSearchBar() {
- return mSearchDropTargetBar;
- }
-
- /**
- * Returns the CellLayout of the specified container at the specified screen.
- */
- CellLayout getCellLayout(long container, int screen) {
- if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- if (mHotseat != null) {
- return mHotseat.getLayout();
- } else {
- return null;
- }
- } else {
- return (CellLayout) mWorkspace.getChildAt(screen);
- }
- }
-
- Workspace getWorkspace() {
- return mWorkspace;
- }
-
- // Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
- public boolean isAllAppsVisible() {
- return (mState == State.APPS_CUSTOMIZE);
- }
-
- public boolean isAllAppsButtonRank(int rank) {
- return mHotseat.isAllAppsButtonRank(rank);
- }
-
- // AllAppsView.Watcher
- public void zoomed(float zoom) {
- if (zoom == 1.0f) {
- mWorkspace.setVisibility(View.GONE);
- }
- }
-
- /**
- * Helper method for the cameraZoomIn/cameraZoomOut animations
- * @param view The view being animated
- * @param state The state that we are moving in or out of (eg. APPS_CUSTOMIZE)
- * @param scaleFactor The scale factor used for the zoom
- */
- private void setPivotsForZoom(View view, float scaleFactor) {
- view.setPivotX(view.getWidth() / 2.0f);
- view.setPivotY(view.getHeight() / 2.0f);
- }
-
- void disableWallpaperIfInAllApps() {
- // Only disable it if we are in all apps
- if (mState == State.APPS_CUSTOMIZE) {
- if (mAppsCustomizeTabHost != null &&
- !mAppsCustomizeTabHost.isTransitioning()) {
- updateWallpaperVisibility(false);
- }
- }
- }
-
- void updateWallpaperVisibility(boolean visible) {
- int wpflags = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
- int curflags = getWindow().getAttributes().flags
- & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
- if (wpflags != curflags) {
- getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
- }
- }
-
- private void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionPrepare(this, animated, toWorkspace);
- }
- }
-
- private void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionStart(this, animated, toWorkspace);
- }
-
- // Update the workspace transition step as well
- dispatchOnLauncherTransitionStep(v, 0f);
- }
-
- private void dispatchOnLauncherTransitionStep(View v, float t) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionStep(this, t);
- }
- }
-
- private void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionEnd(this, animated, toWorkspace);
- }
-
- // Update the workspace transition step as well
- dispatchOnLauncherTransitionStep(v, 1f);
- }
-
- /**
- * Things to test when changing the following seven functions.
- * - Home from workspace
- * - from center screen
- * - from other screens
- * - Home from all apps
- * - from center screen
- * - from other screens
- * - Back from all apps
- * - from center screen
- * - from other screens
- * - Launch app from workspace and quit
- * - with back
- * - with home
- * - Launch app from all apps and quit
- * - with back
- * - with home
- * - Go to a screen that's not the default, then all
- * apps, and launch and app, and go back
- * - with back
- * -with home
- * - On workspace, long press power and go back
- * - with back
- * - with home
- * - On all apps, long press power and go back
- * - with back
- * - with home
- * - On workspace, power off
- * - On all apps, power off
- * - Launch an app and turn off the screen while in that app
- * - Go back with home key
- * - Go back with back key TODO: make this not go to workspace
- * - From all apps
- * - From workspace
- * - Enter and exit car mode (becuase it causes an extra configuration changed)
- * - From all apps
- * - From the center workspace
- * - From another workspace
- */
-
- /**
- * Zoom the camera out from the workspace to reveal 'toView'.
- * Assumes that the view to show is anchored at either the very top or very bottom
- * of the screen.
- */
- private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded) {
- if (mStateAnimation != null) {
- mStateAnimation.cancel();
- mStateAnimation = null;
- }
- final Resources res = getResources();
-
- final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime);
- final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime);
- final float scale = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
- final View fromView = mWorkspace;
- final AppsCustomizeTabHost toView = mAppsCustomizeTabHost;
- final int startDelay =
- res.getInteger(R.integer.config_workspaceAppsCustomizeAnimationStagger);
-
- setPivotsForZoom(toView, scale);
-
- // Shrink workspaces away if going to AppsCustomize from workspace
- Animator workspaceAnim =
- mWorkspace.getChangeStateAnimation(Workspace.State.SMALL, animated);
-
- if (animated) {
- toView.setScaleX(scale);
- toView.setScaleY(scale);
- final LauncherViewPropertyAnimator scaleAnim = new LauncherViewPropertyAnimator(toView);
- scaleAnim.
- scaleX(1f).scaleY(1f).
- setDuration(duration).
- setInterpolator(new Workspace.ZoomOutInterpolator());
-
- toView.setVisibility(View.VISIBLE);
- toView.setAlpha(0f);
- final ObjectAnimator alphaAnim = ObjectAnimator
- .ofFloat(toView, "alpha", 0f, 1f)
- .setDuration(fadeDuration);
- alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (Float) animation.getAnimatedValue();
- dispatchOnLauncherTransitionStep(fromView, t);
- dispatchOnLauncherTransitionStep(toView, t);
- }
- });
-
- // toView should appear right at the end of the workspace shrink
- // animation
- mStateAnimation = new AnimatorSet();
- mStateAnimation.play(scaleAnim).after(startDelay);
- mStateAnimation.play(alphaAnim).after(startDelay);
-
- mStateAnimation.addListener(new AnimatorListenerAdapter() {
- boolean animationCancelled = false;
-
- @Override
- public void onAnimationStart(Animator animation) {
- updateWallpaperVisibility(true);
- // Prepare the position
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- dispatchOnLauncherTransitionEnd(fromView, animated, false);
- dispatchOnLauncherTransitionEnd(toView, animated, false);
-
- if (!springLoaded && !LauncherApplication.isScreenLarge()) {
- // Hide the workspace scrollbar
- mWorkspace.hideScrollingIndicator(true);
- hideDockDivider();
- }
- if (!animationCancelled) {
- updateWallpaperVisibility(false);
- }
-
- // Hide the search bar
- mSearchDropTargetBar.hideSearchBar(false);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- animationCancelled = true;
- }
- });
-
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
- }
-
- boolean delayAnim = false;
- final ViewTreeObserver observer;
-
- dispatchOnLauncherTransitionPrepare(fromView, animated, false);
- dispatchOnLauncherTransitionPrepare(toView, animated, false);
-
- // If any of the objects being animated haven't been measured/laid out
- // yet, delay the animation until we get a layout pass
- if ((((LauncherTransitionable) toView).getContent().getMeasuredWidth() == 0) ||
- (mWorkspace.getMeasuredWidth() == 0) ||
- (toView.getMeasuredWidth() == 0)) {
- observer = mWorkspace.getViewTreeObserver();
- delayAnim = true;
- } else {
- observer = null;
- }
-
- final AnimatorSet stateAnimation = mStateAnimation;
- final Runnable startAnimRunnable = new Runnable() {
- public void run() {
- // Check that mStateAnimation hasn't changed while
- // we waited for a layout/draw pass
- if (mStateAnimation != stateAnimation)
- return;
- setPivotsForZoom(toView, scale);
- dispatchOnLauncherTransitionStart(fromView, animated, false);
- dispatchOnLauncherTransitionStart(toView, animated, false);
- toView.post(new Runnable() {
- public void run() {
- // Check that mStateAnimation hasn't changed while
- // we waited for a layout/draw pass
- if (mStateAnimation != stateAnimation)
- return;
- mStateAnimation.start();
- }
- });
- }
- };
- if (delayAnim) {
- final OnGlobalLayoutListener delayedStart = new OnGlobalLayoutListener() {
- public void onGlobalLayout() {
- toView.post(startAnimRunnable);
- observer.removeOnGlobalLayoutListener(this);
- }
- };
- observer.addOnGlobalLayoutListener(delayedStart);
- } else {
- startAnimRunnable.run();
- }
- } else {
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setScaleX(1.0f);
- toView.setScaleY(1.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
-
- if (!springLoaded && !LauncherApplication.isScreenLarge()) {
- // Hide the workspace scrollbar
- mWorkspace.hideScrollingIndicator(true);
- hideDockDivider();
-
- // Hide the search bar
- mSearchDropTargetBar.hideSearchBar(false);
- }
- dispatchOnLauncherTransitionPrepare(fromView, animated, false);
- dispatchOnLauncherTransitionStart(fromView, animated, false);
- dispatchOnLauncherTransitionEnd(fromView, animated, false);
- dispatchOnLauncherTransitionPrepare(toView, animated, false);
- dispatchOnLauncherTransitionStart(toView, animated, false);
- dispatchOnLauncherTransitionEnd(toView, animated, false);
- updateWallpaperVisibility(false);
- }
- }
-
- /**
- * Zoom the camera back into the workspace, hiding 'fromView'.
- * This is the opposite of showAppsCustomizeHelper.
- * @param animated If true, the transition will be animated.
- */
- private void hideAppsCustomizeHelper(State toState, final boolean animated,
- final boolean springLoaded, final Runnable onCompleteRunnable) {
-
- if (mStateAnimation != null) {
- mStateAnimation.cancel();
- mStateAnimation = null;
- }
- Resources res = getResources();
-
- final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime);
- final int fadeOutDuration =
- res.getInteger(R.integer.config_appsCustomizeFadeOutTime);
- final float scaleFactor = (float)
- res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
- final View fromView = mAppsCustomizeTabHost;
- final View toView = mWorkspace;
- Animator workspaceAnim = null;
-
- if (toState == State.WORKSPACE) {
- int stagger = res.getInteger(R.integer.config_appsCustomizeWorkspaceAnimationStagger);
- workspaceAnim = mWorkspace.getChangeStateAnimation(
- Workspace.State.NORMAL, animated, stagger);
- } else if (toState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
- workspaceAnim = mWorkspace.getChangeStateAnimation(
- Workspace.State.SPRING_LOADED, animated);
- }
-
- setPivotsForZoom(fromView, scaleFactor);
- updateWallpaperVisibility(true);
- showHotseat(animated);
- if (animated) {
- final LauncherViewPropertyAnimator scaleAnim =
- new LauncherViewPropertyAnimator(fromView);
- scaleAnim.
- scaleX(scaleFactor).scaleY(scaleFactor).
- setDuration(duration).
- setInterpolator(new Workspace.ZoomInInterpolator());
-
- final ObjectAnimator alphaAnim = ObjectAnimator
- .ofFloat(fromView, "alpha", 1f, 0f)
- .setDuration(fadeOutDuration);
- alphaAnim.setInterpolator(new AccelerateDecelerateInterpolator());
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = 1f - (Float) animation.getAnimatedValue();
- dispatchOnLauncherTransitionStep(fromView, t);
- dispatchOnLauncherTransitionStep(toView, t);
- }
- });
-
- mStateAnimation = new AnimatorSet();
-
- dispatchOnLauncherTransitionPrepare(fromView, animated, true);
- dispatchOnLauncherTransitionPrepare(toView, animated, true);
-
- mStateAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- updateWallpaperVisibility(true);
- fromView.setVisibility(View.GONE);
- dispatchOnLauncherTransitionEnd(fromView, animated, true);
- dispatchOnLauncherTransitionEnd(toView, animated, true);
- if (mWorkspace != null) {
- mWorkspace.hideScrollingIndicator(false);
- }
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- }
- });
-
- mStateAnimation.playTogether(scaleAnim, alphaAnim);
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
- }
- dispatchOnLauncherTransitionStart(fromView, animated, true);
- dispatchOnLauncherTransitionStart(toView, animated, true);
- final Animator stateAnimation = mStateAnimation;
- mWorkspace.post(new Runnable() {
- public void run() {
- if (stateAnimation != mStateAnimation)
- return;
- mStateAnimation.start();
- }
- });
- } else {
- fromView.setVisibility(View.GONE);
- dispatchOnLauncherTransitionPrepare(fromView, animated, true);
- dispatchOnLauncherTransitionStart(fromView, animated, true);
- dispatchOnLauncherTransitionEnd(fromView, animated, true);
- dispatchOnLauncherTransitionPrepare(toView, animated, true);
- dispatchOnLauncherTransitionStart(toView, animated, true);
- dispatchOnLauncherTransitionEnd(toView, animated, true);
- mWorkspace.hideScrollingIndicator(false);
- }
- }
-
- @Override
- public void onTrimMemory(int level) {
- super.onTrimMemory(level);
- if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
- mAppsCustomizeTabHost.onTrimMemory();
- }
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- if (!hasFocus) {
- // When another window occludes launcher (like the notification shade, or recents),
- // ensure that we enable the wallpaper flag so that transitions are done correctly.
- updateWallpaperVisibility(true);
- } else {
- // When launcher has focus again, disable the wallpaper if we are in AllApps
- mWorkspace.postDelayed(new Runnable() {
- @Override
- public void run() {
- disableWallpaperIfInAllApps();
- }
- }, 500);
- }
- }
-
- void showWorkspace(boolean animated) {
- showWorkspace(animated, null);
- }
-
- void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
- if (mState != State.WORKSPACE) {
- boolean wasInSpringLoadedMode = (mState == State.APPS_CUSTOMIZE_SPRING_LOADED);
- mWorkspace.setVisibility(View.VISIBLE);
- hideAppsCustomizeHelper(State.WORKSPACE, animated, false, onCompleteRunnable);
-
- // Show the search bar (only animate if we were showing the drop target bar in spring
- // loaded mode)
- mSearchDropTargetBar.showSearchBar(wasInSpringLoadedMode);
-
- // We only need to animate in the dock divider if we're going from spring loaded mode
- showDockDivider(animated && wasInSpringLoadedMode);
-
- // Set focus to the AppsCustomize button
- if (mAllAppsButton != null) {
- mAllAppsButton.requestFocus();
- }
- }
-
- mWorkspace.flashScrollingIndicator(animated);
-
- // Change the state *after* we've called all the transition code
- mState = State.WORKSPACE;
-
- // Resume the auto-advance of widgets
- mUserPresent = true;
- updateRunning();
-
- // send an accessibility event to announce the context change
- getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
-
- void showAllApps(boolean animated) {
- if (mState != State.WORKSPACE) return;
-
- showAppsCustomizeHelper(animated, false);
- mAppsCustomizeTabHost.requestFocus();
-
- // Change the state *after* we've called all the transition code
- mState = State.APPS_CUSTOMIZE;
-
- // Pause the auto-advance of widgets until we are out of AllApps
- mUserPresent = false;
- updateRunning();
- closeFolder();
-
- // Send an accessibility event to announce the context change
- getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
-
- void enterSpringLoadedDragMode() {
- if (mState == State.APPS_CUSTOMIZE) {
- hideAppsCustomizeHelper(State.APPS_CUSTOMIZE_SPRING_LOADED, true, true, null);
- hideDockDivider();
- mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
- }
- }
-
- void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, boolean extendedDelay,
- final Runnable onCompleteRunnable) {
- if (mState != State.APPS_CUSTOMIZE_SPRING_LOADED) return;
-
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (successfulDrop) {
- // Before we show workspace, hide all apps again because
- // exitSpringLoadedDragMode made it visible. This is a bit hacky; we should
- // clean up our state transition functions
- mAppsCustomizeTabHost.setVisibility(View.GONE);
- showWorkspace(true, onCompleteRunnable);
- } else {
- exitSpringLoadedDragMode();
- }
- }
- }, (extendedDelay ?
- EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT :
- EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT));
- }
-
- void exitSpringLoadedDragMode() {
- if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
- final boolean animated = true;
- final boolean springLoaded = true;
- showAppsCustomizeHelper(animated, springLoaded);
- mState = State.APPS_CUSTOMIZE;
- }
- // Otherwise, we are not in spring loaded mode, so don't do anything.
- }
-
- void hideDockDivider() {
- if (mQsbDivider != null && mDockDivider != null) {
- mQsbDivider.setVisibility(View.INVISIBLE);
- mDockDivider.setVisibility(View.INVISIBLE);
- }
- }
-
- void showDockDivider(boolean animated) {
- if (mQsbDivider != null && mDockDivider != null) {
- mQsbDivider.setVisibility(View.VISIBLE);
- mDockDivider.setVisibility(View.VISIBLE);
- if (mDividerAnimator != null) {
- mDividerAnimator.cancel();
- mQsbDivider.setAlpha(1f);
- mDockDivider.setAlpha(1f);
- mDividerAnimator = null;
- }
- if (animated) {
- mDividerAnimator = new AnimatorSet();
- mDividerAnimator.playTogether(ObjectAnimator.ofFloat(mQsbDivider, "alpha", 1f),
- ObjectAnimator.ofFloat(mDockDivider, "alpha", 1f));
- mDividerAnimator.setDuration(mSearchDropTargetBar.getTransitionInDuration());
- mDividerAnimator.start();
- }
- }
- }
-
- void lockAllApps() {
- // TODO
- }
-
- void unlockAllApps() {
- // TODO
- }
-
- public boolean isAllAppsCustomizeOpen() {
- return mState == State.APPS_CUSTOMIZE;
- }
-
- /**
- * Shows the hotseat area.
- */
- void showHotseat(boolean animated) {
- if (!LauncherApplication.isScreenLarge()) {
- if (animated) {
- if (mHotseat.getAlpha() != 1f) {
- int duration = mSearchDropTargetBar.getTransitionInDuration();
- mHotseat.animate().alpha(1f).setDuration(duration);
- }
- } else {
- mHotseat.setAlpha(1f);
- }
- }
- }
-
- /**
- * Hides the hotseat area.
- */
- void hideHotseat(boolean animated) {
- if (!LauncherApplication.isScreenLarge()) {
- if (animated) {
- if (mHotseat.getAlpha() != 0f) {
- int duration = mSearchDropTargetBar.getTransitionOutDuration();
- mHotseat.animate().alpha(0f).setDuration(duration);
- }
- } else {
- mHotseat.setAlpha(0f);
- }
- }
- }
-
- /**
- * Add an item from all apps or customize onto the given workspace screen.
- * If layout is null, add to the current screen.
- */
- void addExternalItemToScreen(ItemInfo itemInfo, final CellLayout layout) {
- if (!mWorkspace.addExternalItemToScreen(itemInfo, layout)) {
- showOutOfSpaceMessage(isHotseatLayout(layout));
- }
- }
-
- /** Maps the current orientation to an index for referencing orientation correct global icons */
- private int getCurrentOrientationIndexForGlobalIcons() {
- // default - 0, landscape - 1
- switch (getResources().getConfiguration().orientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- return 1;
- default:
- return 0;
- }
- }
-
- private Drawable getExternalPackageToolbarIcon(ComponentName activityName, String resourceName) {
- try {
- PackageManager packageManager = getPackageManager();
- // Look for the toolbar icon specified in the activity meta-data
- Bundle metaData = packageManager.getActivityInfo(
- activityName, PackageManager.GET_META_DATA).metaData;
- if (metaData != null) {
- int iconResId = metaData.getInt(resourceName);
- if (iconResId != 0) {
- Resources res = packageManager.getResourcesForActivity(activityName);
- return res.getDrawable(iconResId);
- }
- }
- } catch (NameNotFoundException e) {
- // This can happen if the activity defines an invalid drawable
- Log.w(TAG, "Failed to load toolbar icon; " + activityName.flattenToShortString() +
- " not found", e);
- } catch (Resources.NotFoundException nfe) {
- // This can happen if the activity defines an invalid drawable
- Log.w(TAG, "Failed to load toolbar icon from " + activityName.flattenToShortString(),
- nfe);
- }
- return null;
- }
-
- // if successful in getting icon, return it; otherwise, set button to use default drawable
- private Drawable.ConstantState updateTextButtonWithIconFromExternalActivity(
- int buttonId, ComponentName activityName, int fallbackDrawableId,
- String toolbarResourceName) {
- Drawable toolbarIcon = getExternalPackageToolbarIcon(activityName, toolbarResourceName);
- Resources r = getResources();
- int w = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_width);
- int h = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_height);
-
- TextView button = (TextView) findViewById(buttonId);
- // If we were unable to find the icon via the meta-data, use a generic one
- if (toolbarIcon == null) {
- toolbarIcon = r.getDrawable(fallbackDrawableId);
- toolbarIcon.setBounds(0, 0, w, h);
- if (button != null) {
- button.setCompoundDrawables(toolbarIcon, null, null, null);
- }
- return null;
- } else {
- toolbarIcon.setBounds(0, 0, w, h);
- if (button != null) {
- button.setCompoundDrawables(toolbarIcon, null, null, null);
- }
- return toolbarIcon.getConstantState();
- }
- }
-
- // if successful in getting icon, return it; otherwise, set button to use default drawable
- private Drawable.ConstantState updateButtonWithIconFromExternalActivity(
- int buttonId, ComponentName activityName, int fallbackDrawableId,
- String toolbarResourceName) {
- ImageView button = (ImageView) findViewById(buttonId);
- Drawable toolbarIcon = getExternalPackageToolbarIcon(activityName, toolbarResourceName);
-
- if (button != null) {
- // If we were unable to find the icon via the meta-data, use a
- // generic one
- if (toolbarIcon == null) {
- button.setImageResource(fallbackDrawableId);
- } else {
- button.setImageDrawable(toolbarIcon);
- }
- }
-
- return toolbarIcon != null ? toolbarIcon.getConstantState() : null;
-
- }
-
- private void updateTextButtonWithDrawable(int buttonId, Drawable d) {
- TextView button = (TextView) findViewById(buttonId);
- button.setCompoundDrawables(d, null, null, null);
- }
-
- private void updateButtonWithDrawable(int buttonId, Drawable.ConstantState d) {
- ImageView button = (ImageView) findViewById(buttonId);
- button.setImageDrawable(d.newDrawable(getResources()));
- }
-
- private void invalidatePressedFocusedStates(View container, View button) {
- if (container instanceof HolographicLinearLayout) {
- HolographicLinearLayout layout = (HolographicLinearLayout) container;
- layout.invalidatePressedFocusedStates();
- } else if (button instanceof HolographicImageView) {
- HolographicImageView view = (HolographicImageView) button;
- view.invalidatePressedFocusedStates();
- }
- }
-
- private boolean updateGlobalSearchIcon() {
- final View searchButtonContainer = findViewById(R.id.search_button_container);
- final ImageView searchButton = (ImageView) findViewById(R.id.search_button);
- final View searchDivider = findViewById(R.id.search_divider);
- final View voiceButtonContainer = findViewById(R.id.voice_button_container);
- final View voiceButton = findViewById(R.id.voice_button);
- final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
-
- final SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- ComponentName activityName = searchManager.getGlobalSearchActivity();
- if (activityName != null) {
- int coi = getCurrentOrientationIndexForGlobalIcons();
- sGlobalSearchIcon[coi] = updateButtonWithIconFromExternalActivity(
- R.id.search_button, activityName, R.drawable.ic_home_search_normal_holo,
- TOOLBAR_SEARCH_ICON_METADATA_NAME);
- if (sGlobalSearchIcon[coi] == null) {
- sGlobalSearchIcon[coi] = updateButtonWithIconFromExternalActivity(
- R.id.search_button, activityName, R.drawable.ic_home_search_normal_holo,
- TOOLBAR_ICON_METADATA_NAME);
- }
-
- if (searchDivider != null) searchDivider.setVisibility(View.VISIBLE);
- if (searchButtonContainer != null) searchButtonContainer.setVisibility(View.VISIBLE);
- searchButton.setVisibility(View.VISIBLE);
- invalidatePressedFocusedStates(searchButtonContainer, searchButton);
- return true;
- } else {
- // We disable both search and voice search when there is no global search provider
- if (searchDivider != null) searchDivider.setVisibility(View.GONE);
- if (searchButtonContainer != null) searchButtonContainer.setVisibility(View.GONE);
- if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
- searchButton.setVisibility(View.GONE);
- voiceButton.setVisibility(View.GONE);
- if (voiceButtonProxy != null) {
- voiceButtonProxy.setVisibility(View.GONE);
- }
- return false;
- }
- }
-
- private void updateGlobalSearchIcon(Drawable.ConstantState d) {
- final View searchButtonContainer = findViewById(R.id.search_button_container);
- final View searchButton = (ImageView) findViewById(R.id.search_button);
- updateButtonWithDrawable(R.id.search_button, d);
- invalidatePressedFocusedStates(searchButtonContainer, searchButton);
- }
-
- private boolean updateVoiceSearchIcon(boolean searchVisible) {
- final View searchDivider = findViewById(R.id.search_divider);
- final View voiceButtonContainer = findViewById(R.id.voice_button_container);
- final View voiceButton = findViewById(R.id.voice_button);
- final View voiceButtonProxy = findViewById(R.id.voice_button_proxy);
-
- // We only show/update the voice search icon if the search icon is enabled as well
- final SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity();
-
- ComponentName activityName = null;
- if (globalSearchActivity != null) {
- // Check if the global search activity handles voice search
- Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- intent.setPackage(globalSearchActivity.getPackageName());
- activityName = intent.resolveActivity(getPackageManager());
- }
-
- if (activityName == null) {
- // Fallback: check if an activity other than the global search activity
- // resolves this
- Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- activityName = intent.resolveActivity(getPackageManager());
- }
- if (searchVisible && activityName != null) {
- int coi = getCurrentOrientationIndexForGlobalIcons();
- sVoiceSearchIcon[coi] = updateButtonWithIconFromExternalActivity(
- R.id.voice_button, activityName, R.drawable.ic_home_voice_search_holo,
- TOOLBAR_VOICE_SEARCH_ICON_METADATA_NAME);
- if (sVoiceSearchIcon[coi] == null) {
- sVoiceSearchIcon[coi] = updateButtonWithIconFromExternalActivity(
- R.id.voice_button, activityName, R.drawable.ic_home_voice_search_holo,
- TOOLBAR_ICON_METADATA_NAME);
- }
- if (searchDivider != null) searchDivider.setVisibility(View.VISIBLE);
- if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.VISIBLE);
- voiceButton.setVisibility(View.VISIBLE);
- if (voiceButtonProxy != null) {
- voiceButtonProxy.setVisibility(View.VISIBLE);
- }
- invalidatePressedFocusedStates(voiceButtonContainer, voiceButton);
- return true;
- } else {
- if (searchDivider != null) searchDivider.setVisibility(View.GONE);
- if (voiceButtonContainer != null) voiceButtonContainer.setVisibility(View.GONE);
- voiceButton.setVisibility(View.GONE);
- if (voiceButtonProxy != null) {
- voiceButtonProxy.setVisibility(View.GONE);
- }
- return false;
- }
- }
-
- private void updateVoiceSearchIcon(Drawable.ConstantState d) {
- final View voiceButtonContainer = findViewById(R.id.voice_button_container);
- final View voiceButton = findViewById(R.id.voice_button);
- updateButtonWithDrawable(R.id.voice_button, d);
- invalidatePressedFocusedStates(voiceButtonContainer, voiceButton);
- }
-
- /**
- * Sets the app market icon
- */
- private void updateAppMarketIcon() {
- final View marketButton = findViewById(R.id.market_button);
- Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET);
- // Find the app market activity by resolving an intent.
- // (If multiple app markets are installed, it will return the ResolverActivity.)
- ComponentName activityName = intent.resolveActivity(getPackageManager());
- if (activityName != null) {
- int coi = getCurrentOrientationIndexForGlobalIcons();
- mAppMarketIntent = intent;
- sAppMarketIcon[coi] = updateTextButtonWithIconFromExternalActivity(
- R.id.market_button, activityName, R.drawable.ic_launcher_market_holo,
- TOOLBAR_ICON_METADATA_NAME);
- marketButton.setVisibility(View.VISIBLE);
- } else {
- // We should hide and disable the view so that we don't try and restore the visibility
- // of it when we swap between drag & normal states from IconDropTarget subclasses.
- marketButton.setVisibility(View.GONE);
- marketButton.setEnabled(false);
- }
- }
-
- private void updateAppMarketIcon(Drawable.ConstantState d) {
- // Ensure that the new drawable we are creating has the approprate toolbar icon bounds
- Resources r = getResources();
- Drawable marketIconDrawable = d.newDrawable(r);
- int w = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_width);
- int h = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_height);
- marketIconDrawable.setBounds(0, 0, w, h);
-
- updateTextButtonWithDrawable(R.id.market_button, marketIconDrawable);
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- boolean result = super.dispatchPopulateAccessibilityEvent(event);
- final List<CharSequence> text = event.getText();
- text.clear();
- text.add(getString(R.string.home));
- return result;
- }
-
- /**
- * Receives notifications when system dialogs are to be closed.
- */
- private class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- closeSystemDialogs();
- }
- }
-
- /**
- * Receives notifications whenever the appwidgets are reset.
- */
- private class AppWidgetResetObserver extends ContentObserver {
- public AppWidgetResetObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onAppWidgetReset();
- }
- }
-
- /**
- * If the activity is currently paused, signal that we need to re-run the loader
- * in onResume.
- *
- * This needs to be called from incoming places where resources might have been loaded
- * while we are paused. That is becaues the Configuration might be wrong
- * when we're not running, and if it comes back to what it was when we
- * were paused, we are not restarted.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- *
- * @return true if we are currently paused. The caller might be able to
- * skip some work in that case since we will come back again.
- */
- public boolean setLoadOnResume() {
- if (mPaused) {
- Log.i(TAG, "setLoadOnResume");
- mOnResumeNeedsLoad = true;
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public int getCurrentWorkspaceScreen() {
- if (mWorkspace != null) {
- return mWorkspace.getCurrentPage();
- } else {
- return SCREEN_COUNT / 2;
- }
- }
-
- /**
- * Refreshes the shortcuts shown on the workspace.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void startBinding() {
- final Workspace workspace = mWorkspace;
-
- mNewShortcutAnimatePage = -1;
- mNewShortcutAnimateViews.clear();
- mWorkspace.clearDropTargets();
- int count = workspace.getChildCount();
- for (int i = 0; i < count; i++) {
- // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().
- final CellLayout layoutParent = (CellLayout) workspace.getChildAt(i);
- layoutParent.removeAllViewsInLayout();
- }
- mWidgetsToAdvance.clear();
- if (mHotseat != null) {
- mHotseat.resetLayout();
- }
- }
-
- /**
- * Bind the items start-end from the list.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {
- setLoadOnResume();
-
- // Get the list of added shortcuts and intersect them with the set of shortcuts here
- Set<String> newApps = new HashSet<String>();
- newApps = mSharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps);
-
- Workspace workspace = mWorkspace;
- for (int i = start; i < end; i++) {
- final ItemInfo item = shortcuts.get(i);
-
- // Short circuit if we are loading dock items for a configuration which has no dock
- if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
- mHotseat == null) {
- continue;
- }
-
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- ShortcutInfo info = (ShortcutInfo) item;
- String uri = info.intent.toUri(0).toString();
- View shortcut = createShortcut(info);
- workspace.addInScreen(shortcut, item.container, item.screen, item.cellX,
- item.cellY, 1, 1, false);
- boolean animateIconUp = false;
- synchronized (newApps) {
- if (newApps.contains(uri)) {
- animateIconUp = newApps.remove(uri);
- }
- }
- if (animateIconUp) {
- // Prepare the view to be animated up
- shortcut.setAlpha(0f);
- shortcut.setScaleX(0f);
- shortcut.setScaleY(0f);
- mNewShortcutAnimatePage = item.screen;
- if (!mNewShortcutAnimateViews.contains(shortcut)) {
- mNewShortcutAnimateViews.add(shortcut);
- }
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
- (FolderInfo) item, mIconCache);
- workspace.addInScreen(newFolder, item.container, item.screen, item.cellX,
- item.cellY, 1, 1, false);
- break;
- }
- }
-
- workspace.requestLayout();
- }
-
- /**
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindFolders(HashMap<Long, FolderInfo> folders) {
- setLoadOnResume();
- sFolders.clear();
- sFolders.putAll(folders);
- }
-
- /**
- * Add the views for a widget to the workspace.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindAppWidget(LauncherAppWidgetInfo item) {
- setLoadOnResume();
-
- final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0;
- if (DEBUG_WIDGETS) {
- Log.d(TAG, "bindAppWidget: " + item);
- }
- final Workspace workspace = mWorkspace;
-
- final int appWidgetId = item.appWidgetId;
- final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- if (DEBUG_WIDGETS) {
- Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
- }
-
- item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
-
- item.hostView.setTag(item);
- item.onBindAppWidget(this);
-
- workspace.addInScreen(item.hostView, item.container, item.screen, item.cellX,
- item.cellY, item.spanX, item.spanY, false);
- addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
-
- workspace.requestLayout();
-
- if (DEBUG_WIDGETS) {
- Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
- + (SystemClock.uptimeMillis()-start) + "ms");
- }
- }
-
- /**
- * Callback saying that there aren't any more items to bind.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void finishBindingItems() {
- setLoadOnResume();
-
- if (mSavedState != null) {
- if (!mWorkspace.hasFocus()) {
- mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
- }
- mSavedState = null;
- }
-
- if (mSavedInstanceState != null) {
- super.onRestoreInstanceState(mSavedInstanceState);
- mSavedInstanceState = null;
- }
-
- // If we received the result of any pending adds while the loader was running (e.g. the
- // widget configuration forced an orientation change), process them now.
- for (int i = 0; i < sPendingAddList.size(); i++) {
- completeAdd(sPendingAddList.get(i));
- }
- sPendingAddList.clear();
-
- // Update the market app icon as necessary (the other icons will be managed in response to
- // package changes in bindSearchablesChanged()
- updateAppMarketIcon();
-
- // Animate up any icons as necessary
- if (mVisible || mWorkspaceLoading) {
- Runnable newAppsRunnable = new Runnable() {
- @Override
- public void run() {
- runNewAppsAnimation(false);
- }
- };
-
- boolean willSnapPage = mNewShortcutAnimatePage > -1 &&
- mNewShortcutAnimatePage != mWorkspace.getCurrentPage();
- if (canRunNewAppsAnimation()) {
- // If the user has not interacted recently, then either snap to the new page to show
- // the new-apps animation or just run them if they are to appear on the current page
- if (willSnapPage) {
- mWorkspace.snapToPage(mNewShortcutAnimatePage, newAppsRunnable);
- } else {
- runNewAppsAnimation(false);
- }
- } else {
- // If the user has interacted recently, then just add the items in place if they
- // are on another page (or just normally if they are added to the current page)
- runNewAppsAnimation(willSnapPage);
- }
- }
-
- mWorkspaceLoading = false;
- }
-
- private boolean canRunNewAppsAnimation() {
- long diff = System.currentTimeMillis() - mDragController.getLastGestureUpTime();
- return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000);
- }
-
- /**
- * Runs a new animation that scales up icons that were added while Launcher was in the
- * background.
- *
- * @param immediate whether to run the animation or show the results immediately
- */
- private void runNewAppsAnimation(boolean immediate) {
- AnimatorSet anim = new AnimatorSet();
- Collection<Animator> bounceAnims = new ArrayList<Animator>();
-
- // Order these new views spatially so that they animate in order
- Collections.sort(mNewShortcutAnimateViews, new Comparator<View>() {
- @Override
- public int compare(View a, View b) {
- CellLayout.LayoutParams alp = (CellLayout.LayoutParams) a.getLayoutParams();
- CellLayout.LayoutParams blp = (CellLayout.LayoutParams) b.getLayoutParams();
- int cellCountX = LauncherModel.getCellCountX();
- return (alp.cellY * cellCountX + alp.cellX) - (blp.cellY * cellCountX + blp.cellX);
- }
- });
-
- // Animate each of the views in place (or show them immediately if requested)
- if (immediate) {
- for (View v : mNewShortcutAnimateViews) {
- v.setAlpha(1f);
- v.setScaleX(1f);
- v.setScaleY(1f);
- }
- } else {
- for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) {
- View v = mNewShortcutAnimateViews.get(i);
- ValueAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(v,
- PropertyValuesHolder.ofFloat("alpha", 1f),
- PropertyValuesHolder.ofFloat("scaleX", 1f),
- PropertyValuesHolder.ofFloat("scaleY", 1f));
- bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
- bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
- bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator());
- bounceAnims.add(bounceAnim);
- }
- anim.playTogether(bounceAnims);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspace.postDelayed(mBuildLayersRunnable, 500);
- }
- });
- anim.start();
- }
-
- // Clean up
- mNewShortcutAnimatePage = -1;
- mNewShortcutAnimateViews.clear();
- new Thread("clearNewAppsThread") {
- public void run() {
- mSharedPrefs.edit()
- .putInt(InstallShortcutReceiver.NEW_APPS_PAGE_KEY, -1)
- .putStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, null)
- .commit();
- }
- }.start();
- }
-
- @Override
- public void bindSearchablesChanged() {
- boolean searchVisible = updateGlobalSearchIcon();
- boolean voiceVisible = updateVoiceSearchIcon(searchVisible);
- mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
- }
-
- /**
- * Add the icons for all apps.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {
- // Remove the progress bar entirely; we could also make it GONE
- // but better to remove it since we know it's not going to be used
- View progressBar = mAppsCustomizeTabHost.
- findViewById(R.id.apps_customize_progress_bar);
- if (progressBar != null) {
- ((ViewGroup)progressBar.getParent()).removeView(progressBar);
- }
- // We just post the call to setApps so the user sees the progress bar
- // disappear-- otherwise, it just looks like the progress bar froze
- // which doesn't look great
- mAppsCustomizeTabHost.post(new Runnable() {
- public void run() {
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.setApps(apps);
- }
- }
- });
- }
-
- /**
- * A package was installed.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {
- setLoadOnResume();
-
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.addApps(apps);
- }
- }
-
- /**
- * A package was updated.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindAppsUpdated(ArrayList<ApplicationInfo> apps) {
- setLoadOnResume();
- if (mWorkspace != null) {
- mWorkspace.updateShortcuts(apps);
- }
-
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.updateApps(apps);
- }
- }
-
- /**
- * A package was uninstalled.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent) {
- if (permanent) {
- mWorkspace.removeItems(apps);
- }
-
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.removeApps(apps);
- }
-
- // Notify the drag controller
- mDragController.onAppsRemoved(apps, this);
- }
-
- /**
- * A number of packages were updated.
- */
- public void bindPackagesUpdated() {
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.onPackagesUpdated();
- }
- }
-
- private int mapConfigurationOriActivityInfoOri(int configOri) {
- final Display d = getWindowManager().getDefaultDisplay();
- int naturalOri = Configuration.ORIENTATION_LANDSCAPE;
- switch (d.getRotation()) {
- case Surface.ROTATION_0:
- case Surface.ROTATION_180:
- // We are currently in the same basic orientation as the natural orientation
- naturalOri = configOri;
- break;
- case Surface.ROTATION_90:
- case Surface.ROTATION_270:
- // We are currently in the other basic orientation to the natural orientation
- naturalOri = (configOri == Configuration.ORIENTATION_LANDSCAPE) ?
- Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- break;
- }
-
- int[] oriMap = {
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
- ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
- ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
- ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
- };
- // Since the map starts at portrait, we need to offset if this device's natural orientation
- // is landscape.
- int indexOffset = 0;
- if (naturalOri == Configuration.ORIENTATION_LANDSCAPE) {
- indexOffset = 1;
- }
- return oriMap[(d.getRotation() + indexOffset) % 4];
- }
-
- public boolean isRotationEnabled() {
- boolean forceEnableRotation = "true".equalsIgnoreCase(SystemProperties.get(
- FORCE_ENABLE_ROTATION_PROPERTY, "false"));
- boolean enableRotation = forceEnableRotation ||
- getResources().getBoolean(R.bool.allow_rotation);
- return enableRotation;
- }
- public void lockScreenOrientation() {
- if (isRotationEnabled()) {
- setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
- .getConfiguration().orientation));
- }
- }
- public void unlockScreenOrientation(boolean immediate) {
- if (isRotationEnabled()) {
- if (immediate) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- } else {
- mHandler.postDelayed(new Runnable() {
- public void run() {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
- }, mRestoreScreenOrientationDelay);
- }
- }
- }
-
- /* Cling related */
- private boolean isClingsEnabled() {
- // disable clings when running in a test harness
- if(ActivityManager.isRunningInTestHarness()) return false;
-
- return true;
- }
- private Cling initCling(int clingId, int[] positionData, boolean animate, int delay) {
- Cling cling = (Cling) findViewById(clingId);
- if (cling != null) {
- cling.init(this, positionData);
- cling.setVisibility(View.VISIBLE);
- cling.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- cling.requestAccessibilityFocus();
- if (animate) {
- cling.buildLayer();
- cling.setAlpha(0f);
- cling.animate()
- .alpha(1f)
- .setInterpolator(new AccelerateInterpolator())
- .setDuration(SHOW_CLING_DURATION)
- .setStartDelay(delay)
- .start();
- } else {
- cling.setAlpha(1f);
- }
- }
- return cling;
- }
- private void dismissCling(final Cling cling, final String flag, int duration) {
- if (cling != null) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(cling, "alpha", 0f);
- anim.setDuration(duration);
- anim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- cling.setVisibility(View.GONE);
- cling.cleanup();
- // We should update the shared preferences on a background thread
- new Thread("dismissClingThread") {
- public void run() {
- SharedPreferences.Editor editor = mSharedPrefs.edit();
- editor.putBoolean(flag, true);
- editor.commit();
- }
- }.start();
- };
- });
- anim.start();
- }
- }
- private void removeCling(int id) {
- final View cling = findViewById(id);
- if (cling != null) {
- final ViewGroup parent = (ViewGroup) cling.getParent();
- parent.post(new Runnable() {
- @Override
- public void run() {
- parent.removeView(cling);
- }
- });
- }
- }
-
- private boolean skipCustomClingIfNoAccounts() {
- Cling cling = (Cling) findViewById(R.id.workspace_cling);
- boolean customCling = cling.getDrawIdentifier().equals("workspace_custom");
- if (customCling) {
- AccountManager am = AccountManager.get(this);
- Account[] accounts = am.getAccountsByType("com.google");
- return accounts.length == 0;
- }
- return false;
- }
-
- public void showFirstRunWorkspaceCling() {
- // Enable the clings only if they have not been dismissed before
- if (isClingsEnabled() &&
- !mSharedPrefs.getBoolean(Cling.WORKSPACE_CLING_DISMISSED_KEY, false) &&
- !skipCustomClingIfNoAccounts() ) {
- initCling(R.id.workspace_cling, null, false, 0);
- } else {
- removeCling(R.id.workspace_cling);
- }
- }
- public void showFirstRunAllAppsCling(int[] position) {
- // Enable the clings only if they have not been dismissed before
- if (isClingsEnabled() &&
- !mSharedPrefs.getBoolean(Cling.ALLAPPS_CLING_DISMISSED_KEY, false)) {
- initCling(R.id.all_apps_cling, position, true, 0);
- } else {
- removeCling(R.id.all_apps_cling);
- }
- }
- public Cling showFirstRunFoldersCling() {
- // Enable the clings only if they have not been dismissed before
- if (isClingsEnabled() &&
- !mSharedPrefs.getBoolean(Cling.FOLDER_CLING_DISMISSED_KEY, false)) {
- return initCling(R.id.folder_cling, null, true, 0);
- } else {
- removeCling(R.id.folder_cling);
- return null;
- }
- }
- public boolean isFolderClingVisible() {
- Cling cling = (Cling) findViewById(R.id.folder_cling);
- if (cling != null) {
- return cling.getVisibility() == View.VISIBLE;
- }
- return false;
- }
- public void dismissWorkspaceCling(View v) {
- Cling cling = (Cling) findViewById(R.id.workspace_cling);
- dismissCling(cling, Cling.WORKSPACE_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
- }
- public void dismissAllAppsCling(View v) {
- Cling cling = (Cling) findViewById(R.id.all_apps_cling);
- dismissCling(cling, Cling.ALLAPPS_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
- }
- public void dismissFolderCling(View v) {
- Cling cling = (Cling) findViewById(R.id.folder_cling);
- dismissCling(cling, Cling.FOLDER_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION);
- }
-
- /**
- * Prints out out state for debugging.
- */
- public void dumpState() {
- Log.d(TAG, "BEGIN launcher2 dump state for launcher " + this);
- Log.d(TAG, "mSavedState=" + mSavedState);
- Log.d(TAG, "mWorkspaceLoading=" + mWorkspaceLoading);
- Log.d(TAG, "mRestoring=" + mRestoring);
- Log.d(TAG, "mWaitingForResult=" + mWaitingForResult);
- Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState);
- Log.d(TAG, "sFolders.size=" + sFolders.size());
- mModel.dumpState();
-
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.dumpState();
- }
- Log.d(TAG, "END launcher2 dump state");
- }
-
- @Override
- public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
- super.dump(prefix, fd, writer, args);
- writer.println(" ");
- writer.println("Debug logs: ");
- for (int i = 0; i < sDumpLogs.size(); i++) {
- writer.println(" " + sDumpLogs.get(i));
- }
- }
-}
-
-interface LauncherTransitionable {
- View getContent();
- void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace);
- void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace);
- void onLauncherTransitionStep(Launcher l, float t);
- void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace);
-}
diff --git a/src/com/android/launcher2/LauncherAnimatorUpdateListener.java b/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
deleted file mode 100644
index dd821134d..000000000
--- a/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-
-abstract class LauncherAnimatorUpdateListener implements AnimatorUpdateListener {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
- onAnimationUpdate(a, b);
- }
-
- abstract void onAnimationUpdate(float a, float b);
-} \ No newline at end of file
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
deleted file mode 100644
index 68d4903da..000000000
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2009 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.AppWidgetHost;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-
-/**
- * Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
- * which correctly captures all long-press events. This ensures that users can
- * always pick up and move widgets.
- */
-public class LauncherAppWidgetHost extends AppWidgetHost {
- public LauncherAppWidgetHost(Context context, int hostId) {
- super(context, hostId);
- }
-
- @Override
- protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
- AppWidgetProviderInfo appWidget) {
- return new LauncherAppWidgetHostView(context);
- }
-
- @Override
- public void stopListening() {
- super.stopListening();
- clearViews();
- }
-}
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
deleted file mode 100644
index 9970c7675..000000000
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2009 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.AppWidgetHostView;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RemoteViews;
-
-import com.android.launcher.R;
-
-/**
- * {@inheritDoc}
- */
-public class LauncherAppWidgetHostView extends AppWidgetHostView {
- private CheckLongPressHelper mLongPressHelper;
- private LayoutInflater mInflater;
- private Context mContext;
- private int mPreviousOrientation;
-
- public LauncherAppWidgetHostView(Context context) {
- super(context);
- mContext = context;
- mLongPressHelper = new CheckLongPressHelper(this);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @Override
- protected View getErrorView() {
- return mInflater.inflate(R.layout.appwidget_error, this, false);
- }
-
- @Override
- public void updateAppWidget(RemoteViews remoteViews) {
- // Store the orientation in which the widget was inflated
- mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
- super.updateAppWidget(remoteViews);
- }
-
- public boolean orientationChangedSincedInflation() {
- int orientation = mContext.getResources().getConfiguration().orientation;
- if (mPreviousOrientation != orientation) {
- return true;
- }
- return false;
- }
-
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Consume any touch events for ourselves after longpress is triggered
- if (mLongPressHelper.hasPerformedLongPress()) {
- mLongPressHelper.cancelLongPress();
- return true;
- }
-
- // Watch for longpress events at this level to make sure
- // users can always pick up this widget
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN: {
- mLongPressHelper.postCheckForLongPress();
- break;
- }
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mLongPressHelper.cancelLongPress();
- break;
- }
-
- // Otherwise continue letting touch events fall through to children
- return false;
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- mLongPressHelper.cancelLongPress();
- }
-
- @Override
- public int getDescendantFocusability() {
- return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
- }
-}
diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java
deleted file mode 100644
index f001b2b64..000000000
--- a/src/com/android/launcher2/LauncherAppWidgetInfo.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2009 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.AppWidgetHostView;
-import android.content.ComponentName;
-import android.content.ContentValues;
-
-/**
- * Represents a widget (either instantiated or about to be) in the Launcher.
- */
-class LauncherAppWidgetInfo extends ItemInfo {
-
- /**
- * Indicates that the widget hasn't been instantiated yet.
- */
- static final int NO_ID = -1;
-
- /**
- * Identifier for this widget when talking with
- * {@link android.appwidget.AppWidgetManager} for updates.
- */
- int appWidgetId = NO_ID;
-
- ComponentName providerName;
-
- // TODO: Are these necessary here?
- int minWidth = -1;
- int minHeight = -1;
-
- private boolean mHasNotifiedInitialWidgetSizeChanged;
-
- /**
- * View that holds this widget after it's been created. This view isn't created
- * until Launcher knows it's needed.
- */
- AppWidgetHostView hostView = null;
-
- LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
- this.appWidgetId = appWidgetId;
- this.providerName = providerName;
-
- // Since the widget isn't instantiated yet, we don't know these values. Set them to -1
- // to indicate that they should be calculated based on the layout and minWidth/minHeight
- spanX = -1;
- spanY = -1;
- }
-
- @Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
- values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
- }
-
- /**
- * When we bind the widget, we should notify the widget that the size has changed if we have not
- * done so already (only really for default workspace widgets).
- */
- void onBindAppWidget(Launcher launcher) {
- if (!mHasNotifiedInitialWidgetSizeChanged) {
- notifyWidgetSizeChanged(launcher);
- }
- }
-
- /**
- * Trigger an update callback to the widget to notify it that its size has changed.
- */
- void notifyWidgetSizeChanged(Launcher launcher) {
- AppWidgetResizeFrame.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
- mHasNotifiedInitialWidgetSizeChanged = true;
- }
-
- @Override
- public String toString() {
- return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
- }
-
- @Override
- void unbind() {
- super.unbind();
- hostView = null;
- }
-}
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
deleted file mode 100644
index 28362fd0b..000000000
--- a/src/com/android/launcher2/LauncherApplication.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.Application;
-import android.app.SearchManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.os.Handler;
-
-import com.android.launcher.R;
-
-import java.lang.ref.WeakReference;
-
-public class LauncherApplication extends Application {
- public LauncherModel mModel;
- public IconCache mIconCache;
- private static boolean sIsScreenLarge;
- private static float sScreenDensity;
- private static int sLongPressTimeout = 300;
- private static final String sSharedPreferencesKey = "com.android.launcher2.prefs";
- WeakReference<LauncherProvider> mLauncherProvider;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- // set sIsScreenXLarge and sScreenDensity *before* creating icon cache
- sIsScreenLarge = getResources().getBoolean(R.bool.is_large_screen);
- sScreenDensity = getResources().getDisplayMetrics().density;
-
- mIconCache = new IconCache(this);
- mModel = new LauncherModel(this, mIconCache);
-
- // Register intent receivers
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- registerReceiver(mModel, filter);
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- registerReceiver(mModel, filter);
- filter = new IntentFilter();
- filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
- registerReceiver(mModel, filter);
- filter = new IntentFilter();
- filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
- registerReceiver(mModel, filter);
-
- // Register for changes to the favorites
- ContentResolver resolver = getContentResolver();
- resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
- mFavoritesObserver);
- }
-
- /**
- * There's no guarantee that this function is ever called.
- */
- @Override
- public void onTerminate() {
- super.onTerminate();
-
- unregisterReceiver(mModel);
-
- ContentResolver resolver = getContentResolver();
- resolver.unregisterContentObserver(mFavoritesObserver);
- }
-
- /**
- * Receives notifications whenever the user favorites have changed.
- */
- private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- // If the database has ever changed, then we really need to force a reload of the
- // workspace on the next load
- mModel.resetLoadedState(false, true);
- mModel.startLoaderFromBackground();
- }
- };
-
- LauncherModel setLauncher(Launcher launcher) {
- mModel.initialize(launcher);
- return mModel;
- }
-
- IconCache getIconCache() {
- return mIconCache;
- }
-
- LauncherModel getModel() {
- return mModel;
- }
-
- void setLauncherProvider(LauncherProvider provider) {
- mLauncherProvider = new WeakReference<LauncherProvider>(provider);
- }
-
- LauncherProvider getLauncherProvider() {
- return mLauncherProvider.get();
- }
-
- public static String getSharedPreferencesKey() {
- return sSharedPreferencesKey;
- }
-
- public static boolean isScreenLarge() {
- return sIsScreenLarge;
- }
-
- public static boolean isScreenLandscape(Context context) {
- return context.getResources().getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE;
- }
-
- public static float getScreenDensity() {
- return sScreenDensity;
- }
-
- public static int getLongPressTimeout() {
- return sLongPressTimeout;
- }
-}
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
deleted file mode 100644
index fc1a26d4b..000000000
--- a/src/com/android/launcher2/LauncherModel.java
+++ /dev/null
@@ -1,2176 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.SearchManager;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.launcher.R;
-import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
-
-import java.lang.ref.WeakReference;
-import java.net.URISyntaxException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Maintains in-memory state of the Launcher. It is expected that there should be only one
- * LauncherModel object held in a static. Also provide APIs for updating the database state
- * for the Launcher.
- */
-public class LauncherModel extends BroadcastReceiver {
- static final boolean DEBUG_LOADERS = false;
- static final String TAG = "Launcher.Model";
-
- private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
- private final boolean mAppsCanBeOnExternalStorage;
- private int mBatchSize; // 0 is all apps at once
- private int mAllAppsLoadDelay; // milliseconds between batches
-
- private final LauncherApplication mApp;
- private final Object mLock = new Object();
- private DeferredHandler mHandler = new DeferredHandler();
- private LoaderTask mLoaderTask;
-
- private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
- static {
- sWorkerThread.start();
- }
- private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
-
- // We start off with everything not loaded. After that, we assume that
- // our monitoring of the package manager provides all updates and we never
- // need to do a requery. These are only ever touched from the loader thread.
- private boolean mWorkspaceLoaded;
- private boolean mAllAppsLoaded;
-
- private WeakReference<Callbacks> mCallbacks;
-
- // < only access in worker thread >
- private AllAppsList mAllAppsList;
-
- // sItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
- // LauncherModel to their ids
- static final HashMap<Long, ItemInfo> sItemsIdMap = new HashMap<Long, ItemInfo>();
-
- // sItems is passed to bindItems, which expects a list of all folders and shortcuts created by
- // LauncherModel that are directly on the home screen (however, no widgets or shortcuts
- // within folders).
- static final ArrayList<ItemInfo> sWorkspaceItems = new ArrayList<ItemInfo>();
-
- // sAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
- static final ArrayList<LauncherAppWidgetInfo> sAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
-
- // sFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
- static final HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
-
- // sDbIconCache is the set of ItemInfos that need to have their icons updated in the database
- static final HashMap<Object, byte[]> sDbIconCache = new HashMap<Object, byte[]>();
-
- // </ only access in worker thread >
-
- private IconCache mIconCache;
- private Bitmap mDefaultIcon;
-
- private static int mCellCountX;
- private static int mCellCountY;
-
- protected int mPreviousConfigMcc;
-
- public interface Callbacks {
- public boolean setLoadOnResume();
- public int getCurrentWorkspaceScreen();
- public void startBinding();
- public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);
- public void bindFolders(HashMap<Long,FolderInfo> folders);
- public void finishBindingItems();
- public void bindAppWidget(LauncherAppWidgetInfo info);
- public void bindAllApplications(ArrayList<ApplicationInfo> apps);
- 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();
- public boolean isAllAppsButtonRank(int rank);
- public void bindSearchablesChanged();
- }
-
- LauncherModel(LauncherApplication app, IconCache iconCache) {
- mAppsCanBeOnExternalStorage = !Environment.isExternalStorageEmulated();
- mApp = app;
- mAllAppsList = new AllAppsList(iconCache);
- mIconCache = iconCache;
-
- mDefaultIcon = Utilities.createIconBitmap(
- mIconCache.getFullResDefaultActivityIcon(), app);
-
- final Resources res = app.getResources();
- mAllAppsLoadDelay = res.getInteger(R.integer.config_allAppsBatchLoadDelay);
- mBatchSize = res.getInteger(R.integer.config_allAppsBatchSize);
- Configuration config = res.getConfiguration();
- mPreviousConfigMcc = config.mcc;
- }
-
- public Bitmap getFallbackIcon() {
- return Bitmap.createBitmap(mDefaultIcon);
- }
-
- public void unbindWorkspaceItems() {
- sWorker.post(new Runnable() {
- @Override
- public void run() {
- unbindWorkspaceItemsOnMainThread();
- }
- });
- }
-
- /** Unbinds all the sWorkspaceItems on the main thread, and return a copy of sWorkspaceItems
- * that is save to reference from the main thread. */
- private ArrayList<ItemInfo> unbindWorkspaceItemsOnMainThread() {
- // Ensure that we don't use the same workspace items data structure on the main thread
- // by making a copy of workspace items first.
- final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>(sWorkspaceItems);
- final ArrayList<ItemInfo> appWidgets = new ArrayList<ItemInfo>(sAppWidgets);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (ItemInfo item : workspaceItems) {
- item.unbind();
- }
- for (ItemInfo item : appWidgets) {
- item.unbind();
- }
- }
- });
-
- return workspaceItems;
- }
-
- /**
- * Adds an item to the DB if it was not created previously, or move it to a new
- * <container, screen, cellX, cellY>
- */
- static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
- int screen, int cellX, int cellY) {
- if (item.container == ItemInfo.NO_ID) {
- // From all apps
- addItemToDatabase(context, item, container, screen, cellX, cellY, false);
- } else {
- // From somewhere else
- moveItemInDatabase(context, item, container, screen, cellX, cellY);
- }
- }
-
- static void updateItemInDatabaseHelper(Context context, final ContentValues values,
- final ItemInfo item, final String callingFunction) {
- final long itemId = item.id;
- final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);
- final ContentResolver cr = context.getContentResolver();
-
- Runnable r = new Runnable() {
- public void run() {
- cr.update(uri, values, null, null);
-
- ItemInfo modelItem = sItemsIdMap.get(itemId);
- if (item != modelItem) {
- // the modelItem needs to match up perfectly with item if our model is to be
- // consistent with the database-- for now, just require modelItem == item
- String msg = "item: " + ((item != null) ? item.toString() : "null") +
- "modelItem: " + ((modelItem != null) ? modelItem.toString() : "null") +
- "Error: ItemInfo passed to " + callingFunction + " doesn't match original";
- throw new RuntimeException(msg);
- }
-
- // Items are added/removed from the corresponding FolderInfo elsewhere, such
- // as in Workspace.onDrop. Here, we just add/remove them from the list of items
- // that are on the desktop, as appropriate
- if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- if (!sWorkspaceItems.contains(modelItem)) {
- sWorkspaceItems.add(modelItem);
- }
- } else {
- sWorkspaceItems.remove(modelItem);
- }
- }
- };
-
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run();
- } else {
- sWorker.post(r);
- }
- }
-
- /**
- * Move an item in the DB to a new <container, screen, cellX, cellY>
- */
- static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
- final int screen, final int cellX, final int cellY) {
- item.container = container;
- item.cellX = cellX;
- item.cellY = cellY;
-
- // We store hotseat items in canonical form which is this orientation invariant position
- // in the hotseat
- if (context instanceof Launcher && screen < 0 &&
- container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);
- } else {
- item.screen = screen;
- }
-
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
- values.put(LauncherSettings.Favorites.SCREEN, item.screen);
-
- updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");
- }
-
- /**
- * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>
- */
- static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,
- final int screen, final int cellX, final int cellY, final int spanX, final int spanY) {
- item.container = container;
- item.cellX = cellX;
- item.cellY = cellY;
- item.spanX = spanX;
- item.spanY = spanY;
-
- // We store hotseat items in canonical form which is this orientation invariant position
- // in the hotseat
- if (context instanceof Launcher && screen < 0 &&
- container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);
- } else {
- item.screen = screen;
- }
-
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
- values.put(LauncherSettings.Favorites.SPANX, item.spanX);
- values.put(LauncherSettings.Favorites.SPANY, item.spanY);
- values.put(LauncherSettings.Favorites.SCREEN, item.screen);
-
- updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");
- }
-
- /**
- * Update an item to the database in a specified container.
- */
- static void updateItemInDatabase(Context context, final ItemInfo item) {
- final ContentValues values = new ContentValues();
- item.onAddToDatabase(values);
- item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
- updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
- }
-
- /**
- * Returns true if the shortcuts already exists in the database.
- * we identify a shortcut by its title and intent.
- */
- static boolean shortcutExists(Context context, String title, Intent intent) {
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent" }, "title=? and intent=?",
- new String[] { title, intent.toUri(0) }, null);
- boolean result = false;
- try {
- result = c.moveToFirst();
- } finally {
- c.close();
- }
- return result;
- }
-
- /**
- * Returns an ItemInfo array containing all the items in the LauncherModel.
- * The ItemInfo.id is not set through this function.
- */
- static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
- ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
- LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
- LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
-
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
- try {
- while (c.moveToNext()) {
- ItemInfo item = new ItemInfo();
- item.cellX = c.getInt(cellXIndex);
- item.cellY = c.getInt(cellYIndex);
- item.spanX = c.getInt(spanXIndex);
- item.spanY = c.getInt(spanYIndex);
- item.container = c.getInt(containerIndex);
- item.itemType = c.getInt(itemTypeIndex);
- item.screen = c.getInt(screenIndex);
-
- items.add(item);
- }
- } catch (Exception e) {
- items.clear();
- } finally {
- c.close();
- }
-
- return items;
- }
-
- /**
- * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
- */
- FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
- "_id=? and (itemType=? or itemType=?)",
- new String[] { String.valueOf(id),
- String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);
-
- try {
- if (c.moveToFirst()) {
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-
- FolderInfo folderInfo = null;
- switch (c.getInt(itemTypeIndex)) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- folderInfo = findOrMakeFolder(folderList, id);
- break;
- }
-
- folderInfo.title = c.getString(titleIndex);
- folderInfo.id = id;
- folderInfo.container = c.getInt(containerIndex);
- folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
-
- return folderInfo;
- }
- } finally {
- c.close();
- }
-
- return null;
- }
-
- /**
- * Add an item to the database in a specified container. Sets the container, screen, cellX and
- * cellY fields of the item. Also assigns an ID to the item.
- */
- static void addItemToDatabase(Context context, final ItemInfo item, final long container,
- final int screen, final int cellX, final int cellY, final boolean notify) {
- item.container = container;
- item.cellX = cellX;
- item.cellY = cellY;
- // We store hotseat items in canonical form which is this orientation invariant position
- // in the hotseat
- if (context instanceof Launcher && screen < 0 &&
- container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);
- } else {
- item.screen = screen;
- }
-
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
- item.onAddToDatabase(values);
-
- LauncherApplication app = (LauncherApplication) context.getApplicationContext();
- item.id = app.getLauncherProvider().generateNewId();
- values.put(LauncherSettings.Favorites._ID, item.id);
- item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
-
- Runnable r = new Runnable() {
- public void run() {
- cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
- LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
-
- if (sItemsIdMap.containsKey(item.id)) {
- // we should not be adding new items in the db with the same id
- throw new RuntimeException("Error: ItemInfo id (" + item.id + ") passed to " +
- "addItemToDatabase already exists." + item.toString());
- }
- sItemsIdMap.put(item.id, item);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sFolders.put(item.id, (FolderInfo) item);
- // Fall through
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- sWorkspaceItems.add(item);
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sAppWidgets.add((LauncherAppWidgetInfo) item);
- break;
- }
- }
- };
-
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run();
- } else {
- sWorker.post(r);
- }
- }
-
- /**
- * Creates a new unique child id, for a given cell span across all layouts.
- */
- static int getCellLayoutChildId(
- long container, int screen, int localCellX, int localCellY, int spanX, int spanY) {
- return (((int) container & 0xFF) << 24)
- | (screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
- }
-
- static int getCellCountX() {
- return mCellCountX;
- }
-
- static int getCellCountY() {
- return mCellCountY;
- }
-
- /**
- * Updates the model orientation helper to take into account the current layout dimensions
- * when performing local/canonical coordinate transformations.
- */
- static void updateWorkspaceLayoutCells(int shortAxisCellCount, int longAxisCellCount) {
- mCellCountX = shortAxisCellCount;
- mCellCountY = longAxisCellCount;
- }
-
- /**
- * Removes the specified item from the database
- * @param context
- * @param item
- */
- static void deleteItemFromDatabase(Context context, final ItemInfo item) {
- final ContentResolver cr = context.getContentResolver();
- final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);
- Runnable r = new Runnable() {
- public void run() {
- cr.delete(uriToDelete, null, null);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sFolders.remove(item.id);
- sWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- sWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sAppWidgets.remove((LauncherAppWidgetInfo) item);
- break;
- }
- sItemsIdMap.remove(item.id);
- sDbIconCache.remove(item);
- }
- };
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run();
- } else {
- sWorker.post(r);
- }
- }
-
- /**
- * Remove the contents of the specified folder from the database
- */
- static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
- final ContentResolver cr = context.getContentResolver();
-
- Runnable r = new Runnable() {
- public void run() {
- cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
- sItemsIdMap.remove(info.id);
- sFolders.remove(info.id);
- sDbIconCache.remove(info);
- sWorkspaceItems.remove(info);
-
- cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
- LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
- for (ItemInfo childInfo : info.contents) {
- sItemsIdMap.remove(childInfo.id);
- sDbIconCache.remove(childInfo);
- }
- }
- };
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run();
- } else {
- sWorker.post(r);
- }
- }
-
- /**
- * Set this as the current Launcher activity object for the loader.
- */
- public void initialize(Callbacks callbacks) {
- synchronized (mLock) {
- mCallbacks = new WeakReference<Callbacks>(callbacks);
- }
- }
-
- /**
- * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
- * ACTION_PACKAGE_CHANGED.
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
-
- final String action = intent.getAction();
-
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
- || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- final String packageName = intent.getData().getSchemeSpecificPart();
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-
- int op = PackageUpdatedTask.OP_NONE;
-
- if (packageName == null || packageName.length() == 0) {
- // they sent us a bad intent
- return;
- }
-
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- op = PackageUpdatedTask.OP_UPDATE;
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_REMOVE;
- }
- // else, we are replacing the package, so a PACKAGE_ADDED will be sent
- // later, we will update the package at this time
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_ADD;
- } else {
- op = PackageUpdatedTask.OP_UPDATE;
- }
- }
-
- if (op != PackageUpdatedTask.OP_NONE) {
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));
- }
-
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- // First, schedule to add these apps back in.
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));
- // Then, rebind everything.
- startLoaderFromBackground();
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- enqueuePackageUpdated(new PackageUpdatedTask(
- PackageUpdatedTask.OP_UNAVAILABLE, packages));
- } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
- // If we have changed locale we need to clear out the labels in all apps/workspace.
- forceReload();
- } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
- // Check if configuration change was an mcc/mnc change which would affect app resources
- // and we would need to clear out the labels in all apps/workspace. Same handling as
- // above for ACTION_LOCALE_CHANGED
- Configuration currentConfig = context.getResources().getConfiguration();
- if (mPreviousConfigMcc != currentConfig.mcc) {
- Log.d(TAG, "Reload apps on config change. curr_mcc:"
- + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);
- forceReload();
- }
- // Update previousConfig
- mPreviousConfigMcc = currentConfig.mcc;
- } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||
- SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {
- if (mCallbacks != null) {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- callbacks.bindSearchablesChanged();
- }
- }
- }
- }
-
- private void forceReload() {
- resetLoadedState(true, true);
-
- // Do this here because if the launcher activity is running it will be restarted.
- // If it's not running startLoaderFromBackground will merely tell it that it needs
- // to reload.
- startLoaderFromBackground();
- }
-
- public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {
- synchronized (mLock) {
- // Stop any existing loaders first, so they don't set mAllAppsLoaded or
- // mWorkspaceLoaded to true later
- stopLoaderLocked();
- if (resetAllAppsLoaded) mAllAppsLoaded = false;
- if (resetWorkspaceLoaded) mWorkspaceLoaded = false;
- }
- }
-
- /**
- * When the launcher is in the background, it's possible for it to miss paired
- * configuration changes. So whenever we trigger the loader from the background
- * tell the launcher that it needs to re-run the loader when it comes back instead
- * of doing it now.
- */
- public void startLoaderFromBackground() {
- boolean runLoader = false;
- if (mCallbacks != null) {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- // Only actually run the loader if they're not paused.
- if (!callbacks.setLoadOnResume()) {
- runLoader = true;
- }
- }
- }
- if (runLoader) {
- startLoader(false);
- }
- }
-
- // If there is already a loader task running, tell it to stop.
- // returns true if isLaunching() was true on the old task
- private boolean stopLoaderLocked() {
- boolean isLaunching = false;
- LoaderTask oldTask = mLoaderTask;
- if (oldTask != null) {
- if (oldTask.isLaunching()) {
- isLaunching = true;
- }
- oldTask.stopLocked();
- }
- return isLaunching;
- }
-
- public void startLoader(boolean isLaunching) {
- synchronized (mLock) {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "startLoader isLaunching=" + isLaunching);
- }
-
- // Don't bother to start the thread if we know it's not going to do anything
- if (mCallbacks != null && mCallbacks.get() != null) {
- // If there is already one running, tell it to stop.
- // also, don't downgrade isLaunching if we're already running
- isLaunching = isLaunching || stopLoaderLocked();
- mLoaderTask = new LoaderTask(mApp, isLaunching);
- sWorkerThread.setPriority(Thread.NORM_PRIORITY);
- sWorker.post(mLoaderTask);
- }
- }
- }
-
- public void stopLoader() {
- synchronized (mLock) {
- if (mLoaderTask != null) {
- mLoaderTask.stopLocked();
- }
- }
- }
-
- public boolean isAllAppsLoaded() {
- return mAllAppsLoaded;
- }
-
- boolean isLoadingWorkspace() {
- synchronized (mLock) {
- if (mLoaderTask != null) {
- return mLoaderTask.isLoadingWorkspace();
- }
- }
- return false;
- }
-
- /**
- * Runnable for the thread that loads the contents of the launcher:
- * - workspace icons
- * - widgets
- * - all apps icons
- */
- private class LoaderTask implements Runnable {
- private Context mContext;
- private Thread mWaitThread;
- private boolean mIsLaunching;
- private boolean mIsLoadingAndBindingWorkspace;
- private boolean mStopped;
- private boolean mLoadAndBindStepFinished;
- private HashMap<Object, CharSequence> mLabelCache;
-
- LoaderTask(Context context, boolean isLaunching) {
- mContext = context;
- mIsLaunching = isLaunching;
- mLabelCache = new HashMap<Object, CharSequence>();
- }
-
- boolean isLaunching() {
- return mIsLaunching;
- }
-
- boolean isLoadingWorkspace() {
- return mIsLoadingAndBindingWorkspace;
- }
-
- private void loadAndBindWorkspace() {
- mIsLoadingAndBindingWorkspace = true;
-
- // Load the workspace
- if (DEBUG_LOADERS) {
- Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
- }
-
- if (!mWorkspaceLoaded) {
- loadWorkspace();
- synchronized (LoaderTask.this) {
- if (mStopped) {
- return;
- }
- mWorkspaceLoaded = true;
- }
- }
-
- // Bind the workspace
- bindWorkspace();
- }
-
- private void waitForIdle() {
- // Wait until the either we're stopped or the other threads are done.
- // This way we don't start loading all apps until the workspace has settled
- // down.
- synchronized (LoaderTask.this) {
- final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
- mHandler.postIdle(new Runnable() {
- public void run() {
- synchronized (LoaderTask.this) {
- mLoadAndBindStepFinished = true;
- if (DEBUG_LOADERS) {
- Log.d(TAG, "done with previous binding step");
- }
- LoaderTask.this.notify();
- }
- }
- });
-
- while (!mStopped && !mLoadAndBindStepFinished) {
- try {
- this.wait();
- } catch (InterruptedException ex) {
- // Ignore
- }
- }
- if (DEBUG_LOADERS) {
- Log.d(TAG, "waited "
- + (SystemClock.uptimeMillis()-workspaceWaitTime)
- + "ms for previous step to finish binding");
- }
- }
- }
-
- public void run() {
- // Optimize for end-user experience: if the Launcher is up and // running with the
- // All Apps interface in the foreground, load All Apps first. Otherwise, load the
- // workspace first (default).
- final Callbacks cbk = mCallbacks.get();
- final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;
-
- keep_running: {
- // Elevate priority when Home launches for the first time to avoid
- // starving at boot time. Staring at a blank home is not cool.
- synchronized (mLock) {
- if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +
- (mIsLaunching ? "DEFAULT" : "BACKGROUND"));
- android.os.Process.setThreadPriority(mIsLaunching
- ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
- }
- if (loadWorkspaceFirst) {
- if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
- loadAndBindWorkspace();
- } else {
- if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");
- loadAndBindAllApps();
- }
-
- if (mStopped) {
- break keep_running;
- }
-
- // Whew! Hard work done. Slow us down, and wait until the UI thread has
- // settled down.
- synchronized (mLock) {
- if (mIsLaunching) {
- if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");
- android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
- waitForIdle();
-
- // second step
- if (loadWorkspaceFirst) {
- if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
- loadAndBindAllApps();
- } else {
- if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");
- loadAndBindWorkspace();
- }
-
- // Restore the default thread priority after we are done loading items
- synchronized (mLock) {
- android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- }
- }
-
-
- // Update the saved icons if necessary
- if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
- for (Object key : sDbIconCache.keySet()) {
- updateSavedIcon(mContext, (ShortcutInfo) key, sDbIconCache.get(key));
- }
- sDbIconCache.clear();
-
- // Clear out this reference, otherwise we end up holding it until all of the
- // callback runnables are done.
- mContext = null;
-
- synchronized (mLock) {
- // If we are still the last one to be scheduled, remove ourselves.
- if (mLoaderTask == this) {
- mLoaderTask = null;
- }
- }
- }
-
- public void stopLocked() {
- synchronized (LoaderTask.this) {
- mStopped = true;
- this.notify();
- }
- }
-
- /**
- * Gets the callbacks object. If we've been stopped, or if the launcher object
- * has somehow been garbage collected, return null instead. Pass in the Callbacks
- * object that was around when the deferred message was scheduled, and if there's
- * a new Callbacks object around then also return null. This will save us from
- * calling onto it with data that will be ignored.
- */
- Callbacks tryGetCallbacks(Callbacks oldCallbacks) {
- synchronized (mLock) {
- if (mStopped) {
- return null;
- }
-
- if (mCallbacks == null) {
- return null;
- }
-
- final Callbacks callbacks = mCallbacks.get();
- if (callbacks != oldCallbacks) {
- return null;
- }
- if (callbacks == null) {
- Log.w(TAG, "no mCallbacks");
- return null;
- }
-
- return callbacks;
- }
- }
-
- // check & update map of what's occupied; used to discard overlapping/invalid items
- private boolean checkItemPlacement(ItemInfo occupied[][][], ItemInfo item) {
- int containerIndex = item.screen;
- if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- // Return early if we detect that an item is under the hotseat button
- if (mCallbacks == null || mCallbacks.get().isAllAppsButtonRank(item.screen)) {
- return false;
- }
-
- // We use the last index to refer to the hotseat and the screen as the rank, so
- // test and update the occupied state accordingly
- if (occupied[Launcher.SCREEN_COUNT][item.screen][0] != null) {
- Log.e(TAG, "Error loading shortcut into hotseat " + item
- + " into position (" + item.screen + ":" + item.cellX + "," + item.cellY
- + ") occupied by " + occupied[Launcher.SCREEN_COUNT][item.screen][0]);
- return false;
- } else {
- occupied[Launcher.SCREEN_COUNT][item.screen][0] = item;
- return true;
- }
- } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- // Skip further checking if it is not the hotseat or workspace container
- return true;
- }
-
- // Check if any workspace icons overlap with each other
- for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
- for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
- if (occupied[containerIndex][x][y] != null) {
- Log.e(TAG, "Error loading shortcut " + item
- + " into cell (" + containerIndex + "-" + item.screen + ":"
- + x + "," + y
- + ") occupied by "
- + occupied[containerIndex][x][y]);
- return false;
- }
- }
- }
- for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
- for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
- occupied[containerIndex][x][y] = item;
- }
- }
-
- return true;
- }
-
- private void loadWorkspace() {
- final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
- final Context context = mContext;
- final ContentResolver contentResolver = context.getContentResolver();
- final PackageManager manager = context.getPackageManager();
- final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
- final boolean isSafeMode = manager.isSafeMode();
-
- // Make sure the default workspace is loaded, if needed
- mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary();
-
- sWorkspaceItems.clear();
- sAppWidgets.clear();
- sFolders.clear();
- sItemsIdMap.clear();
- sDbIconCache.clear();
-
- final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
-
- final Cursor c = contentResolver.query(
- LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
-
- // +1 for the hotseat (it can be larger than the workspace)
- // Load workspace in reverse order to ensure that latest items are loaded first (and
- // before any earlier duplicates)
- final ItemInfo occupied[][][] =
- new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];
-
- try {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.TITLE);
- final int iconTypeIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_TYPE);
- final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_RESOURCE);
- final int containerIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ITEM_TYPE);
- final int appWidgetIdIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_ID);
- final int screenIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SPANY);
- //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
- //final int displayModeIndex = c.getColumnIndexOrThrow(
- // LauncherSettings.Favorites.DISPLAY_MODE);
-
- ShortcutInfo info;
- String intentDescription;
- LauncherAppWidgetInfo appWidgetInfo;
- int container;
- long id;
- Intent intent;
-
- while (!mStopped && c.moveToNext()) {
- try {
- int itemType = c.getInt(itemTypeIndex);
-
- switch (itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- intentDescription = c.getString(intentIndex);
- try {
- intent = Intent.parseUri(intentDescription, 0);
- } catch (URISyntaxException e) {
- continue;
- }
-
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getShortcutInfo(manager, intent, context, c, iconIndex,
- titleIndex, mLabelCache);
- } else {
- info = getShortcutInfo(c, context, iconTypeIndex,
- iconPackageIndex, iconResourceIndex, iconIndex,
- titleIndex);
-
- // App shortcuts that used to be automatically added to Launcher
- // didn't always have the correct intent flags set, so do that here
- if (intent.getAction() != null &&
- intent.getCategories() != null &&
- intent.getAction().equals(Intent.ACTION_MAIN) &&
- intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- }
-
- if (info != null) {
- info.intent = intent;
- info.id = c.getLong(idIndex);
- container = c.getInt(containerIndex);
- info.container = container;
- info.screen = c.getInt(screenIndex);
- info.cellX = c.getInt(cellXIndex);
- info.cellY = c.getInt(cellYIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, info)) {
- break;
- }
-
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sWorkspaceItems.add(info);
- break;
- default:
- // Item is in a user folder
- FolderInfo folderInfo =
- findOrMakeFolder(sFolders, container);
- folderInfo.add(info);
- break;
- }
- sItemsIdMap.put(info.id, info);
-
- // now that we've loaded everthing re-save it with the
- // icon in case it disappears somehow.
- queueIconToBeChecked(sDbIconCache, info, c, iconIndex);
- } else {
- // Failed to load the shortcut, probably because the
- // activity manager couldn't resolve it (maybe the app
- // was uninstalled), or the db row was somehow screwed up.
- // Delete it.
- id = c.getLong(idIndex);
- Log.e(TAG, "Error loading shortcut " + id + ", removing it");
- contentResolver.delete(LauncherSettings.Favorites.getContentUri(
- id, false), null, null);
- }
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- id = c.getLong(idIndex);
- FolderInfo folderInfo = findOrMakeFolder(sFolders, id);
-
- folderInfo.title = c.getString(titleIndex);
- folderInfo.id = id;
- container = c.getInt(containerIndex);
- folderInfo.container = container;
- folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, folderInfo)) {
- break;
- }
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sWorkspaceItems.add(folderInfo);
- break;
- }
-
- sItemsIdMap.put(folderInfo.id, folderInfo);
- sFolders.put(folderInfo.id, folderInfo);
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- // Read all Launcher-specific widget details
- int appWidgetId = c.getInt(appWidgetIdIndex);
- id = c.getLong(idIndex);
-
- final AppWidgetProviderInfo provider =
- widgets.getAppWidgetInfo(appWidgetId);
-
- if (!isSafeMode && (provider == null || provider.provider == null ||
- provider.provider.getPackageName() == null)) {
- String log = "Deleting widget that isn't installed anymore: id="
- + id + " appWidgetId=" + appWidgetId;
- Log.e(TAG, log);
- Launcher.sDumpLogs.add(log);
- itemsToRemove.add(id);
- } else {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
- appWidgetInfo.id = id;
- appWidgetInfo.screen = c.getInt(screenIndex);
- appWidgetInfo.cellX = c.getInt(cellXIndex);
- appWidgetInfo.cellY = c.getInt(cellYIndex);
- appWidgetInfo.spanX = c.getInt(spanXIndex);
- appWidgetInfo.spanY = c.getInt(spanYIndex);
- int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
- appWidgetInfo.minSpanX = minSpan[0];
- appWidgetInfo.minSpanY = minSpan[1];
-
- container = c.getInt(containerIndex);
- if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- Log.e(TAG, "Widget found where container "
- + "!= CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
- continue;
- }
- appWidgetInfo.container = c.getInt(containerIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, appWidgetInfo)) {
- break;
- }
- sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
- sAppWidgets.add(appWidgetInfo);
- }
- break;
- }
- } catch (Exception e) {
- Log.w(TAG, "Desktop items loading interrupted:", e);
- }
- }
- } finally {
- c.close();
- }
-
- if (itemsToRemove.size() > 0) {
- ContentProviderClient client = contentResolver.acquireContentProviderClient(
- LauncherSettings.Favorites.CONTENT_URI);
- // Remove dead items
- for (long id : itemsToRemove) {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "Removed id = " + id);
- }
- // Don't notify content observers
- try {
- client.delete(LauncherSettings.Favorites.getContentUri(id, false),
- null, null);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not remove id = " + id);
- }
- }
- }
-
- if (DEBUG_LOADERS) {
- Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
- Log.d(TAG, "workspace layout: ");
- for (int y = 0; y < mCellCountY; y++) {
- String line = "";
- for (int s = 0; s < Launcher.SCREEN_COUNT; s++) {
- if (s > 0) {
- line += " | ";
- }
- for (int x = 0; x < mCellCountX; x++) {
- line += ((occupied[s][x][y] != null) ? "#" : ".");
- }
- }
- Log.d(TAG, "[ " + line + " ]");
- }
- }
- }
-
- /**
- * Read everything out of our database.
- */
- private void bindWorkspace() {
- final long t = SystemClock.uptimeMillis();
-
- // Don't use these two variables in any of the callback runnables.
- // Otherwise we hold a reference to them.
- final Callbacks oldCallbacks = mCallbacks.get();
- if (oldCallbacks == null) {
- // This launcher has exited and nobody bothered to tell us. Just bail.
- Log.w(TAG, "LoaderTask running with no launcher");
- return;
- }
-
- // Get the list of workspace items to load and unbind the existing ShortcutInfos
- // before we call startBinding() below.
- final int currentScreen = oldCallbacks.getCurrentWorkspaceScreen();
- final ArrayList<ItemInfo> tmpWorkspaceItems = unbindWorkspaceItemsOnMainThread();
- // Order the items for loading as follows: current workspace, hotseat, everything else
- Collections.sort(tmpWorkspaceItems, new Comparator<ItemInfo>() {
- @Override
- public int compare(ItemInfo lhs, ItemInfo rhs) {
- int cellCountX = LauncherModel.getCellCountX();
- int cellCountY = LauncherModel.getCellCountY();
- int screenOffset = cellCountX * cellCountY;
- int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat
- long lr = (lhs.container * containerOffset + lhs.screen * screenOffset +
- lhs.cellY * cellCountX + lhs.cellX);
- long rr = (rhs.container * containerOffset + rhs.screen * screenOffset +
- rhs.cellY * cellCountX + rhs.cellX);
- return (int) (lr - rr);
- }
- });
- // Precondition: the items are ordered by page, screen
- final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
- for (ItemInfo ii : tmpWorkspaceItems) {
- // Prepend the current items, hotseat items, append everything else
- if (ii.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- ii.screen == currentScreen) {
- workspaceItems.add(0, ii);
- } else if (ii.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- workspaceItems.add(0, ii);
- } else {
- workspaceItems.add(ii);
- }
- }
-
- // Tell the workspace that we're about to start firing items at it
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.startBinding();
- }
- }
- });
-
- // Add the items to the workspace.
- int N = workspaceItems.size();
- for (int i=0; i<N; i+=ITEMS_CHUNK) {
- final int start = i;
- final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindItems(workspaceItems, start, start+chunkSize);
- }
- }
- });
- }
- // Ensure that we don't use the same folders data structure on the main thread
- final HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>(sFolders);
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindFolders(folders);
- }
- }
- });
- // Wait until the queue goes empty.
- mHandler.post(new Runnable() {
- public void run() {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "Going to start binding widgets soon.");
- }
- }
- });
- // Bind the widgets, one at a time.
- // WARNING: this is calling into the workspace from the background thread,
- // but since getCurrentScreen() just returns the int, we should be okay. This
- // is just a hint for the order, and if it's wrong, we'll be okay.
- // TODO: instead, we should have that push the current screen into here.
- N = sAppWidgets.size();
- // once for the current screen
- for (int i=0; i<N; i++) {
- final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
- if (widget.screen == currentScreen) {
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindAppWidget(widget);
- }
- }
- });
- }
- }
- // once for the other screens
- for (int i=0; i<N; i++) {
- final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
- if (widget.screen != currentScreen) {
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindAppWidget(widget);
- }
- }
- });
- }
- }
- // Tell the workspace that we're done.
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.finishBindingItems();
- }
- }
- });
- // Cleanup
- mHandler.post(new Runnable() {
- public void run() {
- // If we're profiling, ensure this is the last thing in the queue.
- if (DEBUG_LOADERS) {
- Log.d(TAG, "bound workspace in "
- + (SystemClock.uptimeMillis()-t) + "ms");
- }
-
- mIsLoadingAndBindingWorkspace = false;
- }
- });
- }
-
- private void loadAndBindAllApps() {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
- }
- if (!mAllAppsLoaded) {
- loadAllAppsByBatch();
- synchronized (LoaderTask.this) {
- if (mStopped) {
- return;
- }
- mAllAppsLoaded = true;
- }
- } else {
- onlyBindAllApps();
- }
- }
-
- private void onlyBindAllApps() {
- final Callbacks oldCallbacks = mCallbacks.get();
- if (oldCallbacks == null) {
- // This launcher has exited and nobody bothered to tell us. Just bail.
- Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");
- return;
- }
-
- // shallow copy
- @SuppressWarnings("unchecked")
- final ArrayList<ApplicationInfo> list
- = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone();
- mHandler.post(new Runnable() {
- public void run() {
- final long t = SystemClock.uptimeMillis();
- final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindAllApplications(list);
- }
- if (DEBUG_LOADERS) {
- Log.d(TAG, "bound all " + list.size() + " apps from cache in "
- + (SystemClock.uptimeMillis()-t) + "ms");
- }
- }
- });
-
- }
-
- private void loadAllAppsByBatch() {
- final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
- // Don't use these two variables in any of the callback runnables.
- // Otherwise we hold a reference to them.
- final Callbacks oldCallbacks = mCallbacks.get();
- if (oldCallbacks == null) {
- // This launcher has exited and nobody bothered to tell us. Just bail.
- Log.w(TAG, "LoaderTask running with no launcher (loadAllAppsByBatch)");
- return;
- }
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- final PackageManager packageManager = mContext.getPackageManager();
- List<ResolveInfo> apps = null;
-
- int N = Integer.MAX_VALUE;
-
- int startIndex;
- int i=0;
- int batchSize = -1;
- while (i < N && !mStopped) {
- if (i == 0) {
- mAllAppsList.clear();
- final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- apps = packageManager.queryIntentActivities(mainIntent, 0);
- if (DEBUG_LOADERS) {
- Log.d(TAG, "queryIntentActivities took "
- + (SystemClock.uptimeMillis()-qiaTime) + "ms");
- }
- if (apps == null) {
- return;
- }
- N = apps.size();
- if (DEBUG_LOADERS) {
- Log.d(TAG, "queryIntentActivities got " + N + " apps");
- }
- if (N == 0) {
- // There are no apps?!?
- return;
- }
- if (mBatchSize == 0) {
- batchSize = N;
- } else {
- batchSize = mBatchSize;
- }
-
- final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- Collections.sort(apps,
- new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
- if (DEBUG_LOADERS) {
- Log.d(TAG, "sort took "
- + (SystemClock.uptimeMillis()-sortTime) + "ms");
- }
- }
-
- final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
- startIndex = i;
- for (int j=0; i<N && j<batchSize; j++) {
- // This builds the icon bitmaps.
- mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
- mIconCache, mLabelCache));
- i++;
- }
-
- final boolean first = i <= batchSize;
- final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- final ArrayList<ApplicationInfo> added = mAllAppsList.added;
- mAllAppsList.added = new ArrayList<ApplicationInfo>();
-
- mHandler.post(new Runnable() {
- public void run() {
- final long t = SystemClock.uptimeMillis();
- if (callbacks != null) {
- if (first) {
- callbacks.bindAllApplications(added);
- } else {
- callbacks.bindAppsAdded(added);
- }
- if (DEBUG_LOADERS) {
- Log.d(TAG, "bound " + added.size() + " apps in "
- + (SystemClock.uptimeMillis() - t) + "ms");
- }
- } else {
- Log.i(TAG, "not binding apps: no Launcher activity");
- }
- }
- });
-
- if (DEBUG_LOADERS) {
- Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in "
- + (SystemClock.uptimeMillis()-t2) + "ms");
- }
-
- if (mAllAppsLoadDelay > 0 && i < N) {
- try {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms");
- }
- Thread.sleep(mAllAppsLoadDelay);
- } catch (InterruptedException exc) { }
- }
- }
-
- if (DEBUG_LOADERS) {
- Log.d(TAG, "cached all " + N + " apps in "
- + (SystemClock.uptimeMillis()-t) + "ms"
- + (mAllAppsLoadDelay > 0 ? " (including delay)" : ""));
- }
- }
-
- public void dumpState() {
- Log.d(TAG, "mLoaderTask.mContext=" + mContext);
- Log.d(TAG, "mLoaderTask.mWaitThread=" + mWaitThread);
- Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
- Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
- Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
- Log.d(TAG, "mItems size=" + sWorkspaceItems.size());
- }
- }
-
- void enqueuePackageUpdated(PackageUpdatedTask task) {
- sWorker.post(task);
- }
-
- private class PackageUpdatedTask implements Runnable {
- int mOp;
- String[] mPackages;
-
- public static final int OP_NONE = 0;
- public static final int OP_ADD = 1;
- public static final int OP_UPDATE = 2;
- public static final int OP_REMOVE = 3; // uninstlled
- public static final int OP_UNAVAILABLE = 4; // external media unmounted
-
-
- public PackageUpdatedTask(int op, String[] packages) {
- mOp = op;
- mPackages = packages;
- }
-
- public void run() {
- final Context context = mApp;
-
- final String[] packages = mPackages;
- final int N = packages.length;
- switch (mOp) {
- case OP_ADD:
- for (int i=0; i<N; i++) {
- if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
- mAllAppsList.addPackage(context, packages[i]);
- }
- break;
- case OP_UPDATE:
- for (int i=0; i<N; i++) {
- if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
- mAllAppsList.updatePackage(context, packages[i]);
- }
- break;
- case OP_REMOVE:
- case OP_UNAVAILABLE:
- for (int i=0; i<N; i++) {
- if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
- mAllAppsList.removePackage(packages[i]);
- }
- break;
- }
-
- ArrayList<ApplicationInfo> added = null;
- ArrayList<ApplicationInfo> removed = null;
- ArrayList<ApplicationInfo> modified = null;
-
- if (mAllAppsList.added.size() > 0) {
- added = mAllAppsList.added;
- mAllAppsList.added = new ArrayList<ApplicationInfo>();
- }
- if (mAllAppsList.removed.size() > 0) {
- removed = mAllAppsList.removed;
- mAllAppsList.removed = new ArrayList<ApplicationInfo>();
- for (ApplicationInfo info: removed) {
- mIconCache.remove(info.intent.getComponent());
- }
- }
- if (mAllAppsList.modified.size() > 0) {
- modified = mAllAppsList.modified;
- mAllAppsList.modified = new ArrayList<ApplicationInfo>();
- }
-
- final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
- if (callbacks == null) {
- Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading.");
- return;
- }
-
- if (added != null) {
- final ArrayList<ApplicationInfo> addedFinal = added;
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
- if (callbacks == cb && cb != null) {
- callbacks.bindAppsAdded(addedFinal);
- }
- }
- });
- }
- if (modified != null) {
- final ArrayList<ApplicationInfo> modifiedFinal = modified;
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
- if (callbacks == cb && cb != null) {
- callbacks.bindAppsUpdated(modifiedFinal);
- }
- }
- });
- }
- if (removed != null) {
- final boolean permanent = mOp != OP_UNAVAILABLE;
- final ArrayList<ApplicationInfo> removedFinal = removed;
- mHandler.post(new Runnable() {
- public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
- if (callbacks == cb && cb != null) {
- callbacks.bindAppsRemoved(removedFinal, permanent);
- }
- }
- });
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
- if (callbacks == cb && cb != null) {
- callbacks.bindPackagesUpdated();
- }
- }
- });
- }
- }
-
- /**
- * Returns all the Workspace ShortcutInfos associated with a particular package.
- * @param intent
- * @return
- */
- ArrayList<ShortcutInfo> getShortcutInfosForPackage(String packageName) {
- ArrayList<ShortcutInfo> infos = new ArrayList<ShortcutInfo>();
- for (ItemInfo i : sWorkspaceItems) {
- if (i instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) i;
- if (packageName.equals(info.getPackageName())) {
- infos.add(info);
- }
- }
- }
- return infos;
- }
-
- /**
- * This is called from the code that adds shortcuts from the intent receiver. This
- * doesn't have a Cursor, but
- */
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {
- return getShortcutInfo(manager, intent, context, null, -1, -1, null);
- }
-
- /**
- * Make an ShortcutInfo object for a shortcut that is an application.
- *
- * If c is not null, then it will be used to fill in missing data like the title and icon.
- */
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,
- Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {
- Bitmap icon = null;
- final ShortcutInfo info = new ShortcutInfo();
-
- ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- return null;
- }
-
- try {
- PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);
- if (!pi.applicationInfo.enabled) {
- // If we return null here, the corresponding item will be removed from the launcher
- // db and will not appear in the workspace.
- return null;
- }
- } catch (NameNotFoundException e) {
- Log.d(TAG, "getPackInfo failed for package " + componentName.getPackageName());
- }
-
- // TODO: See if the PackageManager knows about this case. If it doesn't
- // then return null & delete this.
-
- // the resource -- This may implicitly give us back the fallback icon,
- // but don't worry about that. All we're doing with usingFallbackIcon is
- // to avoid saving lots of copies of that in the database, and most apps
- // have icons anyway.
-
- // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and
- // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info
- // via resolveActivity().
- ResolveInfo resolveInfo = null;
- ComponentName oldComponent = intent.getComponent();
- Intent newIntent = new Intent(intent.getAction(), null);
- newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- newIntent.setPackage(oldComponent.getPackageName());
- List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);
- for (ResolveInfo i : infos) {
- ComponentName cn = new ComponentName(i.activityInfo.packageName,
- i.activityInfo.name);
- if (cn.equals(oldComponent)) {
- resolveInfo = i;
- }
- }
- if (resolveInfo == null) {
- resolveInfo = manager.resolveActivity(intent, 0);
- }
- if (resolveInfo != null) {
- icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);
- }
- // the db
- if (icon == null) {
- if (c != null) {
- icon = getIconFromCursor(c, iconIndex, context);
- }
- }
- // the fallback icon
- if (icon == null) {
- icon = getFallbackIcon();
- info.usingFallbackIcon = true;
- }
- info.setIcon(icon);
-
- // from the resource
- if (resolveInfo != null) {
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);
- if (labelCache != null && labelCache.containsKey(key)) {
- info.title = labelCache.get(key);
- } else {
- info.title = resolveInfo.activityInfo.loadLabel(manager);
- if (labelCache != null) {
- labelCache.put(key, info.title);
- }
- }
- }
- // from the db
- if (info.title == null) {
- if (c != null) {
- info.title = c.getString(titleIndex);
- }
- }
- // fall back to the class name of the activity
- if (info.title == null) {
- info.title = componentName.getClassName();
- }
- info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
- return info;
- }
-
- /**
- * Make an ShortcutInfo object for a shortcut that isn't an application.
- */
- private ShortcutInfo getShortcutInfo(Cursor c, Context context,
- int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,
- int titleIndex) {
-
- Bitmap icon = null;
- final ShortcutInfo info = new ShortcutInfo();
- info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-
- // TODO: If there's an explicit component and we can't install that, delete it.
-
- info.title = c.getString(titleIndex);
-
- int iconType = c.getInt(iconTypeIndex);
- switch (iconType) {
- case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
- String packageName = c.getString(iconPackageIndex);
- String resourceName = c.getString(iconResourceIndex);
- PackageManager packageManager = context.getPackageManager();
- info.customIcon = false;
- // the resource
- try {
- Resources resources = packageManager.getResourcesForApplication(packageName);
- if (resources != null) {
- final int id = resources.getIdentifier(resourceName, null, null);
- icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, id), context);
- }
- } catch (Exception e) {
- // drop this. we have other places to look for icons
- }
- // the db
- if (icon == null) {
- icon = getIconFromCursor(c, iconIndex, context);
- }
- // the fallback icon
- if (icon == null) {
- icon = getFallbackIcon();
- info.usingFallbackIcon = true;
- }
- break;
- case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
- icon = getIconFromCursor(c, iconIndex, context);
- if (icon == null) {
- icon = getFallbackIcon();
- info.customIcon = false;
- info.usingFallbackIcon = true;
- } else {
- info.customIcon = true;
- }
- break;
- default:
- icon = getFallbackIcon();
- info.usingFallbackIcon = true;
- info.customIcon = false;
- break;
- }
- info.setIcon(icon);
- return info;
- }
-
- Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- Log.d(TAG, "getIconFromCursor app="
- + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));
- }
- byte[] data = c.getBlob(iconIndex);
- try {
- return Utilities.createIconBitmap(
- BitmapFactory.decodeByteArray(data, 0, data.length), context);
- } catch (Exception e) {
- return null;
- }
- }
-
- ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,
- int cellX, int cellY, boolean notify) {
- final ShortcutInfo info = infoFromShortcutIntent(context, data, null);
- if (info == null) {
- return null;
- }
- addItemToDatabase(context, info, container, screen, cellX, cellY, notify);
-
- return info;
- }
-
- /**
- * Attempts to find an AppWidgetProviderInfo that matches the given component.
- */
- AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,
- ComponentName component) {
- List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(context).getInstalledProviders();
- for (AppWidgetProviderInfo info : widgets) {
- if (info.provider.equals(component)) {
- return info;
- }
- }
- return null;
- }
-
- /**
- * Returns a list of all the widgets that can handle configuration with a particular mimeType.
- */
- List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {
- final PackageManager packageManager = context.getPackageManager();
- final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =
- new ArrayList<WidgetMimeTypeHandlerData>();
-
- final Intent supportsIntent =
- new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);
- supportsIntent.setType(mimeType);
-
- // Create a set of widget configuration components that we can test against
- final List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(context).getInstalledProviders();
- final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =
- new HashMap<ComponentName, AppWidgetProviderInfo>();
- for (AppWidgetProviderInfo info : widgets) {
- configurationComponentToWidget.put(info.configure, info);
- }
-
- // Run through each of the intents that can handle this type of clip data, and cross
- // reference them with the components that are actual configuration components
- final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo info : activities) {
- final ActivityInfo activityInfo = info.activityInfo;
- final ComponentName infoComponent = new ComponentName(activityInfo.packageName,
- activityInfo.name);
- if (configurationComponentToWidget.containsKey(infoComponent)) {
- supportedConfigurationActivities.add(
- new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,
- configurationComponentToWidget.get(infoComponent)));
- }
- }
- return supportedConfigurationActivities;
- }
-
- ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {
- Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
-
- if (intent == null) {
- // If the intent is null, we can't construct a valid ShortcutInfo, so we return null
- Log.e(TAG, "Can't construct ShorcutInfo with null intent");
- return null;
- }
-
- Bitmap icon = null;
- boolean customIcon = false;
- ShortcutIconResource iconResource = null;
-
- if (bitmap != null && bitmap instanceof Bitmap) {
- icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);
- customIcon = true;
- } else {
- Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- if (extra != null && extra instanceof ShortcutIconResource) {
- try {
- iconResource = (ShortcutIconResource) extra;
- final PackageManager packageManager = context.getPackageManager();
- Resources resources = packageManager.getResourcesForApplication(
- iconResource.packageName);
- final int id = resources.getIdentifier(iconResource.resourceName, null, null);
- icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, id), context);
- } catch (Exception e) {
- Log.w(TAG, "Could not load shortcut icon: " + extra);
- }
- }
- }
-
- final ShortcutInfo info = new ShortcutInfo();
-
- if (icon == null) {
- if (fallbackIcon != null) {
- icon = fallbackIcon;
- } else {
- icon = getFallbackIcon();
- info.usingFallbackIcon = true;
- }
- }
- info.setIcon(icon);
-
- info.title = name;
- info.intent = intent;
- info.customIcon = customIcon;
- info.iconResource = iconResource;
-
- return info;
- }
-
- boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,
- int iconIndex) {
- // If apps can't be on SD, don't even bother.
- if (!mAppsCanBeOnExternalStorage) {
- return false;
- }
- // If this icon doesn't have a custom icon, check to see
- // what's stored in the DB, and if it doesn't match what
- // we're going to show, store what we are going to show back
- // into the DB. We do this so when we're loading, if the
- // package manager can't find an icon (for example because
- // the app is on SD) then we can use that instead.
- if (!info.customIcon && !info.usingFallbackIcon) {
- cache.put(info, c.getBlob(iconIndex));
- return true;
- }
- return false;
- }
- void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {
- boolean needSave = false;
- try {
- if (data != null) {
- Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);
- Bitmap loaded = info.getIcon(mIconCache);
- needSave = !saved.sameAs(loaded);
- } else {
- needSave = true;
- }
- } catch (Exception e) {
- needSave = true;
- }
- if (needSave) {
- Log.d(TAG, "going to save icon bitmap for info=" + info);
- // This is slower than is ideal, but this only happens once
- // or when the app is updated with a new icon.
- updateItemInDatabase(context, info);
- }
- }
-
- /**
- * Return an existing FolderInfo object if we have encountered this ID previously,
- * or make a new one.
- */
- private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
- // See if a placeholder was created for us already
- FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null) {
- // No placeholder -- create a new instance
- folderInfo = new FolderInfo();
- folders.put(id, folderInfo);
- }
- return folderInfo;
- }
-
- private static final Collator sCollator = Collator.getInstance();
- public static final Comparator<ApplicationInfo> APP_NAME_COMPARATOR
- = new Comparator<ApplicationInfo>() {
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- int result = sCollator.compare(a.title.toString(), b.title.toString());
- if (result == 0) {
- result = a.componentName.compareTo(b.componentName);
- }
- return result;
- }
- };
- public static final Comparator<ApplicationInfo> APP_INSTALL_TIME_COMPARATOR
- = new Comparator<ApplicationInfo>() {
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- if (a.firstInstallTime < b.firstInstallTime) return 1;
- if (a.firstInstallTime > b.firstInstallTime) return -1;
- return 0;
- }
- };
- public static final Comparator<AppWidgetProviderInfo> WIDGET_NAME_COMPARATOR
- = new Comparator<AppWidgetProviderInfo>() {
- public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
- return sCollator.compare(a.label.toString(), b.label.toString());
- }
- };
- static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
- if (info.activityInfo != null) {
- return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
- } else {
- return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
- }
- }
- public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
- private PackageManager mPackageManager;
- private HashMap<Object, CharSequence> mLabelCache;
- ShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
- mLabelCache = new HashMap<Object, CharSequence>();
- }
- ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {
- mPackageManager = pm;
- mLabelCache = labelCache;
- }
- public final int compare(ResolveInfo a, ResolveInfo b) {
- CharSequence labelA, labelB;
- ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);
- ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);
- if (mLabelCache.containsKey(keyA)) {
- labelA = mLabelCache.get(keyA);
- } else {
- labelA = a.loadLabel(mPackageManager).toString();
-
- mLabelCache.put(keyA, labelA);
- }
- if (mLabelCache.containsKey(keyB)) {
- labelB = mLabelCache.get(keyB);
- } else {
- labelB = b.loadLabel(mPackageManager).toString();
-
- mLabelCache.put(keyB, labelB);
- }
- return sCollator.compare(labelA, labelB);
- }
- };
- public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
- private PackageManager mPackageManager;
- private HashMap<Object, String> mLabelCache;
- WidgetAndShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
- mLabelCache = new HashMap<Object, String>();
- }
- public final int compare(Object a, Object b) {
- String labelA, labelB;
- if (mLabelCache.containsKey(a)) {
- labelA = mLabelCache.get(a);
- } else {
- labelA = (a instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) a).label :
- ((ResolveInfo) a).loadLabel(mPackageManager).toString();
- mLabelCache.put(a, labelA);
- }
- if (mLabelCache.containsKey(b)) {
- labelB = mLabelCache.get(b);
- } else {
- labelB = (b instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) b).label :
- ((ResolveInfo) b).loadLabel(mPackageManager).toString();
- mLabelCache.put(b, labelB);
- }
- return sCollator.compare(labelA, labelB);
- }
- };
-
- public void dumpState() {
- Log.d(TAG, "mCallbacks=" + mCallbacks);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mAllAppsList.data);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
- if (mLoaderTask != null) {
- mLoaderTask.dumpState();
- } else {
- Log.d(TAG, "mLoaderTask=null");
- }
- }
-}
diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java
deleted file mode 100644
index 0720259f4..000000000
--- a/src/com/android/launcher2/LauncherProvider.java
+++ /dev/null
@@ -1,1178 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.SearchManager;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.database.sqlite.SQLiteStatement;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.launcher.R;
-import com.android.launcher2.LauncherSettings.Favorites;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-public class LauncherProvider extends ContentProvider {
- private static final String TAG = "Launcher.LauncherProvider";
- private static final boolean LOGD = false;
-
- private static final String DATABASE_NAME = "launcher.db";
-
- private static final int DATABASE_VERSION = 12;
-
- static final String AUTHORITY = "com.android.launcher2.settings";
-
- static final String TABLE_FAVORITES = "favorites";
- static final String PARAMETER_NOTIFY = "notify";
- static final String DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED =
- "DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED";
-
- private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
- "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
-
- /**
- * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
- * {@link AppWidgetHost#deleteHost()} is called during database creation.
- * Use this to recall {@link AppWidgetHost#startListening()} if needed.
- */
- static final Uri CONTENT_APPWIDGET_RESET_URI =
- Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
-
- private DatabaseHelper mOpenHelper;
-
- @Override
- public boolean onCreate() {
- mOpenHelper = new DatabaseHelper(getContext());
- ((LauncherApplication) getContext()).setLauncherProvider(this);
- return true;
- }
-
- @Override
- public String getType(Uri uri) {
- SqlArguments args = new SqlArguments(uri, null, null);
- if (TextUtils.isEmpty(args.where)) {
- return "vnd.android.cursor.dir/" + args.table;
- } else {
- return "vnd.android.cursor.item/" + args.table;
- }
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
-
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(args.table);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
- result.setNotificationUri(getContext().getContentResolver(), uri);
-
- return result;
- }
-
- private static long dbInsertAndCheck(DatabaseHelper helper,
- SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
- if (!values.containsKey(LauncherSettings.Favorites._ID)) {
- throw new RuntimeException("Error: attempting to add item without specifying an id");
- }
- return db.insert(table, nullColumnHack, values);
- }
-
- private static void deleteId(SQLiteDatabase db, long id) {
- Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
- SqlArguments args = new SqlArguments(uri, null, null);
- db.delete(args.table, args.where, args.args);
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- SqlArguments args = new SqlArguments(uri);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
- if (rowId <= 0) return null;
-
- uri = ContentUris.withAppendedId(uri, rowId);
- sendNotify(uri);
-
- return uri;
- }
-
- @Override
- public int bulkInsert(Uri uri, ContentValues[] values) {
- SqlArguments args = new SqlArguments(uri);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- int numValues = values.length;
- for (int i = 0; i < numValues; i++) {
- if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
- return 0;
- }
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
-
- sendNotify(uri);
- return values.length;
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.delete(args.table, args.where, args.args);
- if (count > 0) sendNotify(uri);
-
- return count;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.update(args.table, values, args.where, args.args);
- if (count > 0) sendNotify(uri);
-
- return count;
- }
-
- private void sendNotify(Uri uri) {
- String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
- if (notify == null || "true".equals(notify)) {
- getContext().getContentResolver().notifyChange(uri, null);
- }
- }
-
- public long generateNewId() {
- return mOpenHelper.generateNewId();
- }
-
- synchronized public void loadDefaultFavoritesIfNecessary() {
- String spKey = LauncherApplication.getSharedPreferencesKey();
- SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
- if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) {
- // Populate favorites table with initial favorites
- SharedPreferences.Editor editor = sp.edit();
- editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED);
- mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), R.xml.default_workspace);
- editor.commit();
- }
- }
-
- private static class DatabaseHelper extends SQLiteOpenHelper {
- private static final String TAG_FAVORITES = "favorites";
- private static final String TAG_FAVORITE = "favorite";
- private static final String TAG_CLOCK = "clock";
- private static final String TAG_SEARCH = "search";
- private static final String TAG_APPWIDGET = "appwidget";
- private static final String TAG_SHORTCUT = "shortcut";
- private static final String TAG_FOLDER = "folder";
- private static final String TAG_EXTRA = "extra";
-
- private final Context mContext;
- private final AppWidgetHost mAppWidgetHost;
- private long mMaxId = -1;
-
- DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- mContext = context;
- mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
-
- // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
- // the DB here
- if (mMaxId == -1) {
- mMaxId = initializeMaxId(getWritableDatabase());
- }
- }
-
- /**
- * Send notification that we've deleted the {@link AppWidgetHost},
- * probably as part of the initial database creation. The receiver may
- * want to re-call {@link AppWidgetHost#startListening()} to ensure
- * callbacks are correctly set.
- */
- private void sendAppWidgetResetNotify() {
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- if (LOGD) Log.d(TAG, "creating new launcher database");
-
- mMaxId = 1;
-
- db.execSQL("CREATE TABLE favorites (" +
- "_id INTEGER PRIMARY KEY," +
- "title TEXT," +
- "intent TEXT," +
- "container INTEGER," +
- "screen INTEGER," +
- "cellX INTEGER," +
- "cellY INTEGER," +
- "spanX INTEGER," +
- "spanY INTEGER," +
- "itemType INTEGER," +
- "appWidgetId INTEGER NOT NULL DEFAULT -1," +
- "isShortcut INTEGER," +
- "iconType INTEGER," +
- "iconPackage TEXT," +
- "iconResource TEXT," +
- "icon BLOB," +
- "uri TEXT," +
- "displayMode INTEGER" +
- ");");
-
- // Database was just created, so wipe any previous widgets
- if (mAppWidgetHost != null) {
- mAppWidgetHost.deleteHost();
- sendAppWidgetResetNotify();
- }
-
- if (!convertDatabase(db)) {
- // Set a shared pref so that we know we need to load the default workspace later
- setFlagToLoadDefaultWorkspaceLater();
- }
- }
-
- private void setFlagToLoadDefaultWorkspaceLater() {
- String spKey = LauncherApplication.getSharedPreferencesKey();
- SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, true);
- editor.commit();
- }
-
- private boolean convertDatabase(SQLiteDatabase db) {
- if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade");
- boolean converted = false;
-
- final Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
- "/old_favorites?notify=true");
- final ContentResolver resolver = mContext.getContentResolver();
- Cursor cursor = null;
-
- try {
- cursor = resolver.query(uri, null, null, null, null);
- } catch (Exception e) {
- // Ignore
- }
-
- // We already have a favorites database in the old provider
- if (cursor != null && cursor.getCount() > 0) {
- try {
- converted = copyFromCursor(db, cursor) > 0;
- } finally {
- cursor.close();
- }
-
- if (converted) {
- resolver.delete(uri, null, null);
- }
- }
-
- if (converted) {
- // Convert widgets from this import into widgets
- if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade");
- convertWidgets(db);
- }
-
- return converted;
- }
-
- private int copyFromCursor(SQLiteDatabase db, Cursor c) {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
- final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
- final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
- final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
-
- ContentValues[] rows = new ContentValues[c.getCount()];
- int i = 0;
- while (c.moveToNext()) {
- ContentValues values = new ContentValues(c.getColumnCount());
- values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
- values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
- values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
- values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
- values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
- values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
- values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
- values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
- values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
- values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
- values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
- values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
- values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
- values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
- values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
- rows[i++] = values;
- }
-
- db.beginTransaction();
- int total = 0;
- try {
- int numValues = rows.length;
- for (i = 0; i < numValues; i++) {
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
- return 0;
- } else {
- total++;
- }
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
-
- return total;
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (LOGD) Log.d(TAG, "onUpgrade triggered");
-
- int version = oldVersion;
- if (version < 3) {
- // upgrade 1,2 -> 3 added appWidgetId column
- db.beginTransaction();
- try {
- // Insert new column for holding appWidgetIds
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
- db.setTransactionSuccessful();
- version = 3;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
- }
-
- // Convert existing widgets only if table upgrade was successful
- if (version == 3) {
- convertWidgets(db);
- }
- }
-
- if (version < 4) {
- version = 4;
- }
-
- // Where's version 5?
- // - Donut and sholes on 2.0 shipped with version 4 of launcher1.
- // - Passion shipped on 2.1 with version 6 of launcher2
- // - Sholes shipped on 2.1r1 (aka Mr. 3) with version 5 of launcher 1
- // but version 5 on there was the updateContactsShortcuts change
- // which was version 6 in launcher 2 (first shipped on passion 2.1r1).
- // The updateContactsShortcuts change is idempotent, so running it twice
- // is okay so we'll do that when upgrading the devices that shipped with it.
- if (version < 6) {
- // We went from 3 to 5 screens. Move everything 1 to the right
- db.beginTransaction();
- try {
- db.execSQL("UPDATE favorites SET screen=(screen + 1);");
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
- }
-
- // We added the fast track.
- if (updateContactsShortcuts(db)) {
- version = 6;
- }
- }
-
- if (version < 7) {
- // Version 7 gets rid of the special search widget.
- convertWidgets(db);
- version = 7;
- }
-
- if (version < 8) {
- // Version 8 (froyo) has the icons all normalized. This should
- // already be the case in practice, but we now rely on it and don't
- // resample the images each time.
- normalizeIcons(db);
- version = 8;
- }
-
- if (version < 9) {
- // The max id is not yet set at this point (onUpgrade is triggered in the ctor
- // before it gets a change to get set, so we need to read it here when we use it)
- if (mMaxId == -1) {
- mMaxId = initializeMaxId(db);
- }
-
- // Add default hotseat icons
- loadFavorites(db, R.xml.update_workspace);
- version = 9;
- }
-
- // We bumped the version three time during JB, once to update the launch flags, once to
- // update the override for the default launch animation and once to set the mimetype
- // to improve startup performance
- if (version < 12) {
- // Contact shortcuts need a different set of flags to be launched now
- // The updateContactsShortcuts change is idempotent, so we can keep using it like
- // back in the Donut days
- updateContactsShortcuts(db);
- version = 12;
- }
-
- if (version != DATABASE_VERSION) {
- Log.w(TAG, "Destroying all old data.");
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
- onCreate(db);
- }
- }
-
- private boolean updateContactsShortcuts(SQLiteDatabase db) {
- final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
- new int[] { Favorites.ITEM_TYPE_SHORTCUT });
-
- Cursor c = null;
- final String actionQuickContact = "com.android.contacts.action.QUICK_CONTACT";
- db.beginTransaction();
- try {
- // Select and iterate through each matching widget
- c = db.query(TABLE_FAVORITES,
- new String[] { Favorites._ID, Favorites.INTENT },
- selectWhere, null, null, null, null);
- if (c == null) return false;
-
- if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
-
- final int idIndex = c.getColumnIndex(Favorites._ID);
- final int intentIndex = c.getColumnIndex(Favorites.INTENT);
-
- while (c.moveToNext()) {
- long favoriteId = c.getLong(idIndex);
- final String intentUri = c.getString(intentIndex);
- if (intentUri != null) {
- try {
- final Intent intent = Intent.parseUri(intentUri, 0);
- android.util.Log.d("Home", intent.toString());
- final Uri uri = intent.getData();
- if (uri != null) {
- final String data = uri.toString();
- if ((Intent.ACTION_VIEW.equals(intent.getAction()) ||
- actionQuickContact.equals(intent.getAction())) &&
- (data.startsWith("content://contacts/people/") ||
- data.startsWith("content://com.android.contacts/" +
- "contacts/lookup/"))) {
-
- final Intent newIntent = new Intent(actionQuickContact);
- // When starting from the launcher, start in a new, cleared task
- // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we
- // clear the whole thing preemptively here since
- // QuickContactActivity will finish itself when launching other
- // detail activities.
- newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TASK);
- newIntent.putExtra(
- Launcher.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
- newIntent.setData(uri);
- // Determine the type and also put that in the shortcut
- // (that can speed up launch a bit)
- newIntent.setDataAndType(uri, newIntent.resolveType(mContext));
-
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.INTENT,
- newIntent.toUri(0));
-
- String updateWhere = Favorites._ID + "=" + favoriteId;
- db.update(TABLE_FAVORITES, values, updateWhere, null);
- }
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem upgrading shortcut", ex);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Problem upgrading shortcut", e);
- }
- }
- }
-
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while upgrading contacts", ex);
- return false;
- } finally {
- db.endTransaction();
- if (c != null) {
- c.close();
- }
- }
-
- return true;
- }
-
- private void normalizeIcons(SQLiteDatabase db) {
- Log.d(TAG, "normalizing icons");
-
- db.beginTransaction();
- Cursor c = null;
- SQLiteStatement update = null;
- try {
- boolean logged = false;
- update = db.compileStatement("UPDATE favorites "
- + "SET icon=? WHERE _id=?");
-
- c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
- Favorites.ICON_TYPE_BITMAP, null);
-
- final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
- final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
-
- while (c.moveToNext()) {
- long id = c.getLong(idIndex);
- byte[] data = c.getBlob(iconIndex);
- try {
- Bitmap bitmap = Utilities.resampleIconBitmap(
- BitmapFactory.decodeByteArray(data, 0, data.length),
- mContext);
- if (bitmap != null) {
- update.bindLong(1, id);
- data = ItemInfo.flattenBitmap(bitmap);
- if (data != null) {
- update.bindBlob(2, data);
- update.execute();
- }
- bitmap.recycle();
- }
- } catch (Exception e) {
- if (!logged) {
- Log.e(TAG, "Failed normalizing icon " + id, e);
- } else {
- Log.e(TAG, "Also failed normalizing icon " + id);
- }
- logged = true;
- }
- }
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
- } finally {
- db.endTransaction();
- if (update != null) {
- update.close();
- }
- if (c != null) {
- c.close();
- }
- }
- }
-
- // Generates a new ID to use for an object in your database. This method should be only
- // called from the main UI thread. As an exception, we do call it when we call the
- // constructor from the worker thread; however, this doesn't extend until after the
- // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
- // after that point
- public long generateNewId() {
- if (mMaxId < 0) {
- throw new RuntimeException("Error: max id was not initialized");
- }
- mMaxId += 1;
- return mMaxId;
- }
-
- private long initializeMaxId(SQLiteDatabase db) {
- Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
-
- // get the result
- final int maxIdIndex = 0;
- long id = -1;
- if (c != null && c.moveToNext()) {
- id = c.getLong(maxIdIndex);
- }
- if (c != null) {
- c.close();
- }
-
- if (id == -1) {
- throw new RuntimeException("Error: could not query max id");
- }
-
- return id;
- }
-
- /**
- * Upgrade existing clock and photo frame widgets into their new widget
- * equivalents.
- */
- private void convertWidgets(SQLiteDatabase db) {
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
- final int[] bindSources = new int[] {
- Favorites.ITEM_TYPE_WIDGET_CLOCK,
- Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
- Favorites.ITEM_TYPE_WIDGET_SEARCH,
- };
-
- final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
-
- Cursor c = null;
-
- db.beginTransaction();
- try {
- // Select and iterate through each matching widget
- c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.ITEM_TYPE },
- selectWhere, null, null, null, null);
-
- if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
-
- final ContentValues values = new ContentValues();
- while (c != null && c.moveToNext()) {
- long favoriteId = c.getLong(0);
- int favoriteType = c.getInt(1);
-
- // Allocate and update database with new appWidgetId
- try {
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
- if (LOGD) {
- Log.d(TAG, "allocated appWidgetId=" + appWidgetId
- + " for favoriteId=" + favoriteId);
- }
- values.clear();
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
- values.put(Favorites.APPWIDGET_ID, appWidgetId);
-
- // Original widgets might not have valid spans when upgrading
- if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
- values.put(LauncherSettings.Favorites.SPANX, 4);
- values.put(LauncherSettings.Favorites.SPANY, 1);
- } else {
- values.put(LauncherSettings.Favorites.SPANX, 2);
- values.put(LauncherSettings.Favorites.SPANY, 2);
- }
-
- String updateWhere = Favorites._ID + "=" + favoriteId;
- db.update(TABLE_FAVORITES, values, updateWhere, null);
-
- if (favoriteType == Favorites.ITEM_TYPE_WIDGET_CLOCK) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- new ComponentName("com.android.alarmclock",
- "com.android.alarmclock.AnalogAppWidgetProvider"));
- } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- new ComponentName("com.android.camera",
- "com.android.camera.PhotoAppWidgetProvider"));
- } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- getSearchWidgetProvider());
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem allocating appWidgetId", ex);
- }
- }
-
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
- } finally {
- db.endTransaction();
- if (c != null) {
- c.close();
- }
- }
- }
-
- private static final void beginDocument(XmlPullParser parser, String firstElementName)
- throws XmlPullParserException, IOException {
- int type;
- while ((type = parser.next()) != parser.START_TAG
- && type != parser.END_DOCUMENT) {
- ;
- }
-
- if (type != parser.START_TAG) {
- throw new XmlPullParserException("No start tag found");
- }
-
- if (!parser.getName().equals(firstElementName)) {
- throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
- ", expected " + firstElementName);
- }
- }
-
- /**
- * Loads the default set of favorite packages from an xml file.
- *
- * @param db The database to write the values into
- * @param filterContainerId The specific container id of items to load
- */
- private int loadFavorites(SQLiteDatabase db, int workspaceResourceId) {
- Intent intent = new Intent(Intent.ACTION_MAIN, null);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- ContentValues values = new ContentValues();
-
- PackageManager packageManager = mContext.getPackageManager();
- int allAppsButtonRank =
- mContext.getResources().getInteger(R.integer.hotseat_all_apps_index);
- int i = 0;
- try {
- XmlResourceParser parser = mContext.getResources().getXml(workspaceResourceId);
- AttributeSet attrs = Xml.asAttributeSet(parser);
- beginDocument(parser, TAG_FAVORITES);
-
- final int depth = parser.getDepth();
-
- int type;
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
-
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- boolean added = false;
- final String name = parser.getName();
-
- TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
-
- long container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- if (a.hasValue(R.styleable.Favorite_container)) {
- container = Long.valueOf(a.getString(R.styleable.Favorite_container));
- }
-
- String screen = a.getString(R.styleable.Favorite_screen);
- String x = a.getString(R.styleable.Favorite_x);
- String y = a.getString(R.styleable.Favorite_y);
-
- // If we are adding to the hotseat, the screen is used as the position in the
- // hotseat. This screen can't be at position 0 because AllApps is in the
- // zeroth position.
- if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
- && Integer.valueOf(screen) == allAppsButtonRank) {
- throw new RuntimeException("Invalid screen position for hotseat item");
- }
-
- values.clear();
- values.put(LauncherSettings.Favorites.CONTAINER, container);
- values.put(LauncherSettings.Favorites.SCREEN, screen);
- values.put(LauncherSettings.Favorites.CELLX, x);
- values.put(LauncherSettings.Favorites.CELLY, y);
-
- if (TAG_FAVORITE.equals(name)) {
- long id = addAppShortcut(db, values, a, packageManager, intent);
- added = id >= 0;
- } else if (TAG_SEARCH.equals(name)) {
- added = addSearchWidget(db, values);
- } else if (TAG_CLOCK.equals(name)) {
- added = addClockWidget(db, values);
- } else if (TAG_APPWIDGET.equals(name)) {
- added = addAppWidget(parser, attrs, type, db, values, a, packageManager);
- } else if (TAG_SHORTCUT.equals(name)) {
- long id = addUriShortcut(db, values, a);
- added = id >= 0;
- } else if (TAG_FOLDER.equals(name)) {
- String title;
- int titleResId = a.getResourceId(R.styleable.Favorite_title, -1);
- if (titleResId != -1) {
- title = mContext.getResources().getString(titleResId);
- } else {
- title = mContext.getResources().getString(R.string.folder_name);
- }
- values.put(LauncherSettings.Favorites.TITLE, title);
- long folderId = addFolder(db, values);
- added = folderId >= 0;
-
- ArrayList<Long> folderItems = new ArrayList<Long>();
-
- int folderDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > folderDepth) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
- final String folder_item_name = parser.getName();
-
- TypedArray ar = mContext.obtainStyledAttributes(attrs,
- R.styleable.Favorite);
- values.clear();
- values.put(LauncherSettings.Favorites.CONTAINER, folderId);
-
- if (TAG_FAVORITE.equals(folder_item_name) && folderId >= 0) {
- long id =
- addAppShortcut(db, values, ar, packageManager, intent);
- if (id >= 0) {
- folderItems.add(id);
- }
- } else if (TAG_SHORTCUT.equals(folder_item_name) && folderId >= 0) {
- long id = addUriShortcut(db, values, ar);
- if (id >= 0) {
- folderItems.add(id);
- }
- } else {
- throw new RuntimeException("Folders can " +
- "contain only shortcuts");
- }
- ar.recycle();
- }
- // We can only have folders with >= 2 items, so we need to remove the
- // folder and clean up if less than 2 items were included, or some
- // failed to add, and less than 2 were actually added
- if (folderItems.size() < 2 && folderId >= 0) {
- // We just delete the folder and any items that made it
- deleteId(db, folderId);
- if (folderItems.size() > 0) {
- deleteId(db, folderItems.get(0));
- }
- added = false;
- }
- }
- if (added) i++;
- a.recycle();
- }
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- } catch (IOException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- } catch (RuntimeException e) {
- Log.w(TAG, "Got exception parsing favorites.", e);
- }
-
- return i;
- }
-
- private long addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
- PackageManager packageManager, Intent intent) {
- long id = -1;
- ActivityInfo info;
- String packageName = a.getString(R.styleable.Favorite_packageName);
- String className = a.getString(R.styleable.Favorite_className);
- try {
- ComponentName cn;
- try {
- cn = new ComponentName(packageName, className);
- info = packageManager.getActivityInfo(cn, 0);
- } catch (PackageManager.NameNotFoundException nnfe) {
- String[] packages = packageManager.currentToCanonicalPackageNames(
- new String[] { packageName });
- cn = new ComponentName(packages[0], className);
- info = packageManager.getActivityInfo(cn, 0);
- }
- id = generateNewId();
- intent.setComponent(cn);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- values.put(Favorites.INTENT, intent.toUri(0));
- values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- values.put(Favorites._ID, generateNewId());
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
- return -1;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to add favorite: " + packageName +
- "/" + className, e);
- }
- return id;
- }
-
- private long addFolder(SQLiteDatabase db, ContentValues values) {
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- long id = generateNewId();
- values.put(Favorites._ID, id);
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) <= 0) {
- return -1;
- } else {
- return id;
- }
- }
-
- private ComponentName getSearchWidgetProvider() {
- SearchManager searchManager =
- (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- ComponentName searchComponent = searchManager.getGlobalSearchActivity();
- if (searchComponent == null) return null;
- return getProviderInPackage(searchComponent.getPackageName());
- }
-
- /**
- * Gets an appwidget provider from the given package. If the package contains more than
- * one appwidget provider, an arbitrary one is returned.
- */
- private ComponentName getProviderInPackage(String packageName) {
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
- List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders();
- if (providers == null) return null;
- final int providerCount = providers.size();
- for (int i = 0; i < providerCount; i++) {
- ComponentName provider = providers.get(i).provider;
- if (provider != null && provider.getPackageName().equals(packageName)) {
- return provider;
- }
- }
- return null;
- }
-
- private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
- ComponentName cn = getSearchWidgetProvider();
- return addAppWidget(db, values, cn, 4, 1, null);
- }
-
- private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
- ComponentName cn = new ComponentName("com.android.alarmclock",
- "com.android.alarmclock.AnalogAppWidgetProvider");
- return addAppWidget(db, values, cn, 2, 2, null);
- }
-
- private boolean addAppWidget(XmlResourceParser parser, AttributeSet attrs, int type,
- SQLiteDatabase db, ContentValues values, TypedArray a,
- PackageManager packageManager) throws XmlPullParserException, IOException {
-
- String packageName = a.getString(R.styleable.Favorite_packageName);
- String className = a.getString(R.styleable.Favorite_className);
-
- if (packageName == null || className == null) {
- return false;
- }
-
- boolean hasPackage = true;
- ComponentName cn = new ComponentName(packageName, className);
- try {
- packageManager.getReceiverInfo(cn, 0);
- } catch (Exception e) {
- String[] packages = packageManager.currentToCanonicalPackageNames(
- new String[] { packageName });
- cn = new ComponentName(packages[0], className);
- try {
- packageManager.getReceiverInfo(cn, 0);
- } catch (Exception e1) {
- hasPackage = false;
- }
- }
-
- if (hasPackage) {
- int spanX = a.getInt(R.styleable.Favorite_spanX, 0);
- int spanY = a.getInt(R.styleable.Favorite_spanY, 0);
-
- // Read the extras
- Bundle extras = new Bundle();
- int widgetDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > widgetDepth) {
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- TypedArray ar = mContext.obtainStyledAttributes(attrs, R.styleable.Extra);
- if (TAG_EXTRA.equals(parser.getName())) {
- String key = ar.getString(R.styleable.Extra_key);
- String value = ar.getString(R.styleable.Extra_value);
- if (key != null && value != null) {
- extras.putString(key, value);
- } else {
- throw new RuntimeException("Widget extras must have a key and value");
- }
- } else {
- throw new RuntimeException("Widgets can contain only extras");
- }
- ar.recycle();
- }
-
- return addAppWidget(db, values, cn, spanX, spanY, extras);
- }
-
- return false;
- }
-
- private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
- int spanX, int spanY, Bundle extras) {
- boolean allocatedAppWidgets = false;
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-
- try {
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
- values.put(Favorites.SPANX, spanX);
- values.put(Favorites.SPANY, spanY);
- values.put(Favorites.APPWIDGET_ID, appWidgetId);
- values.put(Favorites._ID, generateNewId());
- dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
-
- allocatedAppWidgets = true;
-
- // TODO: need to check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn);
-
- // Send a broadcast to configure the widget
- if (extras != null && !extras.isEmpty()) {
- Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
- intent.setComponent(cn);
- intent.putExtras(extras);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- mContext.sendBroadcast(intent);
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem allocating appWidgetId", ex);
- }
-
- return allocatedAppWidgets;
- }
-
- private long addUriShortcut(SQLiteDatabase db, ContentValues values,
- TypedArray a) {
- Resources r = mContext.getResources();
-
- final int iconResId = a.getResourceId(R.styleable.Favorite_icon, 0);
- final int titleResId = a.getResourceId(R.styleable.Favorite_title, 0);
-
- Intent intent;
- String uri = null;
- try {
- uri = a.getString(R.styleable.Favorite_uri);
- intent = Intent.parseUri(uri, 0);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Shortcut has malformed uri: " + uri);
- return -1; // Oh well
- }
-
- if (iconResId == 0 || titleResId == 0) {
- Log.w(TAG, "Shortcut is missing title or icon resource ID");
- return -1;
- }
-
- long id = generateNewId();
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- values.put(Favorites.INTENT, intent.toUri(0));
- values.put(Favorites.TITLE, r.getString(titleResId));
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT);
- values.put(Favorites.SPANX, 1);
- values.put(Favorites.SPANY, 1);
- values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
- values.put(Favorites.ICON_PACKAGE, mContext.getPackageName());
- values.put(Favorites.ICON_RESOURCE, r.getResourceName(iconResId));
- values.put(Favorites._ID, id);
-
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
- return -1;
- }
- return id;
- }
- }
-
- /**
- * Build a query string that will match any row where the column matches
- * anything in the values list.
- */
- static String buildOrWhereString(String column, int[] values) {
- StringBuilder selectWhere = new StringBuilder();
- for (int i = values.length - 1; i >= 0; i--) {
- selectWhere.append(column).append("=").append(values[i]);
- if (i > 0) {
- selectWhere.append(" OR ");
- }
- }
- return selectWhere.toString();
- }
-
- static class SqlArguments {
- public final String table;
- public final String where;
- public final String[] args;
-
- SqlArguments(Uri url, String where, String[] args) {
- if (url.getPathSegments().size() == 1) {
- this.table = url.getPathSegments().get(0);
- this.where = where;
- this.args = args;
- } else if (url.getPathSegments().size() != 2) {
- throw new IllegalArgumentException("Invalid URI: " + url);
- } else if (!TextUtils.isEmpty(where)) {
- throw new UnsupportedOperationException("WHERE clause not supported: " + url);
- } else {
- this.table = url.getPathSegments().get(0);
- this.where = "_id=" + ContentUris.parseId(url);
- this.args = null;
- }
- }
-
- SqlArguments(Uri url) {
- if (url.getPathSegments().size() == 1) {
- table = url.getPathSegments().get(0);
- where = null;
- args = null;
- } else {
- throw new IllegalArgumentException("Invalid URI: " + url);
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/LauncherSettings.java b/src/com/android/launcher2/LauncherSettings.java
deleted file mode 100644
index ee003716b..000000000
--- a/src/com/android/launcher2/LauncherSettings.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2008 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.net.Uri;
-import android.provider.BaseColumns;
-
-/**
- * Settings related utilities.
- */
-class LauncherSettings {
- static interface BaseLauncherColumns extends BaseColumns {
- /**
- * Descriptive name of the gesture that can be displayed to the user.
- * <P>Type: TEXT</P>
- */
- static final String TITLE = "title";
-
- /**
- * The Intent URL of the gesture, describing what it points to. This
- * value is given to {@link android.content.Intent#parseUri(String, int)} to create
- * an Intent that can be launched.
- * <P>Type: TEXT</P>
- */
- static final String INTENT = "intent";
-
- /**
- * The type of the gesture
- *
- * <P>Type: INTEGER</P>
- */
- static final String ITEM_TYPE = "itemType";
-
- /**
- * The gesture is an application
- */
- static final int ITEM_TYPE_APPLICATION = 0;
-
- /**
- * The gesture is an application created shortcut
- */
- static final int ITEM_TYPE_SHORTCUT = 1;
-
- /**
- * The icon type.
- * <P>Type: INTEGER</P>
- */
- static final String ICON_TYPE = "iconType";
-
- /**
- * The icon is a resource identified by a package name and an integer id.
- */
- static final int ICON_TYPE_RESOURCE = 0;
-
- /**
- * The icon is a bitmap.
- */
- static final int ICON_TYPE_BITMAP = 1;
-
- /**
- * The icon package name, if icon type is ICON_TYPE_RESOURCE.
- * <P>Type: TEXT</P>
- */
- static final String ICON_PACKAGE = "iconPackage";
-
- /**
- * The icon resource id, if icon type is ICON_TYPE_RESOURCE.
- * <P>Type: TEXT</P>
- */
- static final String ICON_RESOURCE = "iconResource";
-
- /**
- * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
- * <P>Type: BLOB</P>
- */
- static final String ICON = "icon";
- }
-
- /**
- * Favorites.
- */
- static final class Favorites implements BaseLauncherColumns {
- /**
- * The content:// style URL for this table
- */
- static final Uri CONTENT_URI = Uri.parse("content://" +
- LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
- "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
-
- /**
- * The content:// style URL for this table. When this Uri is used, no notification is
- * sent if the content changes.
- */
- static final Uri CONTENT_URI_NO_NOTIFICATION = Uri.parse("content://" +
- LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
- "?" + LauncherProvider.PARAMETER_NOTIFY + "=false");
-
- /**
- * The content:// style URL for a given row, identified by its id.
- *
- * @param id The row id.
- * @param notify True to send a notification is the content changes.
- *
- * @return The unique content URL for the specified row.
- */
- static Uri getContentUri(long id, boolean notify) {
- return Uri.parse("content://" + LauncherProvider.AUTHORITY +
- "/" + LauncherProvider.TABLE_FAVORITES + "/" + id + "?" +
- LauncherProvider.PARAMETER_NOTIFY + "=" + notify);
- }
-
- /**
- * The container holding the favorite
- * <P>Type: INTEGER</P>
- */
- static final String CONTAINER = "container";
-
- /**
- * The icon is a resource identified by a package name and an integer id.
- */
- static final int CONTAINER_DESKTOP = -100;
- static final int CONTAINER_HOTSEAT = -101;
-
- /**
- * The screen holding the favorite (if container is CONTAINER_DESKTOP)
- * <P>Type: INTEGER</P>
- */
- static final String SCREEN = "screen";
-
- /**
- * The X coordinate of the cell holding the favorite
- * (if container is CONTAINER_HOTSEAT or CONTAINER_HOTSEAT)
- * <P>Type: INTEGER</P>
- */
- static final String CELLX = "cellX";
-
- /**
- * The Y coordinate of the cell holding the favorite
- * (if container is CONTAINER_DESKTOP)
- * <P>Type: INTEGER</P>
- */
- static final String CELLY = "cellY";
-
- /**
- * The X span of the cell holding the favorite
- * <P>Type: INTEGER</P>
- */
- static final String SPANX = "spanX";
-
- /**
- * The Y span of the cell holding the favorite
- * <P>Type: INTEGER</P>
- */
- static final String SPANY = "spanY";
-
- /**
- * The favorite is a user created folder
- */
- static final int ITEM_TYPE_FOLDER = 2;
-
- /**
- * The favorite is a live folder
- *
- * Note: live folders can no longer be added to Launcher, and any live folders which
- * exist within the launcher database will be ignored when loading. That said, these
- * entries in the database may still exist, and are not automatically stripped.
- */
- static final int ITEM_TYPE_LIVE_FOLDER = 3;
-
- /**
- * The favorite is a widget
- */
- static final int ITEM_TYPE_APPWIDGET = 4;
-
- /**
- * The favorite is a clock
- */
- static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
-
- /**
- * The favorite is a search widget
- */
- static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
-
- /**
- * The favorite is a photo frame
- */
- static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
-
- /**
- * The appWidgetId of the widget
- *
- * <P>Type: INTEGER</P>
- */
- static final String APPWIDGET_ID = "appWidgetId";
-
- /**
- * Indicates whether this favorite is an application-created shortcut or not.
- * If the value is 0, the favorite is not an application-created shortcut, if the
- * value is 1, it is an application-created shortcut.
- * <P>Type: INTEGER</P>
- */
- @Deprecated
- static final String IS_SHORTCUT = "isShortcut";
-
- /**
- * The URI associated with the favorite. It is used, for instance, by
- * live folders to find the content provider.
- * <P>Type: TEXT</P>
- */
- static final String URI = "uri";
-
- /**
- * The display mode if the item is a live folder.
- * <P>Type: INTEGER</P>
- *
- * @see android.provider.LiveFolders#DISPLAY_MODE_GRID
- * @see android.provider.LiveFolders#DISPLAY_MODE_LIST
- */
- static final String DISPLAY_MODE = "displayMode";
- }
-}
diff --git a/src/com/android/launcher2/LauncherViewPropertyAnimator.java b/src/com/android/launcher2/LauncherViewPropertyAnimator.java
deleted file mode 100644
index 88b4cb4b8..000000000
--- a/src/com/android/launcher2/LauncherViewPropertyAnimator.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2012 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.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.TimeInterpolator;
-import android.view.ViewPropertyAnimator;
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-
-public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener {
- enum Properties {
- TRANSLATION_X,
- TRANSLATION_Y,
- SCALE_X,
- SCALE_Y,
- ROTATION_Y,
- ALPHA,
- START_DELAY,
- DURATION,
- INTERPOLATOR
- }
- EnumSet<Properties> mPropertiesToSet = EnumSet.noneOf(Properties.class);
- ViewPropertyAnimator mViewPropertyAnimator;
- View mTarget;
-
- float mTranslationX;
- float mTranslationY;
- float mScaleX;
- float mScaleY;
- float mRotationY;
- float mAlpha;
- long mStartDelay;
- long mDuration;
- TimeInterpolator mInterpolator;
- ArrayList<Animator.AnimatorListener> mListeners;
- boolean mRunning = false;
-
- public LauncherViewPropertyAnimator(View target) {
- mTarget = target;
- mListeners = new ArrayList<Animator.AnimatorListener>();
- }
-
- @Override
- public void addListener(Animator.AnimatorListener listener) {
- mListeners.add(listener);
- }
-
- @Override
- public void cancel() {
- if (mViewPropertyAnimator != null) {
- mViewPropertyAnimator.cancel();
- }
- }
-
- @Override
- public Animator clone() {
- throw new RuntimeException("Not implemented");
- }
-
- @Override
- public void end() {
- throw new RuntimeException("Not implemented");
- }
-
- @Override
- public long getDuration() {
- return mDuration;
- }
-
- @Override
- public ArrayList<Animator.AnimatorListener> getListeners() {
- return mListeners;
- }
-
- @Override
- public long getStartDelay() {
- return mStartDelay;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- for (int i = 0; i < mListeners.size(); i++) {
- Animator.AnimatorListener listener = mListeners.get(i);
- listener.onAnimationCancel(this);
- }
- mRunning = false;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- for (int i = 0; i < mListeners.size(); i++) {
- Animator.AnimatorListener listener = mListeners.get(i);
- listener.onAnimationEnd(this);
- }
- mRunning = false;
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- for (int i = 0; i < mListeners.size(); i++) {
- Animator.AnimatorListener listener = mListeners.get(i);
- listener.onAnimationRepeat(this);
- }
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- for (int i = 0; i < mListeners.size(); i++) {
- Animator.AnimatorListener listener = mListeners.get(i);
- listener.onAnimationStart(this);
- }
- mRunning = true;
- }
-
- @Override
- public boolean isRunning() {
- return mRunning;
- }
-
- @Override
- public boolean isStarted() {
- return mViewPropertyAnimator != null;
- }
-
- @Override
- public void removeAllListeners() {
- mListeners.clear();
- }
-
- @Override
- public void removeListener(Animator.AnimatorListener listener) {
- mListeners.remove(listener);
- }
-
- @Override
- public Animator setDuration(long duration) {
- mPropertiesToSet.add(Properties.DURATION);
- mDuration = duration;
- return this;
- }
-
- @Override
- public void setInterpolator(TimeInterpolator value) {
- mPropertiesToSet.add(Properties.INTERPOLATOR);
- mInterpolator = value;
- }
-
- @Override
- public void setStartDelay(long startDelay) {
- mPropertiesToSet.add(Properties.START_DELAY);
- mStartDelay = startDelay;
- }
-
- @Override
- public void setTarget(Object target) {
- throw new RuntimeException("Not implemented");
- }
-
- @Override
- public void setupEndValues() {
-
- }
-
- @Override
- public void setupStartValues() {
- }
-
- @Override
- public void start() {
- mViewPropertyAnimator = mTarget.animate();
- if (mPropertiesToSet.contains(Properties.TRANSLATION_X)) {
- mViewPropertyAnimator.translationX(mTranslationX);
- }
- if (mPropertiesToSet.contains(Properties.TRANSLATION_Y)) {
- mViewPropertyAnimator.translationY(mTranslationY);
- }
- if (mPropertiesToSet.contains(Properties.SCALE_X)) {
- mViewPropertyAnimator.scaleX(mScaleX);
- }
- if (mPropertiesToSet.contains(Properties.ROTATION_Y)) {
- mViewPropertyAnimator.rotationY(mRotationY);
- }
- if (mPropertiesToSet.contains(Properties.SCALE_Y)) {
- mViewPropertyAnimator.scaleY(mScaleY);
- }
- if (mPropertiesToSet.contains(Properties.ALPHA)) {
- mViewPropertyAnimator.alpha(mAlpha);
- }
- if (mPropertiesToSet.contains(Properties.START_DELAY)) {
- mViewPropertyAnimator.setStartDelay(mStartDelay);
- }
- if (mPropertiesToSet.contains(Properties.DURATION)) {
- mViewPropertyAnimator.setDuration(mDuration);
- }
- if (mPropertiesToSet.contains(Properties.INTERPOLATOR)) {
- mViewPropertyAnimator.setInterpolator(mInterpolator);
- }
- mViewPropertyAnimator.setListener(this);
- mViewPropertyAnimator.start();
- }
-
- public LauncherViewPropertyAnimator translationX(float value) {
- mPropertiesToSet.add(Properties.TRANSLATION_X);
- mTranslationX = value;
- return this;
- }
-
- public LauncherViewPropertyAnimator translationY(float value) {
- mPropertiesToSet.add(Properties.TRANSLATION_Y);
- mTranslationY = value;
- return this;
- }
-
- public LauncherViewPropertyAnimator scaleX(float value) {
- mPropertiesToSet.add(Properties.SCALE_X);
- mScaleX = value;
- return this;
- }
-
- public LauncherViewPropertyAnimator scaleY(float value) {
- mPropertiesToSet.add(Properties.SCALE_Y);
- mScaleY = value;
- return this;
- }
-
- public LauncherViewPropertyAnimator rotationY(float value) {
- mPropertiesToSet.add(Properties.ROTATION_Y);
- mRotationY = value;
- return this;
- }
-
- public LauncherViewPropertyAnimator alpha(float value) {
- mPropertiesToSet.add(Properties.ALPHA);
- mAlpha = value;
- return this;
- }
-}
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
deleted file mode 100644
index ad0baf44d..000000000
--- a/src/com/android/launcher2/PagedView.java
+++ /dev/null
@@ -1,1913 +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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-import com.android.launcher.R;
-
-import java.util.ArrayList;
-
-/**
- * An abstraction of the original Workspace which supports browsing through a
- * sequential list of "pages"
- */
-public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
- private static final String TAG = "PagedView";
- private static final boolean DEBUG = false;
- protected static final int INVALID_PAGE = -1;
-
- // the min drag distance for a fling to register, to prevent random page shifts
- private static final int MIN_LENGTH_FOR_FLING = 25;
-
- protected static final int PAGE_SNAP_ANIMATION_DURATION = 550;
- protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
- protected static final float NANOTIME_DIV = 1000000000.0f;
-
- private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
- private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
-
- private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
- // The page is moved more than halfway, automatically move to the next page on touch up.
- private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
-
- // The following constants need to be scaled based on density. The scaled versions will be
- // assigned to the corresponding member variables below.
- private static final int FLING_THRESHOLD_VELOCITY = 500;
- private static final int MIN_SNAP_VELOCITY = 1500;
- private static final int MIN_FLING_VELOCITY = 250;
-
- static final int AUTOMATIC_PAGE_SPACING = -1;
-
- protected int mFlingThresholdVelocity;
- protected int mMinFlingVelocity;
- protected int mMinSnapVelocity;
-
- protected float mDensity;
- protected float mSmoothingTime;
- protected float mTouchX;
-
- protected boolean mFirstLayout = true;
-
- protected int mCurrentPage;
- protected int mNextPage = INVALID_PAGE;
- protected int mMaxScrollX;
- protected Scroller mScroller;
- private VelocityTracker mVelocityTracker;
-
- private float mDownMotionX;
- protected float mLastMotionX;
- protected float mLastMotionXRemainder;
- protected float mLastMotionY;
- protected float mTotalMotionX;
- private int mLastScreenCenter = -1;
- private int[] mChildOffsets;
- private int[] mChildRelativeOffsets;
- private int[] mChildOffsetsWithLayoutScale;
-
- protected final static int TOUCH_STATE_REST = 0;
- protected final static int TOUCH_STATE_SCROLLING = 1;
- protected final static int TOUCH_STATE_PREV_PAGE = 2;
- protected final static int TOUCH_STATE_NEXT_PAGE = 3;
- protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
-
- protected int mTouchState = TOUCH_STATE_REST;
- protected boolean mForceScreenScrolled = false;
-
- protected OnLongClickListener mLongClickListener;
-
- protected boolean mAllowLongPress = true;
-
- protected int mTouchSlop;
- private int mPagingTouchSlop;
- private int mMaximumVelocity;
- private int mMinimumWidth;
- protected int mPageSpacing;
- protected int mPageLayoutPaddingTop;
- protected int mPageLayoutPaddingBottom;
- protected int mPageLayoutPaddingLeft;
- protected int mPageLayoutPaddingRight;
- protected int mPageLayoutWidthGap;
- protected int mPageLayoutHeightGap;
- protected int mCellCountX = 0;
- protected int mCellCountY = 0;
- protected boolean mCenterPagesVertically;
- protected boolean mAllowOverScroll = true;
- protected int mUnboundedScrollX;
- protected int[] mTempVisiblePagesRange = new int[2];
- protected boolean mForceDrawAllChildrenNextFrame;
-
- // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
- // it is equal to the scaled overscroll position. We use a separate value so as to prevent
- // the screens from continuing to translate beyond the normal bounds.
- protected int mOverScrollX;
-
- // parameter that adjusts the layout to be optimized for pages with that scale factor
- protected float mLayoutScale = 1.0f;
-
- protected static final int INVALID_POINTER = -1;
-
- protected int mActivePointerId = INVALID_POINTER;
-
- private PageSwitchListener mPageSwitchListener;
-
- protected ArrayList<Boolean> mDirtyPageContent;
-
- // If true, syncPages and syncPageItems will be called to refresh pages
- protected boolean mContentIsRefreshable = true;
-
- // If true, modify alpha of neighboring pages as user scrolls left/right
- protected boolean mFadeInAdjacentScreens = true;
-
- // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
- // to switch to a new page
- protected boolean mUsePagingTouchSlop = true;
-
- // If true, the subclass should directly update scrollX itself in its computeScroll method
- // (SmoothPagedView does this)
- protected boolean mDeferScrollUpdate = false;
-
- protected boolean mIsPageMoving = false;
-
- // All syncs and layout passes are deferred until data is ready.
- protected boolean mIsDataReady = false;
-
- // Scrolling indicator
- private ValueAnimator mScrollIndicatorAnimator;
- private View mScrollIndicator;
- private int mScrollIndicatorPaddingLeft;
- private int mScrollIndicatorPaddingRight;
- private boolean mHasScrollIndicator = true;
- private boolean mShouldShowScrollIndicator = false;
- private boolean mShouldShowScrollIndicatorImmediately = false;
- protected static final int sScrollIndicatorFadeInDuration = 150;
- protected static final int sScrollIndicatorFadeOutDuration = 650;
- protected static final int sScrollIndicatorFlashDuration = 650;
-
- // If set, will defer loading associated pages until the scrolling settles
- private boolean mDeferLoadAssociatedPagesUntilScrollCompletes;
-
- public interface PageSwitchListener {
- void onPageSwitch(View newPage, int newPageIndex);
- }
-
- public PagedView(Context context) {
- this(context, null);
- }
-
- public PagedView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.PagedView, defStyle, 0);
- setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0));
- mPageLayoutPaddingTop = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutPaddingTop, 0);
- mPageLayoutPaddingBottom = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutPaddingBottom, 0);
- mPageLayoutPaddingLeft = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutPaddingLeft, 0);
- mPageLayoutPaddingRight = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutPaddingRight, 0);
- mPageLayoutWidthGap = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutWidthGap, 0);
- mPageLayoutHeightGap = a.getDimensionPixelSize(
- R.styleable.PagedView_pageLayoutHeightGap, 0);
- mScrollIndicatorPaddingLeft =
- a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0);
- mScrollIndicatorPaddingRight =
- a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
- a.recycle();
-
- setHapticFeedbackEnabled(false);
- init();
- }
-
- /**
- * Initializes various states for this workspace.
- */
- protected void init() {
- mDirtyPageContent = new ArrayList<Boolean>();
- mDirtyPageContent.ensureCapacity(32);
- mScroller = new Scroller(getContext(), new ScrollInterpolator());
- mCurrentPage = 0;
- mCenterPagesVertically = true;
-
- final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- mTouchSlop = configuration.getScaledTouchSlop();
- mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
- mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
- mDensity = getResources().getDisplayMetrics().density;
-
- mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
- mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
- mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
- setOnHierarchyChangeListener(this);
- }
-
- public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
- mPageSwitchListener = pageSwitchListener;
- if (mPageSwitchListener != null) {
- mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
- }
- }
-
- /**
- * Called by subclasses to mark that data is ready, and that we can begin loading and laying
- * out pages.
- */
- protected void setDataIsReady() {
- mIsDataReady = true;
- }
- protected boolean isDataReady() {
- return mIsDataReady;
- }
-
- /**
- * Returns the index of the currently displayed page.
- *
- * @return The index of the currently displayed page.
- */
- int getCurrentPage() {
- return mCurrentPage;
- }
- int getNextPage() {
- return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
- }
-
- int getPageCount() {
- return getChildCount();
- }
-
- View getPageAt(int index) {
- return getChildAt(index);
- }
-
- protected int indexToPage(int index) {
- return index;
- }
-
- /**
- * Updates the scroll of the current page immediately to its final scroll position. We use this
- * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
- * the previous tab page.
- */
- protected void updateCurrentPageScroll() {
- int offset = getChildOffset(mCurrentPage);
- int relOffset = getRelativeChildOffset(mCurrentPage);
- int newX = offset - relOffset;
- scrollTo(newX, 0);
- mScroller.setFinalX(newX);
- mScroller.forceFinished(true);
- }
-
- /**
- * Sets the current page.
- */
- void setCurrentPage(int currentPage) {
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
- // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
- // the default
- if (getChildCount() == 0) {
- return;
- }
-
-
- mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
- updateCurrentPageScroll();
- updateScrollingIndicator();
- notifyPageSwitchListener();
- invalidate();
- }
-
- protected void notifyPageSwitchListener() {
- if (mPageSwitchListener != null) {
- mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
- }
- }
-
- protected void pageBeginMoving() {
- if (!mIsPageMoving) {
- mIsPageMoving = true;
- onPageBeginMoving();
- }
- }
-
- protected void pageEndMoving() {
- if (mIsPageMoving) {
- mIsPageMoving = false;
- onPageEndMoving();
- }
- }
-
- protected boolean isPageMoving() {
- return mIsPageMoving;
- }
-
- // a method that subclasses can override to add behavior
- protected void onPageBeginMoving() {
- }
-
- // a method that subclasses can override to add behavior
- protected void onPageEndMoving() {
- }
-
- /**
- * Registers the specified listener on each page contained in this workspace.
- *
- * @param l The listener used to respond to long clicks.
- */
- @Override
- public void setOnLongClickListener(OnLongClickListener l) {
- mLongClickListener = l;
- final int count = getPageCount();
- for (int i = 0; i < count; i++) {
- getPageAt(i).setOnLongClickListener(l);
- }
- }
-
- @Override
- public void scrollBy(int x, int y) {
- scrollTo(mUnboundedScrollX + x, getScrollY() + y);
- }
-
- @Override
- public void scrollTo(int x, int y) {
- mUnboundedScrollX = x;
-
- if (x < 0) {
- super.scrollTo(0, y);
- if (mAllowOverScroll) {
- overScroll(x);
- }
- } else if (x > mMaxScrollX) {
- super.scrollTo(mMaxScrollX, y);
- if (mAllowOverScroll) {
- overScroll(x - mMaxScrollX);
- }
- } else {
- mOverScrollX = x;
- super.scrollTo(x, y);
- }
-
- mTouchX = x;
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- }
-
- // we moved this functionality to a helper function so SmoothPagedView can reuse it
- protected boolean computeScrollHelper() {
- if (mScroller.computeScrollOffset()) {
- // Don't bother scrolling if the page does not need to be moved
- if (getScrollX() != mScroller.getCurrX()
- || getScrollY() != mScroller.getCurrY()
- || mOverScrollX != mScroller.getCurrX()) {
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- }
- invalidate();
- return true;
- } else if (mNextPage != INVALID_PAGE) {
- mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
- mNextPage = INVALID_PAGE;
- notifyPageSwitchListener();
-
- // Load the associated pages if necessary
- if (mDeferLoadAssociatedPagesUntilScrollCompletes) {
- loadAssociatedPages(mCurrentPage);
- mDeferLoadAssociatedPagesUntilScrollCompletes = false;
- }
-
- // We don't want to trigger a page end moving unless the page has settled
- // and the user has stopped scrolling
- if (mTouchState == TOUCH_STATE_REST) {
- pageEndMoving();
- }
-
- // Notify the user when the page changes
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (accessibilityManager.isEnabled()) {
- AccessibilityEvent ev =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
- ev.getText().add(getCurrentPageDescription());
- sendAccessibilityEventUnchecked(ev);
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void computeScroll() {
- computeScrollHelper();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (!mIsDataReady) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- return;
- }
-
- final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- if (widthMode != MeasureSpec.EXACTLY) {
- throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
- }
-
- // Return early if we aren't given a proper dimension
- if (widthSize <= 0 || heightSize <= 0) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- return;
- }
-
- /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
- * of the All apps view on XLarge displays to not take up more space then it needs. Width
- * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
- * each page to have the same width.
- */
- int maxChildHeight = 0;
-
- final int verticalPadding = getPaddingTop() + getPaddingBottom();
- final int horizontalPadding = getPaddingLeft() + getPaddingRight();
-
-
- // The children are given the same width and height as the workspace
- // unless they were set to WRAP_CONTENT
- if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- // disallowing padding in paged view (just pass 0)
- final View child = getPageAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- int childWidthMode;
- if (lp.width == LayoutParams.WRAP_CONTENT) {
- childWidthMode = MeasureSpec.AT_MOST;
- } else {
- childWidthMode = MeasureSpec.EXACTLY;
- }
-
- int childHeightMode;
- if (lp.height == LayoutParams.WRAP_CONTENT) {
- childHeightMode = MeasureSpec.AT_MOST;
- } else {
- childHeightMode = MeasureSpec.EXACTLY;
- }
-
- final int childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
- final int childHeightMeasureSpec =
- MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
- if (DEBUG) Log.d(TAG, "\tmeasure-child" + i + ": " + child.getMeasuredWidth() + ", "
- + child.getMeasuredHeight());
- }
-
- if (heightMode == MeasureSpec.AT_MOST) {
- heightSize = maxChildHeight + verticalPadding;
- }
-
- setMeasuredDimension(widthSize, heightSize);
-
- // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
- // We also wait until we set the measured dimensions before flushing the cache as well, to
- // ensure that the cache is filled with good values.
- invalidateCachedOffsets();
-
- if (childCount > 0) {
- if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMeasuredWidth() + ", "
- + getChildWidth(0));
-
- // Calculate the variable page spacing if necessary
- if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
- // The gap between pages in the PagedView should be equal to the gap from the page
- // to the edge of the screen (so it is not visible in the current screen). To
- // account for unequal padding on each side of the paged view, we take the maximum
- // of the left/right gap and use that as the gap between each page.
- int offset = getRelativeChildOffset(0);
- int spacing = Math.max(offset, widthSize - offset -
- getChildAt(0).getMeasuredWidth());
- setPageSpacing(spacing);
- }
- }
-
- updateScrollingIndicatorPosition();
-
- if (childCount > 0) {
- mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
- } else {
- mMaxScrollX = 0;
- }
- }
-
- protected void scrollToNewPageWithoutMovingPages(int newCurrentPage) {
- int newX = getChildOffset(newCurrentPage) - getRelativeChildOffset(newCurrentPage);
- int delta = newX - getScrollX();
-
- final int pageCount = getChildCount();
- for (int i = 0; i < pageCount; i++) {
- View page = (View) getPageAt(i);
- page.setX(page.getX() + delta);
- }
- setCurrentPage(newCurrentPage);
- }
-
- // A layout scale of 1.0f assumes that the pages, in their unshrunken state, have a
- // scale of 1.0f. A layout scale of 0.8f assumes the pages have a scale of 0.8f, and
- // tightens the layout accordingly
- public void setLayoutScale(float childrenScale) {
- mLayoutScale = childrenScale;
- invalidateCachedOffsets();
-
- // Now we need to do a re-layout, but preserving absolute X and Y coordinates
- int childCount = getChildCount();
- float childrenX[] = new float[childCount];
- float childrenY[] = new float[childCount];
- for (int i = 0; i < childCount; i++) {
- final View child = getPageAt(i);
- childrenX[i] = child.getX();
- childrenY[i] = child.getY();
- }
- // Trigger a full re-layout (never just call onLayout directly!)
- int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
- int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY);
- requestLayout();
- measure(widthSpec, heightSpec);
- layout(getLeft(), getTop(), getRight(), getBottom());
- for (int i = 0; i < childCount; i++) {
- final View child = getPageAt(i);
- child.setX(childrenX[i]);
- child.setY(childrenY[i]);
- }
-
- // Also, the page offset has changed (since the pages are now smaller);
- // update the page offset, but again preserving absolute X and Y coordinates
- scrollToNewPageWithoutMovingPages(mCurrentPage);
- }
-
- public void setPageSpacing(int pageSpacing) {
- mPageSpacing = pageSpacing;
- invalidateCachedOffsets();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (!mIsDataReady) {
- return;
- }
-
- if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
- final int verticalPadding = getPaddingTop() + getPaddingBottom();
- final int childCount = getChildCount();
- int childLeft = getRelativeChildOffset(0);
-
- for (int i = 0; i < childCount; i++) {
- final View child = getPageAt(i);
- if (child.getVisibility() != View.GONE) {
- final int childWidth = getScaledMeasuredWidth(child);
- final int childHeight = child.getMeasuredHeight();
- int childTop = getPaddingTop();
- if (mCenterPagesVertically) {
- childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
- }
-
- if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
- child.layout(childLeft, childTop,
- childLeft + child.getMeasuredWidth(), childTop + childHeight);
- childLeft += childWidth + mPageSpacing;
- }
- }
-
- if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
- setHorizontalScrollBarEnabled(false);
- updateCurrentPageScroll();
- setHorizontalScrollBarEnabled(true);
- mFirstLayout = false;
- }
- }
-
- protected void screenScrolled(int screenCenter) {
- if (isScrollingIndicatorEnabled()) {
- updateScrollingIndicator();
- }
- boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
-
- if (mFadeInAdjacentScreens && !isInOverscroll) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child != null) {
- float scrollProgress = getScrollProgress(screenCenter, child, i);
- float alpha = 1 - Math.abs(scrollProgress);
- child.setAlpha(alpha);
- }
- }
- invalidate();
- }
- }
-
- @Override
- public void onChildViewAdded(View parent, View child) {
- // This ensures that when children are added, they get the correct transforms / alphas
- // in accordance with any scroll effects.
- mForceScreenScrolled = true;
- invalidate();
- invalidateCachedOffsets();
- }
-
- @Override
- public void onChildViewRemoved(View parent, View child) {
- }
-
- protected void invalidateCachedOffsets() {
- int count = getChildCount();
- if (count == 0) {
- mChildOffsets = null;
- mChildRelativeOffsets = null;
- mChildOffsetsWithLayoutScale = null;
- return;
- }
-
- mChildOffsets = new int[count];
- mChildRelativeOffsets = new int[count];
- mChildOffsetsWithLayoutScale = new int[count];
- for (int i = 0; i < count; i++) {
- mChildOffsets[i] = -1;
- mChildRelativeOffsets[i] = -1;
- mChildOffsetsWithLayoutScale[i] = -1;
- }
- }
-
- protected int getChildOffset(int index) {
- int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
- mChildOffsets : mChildOffsetsWithLayoutScale;
-
- if (childOffsets != null && childOffsets[index] != -1) {
- return childOffsets[index];
- } else {
- if (getChildCount() == 0)
- return 0;
-
- int offset = getRelativeChildOffset(0);
- for (int i = 0; i < index; ++i) {
- offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
- }
- if (childOffsets != null) {
- childOffsets[index] = offset;
- }
- return offset;
- }
- }
-
- protected int getRelativeChildOffset(int index) {
- if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
- return mChildRelativeOffsets[index];
- } else {
- final int padding = getPaddingLeft() + getPaddingRight();
- final int offset = getPaddingLeft() +
- (getMeasuredWidth() - padding - getChildWidth(index)) / 2;
- if (mChildRelativeOffsets != null) {
- mChildRelativeOffsets[index] = offset;
- }
- return offset;
- }
- }
-
- protected int getScaledMeasuredWidth(View child) {
- // This functions are called enough times that it actually makes a difference in the
- // profiler -- so just inline the max() here
- final int measuredWidth = child.getMeasuredWidth();
- final int minWidth = mMinimumWidth;
- final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
- return (int) (maxWidth * mLayoutScale + 0.5f);
- }
-
- protected void getVisiblePages(int[] range) {
- final int pageCount = getChildCount();
-
- if (pageCount > 0) {
- final int screenWidth = getMeasuredWidth();
- int leftScreen = 0;
- int rightScreen = 0;
- View currPage = getPageAt(leftScreen);
- while (leftScreen < pageCount - 1 &&
- currPage.getX() + currPage.getWidth() -
- currPage.getPaddingRight() < getScrollX()) {
- leftScreen++;
- currPage = getPageAt(leftScreen);
- }
- rightScreen = leftScreen;
- currPage = getPageAt(rightScreen + 1);
- while (rightScreen < pageCount - 1 &&
- currPage.getX() - currPage.getPaddingLeft() < getScrollX() + screenWidth) {
- rightScreen++;
- currPage = getPageAt(rightScreen + 1);
- }
- range[0] = leftScreen;
- range[1] = rightScreen;
- } else {
- range[0] = -1;
- range[1] = -1;
- }
- }
-
- protected boolean shouldDrawChild(View child) {
- return child.getAlpha() > 0;
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- int halfScreenSize = getMeasuredWidth() / 2;
- // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
- // Otherwise it is equal to the scaled overscroll position.
- int screenCenter = mOverScrollX + halfScreenSize;
-
- if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
- // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
- // set it for the next frame
- mForceScreenScrolled = false;
- screenScrolled(screenCenter);
- mLastScreenCenter = screenCenter;
- }
-
- // Find out which screens are visible; as an optimization we only call draw on them
- final int pageCount = getChildCount();
- if (pageCount > 0) {
- getVisiblePages(mTempVisiblePagesRange);
- final int leftScreen = mTempVisiblePagesRange[0];
- final int rightScreen = mTempVisiblePagesRange[1];
- if (leftScreen != -1 && rightScreen != -1) {
- final long drawingTime = getDrawingTime();
- // Clip to the bounds
- canvas.save();
- canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
- getScrollY() + getBottom() - getTop());
-
- // On certain graphics drivers, if you draw to a off-screen buffer that's not
- // used, it can lead to poor performance. We were running into this when
- // setChildrenLayersEnabled was called on a CellLayout; that triggered a re-draw
- // of that CellLayout's hardware layer, even if that CellLayout wasn't visible.
- // As a fix, below we set pages that aren't going to be rendered are to be
- // View.INVISIBLE, preventing re-drawing of their hardware layer
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final View v = getPageAt(i);
- if (mForceDrawAllChildrenNextFrame ||
- (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
- v.setVisibility(VISIBLE);
- drawChild(canvas, v, drawingTime);
- } else {
- v.setVisibility(INVISIBLE);
- }
- }
- mForceDrawAllChildrenNextFrame = false;
- canvas.restore();
- }
- }
- }
-
- @Override
- public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
- int page = indexToPage(indexOfChild(child));
- if (page != mCurrentPage || !mScroller.isFinished()) {
- snapToPage(page);
- return true;
- }
- return false;
- }
-
- @Override
- protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- int focusablePage;
- if (mNextPage != INVALID_PAGE) {
- focusablePage = mNextPage;
- } else {
- focusablePage = mCurrentPage;
- }
- View v = getPageAt(focusablePage);
- if (v != null) {
- return v.requestFocus(direction, previouslyFocusedRect);
- }
- return false;
- }
-
- @Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- if (direction == View.FOCUS_LEFT) {
- if (getCurrentPage() > 0) {
- snapToPage(getCurrentPage() - 1);
- return true;
- }
- } else if (direction == View.FOCUS_RIGHT) {
- if (getCurrentPage() < getPageCount() - 1) {
- snapToPage(getCurrentPage() + 1);
- return true;
- }
- }
- return super.dispatchUnhandledMove(focused, direction);
- }
-
- @Override
- public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
- getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
- }
- if (direction == View.FOCUS_LEFT) {
- if (mCurrentPage > 0) {
- getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode);
- }
- } else if (direction == View.FOCUS_RIGHT){
- if (mCurrentPage < getPageCount() - 1) {
- getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode);
- }
- }
- }
-
- /**
- * If one of our descendant views decides that it could be focused now, only
- * pass that along if it's on the current page.
- *
- * This happens when live folders requery, and if they're off page, they
- * end up calling requestFocus, which pulls it on page.
- */
- @Override
- public void focusableViewAvailable(View focused) {
- View current = getPageAt(mCurrentPage);
- View v = focused;
- while (true) {
- if (v == current) {
- super.focusableViewAvailable(focused);
- return;
- }
- if (v == this) {
- return;
- }
- ViewParent parent = v.getParent();
- if (parent instanceof View) {
- v = (View)v.getParent();
- } else {
- return;
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- if (disallowIntercept) {
- // We need to make sure to cancel our long press if
- // a scrollable widget takes over touch events
- final View currentPage = getPageAt(mCurrentPage);
- currentPage.cancelLongPress();
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
- /**
- * Return true if a tap at (x, y) should trigger a flip to the previous page.
- */
- protected boolean hitsPreviousPage(float x, float y) {
- return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
- }
-
- /**
- * Return true if a tap at (x, y) should trigger a flip to the next page.
- */
- protected boolean hitsNextPage(float x, float y) {
- return (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- /*
- * This method JUST determines whether we want to intercept the motion.
- * If we return true, onTouchEvent will be called and we do the actual
- * scrolling there.
- */
- acquireVelocityTrackerAndAddMovement(ev);
-
- // Skip touch handling if there are no pages to swipe
- if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
-
- /*
- * Shortcut the most recurring case: the user is in the dragging
- * state and he is moving his finger. We want to intercept this
- * motion.
- */
- final int action = ev.getAction();
- if ((action == MotionEvent.ACTION_MOVE) &&
- (mTouchState == TOUCH_STATE_SCROLLING)) {
- return true;
- }
-
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_MOVE: {
- /*
- * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
- */
- if (mActivePointerId != INVALID_POINTER) {
- determineScrollingStart(ev);
- break;
- }
- // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
- // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
- // i.e. fall through to the next case (don't break)
- // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
- // while it's small- this was causing a crash before we checked for INVALID_POINTER)
- }
-
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- // Remember location of down touch
- mDownMotionX = x;
- mLastMotionX = x;
- mLastMotionY = y;
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
- mActivePointerId = ev.getPointerId(0);
- mAllowLongPress = true;
-
- /*
- * If being flinged and user touches the screen, initiate drag;
- * otherwise don't. mScroller.isFinished should be false when
- * being flinged.
- */
- final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
- final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
- if (finishedScrolling) {
- mTouchState = TOUCH_STATE_REST;
- mScroller.abortAnimation();
- } else {
- mTouchState = TOUCH_STATE_SCROLLING;
- }
-
- // check if this can be the beginning of a tap on the side of the pages
- // to scroll the current page
- if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
- if (getChildCount() > 0) {
- if (hitsPreviousPage(x, y)) {
- mTouchState = TOUCH_STATE_PREV_PAGE;
- } else if (hitsNextPage(x, y)) {
- mTouchState = TOUCH_STATE_NEXT_PAGE;
- }
- }
- }
- break;
- }
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mTouchState = TOUCH_STATE_REST;
- mAllowLongPress = false;
- mActivePointerId = INVALID_POINTER;
- releaseVelocityTracker();
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- releaseVelocityTracker();
- break;
- }
-
- /*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
- return mTouchState != TOUCH_STATE_REST;
- }
-
- protected void determineScrollingStart(MotionEvent ev) {
- determineScrollingStart(ev, 1.0f);
- }
-
- /*
- * Determines if we should change the touch state to start scrolling after the
- * user moves their touch point too far.
- */
- protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
- /*
- * Locally do absolute value. mLastMotionX is set to the y value
- * of the down event.
- */
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == -1) {
- return;
- }
- final float x = ev.getX(pointerIndex);
- final float y = ev.getY(pointerIndex);
- final int xDiff = (int) Math.abs(x - mLastMotionX);
- final int yDiff = (int) Math.abs(y - mLastMotionY);
-
- final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
- boolean xPaged = xDiff > mPagingTouchSlop;
- boolean xMoved = xDiff > touchSlop;
- boolean yMoved = yDiff > touchSlop;
-
- if (xMoved || xPaged || yMoved) {
- if (mUsePagingTouchSlop ? xPaged : xMoved) {
- // Scroll if the user moved far enough along the X axis
- mTouchState = TOUCH_STATE_SCROLLING;
- mTotalMotionX += Math.abs(mLastMotionX - x);
- mLastMotionX = x;
- mLastMotionXRemainder = 0;
- mTouchX = getScrollX();
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- pageBeginMoving();
- }
- // Either way, cancel any pending longpress
- cancelCurrentPageLongPress();
- }
- }
-
- protected void cancelCurrentPageLongPress() {
- if (mAllowLongPress) {
- mAllowLongPress = false;
- // Try canceling the long press. It could also have been scheduled
- // by a distant descendant, so use the mAllowLongPress flag to block
- // everything
- final View currentPage = getPageAt(mCurrentPage);
- if (currentPage != null) {
- currentPage.cancelLongPress();
- }
- }
- }
-
- protected float getScrollProgress(int screenCenter, View v, int page) {
- final int halfScreenSize = getMeasuredWidth() / 2;
-
- int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
- int delta = screenCenter - (getChildOffset(page) -
- getRelativeChildOffset(page) + halfScreenSize);
-
- float scrollProgress = delta / (totalDistance * 1.0f);
- scrollProgress = Math.min(scrollProgress, 1.0f);
- scrollProgress = Math.max(scrollProgress, -1.0f);
- return scrollProgress;
- }
-
- // This curve determines how the effect of scrolling over the limits of the page dimishes
- // as the user pulls further and further from the bounds
- private float overScrollInfluenceCurve(float f) {
- f -= 1.0f;
- return f * f * f + 1.0f;
- }
-
- protected void acceleratedOverScroll(float amount) {
- int screenSize = getMeasuredWidth();
-
- // We want to reach the max over scroll effect when the user has
- // over scrolled half the size of the screen
- float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
-
- if (f == 0) return;
-
- // Clamp this factor, f, to -1 < f < 1
- if (Math.abs(f) >= 1) {
- f /= Math.abs(f);
- }
-
- int overScrollAmount = (int) Math.round(f * screenSize);
- if (amount < 0) {
- mOverScrollX = overScrollAmount;
- super.scrollTo(0, getScrollY());
- } else {
- mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mMaxScrollX, getScrollY());
- }
- invalidate();
- }
-
- protected void dampedOverScroll(float amount) {
- int screenSize = getMeasuredWidth();
-
- float f = (amount / screenSize);
-
- if (f == 0) return;
- f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-
- // Clamp this factor, f, to -1 < f < 1
- if (Math.abs(f) >= 1) {
- f /= Math.abs(f);
- }
-
- int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
- if (amount < 0) {
- mOverScrollX = overScrollAmount;
- super.scrollTo(0, getScrollY());
- } else {
- mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mMaxScrollX, getScrollY());
- }
- invalidate();
- }
-
- protected void overScroll(float amount) {
- dampedOverScroll(amount);
- }
-
- protected float maxOverScroll() {
- // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
- // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
- float f = 1.0f;
- f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
- return OVERSCROLL_DAMP_FACTOR * f;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- // Skip touch handling if there are no pages to swipe
- if (getChildCount() <= 0) return super.onTouchEvent(ev);
-
- acquireVelocityTrackerAndAddMovement(ev);
-
- final int action = ev.getAction();
-
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
- // Remember where the motion event started
- mDownMotionX = mLastMotionX = ev.getX();
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
- mActivePointerId = ev.getPointerId(0);
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- pageBeginMoving();
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- // Scroll to follow the motion event
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- final float x = ev.getX(pointerIndex);
- final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
-
- mTotalMotionX += Math.abs(deltaX);
-
- // Only scroll and update mLastMotionX if we have moved some discrete amount. We
- // keep the remainder because we are actually testing if we've moved from the last
- // scrolled position (which is discrete).
- if (Math.abs(deltaX) >= 1.0f) {
- mTouchX += deltaX;
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- if (!mDeferScrollUpdate) {
- scrollBy((int) deltaX, 0);
- if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
- } else {
- invalidate();
- }
- mLastMotionX = x;
- mLastMotionXRemainder = deltaX - (int) deltaX;
- } else {
- awakenScrollBars();
- }
- } else {
- determineScrollingStart(ev);
- }
- break;
-
- case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- final int activePointerId = mActivePointerId;
- final int pointerIndex = ev.findPointerIndex(activePointerId);
- final float x = ev.getX(pointerIndex);
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
- final int deltaX = (int) (x - mDownMotionX);
- final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
- boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
- SIGNIFICANT_MOVE_THRESHOLD;
-
- mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
-
- boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
- Math.abs(velocityX) > mFlingThresholdVelocity;
-
- // In the case that the page is moved far to one direction and then is flung
- // in the opposite direction, we use a threshold to determine whether we should
- // just return to the starting page, or if we should skip one further.
- boolean returnToOriginalPage = false;
- if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
- Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
- returnToOriginalPage = true;
- }
-
- int finalPage;
- // We give flings precedence over large moves, which is why we short-circuit our
- // test for a large move if a fling has been registered. That is, a large
- // move to the left and fling to the right will register as a fling to the right.
- if (((isSignificantMove && deltaX > 0 && !isFling) ||
- (isFling && velocityX > 0)) && mCurrentPage > 0) {
- finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
- snapToPageWithVelocity(finalPage, velocityX);
- } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
- (isFling && velocityX < 0)) &&
- mCurrentPage < getChildCount() - 1) {
- finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
- snapToPageWithVelocity(finalPage, velocityX);
- } else {
- snapToDestination();
- }
- } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.max(0, mCurrentPage - 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
- } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
- } else {
- onUnhandledTap(ev);
- }
- mTouchState = TOUCH_STATE_REST;
- mActivePointerId = INVALID_POINTER;
- releaseVelocityTracker();
- break;
-
- case MotionEvent.ACTION_CANCEL:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- snapToDestination();
- }
- mTouchState = TOUCH_STATE_REST;
- mActivePointerId = INVALID_POINTER;
- releaseVelocityTracker();
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
- }
-
- return true;
- }
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event) {
- if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_SCROLL: {
- // Handle mouse (or ext. device) by shifting the page depending on the scroll
- final float vscroll;
- final float hscroll;
- if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
- vscroll = 0;
- hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
- } else {
- vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
- hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
- }
- if (hscroll != 0 || vscroll != 0) {
- if (hscroll > 0 || vscroll > 0) {
- scrollRight();
- } else {
- scrollLeft();
- }
- return true;
- }
- }
- }
- }
- return super.onGenericMotionEvent(event);
- }
-
- private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- }
-
- private void releaseVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
- MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- final int pointerId = ev.getPointerId(pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- // TODO: Make this decision more intelligent.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
- mLastMotionY = ev.getY(newPointerIndex);
- mLastMotionXRemainder = 0;
- mActivePointerId = ev.getPointerId(newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
-
- protected void onUnhandledTap(MotionEvent ev) {}
-
- @Override
- public void requestChildFocus(View child, View focused) {
- super.requestChildFocus(child, focused);
- int page = indexToPage(indexOfChild(child));
- if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
- snapToPage(page);
- }
- }
-
- protected int getChildIndexForRelativeOffset(int relativeOffset) {
- final int childCount = getChildCount();
- int left;
- int right;
- for (int i = 0; i < childCount; ++i) {
- left = getRelativeChildOffset(i);
- right = (left + getScaledMeasuredWidth(getPageAt(i)));
- if (left <= relativeOffset && relativeOffset <= right) {
- return i;
- }
- }
- return -1;
- }
-
- protected int getChildWidth(int index) {
- // This functions are called enough times that it actually makes a difference in the
- // profiler -- so just inline the max() here
- final int measuredWidth = getPageAt(index).getMeasuredWidth();
- final int minWidth = mMinimumWidth;
- return (minWidth > measuredWidth) ? minWidth : measuredWidth;
- }
-
- int getPageNearestToCenterOfScreen() {
- int minDistanceFromScreenCenter = Integer.MAX_VALUE;
- int minDistanceFromScreenCenterIndex = -1;
- int screenCenter = getScrollX() + (getMeasuredWidth() / 2);
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; ++i) {
- View layout = (View) getPageAt(i);
- int childWidth = getScaledMeasuredWidth(layout);
- int halfChildWidth = (childWidth / 2);
- int childCenter = getChildOffset(i) + halfChildWidth;
- int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
- if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
- minDistanceFromScreenCenter = distanceFromScreenCenter;
- minDistanceFromScreenCenterIndex = i;
- }
- }
- return minDistanceFromScreenCenterIndex;
- }
-
- protected void snapToDestination() {
- snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
- }
-
- private static class ScrollInterpolator implements Interpolator {
- public ScrollInterpolator() {
- }
-
- public float getInterpolation(float t) {
- t -= 1.0f;
- return t*t*t*t*t + 1;
- }
- }
-
- // We want the duration of the page snap animation to be influenced by the distance that
- // the screen has to travel, however, we don't want this duration to be effected in a
- // purely linear fashion. Instead, we use this method to moderate the effect that the distance
- // of travel has on the overall snap duration.
- float distanceInfluenceForSnapDuration(float f) {
- f -= 0.5f; // center the values about 0.
- f *= 0.3f * Math.PI / 2.0f;
- return (float) Math.sin(f);
- }
-
- protected void snapToPageWithVelocity(int whichPage, int velocity) {
- whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
- int halfScreenSize = getMeasuredWidth() / 2;
-
- if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
- if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
- + getMeasuredWidth() + ", " + getChildWidth(whichPage));
- final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
- int delta = newX - mUnboundedScrollX;
- int duration = 0;
-
- if (Math.abs(velocity) < mMinFlingVelocity) {
- // If the velocity is low enough, then treat this more as an automatic page advance
- // as opposed to an apparent physical response to flinging
- snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
- return;
- }
-
- // Here we compute a "distance" that will be used in the computation of the overall
- // snap duration. This is a function of the actual distance that needs to be traveled;
- // we keep this value close to half screen size in order to reduce the variance in snap
- // duration as a function of the distance the page needs to travel.
- float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize));
- float distance = halfScreenSize + halfScreenSize *
- distanceInfluenceForSnapDuration(distanceRatio);
-
- velocity = Math.abs(velocity);
- velocity = Math.max(mMinSnapVelocity, velocity);
-
- // we want the page's snap velocity to approximately match the velocity at which the
- // user flings, so we scale the duration by a value near to the derivative of the scroll
- // interpolator at zero, ie. 5. We use 4 to make it a little slower.
- duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-
- snapToPage(whichPage, delta, duration);
- }
-
- protected void snapToPage(int whichPage) {
- snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
- }
-
- protected void snapToPage(int whichPage, int duration) {
- whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
-
- if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
- if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getMeasuredWidth() + ", "
- + getChildWidth(whichPage));
- int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
- final int sX = mUnboundedScrollX;
- final int delta = newX - sX;
- snapToPage(whichPage, delta, duration);
- }
-
- protected void snapToPage(int whichPage, int delta, int duration) {
- mNextPage = whichPage;
-
- View focusedChild = getFocusedChild();
- if (focusedChild != null && whichPage != mCurrentPage &&
- focusedChild == getPageAt(mCurrentPage)) {
- focusedChild.clearFocus();
- }
-
- pageBeginMoving();
- awakenScrollBars(duration);
- if (duration == 0) {
- duration = Math.abs(delta);
- }
-
- if (!mScroller.isFinished()) mScroller.abortAnimation();
- mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
-
- // Load associated pages immediately if someone else is handling the scroll, otherwise defer
- // loading associated pages until the scroll settles
- if (mDeferScrollUpdate) {
- loadAssociatedPages(mNextPage);
- } else {
- mDeferLoadAssociatedPagesUntilScrollCompletes = true;
- }
- notifyPageSwitchListener();
- invalidate();
- }
-
- public void scrollLeft() {
- if (mScroller.isFinished()) {
- if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
- } else {
- if (mNextPage > 0) snapToPage(mNextPage - 1);
- }
- }
-
- public void scrollRight() {
- if (mScroller.isFinished()) {
- if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
- } else {
- if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
- }
- }
-
- public int getPageForView(View v) {
- int result = -1;
- if (v != null) {
- ViewParent vp = v.getParent();
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- if (vp == getPageAt(i)) {
- return i;
- }
- }
- }
- return result;
- }
-
- /**
- * @return True is long presses are still allowed for the current touch
- */
- public boolean allowLongPress() {
- return mAllowLongPress;
- }
-
- /**
- * Set true to allow long-press events to be triggered, usually checked by
- * {@link Launcher} to accept or block dpad-initiated long-presses.
- */
- public void setAllowLongPress(boolean allowLongPress) {
- mAllowLongPress = allowLongPress;
- }
-
- public static class SavedState extends BaseSavedState {
- int currentPage = -1;
-
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- private SavedState(Parcel in) {
- super(in);
- currentPage = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeInt(currentPage);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- protected void loadAssociatedPages(int page) {
- loadAssociatedPages(page, false);
- }
- protected void loadAssociatedPages(int page, boolean immediateAndOnly) {
- if (mContentIsRefreshable) {
- final int count = getChildCount();
- if (page < count) {
- int lowerPageBound = getAssociatedLowerPageBound(page);
- int upperPageBound = getAssociatedUpperPageBound(page);
- if (DEBUG) Log.d(TAG, "loadAssociatedPages: " + lowerPageBound + "/"
- + upperPageBound);
- // First, clear any pages that should no longer be loaded
- for (int i = 0; i < count; ++i) {
- Page layout = (Page) getPageAt(i);
- if ((i < lowerPageBound) || (i > upperPageBound)) {
- if (layout.getPageChildCount() > 0) {
- layout.removeAllViewsOnPage();
- }
- mDirtyPageContent.set(i, true);
- }
- }
- // Next, load any new pages
- for (int i = 0; i < count; ++i) {
- if ((i != page) && immediateAndOnly) {
- continue;
- }
- if (lowerPageBound <= i && i <= upperPageBound) {
- if (mDirtyPageContent.get(i)) {
- syncPageItems(i, (i == page) && immediateAndOnly);
- mDirtyPageContent.set(i, false);
- }
- }
- }
- }
- }
- }
-
- protected int getAssociatedLowerPageBound(int page) {
- return Math.max(0, page - 1);
- }
- protected int getAssociatedUpperPageBound(int page) {
- final int count = getChildCount();
- return Math.min(page + 1, count - 1);
- }
-
- /**
- * This method is called ONLY to synchronize the number of pages that the paged view has.
- * To actually fill the pages with information, implement syncPageItems() below. It is
- * guaranteed that syncPageItems() will be called for a particular page before it is shown,
- * and therefore, individual page items do not need to be updated in this method.
- */
- public abstract void syncPages();
-
- /**
- * This method is called to synchronize the items that are on a particular page. If views on
- * the page can be reused, then they should be updated within this method.
- */
- public abstract void syncPageItems(int page, boolean immediate);
-
- protected void invalidatePageData() {
- invalidatePageData(-1, false);
- }
- protected void invalidatePageData(int currentPage) {
- invalidatePageData(currentPage, false);
- }
- protected void invalidatePageData(int currentPage, boolean immediateAndOnly) {
- if (!mIsDataReady) {
- return;
- }
-
- if (mContentIsRefreshable) {
- // Force all scrolling-related behavior to end
- mScroller.forceFinished(true);
- mNextPage = INVALID_PAGE;
-
- // Update all the pages
- syncPages();
-
- // We must force a measure after we've loaded the pages to update the content width and
- // to determine the full scroll width
- measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
-
- // Set a new page as the current page if necessary
- if (currentPage > -1) {
- setCurrentPage(Math.min(getPageCount() - 1, currentPage));
- }
-
- // Mark each of the pages as dirty
- final int count = getChildCount();
- mDirtyPageContent.clear();
- for (int i = 0; i < count; ++i) {
- mDirtyPageContent.add(true);
- }
-
- // Load any pages that are necessary for the current window of views
- loadAssociatedPages(mCurrentPage, immediateAndOnly);
- requestLayout();
- }
- }
-
- protected View getScrollingIndicator() {
- // We use mHasScrollIndicator to prevent future lookups if there is no sibling indicator
- // found
- if (mHasScrollIndicator && mScrollIndicator == null) {
- ViewGroup parent = (ViewGroup) getParent();
- if (parent != null) {
- mScrollIndicator = (View) (parent.findViewById(R.id.paged_view_indicator));
- mHasScrollIndicator = mScrollIndicator != null;
- if (mHasScrollIndicator) {
- mScrollIndicator.setVisibility(View.VISIBLE);
- }
- }
- }
- return mScrollIndicator;
- }
-
- protected boolean isScrollingIndicatorEnabled() {
- return !LauncherApplication.isScreenLarge();
- }
-
- Runnable hideScrollingIndicatorRunnable = new Runnable() {
- @Override
- public void run() {
- hideScrollingIndicator(false);
- }
- };
- protected void flashScrollingIndicator(boolean animated) {
- removeCallbacks(hideScrollingIndicatorRunnable);
- showScrollingIndicator(!animated);
- postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration);
- }
-
- protected void showScrollingIndicator(boolean immediately) {
- mShouldShowScrollIndicator = true;
- mShouldShowScrollIndicatorImmediately = true;
- if (getChildCount() <= 1) return;
- if (!isScrollingIndicatorEnabled()) return;
-
- mShouldShowScrollIndicator = false;
- getScrollingIndicator();
- if (mScrollIndicator != null) {
- // Fade the indicator in
- updateScrollingIndicatorPosition();
- mScrollIndicator.setVisibility(View.VISIBLE);
- cancelScrollingIndicatorAnimations();
- if (immediately) {
- mScrollIndicator.setAlpha(1f);
- } else {
- mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
- mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
- mScrollIndicatorAnimator.start();
- }
- }
- }
-
- protected void cancelScrollingIndicatorAnimations() {
- if (mScrollIndicatorAnimator != null) {
- mScrollIndicatorAnimator.cancel();
- }
- }
-
- protected void hideScrollingIndicator(boolean immediately) {
- if (getChildCount() <= 1) return;
- if (!isScrollingIndicatorEnabled()) return;
-
- getScrollingIndicator();
- if (mScrollIndicator != null) {
- // Fade the indicator out
- updateScrollingIndicatorPosition();
- cancelScrollingIndicatorAnimations();
- if (immediately) {
- mScrollIndicator.setVisibility(View.INVISIBLE);
- mScrollIndicator.setAlpha(0f);
- } else {
- mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
- mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
- mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
- private boolean cancelled = false;
- @Override
- public void onAnimationCancel(android.animation.Animator animation) {
- cancelled = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!cancelled) {
- mScrollIndicator.setVisibility(View.INVISIBLE);
- }
- }
- });
- mScrollIndicatorAnimator.start();
- }
- }
- }
-
- /**
- * To be overridden by subclasses to determine whether the scroll indicator should stretch to
- * fill its space on the track or not.
- */
- protected boolean hasElasticScrollIndicator() {
- return true;
- }
-
- private void updateScrollingIndicator() {
- if (getChildCount() <= 1) return;
- if (!isScrollingIndicatorEnabled()) return;
-
- getScrollingIndicator();
- if (mScrollIndicator != null) {
- updateScrollingIndicatorPosition();
- }
- if (mShouldShowScrollIndicator) {
- showScrollingIndicator(mShouldShowScrollIndicatorImmediately);
- }
- }
-
- private void updateScrollingIndicatorPosition() {
- if (!isScrollingIndicatorEnabled()) return;
- if (mScrollIndicator == null) return;
- int numPages = getChildCount();
- int pageWidth = getMeasuredWidth();
- int lastChildIndex = Math.max(0, getChildCount() - 1);
- int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
- int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
- int indicatorWidth = mScrollIndicator.getMeasuredWidth() -
- mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight();
-
- float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX));
- int indicatorSpace = trackWidth / numPages;
- int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
- if (hasElasticScrollIndicator()) {
- if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) {
- mScrollIndicator.getLayoutParams().width = indicatorSpace;
- mScrollIndicator.requestLayout();
- }
- } else {
- int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2;
- indicatorPos += indicatorCenterOffset;
- }
- mScrollIndicator.setTranslationX(indicatorPos);
- }
-
- public void showScrollIndicatorTrack() {
- }
-
- public void hideScrollIndicatorTrack() {
- }
-
- /* Accessibility */
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setScrollable(getPageCount() > 1);
- if (getCurrentPage() < getPageCount() - 1) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- }
- if (getCurrentPage() > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
- }
- }
-
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setScrollable(true);
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- event.setFromIndex(mCurrentPage);
- event.setToIndex(mCurrentPage);
- event.setItemCount(getChildCount());
- }
- }
-
- @Override
- public boolean performAccessibilityAction(int action, Bundle arguments) {
- if (super.performAccessibilityAction(action, arguments)) {
- return true;
- }
- switch (action) {
- case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (getCurrentPage() < getPageCount() - 1) {
- scrollRight();
- return true;
- }
- } break;
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (getCurrentPage() > 0) {
- scrollLeft();
- return true;
- }
- } break;
- }
- return false;
- }
-
- protected String getCurrentPageDescription() {
- return String.format(getContext().getString(R.string.default_scroll_format),
- getNextPage() + 1, getChildCount());
- }
-
- @Override
- public boolean onHoverEvent(android.view.MotionEvent event) {
- return true;
- }
-}
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
deleted file mode 100644
index 6f73e6341..000000000
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ /dev/null
@@ -1,516 +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.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-
-import com.android.launcher.R;
-
-/**
- * An abstraction of the original CellLayout which supports laying out items
- * which span multiple cells into a grid-like layout. Also supports dimming
- * to give a preview of its contents.
- */
-public class PagedViewCellLayout extends ViewGroup implements Page {
- static final String TAG = "PagedViewCellLayout";
-
- private int mCellCountX;
- private int mCellCountY;
- private int mOriginalCellWidth;
- private int mOriginalCellHeight;
- private int mCellWidth;
- private int mCellHeight;
- private int mOriginalWidthGap;
- private int mOriginalHeightGap;
- private int mWidthGap;
- private int mHeightGap;
- private int mMaxGap;
- protected PagedViewCellLayoutChildren mChildren;
-
- public PagedViewCellLayout(Context context) {
- this(context, null);
- }
-
- public PagedViewCellLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- setAlwaysDrawnWithCacheEnabled(false);
-
- // setup default cell parameters
- Resources resources = context.getResources();
- mOriginalCellWidth = mCellWidth =
- resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
- mOriginalCellHeight = mCellHeight =
- resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
- mCellCountX = LauncherModel.getCellCountX();
- mCellCountY = LauncherModel.getCellCountY();
- mOriginalWidthGap = mOriginalHeightGap = mWidthGap = mHeightGap = -1;
- mMaxGap = resources.getDimensionPixelSize(R.dimen.apps_customize_max_gap);
-
- mChildren = new PagedViewCellLayoutChildren(context);
- mChildren.setCellDimensions(mCellWidth, mCellHeight);
- mChildren.setGap(mWidthGap, mHeightGap);
-
- addView(mChildren);
- }
-
- public int getCellWidth() {
- return mCellWidth;
- }
-
- public int getCellHeight() {
- return mCellHeight;
- }
-
- void destroyHardwareLayers() {
- // called when a page is no longer visible (triggered by loadAssociatedPages ->
- // removeAllViewsOnPage)
- setLayerType(LAYER_TYPE_NONE, null);
- }
-
- void createHardwareLayers() {
- // called when a page is visible (triggered by loadAssociatedPages -> syncPageItems)
- setLayerType(LAYER_TYPE_HARDWARE, null);
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- // Cancel long press for all children
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- child.cancelLongPress();
- }
- }
-
- public boolean addViewToCellLayout(View child, int index, int childId,
- PagedViewCellLayout.LayoutParams params) {
- final PagedViewCellLayout.LayoutParams lp = params;
-
- // Generate an id for each view, this assumes we have at most 256x256 cells
- // per workspace screen
- if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
- lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
- // If the horizontal or vertical span is set to -1, it is taken to
- // mean that it spans the extent of the CellLayout
- if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
- if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
-
- child.setId(childId);
- mChildren.addView(child, index, lp);
-
- return true;
- }
- return false;
- }
-
- @Override
- public void removeAllViewsOnPage() {
- mChildren.removeAllViews();
- destroyHardwareLayers();
- }
-
- @Override
- public void removeViewOnPageAt(int index) {
- mChildren.removeViewAt(index);
- }
-
- /**
- * Clears all the key listeners for the individual icons.
- */
- public void resetChildrenOnKeyListeners() {
- int childCount = mChildren.getChildCount();
- for (int j = 0; j < childCount; ++j) {
- mChildren.getChildAt(j).setOnKeyListener(null);
- }
- }
-
- @Override
- public int getPageChildCount() {
- return mChildren.getChildCount();
- }
-
- public PagedViewCellLayoutChildren getChildrenLayout() {
- return mChildren;
- }
-
- @Override
- public View getChildOnPageAt(int i) {
- return mChildren.getChildAt(i);
- }
-
- @Override
- public int indexOfChildOnPage(View v) {
- return mChildren.indexOfChild(v);
- }
-
- public int getCellCountX() {
- return mCellCountX;
- }
-
- public int getCellCountY() {
- return mCellCountY;
- }
-
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
- }
-
- int numWidthGaps = mCellCountX - 1;
- int numHeightGaps = mCellCountY - 1;
-
- if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
- int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
- int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
- int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
- int vFreeSpace = vSpace - (mCellCountY * mOriginalCellHeight);
- mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
- mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
-
- mChildren.setGap(mWidthGap, mHeightGap);
- } else {
- mWidthGap = mOriginalWidthGap;
- mHeightGap = mOriginalHeightGap;
- }
-
- // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
- int newWidth = widthSpecSize;
- int newHeight = heightSpecSize;
- if (widthSpecMode == MeasureSpec.AT_MOST) {
- newWidth = getPaddingLeft() + getPaddingRight() + (mCellCountX * mCellWidth) +
- ((mCellCountX - 1) * mWidthGap);
- newHeight = getPaddingTop() + getPaddingBottom() + (mCellCountY * mCellHeight) +
- ((mCellCountY - 1) * mHeightGap);
- setMeasuredDimension(newWidth, newHeight);
- }
-
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- int childWidthMeasureSpec =
- MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
- getPaddingRight(), MeasureSpec.EXACTLY);
- int childheightMeasureSpec =
- MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
- getPaddingBottom(), MeasureSpec.EXACTLY);
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
-
- setMeasuredDimension(newWidth, newHeight);
- }
-
- int getContentWidth() {
- return getWidthBeforeFirstLayout() + getPaddingLeft() + getPaddingRight();
- }
-
- int getContentHeight() {
- if (mCellCountY > 0) {
- return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
- }
- return 0;
- }
-
- int getWidthBeforeFirstLayout() {
- if (mCellCountX > 0) {
- return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
- }
- return 0;
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- child.layout(getPaddingLeft(), getPaddingTop(),
- r - l - getPaddingRight(), b - t - getPaddingBottom());
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean result = super.onTouchEvent(event);
- int count = getPageChildCount();
- if (count > 0) {
- // We only intercept the touch if we are tapping in empty space after the final row
- View child = getChildOnPageAt(count - 1);
- int bottom = child.getBottom();
- int numRows = (int) Math.ceil((float) getPageChildCount() / getCellCountX());
- if (numRows < getCellCountY()) {
- // Add a little bit of buffer if there is room for another row
- bottom += mCellHeight / 2;
- }
- result = result || (event.getY() < bottom);
- }
- return result;
- }
-
- public void enableCenteredContent(boolean enabled) {
- mChildren.enableCenteredContent(enabled);
- }
-
- @Override
- protected void setChildrenDrawingCacheEnabled(boolean enabled) {
- mChildren.setChildrenDrawingCacheEnabled(enabled);
- }
-
- public void setCellCount(int xCount, int yCount) {
- mCellCountX = xCount;
- mCellCountY = yCount;
- requestLayout();
- }
-
- public void setGap(int widthGap, int heightGap) {
- mOriginalWidthGap = mWidthGap = widthGap;
- mOriginalHeightGap = mHeightGap = heightGap;
- mChildren.setGap(widthGap, heightGap);
- }
-
- 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
- *
- * @param child The child that is being dragged
- */
- void onDragChild(View child) {
- PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
- lp.isDragging = true;
- }
-
- /**
- * Estimates the number of cells that the specified width would take up.
- */
- public int estimateCellHSpan(int width) {
- // We don't show the next/previous pages any more, so we use the full width, minus the
- // padding
- int availWidth = width - (getPaddingLeft() + getPaddingRight());
-
- // We know that we have to fit N cells with N-1 width gaps, so we just juggle to solve for N
- int n = Math.max(1, (availWidth + mWidthGap) / (mCellWidth + mWidthGap));
-
- // We don't do anything fancy to determine if we squeeze another row in.
- return n;
- }
-
- /**
- * Estimates the number of cells that the specified height would take up.
- */
- public int estimateCellVSpan(int height) {
- // The space for a page is the height - top padding (current page) - bottom padding (current
- // page)
- int availHeight = height - (getPaddingTop() + getPaddingBottom());
-
- // We know that we have to fit N cells with N-1 height gaps, so we juggle to solve for N
- int n = Math.max(1, (availHeight + mHeightGap) / (mCellHeight + mHeightGap));
-
- // We don't do anything fancy to determine if we squeeze another row in.
- return n;
- }
-
- /** Returns an estimated center position of the cell at the specified index */
- public int[] estimateCellPosition(int x, int y) {
- return new int[] {
- getPaddingLeft() + (x * mCellWidth) + (x * mWidthGap) + (mCellWidth / 2),
- getPaddingTop() + (y * mCellHeight) + (y * mHeightGap) + (mCellHeight / 2)
- };
- }
-
- public void calculateCellCount(int width, int height, int maxCellCountX, int maxCellCountY) {
- mCellCountX = Math.min(maxCellCountX, estimateCellHSpan(width));
- mCellCountY = Math.min(maxCellCountY, estimateCellVSpan(height));
- requestLayout();
- }
-
- /**
- * Estimates the width that the number of hSpan cells will take up.
- */
- public int estimateCellWidth(int hSpan) {
- // TODO: we need to take widthGap into effect
- return hSpan * mCellWidth;
- }
-
- /**
- * Estimates the height that the number of vSpan cells will take up.
- */
- public int estimateCellHeight(int vSpan) {
- // TODO: we need to take heightGap into effect
- return vSpan * mCellHeight;
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof PagedViewCellLayout.LayoutParams;
- }
-
- @Override
- protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
- return new PagedViewCellLayout.LayoutParams(p);
- }
-
- public static class LayoutParams extends ViewGroup.MarginLayoutParams {
- /**
- * Horizontal location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellX;
-
- /**
- * Vertical location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellY;
-
- /**
- * Number of cells spanned horizontally by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellHSpan;
-
- /**
- * Number of cells spanned vertically by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellVSpan;
-
- /**
- * Is this item currently being dragged
- */
- 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;
- // Y coordinate of the view in the layout.
- @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;
- cellVSpan = 1;
- }
-
- public LayoutParams(ViewGroup.LayoutParams source) {
- super(source);
- cellHSpan = 1;
- cellVSpan = 1;
- }
-
- public LayoutParams(LayoutParams source) {
- super(source);
- this.cellX = source.cellX;
- this.cellY = source.cellY;
- this.cellHSpan = source.cellHSpan;
- this.cellVSpan = source.cellVSpan;
- }
-
- public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
- super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- this.cellX = cellX;
- this.cellY = cellY;
- this.cellHSpan = cellHSpan;
- this.cellVSpan = cellVSpan;
- }
-
- public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
- int hStartPadding, int vStartPadding) {
-
- final int myCellHSpan = cellHSpan;
- final int myCellVSpan = cellVSpan;
- final int myCellX = cellX;
- final int myCellY = cellY;
-
- width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
- leftMargin - rightMargin;
- height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
- topMargin - bottomMargin;
-
- if (LauncherApplication.isScreenLarge()) {
- x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
- y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
- } else {
- x = myCellX * (cellWidth + widthGap) + leftMargin;
- y = myCellY * (cellHeight + heightGap) + topMargin;
- }
- }
-
- public Object getTag() {
- return mTag;
- }
-
- public void setTag(Object tag) {
- mTag = tag;
- }
-
- public String toString() {
- return "(" + this.cellX + ", " + this.cellY + ", " +
- this.cellHSpan + ", " + this.cellVSpan + ")";
- }
- }
-}
-
-interface Page {
- public int getPageChildCount();
- public View getChildOnPageAt(int i);
- public void removeAllViewsOnPage();
- public void removeViewOnPageAt(int i);
- public int indexOfChildOnPage(View v);
-}
diff --git a/src/com/android/launcher2/PagedViewCellLayoutChildren.java b/src/com/android/launcher2/PagedViewCellLayoutChildren.java
deleted file mode 100644
index 187a22d55..000000000
--- a/src/com/android/launcher2/PagedViewCellLayoutChildren.java
+++ /dev/null
@@ -1,160 +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.graphics.Rect;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * An abstraction of the original CellLayout which supports laying out items
- * which span multiple cells into a grid-like layout. Also supports dimming
- * to give a preview of its contents.
- */
-public class PagedViewCellLayoutChildren extends ViewGroup {
- static final String TAG = "PagedViewCellLayout";
-
- private boolean mCenterContent;
-
- private int mCellWidth;
- private int mCellHeight;
- private int mWidthGap;
- private int mHeightGap;
-
- public PagedViewCellLayoutChildren(Context context) {
- super(context);
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- // Cancel long press for all children
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- child.cancelLongPress();
- }
- }
-
- public void setGap(int widthGap, int heightGap) {
- mWidthGap = widthGap;
- mHeightGap = heightGap;
- requestLayout();
- }
-
- public void setCellDimensions(int width, int height) {
- mCellWidth = width;
- mCellHeight = height;
- requestLayout();
- }
-
- @Override
- public void requestChildFocus(View child, View focused) {
- super.requestChildFocus(child, focused);
- if (child != null) {
- Rect r = new Rect();
- child.getDrawingRect(r);
- requestRectangleOnScreen(r);
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
- }
-
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- PagedViewCellLayout.LayoutParams lp =
- (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
- lp.setup(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
- getPaddingLeft(),
- getPaddingTop());
-
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
- MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
- MeasureSpec.EXACTLY);
-
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
-
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int count = getChildCount();
-
- int offsetX = 0;
- if (mCenterContent && count > 0) {
- // determine the max width of all the rows and center accordingly
- int maxRowX = 0;
- int minRowX = Integer.MAX_VALUE;
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
- PagedViewCellLayout.LayoutParams lp =
- (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
- minRowX = Math.min(minRowX, lp.x);
- maxRowX = Math.max(maxRowX, lp.x + lp.width);
- }
- }
- int maxRowWidth = maxRowX - minRowX;
- offsetX = (getMeasuredWidth() - 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 = offsetX + lp.x;
- int childTop = lp.y;
- child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
- }
- }
- }
-
- public void enableCenteredContent(boolean enabled) {
- mCenterContent = enabled;
- }
-
- @Override
- protected void setChildrenDrawingCacheEnabled(boolean enabled) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View view = getChildAt(i);
- view.setDrawingCacheEnabled(enabled);
- // Update the drawing caches
- if (!view.isHardwareAccelerated()) {
- view.buildDrawingCache(true);
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/PagedViewGridLayout.java b/src/com/android/launcher2/PagedViewGridLayout.java
deleted file mode 100644
index 90bfe88ec..000000000
--- a/src/com/android/launcher2/PagedViewGridLayout.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.GridLayout;
-
-/**
- * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
- */
-public class PagedViewGridLayout extends GridLayout implements Page {
- static final String TAG = "PagedViewGridLayout";
-
- private int mCellCountX;
- private int mCellCountY;
- private Runnable mOnLayoutListener;
-
- public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
- super(context, null, 0);
- mCellCountX = cellCountX;
- mCellCountY = cellCountY;
- }
-
- int getCellCountX() {
- return mCellCountX;
- }
-
- int getCellCountY() {
- return mCellCountY;
- }
-
- /**
- * Clears all the key listeners for the individual widgets.
- */
- public void resetChildrenOnKeyListeners() {
- int childCount = getChildCount();
- for (int j = 0; j < childCount; ++j) {
- getChildAt(j).setOnKeyListener(null);
- }
- }
-
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // PagedView currently has issues with different-sized pages since it calculates the
- // offset of each page to scroll to before it updates the actual size of each page
- // (which can change depending on the content if the contents aren't a fixed size).
- // We work around this by having a minimum size on each widget page).
- int widthSpecSize = Math.min(getSuggestedMinimumWidth(),
- MeasureSpec.getSize(widthMeasureSpec));
- int widthSpecMode = MeasureSpec.EXACTLY;
- super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode),
- heightMeasureSpec);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mOnLayoutListener = null;
- }
-
- public void setOnLayoutListener(Runnable r) {
- mOnLayoutListener = r;
- }
-
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mOnLayoutListener != null) {
- mOnLayoutListener.run();
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean result = super.onTouchEvent(event);
- int count = getPageChildCount();
- if (count > 0) {
- // We only intercept the touch if we are tapping in empty space after the final row
- View child = getChildOnPageAt(count - 1);
- int bottom = child.getBottom();
- result = result || (event.getY() < bottom);
- }
- return result;
- }
-
- void destroyHardwareLayer() {
- setLayerType(LAYER_TYPE_NONE, null);
- }
-
- void createHardwareLayer() {
- setLayerType(LAYER_TYPE_HARDWARE, null);
- }
-
- @Override
- public void removeAllViewsOnPage() {
- removeAllViews();
- mOnLayoutListener = null;
- destroyHardwareLayer();
- }
-
- @Override
- public void removeViewOnPageAt(int index) {
- removeViewAt(index);
- }
-
- @Override
- public int getPageChildCount() {
- return getChildCount();
- }
-
- @Override
- public View getChildOnPageAt(int i) {
- return getChildAt(i);
- }
-
- @Override
- public int indexOfChildOnPage(View v) {
- return indexOfChild(v);
- }
-
- public static class LayoutParams extends FrameLayout.LayoutParams {
- public LayoutParams(int width, int height) {
- super(width, height);
- }
- }
-}
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
deleted file mode 100644
index d2aa31f86..000000000
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ /dev/null
@@ -1,92 +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.graphics.Bitmap;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-/**
- * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
- * drawables on the top).
- */
-public class PagedViewIcon extends TextView {
- /** A simple callback interface to allow a PagedViewIcon to notify when it has been pressed */
- public static interface PressedCallback {
- void iconPressed(PagedViewIcon icon);
- }
-
- @SuppressWarnings("unused")
- private static final String TAG = "PagedViewIcon";
- private static final float PRESS_ALPHA = 0.4f;
-
- private PagedViewIcon.PressedCallback mPressedCallback;
- private boolean mLockDrawableState = false;
-
- private Bitmap mIcon;
-
- public PagedViewIcon(Context context) {
- this(context, null);
- }
-
- public PagedViewIcon(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public void applyFromApplicationInfo(ApplicationInfo info, boolean scaleUp,
- PagedViewIcon.PressedCallback cb) {
- mIcon = info.iconBitmap;
- mPressedCallback = cb;
- setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
- setText(info.title);
- setTag(info);
- }
-
- public void lockDrawableState() {
- mLockDrawableState = true;
- }
-
- public void resetDrawableState() {
- mLockDrawableState = false;
- post(new Runnable() {
- @Override
- public void run() {
- refreshDrawableState();
- }
- });
- }
-
- protected void drawableStateChanged() {
- super.drawableStateChanged();
-
- // We keep in the pressed state until resetDrawableState() is called to reset the press
- // feedback
- if (isPressed()) {
- setAlpha(PRESS_ALPHA);
- if (mPressedCallback != null) {
- mPressedCallback.iconPressed(this);
- }
- } else if (!mLockDrawableState) {
- setAlpha(1f);
- }
- }
-}
diff --git a/src/com/android/launcher2/PagedViewIconCache.java b/src/com/android/launcher2/PagedViewIconCache.java
deleted file mode 100644
index d65f68baf..000000000
--- a/src/com/android/launcher2/PagedViewIconCache.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.pm.ComponentInfo;
-import android.content.pm.ResolveInfo;
-import android.graphics.Bitmap;
-
-/**
- * Simple cache mechanism for PagedView outlines.
- */
-public class PagedViewIconCache {
- public static class Key {
- public enum Type {
- ApplicationInfoKey,
- AppWidgetProviderInfoKey,
- ResolveInfoKey
- }
- private final ComponentName mComponentName;
- private final Type mType;
-
- public Key(ApplicationInfo info) {
- mComponentName = info.componentName;
- mType = Type.ApplicationInfoKey;
- }
- public Key(ResolveInfo info) {
- final ComponentInfo ci = info.activityInfo != null ? info.activityInfo :
- info.serviceInfo;
- mComponentName = new ComponentName(ci.packageName, ci.name);
- mType = Type.ResolveInfoKey;
- }
- public Key(AppWidgetProviderInfo info) {
- mComponentName = info.provider;
- mType = Type.AppWidgetProviderInfoKey;
- }
-
- private ComponentName getComponentName() {
- return mComponentName;
- }
- public boolean isKeyType(Type t) {
- return (mType == t);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof Key) {
- Key k = (Key) o;
- return mComponentName.equals(k.mComponentName);
- }
- return super.equals(o);
- }
- @Override
- public int hashCode() {
- return getComponentName().hashCode();
- }
- }
-
- private final HashMap<Key, Bitmap> mIconOutlineCache = new HashMap<Key, Bitmap>();
-
- public void clear() {
- for (Key key : mIconOutlineCache.keySet()) {
- mIconOutlineCache.get(key).recycle();
- }
- mIconOutlineCache.clear();
- }
- private void retainAll(HashSet<Key> keysToKeep, Key.Type t) {
- HashSet<Key> keysToRemove = new HashSet<Key>(mIconOutlineCache.keySet());
- keysToRemove.removeAll(keysToKeep);
- for (Key key : keysToRemove) {
- if (key.isKeyType(t)) {
- mIconOutlineCache.get(key).recycle();
- mIconOutlineCache.remove(key);
- }
- }
- }
- /** Removes all the keys to applications that aren't in the passed in collection */
- public void retainAllApps(ArrayList<ApplicationInfo> keys) {
- HashSet<Key> keysSet = new HashSet<Key>();
- for (ApplicationInfo info : keys) {
- keysSet.add(new Key(info));
- }
- retainAll(keysSet, Key.Type.ApplicationInfoKey);
- }
- /** Removes all the keys to shortcuts that aren't in the passed in collection */
- public void retainAllShortcuts(List<ResolveInfo> keys) {
- HashSet<Key> keysSet = new HashSet<Key>();
- for (ResolveInfo info : keys) {
- keysSet.add(new Key(info));
- }
- retainAll(keysSet, Key.Type.ResolveInfoKey);
- }
- /** Removes all the keys to widgets that aren't in the passed in collection */
- public void retainAllAppWidgets(List<AppWidgetProviderInfo> keys) {
- HashSet<Key> keysSet = new HashSet<Key>();
- for (AppWidgetProviderInfo info : keys) {
- keysSet.add(new Key(info));
- }
- retainAll(keysSet, Key.Type.AppWidgetProviderInfoKey);
- }
- public void addOutline(Key key, Bitmap b) {
- mIconOutlineCache.put(key, b);
- }
- public void removeOutline(Key key) {
- if (mIconOutlineCache.containsKey(key)) {
- mIconOutlineCache.get(key).recycle();
- mIconOutlineCache.remove(key);
- }
- }
- public Bitmap getOutline(Key key) {
- return mIconOutlineCache.get(key);
- }
-}
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
deleted file mode 100644
index 66b7080d4..000000000
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ /dev/null
@@ -1,223 +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.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-/**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
- */
-public class PagedViewWidget extends LinearLayout {
- static final String TAG = "PagedViewWidgetLayout";
-
- private static boolean sDeletePreviewsWhenDetachedFromWindow = true;
-
- private String mDimensionsFormatString;
- CheckForShortPress mPendingCheckForShortPress = null;
- ShortPressListener mShortPressListener = null;
- boolean mShortPressTriggered = false;
- static PagedViewWidget sShortpressTarget = null;
- boolean mIsAppWidget;
-
- public PagedViewWidget(Context context) {
- this(context, null);
- }
-
- public PagedViewWidget(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- final Resources r = context.getResources();
- mDimensionsFormatString = r.getString(R.string.widget_dims_format);
-
- setWillNotDraw(false);
- setClipToPadding(false);
- }
-
- public static void setDeletePreviewsWhenDetachedFromWindow(boolean value) {
- sDeletePreviewsWhenDetachedFromWindow = value;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- if (sDeletePreviewsWhenDetachedFromWindow) {
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- if (image != null) {
- FastBitmapDrawable preview = (FastBitmapDrawable) image.getDrawable();
- if (preview != null && preview.getBitmap() != null) {
- preview.getBitmap().recycle();
- }
- image.setImageDrawable(null);
- }
- }
- }
-
- public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info,
- int maxWidth, int[] cellSpan) {
- mIsAppWidget = true;
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- if (maxWidth > -1) {
- image.setMaxWidth(maxWidth);
- }
- image.setContentDescription(info.label);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(info.label);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- int hSpan = Math.min(cellSpan[0], LauncherModel.getCellCountX());
- int vSpan = Math.min(cellSpan[1], LauncherModel.getCellCountY());
- dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
- }
- }
-
- public void applyFromResolveInfo(PackageManager pm, ResolveInfo info) {
- mIsAppWidget = false;
- CharSequence label = info.loadLabel(pm);
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- image.setContentDescription(label);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(label);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- dims.setText(String.format(mDimensionsFormatString, 1, 1));
- }
- }
-
- public int[] getPreviewSize() {
- final ImageView i = (ImageView) findViewById(R.id.widget_preview);
- int[] maxSize = new int[2];
- maxSize[0] = i.getWidth() - i.getPaddingLeft() - i.getPaddingRight();
- maxSize[1] = i.getHeight() - i.getPaddingTop();
- return maxSize;
- }
-
- void applyPreview(FastBitmapDrawable preview, int index) {
- final PagedViewWidgetImageView image =
- (PagedViewWidgetImageView) findViewById(R.id.widget_preview);
- if (preview != null) {
- image.mAllowRequestLayout = false;
- image.setImageDrawable(preview);
- if (mIsAppWidget) {
- // center horizontally
- int[] imageSize = getPreviewSize();
- int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
- image.setPadding(image.getPaddingLeft() + centerAmount,
- image.getPaddingTop(),
- image.getPaddingRight(),
- image.getPaddingBottom());
- }
- image.setAlpha(1f);
- image.mAllowRequestLayout = true;
- }
- }
-
- void setShortPressListener(ShortPressListener listener) {
- mShortPressListener = listener;
- }
-
- interface ShortPressListener {
- void onShortPress(View v);
- void cleanUpShortPress(View v);
- }
-
- class CheckForShortPress implements Runnable {
- public void run() {
- if (sShortpressTarget != null) return;
- if (mShortPressListener != null) {
- mShortPressListener.onShortPress(PagedViewWidget.this);
- sShortpressTarget = PagedViewWidget.this;
- }
- mShortPressTriggered = true;
- }
- }
-
- private void checkForShortPress() {
- if (sShortpressTarget != null) return;
- if (mPendingCheckForShortPress == null) {
- mPendingCheckForShortPress = new CheckForShortPress();
- }
- postDelayed(mPendingCheckForShortPress, 120);
- }
-
- /**
- * Remove the longpress detection timer.
- */
- private void removeShortPressCallback() {
- if (mPendingCheckForShortPress != null) {
- removeCallbacks(mPendingCheckForShortPress);
- }
- }
-
- private void cleanUpShortPress() {
- removeShortPressCallback();
- if (mShortPressTriggered) {
- if (mShortPressListener != null) {
- mShortPressListener.cleanUpShortPress(PagedViewWidget.this);
- }
- mShortPressTriggered = false;
- }
- }
-
- static void resetShortPressTarget() {
- sShortpressTarget = null;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_DOWN:
- checkForShortPress();
- break;
- case MotionEvent.ACTION_CANCEL:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- }
-
- // We eat up the touch events here, since the PagedView (which uses the same swiping
- // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
- // the user is scrolling between pages. This means that if the pages themselves don't
- // handle touch events, it gets forwarded up to PagedView itself, and it's own
- // onTouchEvent() handling will prevent further intercept touch events from being called
- // (it's the same view in that case). This is not ideal, but to prevent more changes,
- // we just always mark the touch event as handled.
- return true;
- }
-}
diff --git a/src/com/android/launcher2/PagedViewWidgetImageView.java b/src/com/android/launcher2/PagedViewWidgetImageView.java
deleted file mode 100644
index 22db0abd8..000000000
--- a/src/com/android/launcher2/PagedViewWidgetImageView.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Insets;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-
-
-class PagedViewWidgetImageView extends ImageView {
- public boolean mAllowRequestLayout = true;
-
- public PagedViewWidgetImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void requestLayout() {
- if (mAllowRequestLayout) {
- super.requestLayout();
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
-
- Insets insets = Insets.NONE;
- if (getBackground() != null) {
- insets = getBackground().getLayoutInsets();
- }
- canvas.save();
- canvas.clipRect(getScrollX() + getPaddingLeft() + insets.left,
- getScrollY() + getPaddingTop() + insets.top,
- getScrollX() + getRight() - getLeft() - getPaddingRight() - insets.right,
- getScrollY() + getBottom() - getTop() - getPaddingBottom() - insets.bottom);
-
- super.onDraw(canvas);
- canvas.restore();
-
- }
-}
diff --git a/src/com/android/launcher2/PagedViewWithDraggableItems.java b/src/com/android/launcher2/PagedViewWithDraggableItems.java
deleted file mode 100644
index 22fd82b69..000000000
--- a/src/com/android/launcher2/PagedViewWithDraggableItems.java
+++ /dev/null
@@ -1,178 +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.view.View;
-
-
-/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
- * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
- * Subclasses must do the following:
- * * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
- * * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
- * (good place to do it is in syncPageItems)
- * * override beginDragging(View) (but be careful to call super.beginDragging(View)
- *
- */
-public abstract class PagedViewWithDraggableItems extends PagedView
- implements View.OnLongClickListener, View.OnTouchListener {
- private View mLastTouchedItem;
- private boolean mIsDragging;
- private boolean mIsDragEnabled;
- private float mDragSlopeThreshold;
- private Launcher mLauncher;
-
- public PagedViewWithDraggableItems(Context context) {
- this(context, null);
- }
-
- public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mLauncher = (Launcher) context;
- }
-
- protected boolean beginDragging(View v) {
- boolean wasDragging = mIsDragging;
- mIsDragging = true;
- return !wasDragging;
- }
-
- protected void cancelDragging() {
- mIsDragging = false;
- mLastTouchedItem = null;
- mIsDragEnabled = false;
- }
-
- private void handleTouchEvent(MotionEvent ev) {
- final int action = ev.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- cancelDragging();
- mIsDragEnabled = true;
- break;
- case MotionEvent.ACTION_MOVE:
- if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) {
- determineDraggingStart(ev);
- }
- break;
- }
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- handleTouchEvent(ev);
- return super.onInterceptTouchEvent(ev);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- handleTouchEvent(ev);
- return super.onTouchEvent(ev);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mLastTouchedItem = v;
- mIsDragEnabled = true;
- return false;
- }
-
- @Override
- public boolean onLongClick(View v) {
- // Return early if this is not initiated from a touch
- if (!v.isInTouchMode()) return false;
- // Return early if we are still animating the pages
- if (mNextPage != INVALID_PAGE) return false;
- // When we have exited all apps or are in transition, disregard long clicks
- if (!mLauncher.isAllAppsCustomizeOpen() ||
- mLauncher.getWorkspace().isSwitchingState()) return false;
- // Return if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return false;
-
- return beginDragging(v);
- }
-
- /*
- * Determines if we should change the touch state to start scrolling after the
- * user moves their touch point too far.
- */
- protected void determineScrollingStart(MotionEvent ev) {
- if (!mIsDragging) super.determineScrollingStart(ev);
- }
-
- /*
- * Determines if we should change the touch state to start dragging after the
- * user moves their touch point far enough.
- */
- protected void determineDraggingStart(MotionEvent ev) {
- /*
- * Locally do absolute value. mLastMotionX is set to the y value
- * of the down event.
- */
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- final float x = ev.getX(pointerIndex);
- final float y = ev.getY(pointerIndex);
- final int xDiff = (int) Math.abs(x - mLastMotionX);
- final int yDiff = (int) Math.abs(y - mLastMotionY);
-
- final int touchSlop = mTouchSlop;
- boolean yMoved = yDiff > touchSlop;
- boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
-
- if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
- // Drag if the user moved far enough along the Y axis
- beginDragging(mLastTouchedItem);
-
- // Cancel any pending long press
- if (mAllowLongPress) {
- mAllowLongPress = false;
- // Try canceling the long press. It could also have been scheduled
- // by a distant descendant, so use the mAllowLongPress flag to block
- // everything
- final View currentPage = getPageAt(mCurrentPage);
- if (currentPage != null) {
- currentPage.cancelLongPress();
- }
- }
- }
- }
-
- public void setDragSlopeThreshold(float dragSlopeThreshold) {
- mDragSlopeThreshold = dragSlopeThreshold;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- cancelDragging();
- super.onDetachedFromWindow();
- }
-
- /** Show the scrolling indicators when we move the page */
- protected void onPageBeginMoving() {
- showScrollingIndicator(false);
- }
- protected void onPageEndMoving() {
- hideScrollingIndicator(false);
- }
-}
diff --git a/src/com/android/launcher2/PendingAddItemInfo.java b/src/com/android/launcher2/PendingAddItemInfo.java
deleted file mode 100644
index 9a133ed27..000000000
--- a/src/com/android/launcher2/PendingAddItemInfo.java
+++ /dev/null
@@ -1,104 +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.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.os.Parcelable;
-
-/**
- * We pass this object with a drag from the customization tray
- */
-class PendingAddItemInfo extends ItemInfo {
- /**
- * The component that will be created.
- */
- ComponentName componentName;
-}
-
-class PendingAddShortcutInfo extends PendingAddItemInfo {
-
- ActivityInfo shortcutActivityInfo;
-
- public PendingAddShortcutInfo(ActivityInfo activityInfo) {
- shortcutActivityInfo = activityInfo;
- }
-
- @Override
- public String toString() {
- return "Shortcut: " + shortcutActivityInfo.packageName;
- }
-}
-
-class PendingAddWidgetInfo extends PendingAddItemInfo {
- int minWidth;
- int minHeight;
- int minResizeWidth;
- int minResizeHeight;
- int previewImage;
- int icon;
- AppWidgetProviderInfo info;
- AppWidgetHostView boundWidget;
-
- // Any configuration data that we want to pass to a configuration activity when
- // starting up a widget
- String mimeType;
- Parcelable configurationData;
-
- public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
- this.info = i;
- componentName = i.provider;
- minWidth = i.minWidth;
- minHeight = i.minHeight;
- minResizeWidth = i.minResizeWidth;
- minResizeHeight = i.minResizeHeight;
- previewImage = i.previewImage;
- icon = i.icon;
- if (dataMimeType != null && data != null) {
- mimeType = dataMimeType;
- configurationData = data;
- }
- }
-
- // Copy constructor
- public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
- minWidth = copy.minWidth;
- minHeight = copy.minHeight;
- minResizeWidth = copy.minResizeWidth;
- minResizeHeight = copy.minResizeHeight;
- previewImage = copy.previewImage;
- icon = copy.icon;
- info = copy.info;
- boundWidget = copy.boundWidget;
- mimeType = copy.mimeType;
- configurationData = copy.configurationData;
- componentName = copy.componentName;
- itemType = copy.itemType;
- spanX = copy.spanX;
- spanY = copy.spanY;
- minSpanX = copy.minSpanX;
- minSpanY = copy.minSpanY;
- }
-
- @Override
- public String toString() {
- return "Widget: " + componentName.toShortString();
- }
-}
diff --git a/src/com/android/launcher2/PreloadReceiver.java b/src/com/android/launcher2/PreloadReceiver.java
deleted file mode 100644
index d1bc6393d..000000000
--- a/src/com/android/launcher2/PreloadReceiver.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 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.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-public class PreloadReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final LauncherApplication app = (LauncherApplication) context.getApplicationContext();
- final LauncherProvider provider = app.getLauncherProvider();
- if (provider != null) {
- new Thread(new Runnable() {
- public void run() {
- provider.loadDefaultFavoritesIfNecessary();
- }
- }).start();
- }
- }
-}
diff --git a/src/com/android/launcher2/RocketLauncher.java b/src/com/android/launcher2/RocketLauncher.java
deleted file mode 100644
index 268769d2f..000000000
--- a/src/com/android/launcher2/RocketLauncher.java
+++ /dev/null
@@ -1,417 +0,0 @@
-/*);
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO:
-// background stellar matter:
-// - add some slow horizontal parallax motion, or perhaps veeeeery gradual outward drift
-
-package com.android.launcher2;
-
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeAnimator;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.support.v13.dreams.BasicDream;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.launcher.R;
-
-import java.util.HashMap;
-import java.util.Random;
-
-public class RocketLauncher extends BasicDream {
- public static final boolean ROCKET_LAUNCHER = true;
-
- public static class Board extends FrameLayout
- {
- public static final boolean FIXED_STARS = true;
- public static final boolean FLYING_STARS = true;
- public static final int NUM_ICONS = 20;
-
- public static final float MANEUVERING_THRUST_SCALE = 0.1f; // tenth speed
- private boolean mManeuveringThrusters = false;
- private float mSpeedScale = 1.0f;
-
- public static final int LAUNCH_ZOOM_TIME = 400; // ms
-
- HashMap<ComponentName, Bitmap> mIcons;
- ComponentName[] mComponentNames;
-
- static Random sRNG = new Random();
-
- static float lerp(float a, float b, float f) {
- return (b-a)*f + a;
- }
-
- static float randfrange(float a, float b) {
- return lerp(a, b, sRNG.nextFloat());
- }
-
- static int randsign() {
- return sRNG.nextBoolean() ? 1 : -1;
- }
-
- static <E> E pick(E[] array) {
- if (array.length == 0) return null;
- return array[sRNG.nextInt(array.length)];
- }
-
- public class FlyingIcon extends ImageView {
- public static final float VMAX = 1000.0f;
- public static final float VMIN = 100.0f;
- public static final float ANGULAR_VMAX = 45f;
- public static final float ANGULAR_VMIN = 0f;
- public static final float SCALE_MIN = 0.5f;
- public static final float SCALE_MAX = 4f;
-
- public float v, vr;
-
- public final float[] hsv = new float[3];
-
- public float angle, anglex, angley;
- public float fuse;
- public float dist;
- public float endscale;
- public float boardCenterX, boardCenterY;
-
- public ComponentName component;
-
- public FlyingIcon(Context context, AttributeSet as) {
- super(context, as);
- setLayerType(View.LAYER_TYPE_HARDWARE, null);
-
- setBackgroundResource(R.drawable.flying_icon_bg);
- //android.util.Log.d("RocketLauncher", "ctor: " + this);
- hsv[1] = 1f;
- hsv[2] = 1f;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!mManeuveringThrusters || component == null) {
- return false;
- }
- if (getAlpha() < 0.5f) {
- setPressed(false);
- return false;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- setPressed(true);
- Board.this.resetWarpTimer();
- break;
- case MotionEvent.ACTION_MOVE:
- final Rect hit = new Rect();
- final Point offset = new Point();
- getGlobalVisibleRect(hit, offset);
- final int globx = (int) event.getX() + offset.x;
- final int globy = (int) event.getY() + offset.y;
- setPressed(hit.contains(globx, globy));
- Board.this.resetWarpTimer();
- break;
- case MotionEvent.ACTION_UP:
- if (isPressed()) {
- setPressed(false);
- postDelayed(new Runnable() {
- public void run() {
- try {
- getContext().startActivity(new Intent(Intent.ACTION_MAIN)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .setComponent(component));
- } catch (android.content.ActivityNotFoundException e) {
- } catch (SecurityException e) {
- }
- }
- }, LAUNCH_ZOOM_TIME);
- endscale = 0;
- AnimatorSet s = new AnimatorSet();
- s.playTogether(
- ObjectAnimator.ofFloat(this, "scaleX", 15f),
- ObjectAnimator.ofFloat(this, "scaleY", 15f),
- ObjectAnimator.ofFloat(this, "alpha", 0f)
- );
-
- // make sure things are still moving until the very last instant the
- // activity is visible
- s.setDuration((int)(LAUNCH_ZOOM_TIME * 1.25));
- s.setInterpolator(new android.view.animation.AccelerateInterpolator(3));
- s.start();
- }
- break;
- }
- return true;
- }
-
- public String toString() {
- return String.format("<'%s' @ (%.1f, %.1f) v=%.1f a=%.1f dist/fuse=%.1f/%.1f>",
- "icon", getX(), getY(), v, angle, dist, fuse);
- }
-
- public void randomizeIcon() {
- component = pick(mComponentNames);
- setImageBitmap(mIcons.get(component));
- }
-
- public void randomize() {
- v = randfrange(VMIN, VMAX);
- angle = randfrange(0, 360f);
- anglex = (float) Math.sin(angle / 180. * Math.PI);
- angley = (float) Math.cos(angle / 180. * Math.PI);
- vr = randfrange(ANGULAR_VMIN, ANGULAR_VMAX) * randsign();
- endscale = randfrange(SCALE_MIN, SCALE_MAX);
-
- randomizeIcon();
- }
- public void reset() {
- randomize();
- boardCenterX = (Board.this.getWidth() - getWidth()) / 2;
- boardCenterY = (Board.this.getHeight() - getHeight()) / 2;
- setX(boardCenterX);
- setY(boardCenterY);
- fuse = (float) Math.max(boardCenterX, boardCenterY);
- setRotation(180-angle);
- setScaleX(0f);
- setScaleY(0f);
- dist = 0;
- setAlpha(0f);
- }
- public void update(float dt) {
- dist += v * dt;
- setX(getX() + anglex * v * dt);
- setY(getY() + angley * v * dt);
- //setRotation(getRotation() + vr * dt);
- if (endscale > 0) {
- float scale = lerp(0, endscale, (float) Math.sqrt(dist / fuse));
- setScaleX(scale * lerp(1f, 0.75f, (float) Math.pow((v-VMIN)/(VMAX-VMIN),3)));
- setScaleY(scale * lerp(1f, 1.5f, (float) Math.pow((v-VMIN)/(VMAX-VMIN),3)));
- final float q1 = fuse*0.15f;
- final float q4 = fuse*0.75f;
- if (dist < q1) {
- setAlpha((float) Math.sqrt(dist/q1));
- } else if (dist > q4) {
- setAlpha((dist >= fuse) ? 0f : (1f-(float)Math.pow((dist-q4)/(fuse-q4),2)));
- } else {
- setAlpha(1f);
- }
- }
- }
- }
-
- public class FlyingStar extends FlyingIcon {
- public FlyingStar(Context context, AttributeSet as) {
- super(context, as);
- }
- public void randomizeIcon() {
- setImageResource(R.drawable.widget_resize_handle_bottom);
- }
- public void randomize() {
- super.randomize();
- v = randfrange(VMAX*0.75f, VMAX*2f); // fasticate
- endscale = randfrange(1f, 2f); // ensmallen
- }
- }
-
- TimeAnimator mAnim;
-
- public Board(Context context, AttributeSet as) {
- super(context, as);
-
- setBackgroundColor(0xFF000000);
-
- LauncherApplication app = (LauncherApplication)context.getApplicationContext();
- mIcons = app.getIconCache().getAllIcons();
- mComponentNames = new ComponentName[mIcons.size()];
- mComponentNames = mIcons.keySet().toArray(mComponentNames);
- }
-
- private void reset() {
- removeAllViews();
-
- final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
-
- if (FIXED_STARS) {
- for(int i=0; i<20; i++) {
- ImageView fixedStar = new ImageView(getContext(), null);
- fixedStar.setImageResource(R.drawable.widget_resize_handle_bottom);
- final float s = randfrange(0.25f, 0.75f);
- fixedStar.setScaleX(s);
- fixedStar.setScaleY(s);
- fixedStar.setAlpha(0.75f);
- addView(fixedStar, wrap);
- fixedStar.setX(randfrange(0, getWidth()));
- fixedStar.setY(randfrange(0, getHeight()));
- }
- }
-
- for(int i=0; i<NUM_ICONS*2; i++) {
- FlyingIcon nv = (FLYING_STARS && (i < NUM_ICONS))
- ? new FlyingStar(getContext(), null)
- : new FlyingIcon(getContext(), null);
- addView(nv, wrap);
- nv.reset();
- }
-
- mAnim = new TimeAnimator();
- mAnim.setTimeListener(new TimeAnimator.TimeListener() {
- public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
- // setRotation(totalTime * 0.01f); // not as cool as you would think
-
- final int START_ZOOM_TIME = 3000;
- if (totalTime < START_ZOOM_TIME) {
- final float x = totalTime/(float)START_ZOOM_TIME;
- final float s = 1f-(float)Math.pow(x-1, 4);
- setScaleX(s); setScaleY(s);
- } else {
- setScaleX(1.0f); setScaleY(1.0f);
- }
-
- if (mManeuveringThrusters) {
- if (mSpeedScale > MANEUVERING_THRUST_SCALE) {
- mSpeedScale -= (2*deltaTime/1000f);
- }
- if (mSpeedScale < MANEUVERING_THRUST_SCALE) {
- mSpeedScale = MANEUVERING_THRUST_SCALE;
- }
- } else {
- if (mSpeedScale < 1.0f) {
- mSpeedScale += (deltaTime/1000f);
- }
- if (mSpeedScale > 1.0f) {
- mSpeedScale = 1.0f;
- }
- }
-
- for (int i=0; i<getChildCount(); i++) {
- View v = getChildAt(i);
- if (!(v instanceof FlyingIcon)) continue;
- FlyingIcon nv = (FlyingIcon) v;
- nv.update(deltaTime / 1000f * mSpeedScale);
- final float scaledWidth = nv.getWidth() * nv.getScaleX();
- final float scaledHeight = nv.getHeight() * nv.getScaleY();
- if ( nv.getX() + scaledWidth < 0
- || nv.getX() - scaledWidth > getWidth()
- || nv.getY() + scaledHeight < 0
- || nv.getY() - scaledHeight > getHeight())
- {
- nv.reset();
- }
- }
- }
- });
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- setLayerType(View.LAYER_TYPE_HARDWARE, null);
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
-
- reset();
- mAnim.start();
- }
-
- protected void onSizeChanged (int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w,h,oldw,oldh);
- mAnim.cancel();
- reset();
- mAnim.start();
- }
-
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mAnim.cancel();
- }
-
- @Override
- public boolean isOpaque() {
- return true;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent e) {
- // we want to eat touch events ourselves if we're in warp speed
- return (!(ROCKET_LAUNCHER && mManeuveringThrusters));
- }
-
- final Runnable mEngageWarp = new Runnable() {
- @Override
- public void run() {
- mManeuveringThrusters = false;
- }
- };
- public void resetWarpTimer() {
- final Handler h = getHandler();
- h.removeCallbacks(mEngageWarp);
- h.postDelayed(mEngageWarp, 5000);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!ROCKET_LAUNCHER) {
- return true;
- }
-
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (!mManeuveringThrusters) {
- mManeuveringThrusters = true;
- resetWarpTimer();
- return true;
- }
- }
-
- return false;
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- final int longside = metrics.widthPixels > metrics.heightPixels
- ? metrics.widthPixels : metrics.heightPixels;
-
- Board b = new Board(this, null);
- setContentView(b, new ViewGroup.LayoutParams(longside, longside));
- b.setX((metrics.widthPixels - longside) / 2);
- b.setY((metrics.heightPixels - longside) / 2);
- }
-
- @Override
- public void onUserInteraction() {
- if (!ROCKET_LAUNCHER) {
- finish();
- }
- }
-}
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
deleted file mode 100644
index a1d36cdfa..000000000
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.FrameLayout;
-
-import com.android.launcher.R;
-
-/*
- * Ths bar will manage the transition between the QSB search bar and the delete drop
- * targets so that each of the individual IconDropTargets don't have to.
- */
-public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
-
- private static final int sTransitionInDuration = 200;
- private static final int sTransitionOutDuration = 175;
-
- private ObjectAnimator mDropTargetBarAnim;
- private ObjectAnimator mQSBSearchBarAnim;
- private static final AccelerateInterpolator sAccelerateInterpolator =
- new AccelerateInterpolator();
-
- private boolean mIsSearchBarHidden;
- private View mQSBSearchBar;
- private View mDropTargetBar;
- private ButtonDropTarget mInfoDropTarget;
- private ButtonDropTarget mDeleteDropTarget;
- private int mBarHeight;
- private boolean mDeferOnDragEnd = false;
-
- private Drawable mPreviousBackground;
- private boolean mEnableDropDownDropTargets;
-
- public SearchDropTargetBar(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SearchDropTargetBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public void setup(Launcher launcher, DragController dragController) {
- dragController.addDragListener(this);
- dragController.addDragListener(mInfoDropTarget);
- dragController.addDragListener(mDeleteDropTarget);
- dragController.addDropTarget(mInfoDropTarget);
- dragController.addDropTarget(mDeleteDropTarget);
- dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
- mInfoDropTarget.setLauncher(launcher);
- mDeleteDropTarget.setLauncher(launcher);
- }
-
- private void prepareStartAnimation(View v) {
- // Enable the hw layers before the animation starts (will be disabled in the onAnimationEnd
- // callback below)
- v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- v.buildLayer();
- }
-
- private void setupAnimation(ObjectAnimator anim, final View v) {
- anim.setInterpolator(sAccelerateInterpolator);
- anim.setDuration(sTransitionInDuration);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- v.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- });
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- // Get the individual components
- mQSBSearchBar = findViewById(R.id.qsb_search_bar);
- mDropTargetBar = findViewById(R.id.drag_target_bar);
- mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
- mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
- mBarHeight = getResources().getDimensionPixelSize(R.dimen.qsb_bar_height);
-
- mInfoDropTarget.setSearchDropTargetBar(this);
- mDeleteDropTarget.setSearchDropTargetBar(this);
-
- mEnableDropDownDropTargets =
- getResources().getBoolean(R.bool.config_useDropTargetDownTransition);
-
- // Create the various fade animations
- if (mEnableDropDownDropTargets) {
- mDropTargetBar.setTranslationY(-mBarHeight);
- mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY",
- -mBarHeight, 0f);
- mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY", 0,
- -mBarHeight);
- } else {
- mDropTargetBar.setAlpha(0f);
- mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
- mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
- }
- setupAnimation(mDropTargetBarAnim, mDropTargetBar);
- setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
- }
-
- public void finishAnimations() {
- prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.reverse();
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
- }
-
- /*
- * Shows and hides the search bar.
- */
- public void showSearchBar(boolean animated) {
- if (!mIsSearchBarHidden) return;
- if (animated) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
- } else {
- mQSBSearchBarAnim.cancel();
- if (mEnableDropDownDropTargets) {
- mQSBSearchBar.setTranslationY(0);
- } else {
- mQSBSearchBar.setAlpha(1f);
- }
- }
- mIsSearchBarHidden = false;
- }
- public void hideSearchBar(boolean animated) {
- if (mIsSearchBarHidden) return;
- if (animated) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.start();
- } else {
- mQSBSearchBarAnim.cancel();
- if (mEnableDropDownDropTargets) {
- mQSBSearchBar.setTranslationY(-mBarHeight);
- } else {
- mQSBSearchBar.setAlpha(0f);
- }
- }
- mIsSearchBarHidden = true;
- }
-
- /*
- * Gets various transition durations.
- */
- public int getTransitionInDuration() {
- return sTransitionInDuration;
- }
- public int getTransitionOutDuration() {
- return sTransitionOutDuration;
- }
-
- /*
- * DragController.DragListener implementation
- */
- @Override
- public void onDragStart(DragSource source, Object info, int dragAction) {
- // Animate out the QSB search bar, and animate in the drop target bar
- prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.start();
- if (!mIsSearchBarHidden) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.start();
- }
- }
-
- public void deferOnDragEnd() {
- mDeferOnDragEnd = true;
- }
-
- @Override
- public void onDragEnd() {
- if (!mDeferOnDragEnd) {
- // Restore the QSB search bar, and animate out the drop target bar
- prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.reverse();
- if (!mIsSearchBarHidden) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
- }
- } else {
- mDeferOnDragEnd = false;
- }
- }
-
- public void onSearchPackagesChanged(boolean searchVisible, boolean voiceVisible) {
- if (mQSBSearchBar != null) {
- Drawable bg = mQSBSearchBar.getBackground();
- if (bg != null && (!searchVisible && !voiceVisible)) {
- // Save the background and disable it
- mPreviousBackground = bg;
- mQSBSearchBar.setBackgroundResource(0);
- } else if (mPreviousBackground != null && (searchVisible || voiceVisible)) {
- // Restore the background
- mQSBSearchBar.setBackground(mPreviousBackground);
- }
- }
- }
-
- public Rect getSearchBarBounds() {
- if (mQSBSearchBar != null) {
- final float appScale = mQSBSearchBar.getContext().getResources()
- .getCompatibilityInfo().applicationScale;
- final int[] pos = new int[2];
- mQSBSearchBar.getLocationOnScreen(pos);
-
- final Rect rect = new Rect();
- rect.left = (int) (pos[0] * appScale + 0.5f);
- rect.top = (int) (pos[1] * appScale + 0.5f);
- rect.right = (int) ((pos[0] + mQSBSearchBar.getWidth()) * appScale + 0.5f);
- rect.bottom = (int) ((pos[1] + mQSBSearchBar.getHeight()) * appScale + 0.5f);
- return rect;
- } else {
- return null;
- }
- }
-}
diff --git a/src/com/android/launcher2/ShortcutAndWidgetContainer.java b/src/com/android/launcher2/ShortcutAndWidgetContainer.java
deleted file mode 100644
index 8bebdcd45..000000000
--- a/src/com/android/launcher2/ShortcutAndWidgetContainer.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.WallpaperManager;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.ViewGroup;
-
-public class ShortcutAndWidgetContainer extends ViewGroup {
- static final String TAG = "CellLayoutChildren";
-
- // These are temporary variables to prevent having to allocate a new object just to
- // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
- private final int[] mTmpCellXY = new int[2];
-
- private final WallpaperManager mWallpaperManager;
-
- private int mCellWidth;
- private int mCellHeight;
-
- private int mWidthGap;
- private int mHeightGap;
-
- public ShortcutAndWidgetContainer(Context context) {
- super(context);
- mWallpaperManager = WallpaperManager.getInstance(context);
- }
-
- public void enableHardwareLayers() {
- setLayerType(LAYER_TYPE_HARDWARE, null);
- }
-
- public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) {
- mCellWidth = cellWidth;
- mCellHeight = cellHeight;
- mWidthGap = widthGap;
- mHeightGap = heightGap;
- }
-
- public View getChildAt(int x, int y) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
- (lp.cellY <= y) && (y < lp.cellY + lp.cellVSpan)) {
- return child;
- }
- }
- return null;
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- // Debug drawing for hit space
- Paint p = new Paint();
- p.setColor(0x6600FF00);
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final View child = getChildAt(i);
- final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- canvas.drawRect(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height, p);
- }
- }
- super.dispatchDraw(canvas);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- measureChild(child);
- }
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
- public void setupLp(CellLayout.LayoutParams lp) {
- lp.setup(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
- }
-
- public void measureChild(View child) {
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap);
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
- MeasureSpec.EXACTLY);
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- int childLeft = lp.x;
- int childTop = lp.y;
- child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
-
- if (lp.dropped) {
- lp.dropped = false;
-
- final int[] cellXY = mTmpCellXY;
- getLocationOnScreen(cellXY);
- mWallpaperManager.sendWallpaperCommand(getWindowToken(),
- WallpaperManager.COMMAND_DROP,
- cellXY[0] + childLeft + lp.width / 2,
- cellXY[1] + childTop + lp.height / 2, 0, null);
- }
- }
- }
- }
-
- @Override
- public boolean shouldDelayChildPressedState() {
- return false;
- }
-
- @Override
- public void requestChildFocus(View child, View focused) {
- super.requestChildFocus(child, focused);
- if (child != null) {
- Rect r = new Rect();
- child.getDrawingRect(r);
- requestRectangleOnScreen(r);
- }
- }
-
- @Override
- public void cancelLongPress() {
- super.cancelLongPress();
-
- // Cancel long press for all children
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- child.cancelLongPress();
- }
- }
-
- @Override
- protected void setChildrenDrawingCacheEnabled(boolean enabled) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View view = getChildAt(i);
- view.setDrawingCacheEnabled(enabled);
- // Update the drawing caches
- if (!view.isHardwareAccelerated() && enabled) {
- view.buildDrawingCache(true);
- }
- }
- }
-
- @Override
- protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
- super.setChildrenDrawnWithCacheEnabled(enabled);
- }
-}
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
deleted file mode 100644
index 533059f57..000000000
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2008 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 android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.util.Log;
-
-/**
- * Represents a launchable icon on the workspaces and in folders.
- */
-class ShortcutInfo extends ItemInfo {
-
- /**
- * The application name.
- */
- CharSequence title;
-
- /**
- * The intent used to start the application.
- */
- Intent intent;
-
- /**
- * Indicates whether the icon comes from an application's resource (if false)
- * or from a custom Bitmap (if true.)
- */
- boolean customIcon;
-
- /**
- * Indicates whether we're using the default fallback icon instead of something from the
- * app.
- */
- boolean usingFallbackIcon;
-
- /**
- * If isShortcut=true and customIcon=false, this contains a reference to the
- * shortcut icon as an application's resource.
- */
- Intent.ShortcutIconResource iconResource;
-
- /**
- * The application icon.
- */
- private Bitmap mIcon;
-
- ShortcutInfo() {
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
- }
-
- public ShortcutInfo(ShortcutInfo info) {
- super(info);
- title = info.title.toString();
- intent = new Intent(info.intent);
- if (info.iconResource != null) {
- iconResource = new Intent.ShortcutIconResource();
- iconResource.packageName = info.iconResource.packageName;
- iconResource.resourceName = info.iconResource.resourceName;
- }
- mIcon = info.mIcon; // TODO: should make a copy here. maybe we don't need this ctor at all
- customIcon = info.customIcon;
- }
-
- /** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */
- public ShortcutInfo(ApplicationInfo info) {
- super(info);
- title = info.title.toString();
- intent = new Intent(info.intent);
- customIcon = false;
- }
-
- public void setIcon(Bitmap b) {
- mIcon = b;
- }
-
- public Bitmap getIcon(IconCache iconCache) {
- if (mIcon == null) {
- updateIcon(iconCache);
- }
- return mIcon;
- }
-
- /** Returns the package name that the shortcut's intent will resolve to, or an empty string if
- * none exists. */
- String getPackageName() {
- return super.getPackageName(intent);
- }
-
- public void updateIcon(IconCache iconCache) {
- mIcon = iconCache.getIcon(intent);
- usingFallbackIcon = iconCache.isDefaultIcon(mIcon);
- }
-
- /**
- * Creates the application intent based on a component name and various launch flags.
- * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
- *
- * @param className the class name of the component representing the intent
- * @param launchFlags the launch flags
- */
- final void setActivity(ComponentName className, int launchFlags) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(className);
- intent.setFlags(launchFlags);
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
- }
-
- @Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
-
- String titleStr = title != null ? title.toString() : null;
- values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
-
- String uri = intent != null ? intent.toUri(0) : null;
- values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
-
- if (customIcon) {
- values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
- LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP);
- writeBitmap(values, mIcon);
- } else {
- if (!usingFallbackIcon) {
- writeBitmap(values, mIcon);
- }
- values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
- LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
- if (iconResource != null) {
- values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
- iconResource.packageName);
- values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
- iconResource.resourceName);
- }
- }
- }
-
- @Override
- public String toString() {
- return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id
- + " type=" + this.itemType + " container=" + this.container + " screen=" + screen
- + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
- + " isGesture=" + isGesture + " dropPos=" + dropPos + ")";
- }
-
- public static void dumpShortcutInfoList(String tag, String label,
- ArrayList<ShortcutInfo> list) {
- Log.d(tag, label + " size=" + list.size());
- for (ShortcutInfo info: list) {
- Log.d(tag, " title=\"" + info.title + " icon=" + info.mIcon
- + " customIcon=" + info.customIcon);
- }
- }
-}
-
diff --git a/src/com/android/launcher2/SmoothPagedView.java b/src/com/android/launcher2/SmoothPagedView.java
deleted file mode 100644
index 7e47f1a3f..000000000
--- a/src/com/android/launcher2/SmoothPagedView.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Interpolator;
-import android.widget.Scroller;
-
-public abstract class SmoothPagedView extends PagedView {
- private static final float SMOOTHING_SPEED = 0.75f;
- private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
-
- private float mBaseLineFlingVelocity;
- private float mFlingVelocityInfluence;
-
- static final int DEFAULT_MODE = 0;
- static final int X_LARGE_MODE = 1;
-
- int mScrollMode;
-
- private Interpolator mScrollInterpolator;
-
- public static class OvershootInterpolator implements Interpolator {
- private static final float DEFAULT_TENSION = 1.3f;
- private float mTension;
-
- public OvershootInterpolator() {
- mTension = DEFAULT_TENSION;
- }
-
- public void setDistance(int distance) {
- mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
- }
-
- public void disableSettle() {
- mTension = 0.f;
- }
-
- public float getInterpolation(float t) {
- // _o(t) = t * t * ((tension + 1) * t + tension)
- // o(t) = _o(t - 1) + 1
- t -= 1.0f;
- return t * t * ((mTension + 1) * t + mTension) + 1.0f;
- }
- }
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- */
- public SmoothPagedView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- * @param defStyle Unused.
- */
- public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mUsePagingTouchSlop = false;
-
- // This means that we'll take care of updating the scroll parameter ourselves (we do it
- // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
- mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
- }
-
- protected int getScrollMode() {
- return X_LARGE_MODE;
- }
-
- /**
- * Initializes various states for this workspace.
- */
- @Override
- protected void init() {
- super.init();
-
- mScrollMode = getScrollMode();
- if (mScrollMode == DEFAULT_MODE) {
- mBaseLineFlingVelocity = 2500.0f;
- mFlingVelocityInfluence = 0.4f;
- mScrollInterpolator = new OvershootInterpolator();
- mScroller = new Scroller(getContext(), mScrollInterpolator);
- }
- }
-
- @Override
- protected void snapToDestination() {
- if (mScrollMode == X_LARGE_MODE) {
- super.snapToDestination();
- } else {
- snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
- }
- }
-
- @Override
- protected void snapToPageWithVelocity(int whichPage, int velocity) {
- if (mScrollMode == X_LARGE_MODE) {
- super.snapToPageWithVelocity(whichPage, velocity);
- } else {
- snapToPageWithVelocity(whichPage, 0, true);
- }
- }
-
- private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
- // if (!mScroller.isFinished()) return;
-
- whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
-
- final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
- final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
- final int delta = newX - mUnboundedScrollX;
- int duration = (screenDelta + 1) * 100;
-
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
- if (settle) {
- ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
- } else {
- ((OvershootInterpolator) mScrollInterpolator).disableSettle();
- }
-
- velocity = Math.abs(velocity);
- if (velocity > 0) {
- duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
- } else {
- duration += 100;
- }
-
- snapToPage(whichPage, delta, duration);
- }
-
- @Override
- protected void snapToPage(int whichPage) {
- if (mScrollMode == X_LARGE_MODE) {
- super.snapToPage(whichPage);
- } else {
- snapToPageWithVelocity(whichPage, 0, false);
- }
- }
-
- @Override
- public void computeScroll() {
- if (mScrollMode == X_LARGE_MODE) {
- super.computeScroll();
- } else {
- boolean scrollComputed = computeScrollHelper();
-
- if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
- final float now = System.nanoTime() / NANOTIME_DIV;
- final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
-
- final float dx = mTouchX - mUnboundedScrollX;
- scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY());
- mSmoothingTime = now;
-
- // Keep generating points as long as we're more than 1px away from the target
- if (dx > 1.f || dx < -1.f) {
- invalidate();
- }
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/SpringLoadedDragController.java b/src/com/android/launcher2/SpringLoadedDragController.java
deleted file mode 100644
index d96aab794..000000000
--- a/src/com/android/launcher2/SpringLoadedDragController.java
+++ /dev/null
@@ -1,62 +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;
-
-public class SpringLoadedDragController implements OnAlarmListener {
- // how long the user must hover over a mini-screen before it unshrinks
- final long ENTER_SPRING_LOAD_HOVER_TIME = 500;
- final long ENTER_SPRING_LOAD_CANCEL_HOVER_TIME = 950;
- final long EXIT_SPRING_LOAD_HOVER_TIME = 200;
-
- Alarm mAlarm;
-
- // the screen the user is currently hovering over, if any
- private CellLayout mScreen;
- private Launcher mLauncher;
-
- public SpringLoadedDragController(Launcher launcher) {
- mLauncher = launcher;
- mAlarm = new Alarm();
- mAlarm.setOnAlarmListener(this);
- }
-
- public void cancel() {
- mAlarm.cancelAlarm();
- }
-
- // Set a new alarm to expire for the screen that we are hovering over now
- public void setAlarm(CellLayout cl) {
- mAlarm.cancelAlarm();
- mAlarm.setAlarm((cl == null) ? ENTER_SPRING_LOAD_CANCEL_HOVER_TIME :
- ENTER_SPRING_LOAD_HOVER_TIME);
- mScreen = cl;
- }
-
- // this is called when our timer runs out
- public void onAlarm(Alarm alarm) {
- if (mScreen != null) {
- // Snap to the screen that we are hovering over now
- Workspace w = mLauncher.getWorkspace();
- int page = w.indexOfChild(mScreen);
- if (page != w.getCurrentPage()) {
- w.snapToPage(page);
- }
- } else {
- mLauncher.getDragController().cancelDrag();
- }
- }
-}
diff --git a/src/com/android/launcher2/StrokedTextView.java b/src/com/android/launcher2/StrokedTextView.java
deleted file mode 100644
index 4e28d17d7..000000000
--- a/src/com/android/launcher2/StrokedTextView.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-
-/**
- * This class adds a stroke to the generic TextView allowing the text to stand out better against
- * the background (ie. in the AllApps button).
- */
-public class StrokedTextView extends TextView {
- private final Canvas mCanvas = new Canvas();
- private final Paint mPaint = new Paint();
- private Bitmap mCache;
- private boolean mUpdateCachedBitmap;
- private int mStrokeColor;
- private float mStrokeWidth;
- private int mTextColor;
-
- public StrokedTextView(Context context) {
- super(context);
- init(context, null, 0);
- }
-
- public StrokedTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
-
- public StrokedTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context, attrs, defStyle);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyle) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StrokedTextView,
- defStyle, 0);
- mStrokeColor = a.getColor(R.styleable.StrokedTextView_strokeColor, 0xFF000000);
- mStrokeWidth = a.getFloat(R.styleable.StrokedTextView_strokeWidth, 0.0f);
- mTextColor = a.getColor(R.styleable.StrokedTextView_strokeTextColor, 0xFFFFFFFF);
- a.recycle();
- mUpdateCachedBitmap = true;
-
- // Setup the text paint
- mPaint.setAntiAlias(true);
- mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- }
-
- protected void onTextChanged(CharSequence text, int start, int before, int after) {
- super.onTextChanged(text, start, before, after);
- mUpdateCachedBitmap = true;
- }
-
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- if (w > 0 && h > 0) {
- mUpdateCachedBitmap = true;
- mCache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- } else {
- mCache = null;
- }
- }
-
- protected void onDraw(Canvas canvas) {
- if (mCache != null) {
- if (mUpdateCachedBitmap) {
- final int w = getMeasuredWidth();
- final int h = getMeasuredHeight();
- final String text = getText().toString();
- final Rect textBounds = new Rect();
- final Paint textPaint = getPaint();
- final int textWidth = (int) textPaint.measureText(text);
- textPaint.getTextBounds("x", 0, 1, textBounds);
-
- // Clear the old cached image
- mCanvas.setBitmap(mCache);
- mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
-
- // Draw the drawable
- final int drawableLeft = getPaddingLeft();
- final int drawableTop = getPaddingTop();
- final Drawable[] drawables = getCompoundDrawables();
- for (int i = 0; i < drawables.length; ++i) {
- if (drawables[i] != null) {
- drawables[i].setBounds(drawableLeft, drawableTop,
- drawableLeft + drawables[i].getIntrinsicWidth(),
- drawableTop + drawables[i].getIntrinsicHeight());
- drawables[i].draw(mCanvas);
- }
- }
-
- final int left = w - getPaddingRight() - textWidth;
- final int bottom = (h + textBounds.height()) / 2;
-
- // Draw the outline of the text
- mPaint.setStrokeWidth(mStrokeWidth);
- mPaint.setColor(mStrokeColor);
- mPaint.setTextSize(getTextSize());
- mCanvas.drawText(text, left, bottom, mPaint);
-
- // Draw the text itself
- mPaint.setStrokeWidth(0);
- mPaint.setColor(mTextColor);
- mCanvas.drawText(text, left, bottom, mPaint);
-
- mUpdateCachedBitmap = false;
- }
- canvas.drawBitmap(mCache, 0, 0, mPaint);
- } else {
- super.onDraw(canvas);
- }
- }
-}
diff --git a/src/com/android/launcher2/SymmetricalLinearTween.java b/src/com/android/launcher2/SymmetricalLinearTween.java
deleted file mode 100644
index da02242c8..000000000
--- a/src/com/android/launcher2/SymmetricalLinearTween.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2009 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.os.Handler;
-import android.os.SystemClock;
-
-/**
- * Provides an animation between 0.0f and 1.0f over a given duration.
- */
-class SymmetricalLinearTween {
-
- private static final int FPS = 30;
- private static final int FRAME_TIME = 1000 / FPS;
-
- Handler mHandler;
- int mDuration;
- TweenCallback mCallback;
-
- boolean mRunning;
- long mBase;
- boolean mDirection;
- float mValue;
-
- /**
- * @param duration milliseconds duration
- * @param callback callbacks
- */
- public SymmetricalLinearTween(boolean initial, int duration, TweenCallback callback) {
- mValue = initial ? 1.0f : 0.0f;
- mDirection = initial;
- mDuration = duration;
- mCallback = callback;
- mHandler = new Handler();
- }
-
- /**
- * Starts the tweening.
- *
- * @param direction If direction is true, the value goes towards 1.0f. If direction
- * is false, the value goes towards 0.0f.
- */
- public void start(boolean direction) {
- start(direction, SystemClock.uptimeMillis());
- }
-
- /**
- * Starts the tweening.
- *
- * @param direction If direction is true, the value goes towards 1.0f. If direction
- * is false, the value goes towards 0.0f.
- * @param baseTime The time to use as zero for this animation, in the
- * {@link SystemClock.uptimeMillis} time base. This allows you to
- * synchronize multiple animations.
- */
- public void start(boolean direction, long baseTime) {
- if (direction != mDirection) {
- if (!mRunning) {
- mBase = baseTime;
- mRunning = true;
- mCallback.onTweenStarted();
- long next = SystemClock.uptimeMillis() + FRAME_TIME;
- mHandler.postAtTime(mTick, next);
- } else {
- // reverse direction
- long now = SystemClock.uptimeMillis();
- long diff = now - mBase;
- mBase = now + diff - mDuration;
- }
- mDirection = direction;
- }
- }
-
- Runnable mTick = new Runnable() {
- public void run() {
- long base = mBase;
- long now = SystemClock.uptimeMillis();
- long diff = now-base;
- int duration = mDuration;
- float val = diff/(float)duration;
- if (!mDirection) {
- val = 1.0f - val;
- }
- if (val > 1.0f) {
- val = 1.0f;
- } else if (val < 0.0f) {
- val = 0.0f;
- }
- float old = mValue;
- mValue = val;
- mCallback.onTweenValueChanged(val, old);
- int frame = (int)(diff / FRAME_TIME);
- long next = base + ((frame+1)*FRAME_TIME);
- if (diff < duration) {
- mHandler.postAtTime(this, next);
- }
- if (diff >= duration) {
- mCallback.onTweenFinished();
- mRunning = false;
- }
- }
- };
-}
-
diff --git a/src/com/android/launcher2/TweenCallback.java b/src/com/android/launcher2/TweenCallback.java
deleted file mode 100644
index 380a21774..000000000
--- a/src/com/android/launcher2/TweenCallback.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-interface TweenCallback {
- void onTweenValueChanged(float value, float oldValue);
- void onTweenStarted();
- void onTweenFinished();
-}
-
diff --git a/src/com/android/launcher2/UninstallShortcutReceiver.java b/src/com/android/launcher2/UninstallShortcutReceiver.java
deleted file mode 100644
index 02590c9f6..000000000
--- a/src/com/android/launcher2/UninstallShortcutReceiver.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2008 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.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.widget.Toast;
-
-import com.android.launcher.R;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-public class UninstallShortcutReceiver extends BroadcastReceiver {
- private static final String ACTION_UNINSTALL_SHORTCUT =
- "com.android.launcher.action.UNINSTALL_SHORTCUT";
-
- // The set of shortcuts that are pending uninstall
- private static ArrayList<PendingUninstallShortcutInfo> mUninstallQueue =
- new ArrayList<PendingUninstallShortcutInfo>();
-
- // Determines whether to defer uninstalling shortcuts immediately until
- // disableAndFlushUninstallQueue() is called.
- private static boolean mUseUninstallQueue = false;
-
- private static class PendingUninstallShortcutInfo {
- Intent data;
-
- public PendingUninstallShortcutInfo(Intent rawData) {
- data = rawData;
- }
- }
-
- public void onReceive(Context context, Intent data) {
- if (!ACTION_UNINSTALL_SHORTCUT.equals(data.getAction())) {
- return;
- }
-
- PendingUninstallShortcutInfo info = new PendingUninstallShortcutInfo(data);
- if (mUseUninstallQueue) {
- mUninstallQueue.add(info);
- } else {
- processUninstallShortcut(context, info);
- }
- }
-
- static void enableUninstallQueue() {
- mUseUninstallQueue = true;
- }
-
- static void disableAndFlushUninstallQueue(Context context) {
- mUseUninstallQueue = false;
- Iterator<PendingUninstallShortcutInfo> iter = mUninstallQueue.iterator();
- while (iter.hasNext()) {
- processUninstallShortcut(context, iter.next());
- iter.remove();
- }
- }
-
- private static void processUninstallShortcut(Context context,
- PendingUninstallShortcutInfo pendingInfo) {
- String spKey = LauncherApplication.getSharedPreferencesKey();
- SharedPreferences sharedPrefs = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
-
- final Intent data = pendingInfo.data;
-
- LauncherApplication app = (LauncherApplication) context.getApplicationContext();
- synchronized (app) {
- removeShortcut(context, data, sharedPrefs);
- }
- }
-
- private static void removeShortcut(Context context, Intent data,
- final SharedPreferences sharedPrefs) {
- Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
-
- if (intent != null && name != null) {
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT },
- LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null);
-
- final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
-
- boolean changed = false;
-
- try {
- while (c.moveToNext()) {
- try {
- if (intent.filterEquals(Intent.parseUri(c.getString(intentIndex), 0))) {
- final long id = c.getLong(idIndex);
- final Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
- cr.delete(uri, null, null);
- changed = true;
- if (!duplicate) {
- break;
- }
- }
- } catch (URISyntaxException e) {
- // Ignore
- }
- }
- } finally {
- c.close();
- }
-
- if (changed) {
- cr.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null);
- Toast.makeText(context, context.getString(R.string.shortcut_uninstalled, name),
- Toast.LENGTH_SHORT).show();
- }
-
- // Remove any items due to be animated
- boolean appRemoved;
- Set<String> newApps = new HashSet<String>();
- newApps = sharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps);
- synchronized (newApps) {
- do {
- appRemoved = newApps.remove(intent.toUri(0).toString());
- } while (appRemoved);
- }
- if (appRemoved) {
- final Set<String> savedNewApps = newApps;
- new Thread("setNewAppsThread-remove") {
- public void run() {
- synchronized (savedNewApps) {
- SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
- savedNewApps);
- if (savedNewApps.isEmpty()) {
- // Reset the page index if there are no more items
- editor.putInt(InstallShortcutReceiver.NEW_APPS_PAGE_KEY, -1);
- }
- editor.commit();
- }
- }
- }.start();
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
deleted file mode 100644
index b27f7bb11..000000000
--- a/src/com/android/launcher2/Utilities.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2008 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.Random;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.TableMaskFilter;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
-import android.util.DisplayMetrics;
-
-import com.android.launcher.R;
-
-/**
- * Various utilities shared amongst the Launcher's classes.
- */
-final class Utilities {
- @SuppressWarnings("unused")
- private static final String TAG = "Launcher.Utilities";
-
- private static int sIconWidth = -1;
- private static int sIconHeight = -1;
- private static int sIconTextureWidth = -1;
- private static int sIconTextureHeight = -1;
-
- private static final Paint sBlurPaint = new Paint();
- private static final Paint sGlowColorPressedPaint = new Paint();
- private static final Paint sGlowColorFocusedPaint = new Paint();
- private static final Paint sDisabledPaint = new Paint();
- private static final Rect sOldBounds = new Rect();
- private static final Canvas sCanvas = new Canvas();
-
- static {
- sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
- Paint.FILTER_BITMAP_FLAG));
- }
- static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
- static int sColorIndex = 0;
-
- /**
- * Returns a bitmap suitable for the all apps view. Used to convert pre-ICS
- * icon bitmaps that are stored in the database (which were 74x74 pixels at hdpi size)
- * to the proper size (48dp)
- */
- static Bitmap createIconBitmap(Bitmap icon, Context context) {
- int textureWidth = sIconTextureWidth;
- int textureHeight = sIconTextureHeight;
- int sourceWidth = icon.getWidth();
- int sourceHeight = icon.getHeight();
- if (sourceWidth > textureWidth && sourceHeight > textureHeight) {
- // Icon is bigger than it should be; clip it (solves the GB->ICS migration case)
- return Bitmap.createBitmap(icon,
- (sourceWidth - textureWidth) / 2,
- (sourceHeight - textureHeight) / 2,
- textureWidth, textureHeight);
- } else if (sourceWidth == textureWidth && sourceHeight == textureHeight) {
- // Icon is the right size, no need to change it
- return icon;
- } else {
- // Icon is too small, render to a larger bitmap
- final Resources resources = context.getResources();
- return createIconBitmap(new BitmapDrawable(resources, icon), context);
- }
- }
-
- /**
- * Returns a bitmap suitable for the all apps view.
- */
- static Bitmap createIconBitmap(Drawable icon, Context context) {
- synchronized (sCanvas) { // we share the statics :-(
- if (sIconWidth == -1) {
- initStatics(context);
- }
-
- int width = sIconWidth;
- int height = sIconHeight;
-
- if (icon instanceof PaintDrawable) {
- PaintDrawable painter = (PaintDrawable) icon;
- painter.setIntrinsicWidth(width);
- painter.setIntrinsicHeight(height);
- } else if (icon instanceof BitmapDrawable) {
- // Ensure the bitmap has a density.
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
- }
- }
- int sourceWidth = icon.getIntrinsicWidth();
- int sourceHeight = icon.getIntrinsicHeight();
- if (sourceWidth > 0 && sourceHeight > 0) {
- // There are intrinsic sizes.
- if (width < sourceWidth || height < sourceHeight) {
- // It's too big, scale it down.
- final float ratio = (float) sourceWidth / sourceHeight;
- if (sourceWidth > sourceHeight) {
- height = (int) (width / ratio);
- } else if (sourceHeight > sourceWidth) {
- width = (int) (height * ratio);
- }
- } else if (sourceWidth < width && sourceHeight < height) {
- // Don't scale up the icon
- width = sourceWidth;
- height = sourceHeight;
- }
- }
-
- // no intrinsic size --> use default size
- int textureWidth = sIconTextureWidth;
- int textureHeight = sIconTextureHeight;
-
- final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
- Bitmap.Config.ARGB_8888);
- final Canvas canvas = sCanvas;
- canvas.setBitmap(bitmap);
-
- final int left = (textureWidth-width) / 2;
- final int top = (textureHeight-height) / 2;
-
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- // draw a big box for the icon for debugging
- canvas.drawColor(sColors[sColorIndex]);
- if (++sColorIndex >= sColors.length) sColorIndex = 0;
- Paint debugPaint = new Paint();
- debugPaint.setColor(0xffcccc00);
- canvas.drawRect(left, top, left+width, top+height, debugPaint);
- }
-
- sOldBounds.set(icon.getBounds());
- icon.setBounds(left, top, left+width, top+height);
- icon.draw(canvas);
- icon.setBounds(sOldBounds);
- canvas.setBitmap(null);
-
- return bitmap;
- }
- }
-
- static void drawSelectedAllAppsBitmap(Canvas dest, int destWidth, int destHeight,
- boolean pressed, Bitmap src) {
- synchronized (sCanvas) { // we share the statics :-(
- if (sIconWidth == -1) {
- // We can't have gotten to here without src being initialized, which
- // comes from this file already. So just assert.
- //initStatics(context);
- throw new RuntimeException("Assertion failed: Utilities not initialized");
- }
-
- dest.drawColor(0, PorterDuff.Mode.CLEAR);
-
- int[] xy = new int[2];
- Bitmap mask = src.extractAlpha(sBlurPaint, xy);
-
- float px = (destWidth - src.getWidth()) / 2;
- float py = (destHeight - src.getHeight()) / 2;
- dest.drawBitmap(mask, px + xy[0], py + xy[1],
- pressed ? sGlowColorPressedPaint : sGlowColorFocusedPaint);
-
- mask.recycle();
- }
- }
-
- /**
- * Returns a Bitmap representing the thumbnail of the specified Bitmap.
- * The size of the thumbnail is defined by the dimension
- * android.R.dimen.launcher_application_icon_size.
- *
- * @param bitmap The bitmap to get a thumbnail of.
- * @param context The application's context.
- *
- * @return A thumbnail for the specified bitmap or the bitmap itself if the
- * thumbnail could not be created.
- */
- static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
- synchronized (sCanvas) { // we share the statics :-(
- if (sIconWidth == -1) {
- initStatics(context);
- }
-
- if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
- return bitmap;
- } else {
- final Resources resources = context.getResources();
- return createIconBitmap(new BitmapDrawable(resources, bitmap), context);
- }
- }
- }
-
- static Bitmap drawDisabledBitmap(Bitmap bitmap, Context context) {
- synchronized (sCanvas) { // we share the statics :-(
- if (sIconWidth == -1) {
- initStatics(context);
- }
- final Bitmap disabled = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
- Bitmap.Config.ARGB_8888);
- final Canvas canvas = sCanvas;
- canvas.setBitmap(disabled);
-
- canvas.drawBitmap(bitmap, 0.0f, 0.0f, sDisabledPaint);
-
- canvas.setBitmap(null);
-
- return disabled;
- }
- }
-
- private static void initStatics(Context context) {
- final Resources resources = context.getResources();
- final DisplayMetrics metrics = resources.getDisplayMetrics();
- final float density = metrics.density;
-
- sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
- sIconTextureWidth = sIconTextureHeight = sIconWidth;
-
- sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
- sGlowColorPressedPaint.setColor(0xffffc300);
- sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
- sGlowColorFocusedPaint.setColor(0xffff8e00);
- sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-
- ColorMatrix cm = new ColorMatrix();
- cm.setSaturation(0.2f);
- sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
- sDisabledPaint.setAlpha(0x88);
- }
-
- /** Only works for positive numbers. */
- static int roundToPow2(int n) {
- int orig = n;
- n >>= 1;
- int mask = 0x8000000;
- while (mask != 0 && (n & mask) == 0) {
- mask >>= 1;
- }
- while (mask != 0) {
- n |= mask;
- mask >>= 1;
- }
- n += 1;
- if (n != orig) {
- n <<= 1;
- }
- return n;
- }
-
- static int generateRandomId() {
- return new Random(System.currentTimeMillis()).nextInt(1 << 24);
- }
-}
diff --git a/src/com/android/launcher2/WallpaperChooser.java b/src/com/android/launcher2/WallpaperChooser.java
deleted file mode 100644
index 77e1e6ffb..000000000
--- a/src/com/android/launcher2/WallpaperChooser.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2008 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 com.android.launcher.R;
-
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.os.Bundle;
-
-public class WallpaperChooser extends Activity {
- @SuppressWarnings("unused")
- private static final String TAG = "Launcher.WallpaperChooser";
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.wallpaper_chooser_base);
-
- Fragment fragmentView =
- getFragmentManager().findFragmentById(R.id.wallpaper_chooser_fragment);
- // TODO: The following code is currently not exercised. Leaving it here in case it
- // needs to be revived again.
- if (fragmentView == null) {
- /* When the screen is XLarge, the fragment is not included in the layout, so show it
- * as a dialog
- */
- DialogFragment fragment = WallpaperChooserDialogFragment.newInstance();
- fragment.show(getFragmentManager(), "dialog");
- }
- }
-}
diff --git a/src/com/android/launcher2/WallpaperChooserDialogFragment.java b/src/com/android/launcher2/WallpaperChooserDialogFragment.java
deleted file mode 100644
index b99d8ecb3..000000000
--- a/src/com/android/launcher2/WallpaperChooserDialogFragment.java
+++ /dev/null
@@ -1,360 +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.app.Activity;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.SpinnerAdapter;
-
-import com.android.launcher.R;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-public class WallpaperChooserDialogFragment extends DialogFragment implements
- AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
-
- private static final String TAG = "Launcher.WallpaperChooserDialogFragment";
- private static final String EMBEDDED_KEY = "com.android.launcher2."
- + "WallpaperChooserDialogFragment.EMBEDDED_KEY";
-
- private boolean mEmbedded;
- private Bitmap mBitmap = null;
-
- private ArrayList<Integer> mThumbs;
- private ArrayList<Integer> mImages;
- private WallpaperLoader mLoader;
- private WallpaperDrawable mWallpaperDrawable = new WallpaperDrawable();
-
- public static WallpaperChooserDialogFragment newInstance() {
- WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
- fragment.setCancelable(true);
- return fragment;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null && savedInstanceState.containsKey(EMBEDDED_KEY)) {
- mEmbedded = savedInstanceState.getBoolean(EMBEDDED_KEY);
- } else {
- mEmbedded = isInLayout();
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- outState.putBoolean(EMBEDDED_KEY, mEmbedded);
- }
-
- private void cancelLoader() {
- if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
- mLoader.cancel(true);
- mLoader = null;
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
-
- cancelLoader();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- cancelLoader();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- super.onDismiss(dialog);
- /* On orientation changes, the dialog is effectively "dismissed" so this is called
- * when the activity is no longer associated with this dying dialog fragment. We
- * should just safely ignore this case by checking if getActivity() returns null
- */
- Activity activity = getActivity();
- if (activity != null) {
- activity.finish();
- }
- }
-
- /* This will only be called when in XLarge mode, since this Fragment is invoked like
- * a dialog in that mode
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- findWallpapers();
-
- return null;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- findWallpapers();
-
- /* If this fragment is embedded in the layout of this activity, then we should
- * generate a view to display. Otherwise, a dialog will be created in
- * onCreateDialog()
- */
- if (mEmbedded) {
- View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
- view.setBackground(mWallpaperDrawable);
-
- final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
- gallery.setCallbackDuringFling(false);
- gallery.setOnItemSelectedListener(this);
- gallery.setAdapter(new ImageAdapter(getActivity()));
-
- View setButton = view.findViewById(R.id.set);
- setButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- selectWallpaper(gallery.getSelectedItemPosition());
- }
- });
- return view;
- }
- return null;
- }
-
- private void selectWallpaper(int position) {
- try {
- WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
- Context.WALLPAPER_SERVICE);
- wpm.setResource(mImages.get(position));
- Activity activity = getActivity();
- activity.setResult(Activity.RESULT_OK);
- activity.finish();
- } catch (IOException e) {
- Log.e(TAG, "Failed to set wallpaper: " + e);
- }
- }
-
- // Click handler for the Dialog's GridView
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- selectWallpaper(position);
- }
-
- // Selection handler for the embedded Gallery view
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
- mLoader.cancel();
- }
- mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
-
- private void findWallpapers() {
- mThumbs = new ArrayList<Integer>(24);
- mImages = new ArrayList<Integer>(24);
-
- final Resources resources = getResources();
- // Context.getPackageName() may return the "original" package name,
- // com.android.launcher2; Resources needs the real package name,
- // com.android.launcher. So we ask Resources for what it thinks the
- // package name should be.
- final String packageName = resources.getResourcePackageName(R.array.wallpapers);
-
- addWallpapers(resources, packageName, R.array.wallpapers);
- addWallpapers(resources, packageName, R.array.extra_wallpapers);
- }
-
- private void addWallpapers(Resources resources, String packageName, int list) {
- final String[] extras = resources.getStringArray(list);
- for (String extra : extras) {
- int res = resources.getIdentifier(extra, "drawable", packageName);
- if (res != 0) {
- final int thumbRes = resources.getIdentifier(extra + "_small",
- "drawable", packageName);
-
- if (thumbRes != 0) {
- mThumbs.add(thumbRes);
- mImages.add(res);
- // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
- }
- }
- }
- }
-
- private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
- private LayoutInflater mLayoutInflater;
-
- ImageAdapter(Activity activity) {
- mLayoutInflater = activity.getLayoutInflater();
- }
-
- public int getCount() {
- return mThumbs.size();
- }
-
- public Object getItem(int position) {
- return position;
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View view;
-
- if (convertView == null) {
- view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
- } else {
- view = convertView;
- }
-
- ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
-
- int thumbRes = mThumbs.get(position);
- image.setImageResource(thumbRes);
- Drawable thumbDrawable = image.getDrawable();
- if (thumbDrawable != null) {
- thumbDrawable.setDither(true);
- } else {
- Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
- + position);
- }
-
- return view;
- }
- }
-
- class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
- BitmapFactory.Options mOptions;
-
- WallpaperLoader() {
- mOptions = new BitmapFactory.Options();
- mOptions.inDither = false;
- mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
- }
-
- @Override
- protected Bitmap doInBackground(Integer... params) {
- if (isCancelled()) return null;
- try {
- return BitmapFactory.decodeResource(getResources(),
- mImages.get(params[0]), mOptions);
- } catch (OutOfMemoryError e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(Bitmap b) {
- if (b == null) return;
-
- if (!isCancelled() && !mOptions.mCancel) {
- // Help the GC
- if (mBitmap != null) {
- mBitmap.recycle();
- }
-
- View v = getView();
- if (v != null) {
- mBitmap = b;
- mWallpaperDrawable.setBitmap(b);
- v.postInvalidate();
- } else {
- mBitmap = null;
- mWallpaperDrawable.setBitmap(null);
- }
- mLoader = null;
- } else {
- b.recycle();
- }
- }
-
- void cancel() {
- mOptions.requestCancelDecode();
- super.cancel(true);
- }
- }
-
- /**
- * Custom drawable that centers the bitmap fed to it.
- */
- static class WallpaperDrawable extends Drawable {
-
- Bitmap mBitmap;
- int mIntrinsicWidth;
- int mIntrinsicHeight;
-
- /* package */void setBitmap(Bitmap bitmap) {
- mBitmap = bitmap;
- if (mBitmap == null)
- return;
- mIntrinsicWidth = mBitmap.getWidth();
- mIntrinsicHeight = mBitmap.getHeight();
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (mBitmap == null) return;
- int width = canvas.getWidth();
- int height = canvas.getHeight();
- int x = (width - mIntrinsicWidth) / 2;
- int y = (height - mIntrinsicHeight) / 2;
- canvas.drawBitmap(mBitmap, x, y, null);
- }
-
- @Override
- public int getOpacity() {
- return android.graphics.PixelFormat.OPAQUE;
- }
-
- @Override
- public void setAlpha(int alpha) {
- // Ignore
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- // Ignore
- }
- }
-}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
deleted file mode 100644
index 2d2340a3e..000000000
--- a/src/com/android/launcher2/Workspace.java
+++ /dev/null
@@ -1,3781 +0,0 @@
-/*
- * Copyright (C) 2008 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.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.WallpaperManager;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Camera;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.Region.Op;
-import android.graphics.drawable.Drawable;
-import android.os.IBinder;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.launcher.R;
-import com.android.launcher2.FolderIcon.FolderRingAnimator;
-import com.android.launcher2.LauncherSettings.Favorites;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-/**
- * The workspace is a wide area with a wallpaper and a finite number of pages.
- * Each page contains a number of icons, folders or widgets the user can
- * interact with. A workspace is meant to be used with a fixed width only.
- */
-public class Workspace extends SmoothPagedView
- implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
- DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener {
- private static final String TAG = "Launcher.Workspace";
-
- // Y rotation to apply to the workspace screens
- private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
-
- private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
- private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
- private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
-
- private static final int BACKGROUND_FADE_OUT_DURATION = 350;
- private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
- private static final int FLING_THRESHOLD_VELOCITY = 500;
-
- // These animators are used to fade the children's outlines
- private ObjectAnimator mChildrenOutlineFadeInAnimation;
- private ObjectAnimator mChildrenOutlineFadeOutAnimation;
- private float mChildrenOutlineAlpha = 0;
-
- // These properties refer to the background protection gradient used for AllApps and Customize
- private ValueAnimator mBackgroundFadeInAnimation;
- private ValueAnimator mBackgroundFadeOutAnimation;
- private Drawable mBackground;
- boolean mDrawBackground = true;
- private float mBackgroundAlpha = 0;
- private float mOverScrollMaxBackgroundAlpha = 0.0f;
-
- private float mWallpaperScrollRatio = 1.0f;
-
- private final WallpaperManager mWallpaperManager;
- private IBinder mWindowToken;
- private static final float WALLPAPER_SCREENS_SPAN = 2f;
-
- private int mDefaultPage;
-
- /**
- * CellInfo for the cell that is currently being dragged
- */
- private CellLayout.CellInfo mDragInfo;
-
- /**
- * Target drop area calculated during last acceptDrop call.
- */
- private int[] mTargetCell = new int[2];
- private int mDragOverX = -1;
- private int mDragOverY = -1;
-
- static Rect mLandscapeCellLayoutMetrics = null;
- static Rect mPortraitCellLayoutMetrics = null;
-
- /**
- * The CellLayout that is currently being dragged over
- */
- private CellLayout mDragTargetLayout = null;
- /**
- * The CellLayout that we will show as glowing
- */
- private CellLayout mDragOverlappingLayout = null;
-
- /**
- * The CellLayout which will be dropped to
- */
- private CellLayout mDropToLayout = null;
-
- private Launcher mLauncher;
- private IconCache mIconCache;
- private DragController mDragController;
-
- // These are temporary variables to prevent having to allocate a new object just to
- // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
- private int[] mTempCell = new int[2];
- private int[] mTempEstimate = new int[2];
- private float[] mDragViewVisualCenter = new float[2];
- private float[] mTempDragCoordinates = new float[2];
- private float[] mTempCellLayoutCenterCoordinates = new float[2];
- private float[] mTempDragBottomRightCoordinates = new float[2];
- private Matrix mTempInverseMatrix = new Matrix();
-
- private SpringLoadedDragController mSpringLoadedDragController;
- private float mSpringLoadedShrinkFactor;
-
- private static final int DEFAULT_CELL_COUNT_X = 4;
- private static final int DEFAULT_CELL_COUNT_Y = 4;
-
- // State variable that indicates whether the pages are small (ie when you're
- // in all apps or customize mode)
-
- enum State { NORMAL, SPRING_LOADED, SMALL };
- private State mState = State.NORMAL;
- private boolean mIsSwitchingState = false;
-
- boolean mAnimatingViewIntoPlace = false;
- boolean mIsDragOccuring = false;
- boolean mChildrenLayersEnabled = true;
-
- /** Is the user is dragging an item near the edge of a page? */
- private boolean mInScrollArea = false;
-
- private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
- private Bitmap mDragOutline = null;
- private final Rect mTempRect = new Rect();
- private final int[] mTempXY = new int[2];
- private float mOverscrollFade = 0;
- private boolean mOverscrollTransformsSet;
- public static final int DRAG_BITMAP_PADDING = 2;
- private boolean mWorkspaceFadeInAdjacentScreens;
-
- // Camera and Matrix used to determine the final position of a neighboring CellLayout
- private final Matrix mMatrix = new Matrix();
- private final Camera mCamera = new Camera();
- private final float mTempFloat2[] = new float[2];
-
- enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
- int mWallpaperWidth;
- int mWallpaperHeight;
- WallpaperOffsetInterpolator mWallpaperOffset;
- boolean mUpdateWallpaperOffsetImmediately = false;
- private Runnable mDelayedResizeRunnable;
- private Runnable mDelayedSnapToPageRunnable;
- private Point mDisplaySize = new Point();
- private boolean mIsStaticWallpaper;
- private int mWallpaperTravelWidth;
- private int mSpringLoadedPageSpacing;
- private int mCameraDistance;
-
- // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
- private static final int FOLDER_CREATION_TIMEOUT = 0;
- private static final int REORDER_TIMEOUT = 250;
- private final Alarm mFolderCreationAlarm = new Alarm();
- private final Alarm mReorderAlarm = new Alarm();
- private FolderRingAnimator mDragFolderRingAnimator = null;
- private FolderIcon mDragOverFolderIcon = null;
- private boolean mCreateUserFolderOnDrop = false;
- private boolean mAddToExistingFolderOnDrop = false;
- private DropTarget.DragEnforcer mDragEnforcer;
- private float mMaxDistanceForFolderCreation;
-
- // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
- private float mXDown;
- private float mYDown;
- final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
- final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
- final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
-
- // Relating to the animation of items being dropped externally
- public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;
- public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;
- public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;
- public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;
- public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;
-
- // Related to dragging, folder creation and reordering
- private static final int DRAG_MODE_NONE = 0;
- private static final int DRAG_MODE_CREATE_FOLDER = 1;
- private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
- private static final int DRAG_MODE_REORDER = 3;
- private int mDragMode = DRAG_MODE_NONE;
- private int mLastReorderX = -1;
- private int mLastReorderY = -1;
-
- // These variables are used for storing the initial and final values during workspace animations
- private int mSavedScrollX;
- private float mSavedRotationY;
- private float mSavedTranslationX;
- private float mCurrentScaleX;
- private float mCurrentScaleY;
- private float mCurrentRotationY;
- private float mCurrentTranslationX;
- private float mCurrentTranslationY;
- private float[] mOldTranslationXs;
- private float[] mOldTranslationYs;
- private float[] mOldScaleXs;
- private float[] mOldScaleYs;
- private float[] mOldBackgroundAlphas;
- private float[] mOldAlphas;
- private float[] mNewTranslationXs;
- private float[] mNewTranslationYs;
- private float[] mNewScaleXs;
- private float[] mNewScaleYs;
- private float[] mNewBackgroundAlphas;
- private float[] mNewAlphas;
- private float[] mNewRotationYs;
- private float mTransitionProgress;
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- */
- public Workspace(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- * @param defStyle Unused.
- */
- public Workspace(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mContentIsRefreshable = false;
-
- mDragEnforcer = new DropTarget.DragEnforcer(context);
- // With workspace, data is available straight from the get-go
- setDataIsReady();
-
- final Resources res = getResources();
- mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
- mFadeInAdjacentScreens = false;
- mWallpaperManager = WallpaperManager.getInstance(context);
-
- int cellCountX = DEFAULT_CELL_COUNT_X;
- int cellCountY = DEFAULT_CELL_COUNT_Y;
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.Workspace, defStyle, 0);
-
- if (LauncherApplication.isScreenLarge()) {
- // Determine number of rows/columns dynamically
- // TODO: This code currently fails on tablets with an aspect ratio < 1.3.
- // Around that ratio we should make cells the same size in portrait and
- // landscape
- TypedArray actionBarSizeTypedArray =
- context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
- DisplayMetrics displayMetrics = res.getDisplayMetrics();
- final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
- final float systemBarHeight = res.getDimension(R.dimen.status_bar_height);
- final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp *
- displayMetrics.density;
-
- cellCountX = 1;
- while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) {
- cellCountX++;
- }
-
- cellCountY = 1;
- while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
- <= smallestScreenDim - systemBarHeight) {
- cellCountY++;
- }
- }
-
- mSpringLoadedShrinkFactor =
- res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
- mSpringLoadedPageSpacing =
- res.getDimensionPixelSize(R.dimen.workspace_spring_loaded_page_spacing);
- mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
-
- // if the value is manually specified, use that instead
- cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
- cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY);
- mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
- a.recycle();
-
- setOnHierarchyChangeListener(this);
-
- LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
- setHapticFeedbackEnabled(false);
-
- mLauncher = (Launcher) context;
- initWorkspace();
-
- // Disable multitouch across the workspace/all apps/customize tray
- setMotionEventSplittingEnabled(true);
-
- // Unless otherwise specified this view is important for accessibility.
- if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
- }
-
- // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
- // dimension if unsuccessful
- public int[] estimateItemSize(int hSpan, int vSpan,
- ItemInfo itemInfo, boolean springLoaded) {
- int[] size = new int[2];
- if (getChildCount() > 0) {
- CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
- Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
- size[0] = r.width();
- size[1] = r.height();
- if (springLoaded) {
- size[0] *= mSpringLoadedShrinkFactor;
- size[1] *= mSpringLoadedShrinkFactor;
- }
- return size;
- } else {
- size[0] = Integer.MAX_VALUE;
- size[1] = Integer.MAX_VALUE;
- return size;
- }
- }
- public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
- int hCell, int vCell, int hSpan, int vSpan) {
- Rect r = new Rect();
- cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
- return r;
- }
-
- public void buildPageHardwareLayers() {
- if (getWindowToken() != null) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- CellLayout cl = (CellLayout) getChildAt(i);
- cl.getShortcutsAndWidgets().buildLayer();
- }
- }
- }
-
- public void onDragStart(DragSource source, Object info, int dragAction) {
- mIsDragOccuring = true;
- updateChildrenLayersEnabled();
- mLauncher.lockScreenOrientation();
- setChildrenBackgroundAlphaMultipliers(1f);
- // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
- InstallShortcutReceiver.enableInstallQueue();
- UninstallShortcutReceiver.enableUninstallQueue();
- }
-
- public void onDragEnd() {
- mIsDragOccuring = false;
- updateChildrenLayersEnabled();
- mLauncher.unlockScreenOrientation(false);
-
- // Re-enable any Un/InstallShortcutReceiver and now process any queued items
- InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
- UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());
- }
-
- /**
- * Initializes various states for this workspace.
- */
- protected void initWorkspace() {
- Context context = getContext();
- mCurrentPage = mDefaultPage;
- Launcher.setScreen(mCurrentPage);
- LauncherApplication app = (LauncherApplication)context.getApplicationContext();
- mIconCache = app.getIconCache();
- setWillNotDraw(false);
- setChildrenDrawnWithCacheEnabled(true);
-
- final Resources res = getResources();
- try {
- mBackground = res.getDrawable(R.drawable.apps_customize_bg);
- } catch (Resources.NotFoundException e) {
- // In this case, we will skip drawing background protection
- }
-
- mWallpaperOffset = new WallpaperOffsetInterpolator();
- Display display = mLauncher.getWindowManager().getDefaultDisplay();
- display.getSize(mDisplaySize);
- mWallpaperTravelWidth = (int) (mDisplaySize.x *
- wallpaperTravelToScreenWidthRatio(mDisplaySize.x, mDisplaySize.y));
-
- mMaxDistanceForFolderCreation = (0.55f * res.getDimensionPixelSize(R.dimen.app_icon_size));
- mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
- }
-
- @Override
- protected int getScrollMode() {
- return SmoothPagedView.X_LARGE_MODE;
- }
-
- @Override
- public void onChildViewAdded(View parent, View child) {
- if (!(child instanceof CellLayout)) {
- throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
- }
- CellLayout cl = ((CellLayout) child);
- cl.setOnInterceptTouchListener(this);
- cl.setClickable(true);
- cl.enableHardwareLayers();
- cl.setContentDescription(getContext().getString(
- R.string.workspace_description_format, getChildCount()));
- }
-
- @Override
- public void onChildViewRemoved(View parent, View child) {
- }
-
- protected boolean shouldDrawChild(View child) {
- final CellLayout cl = (CellLayout) child;
- return super.shouldDrawChild(child) &&
- (cl.getShortcutsAndWidgets().getAlpha() > 0 ||
- cl.getBackgroundAlpha() > 0);
- }
-
- /**
- * @return The open folder on the current screen, or null if there is none
- */
- Folder getOpenFolder() {
- DragLayer dragLayer = mLauncher.getDragLayer();
- int count = dragLayer.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = dragLayer.getChildAt(i);
- if (child instanceof Folder) {
- Folder folder = (Folder) child;
- if (folder.getInfo().opened)
- return folder;
- }
- }
- return null;
- }
-
- boolean isTouchActive() {
- return mTouchState != TOUCH_STATE_REST;
- }
-
- /**
- * Adds the specified child in the specified screen. The position and dimension of
- * the child are defined by x, y, spanX and spanY.
- *
- * @param child The child to add in one of the workspace's screens.
- * @param screen The screen in which to add the child.
- * @param x The X position of the child in the screen's grid.
- * @param y The Y position of the child in the screen's grid.
- * @param spanX The number of cells spanned horizontally by the child.
- * @param spanY The number of cells spanned vertically by the child.
- */
- void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) {
- addInScreen(child, container, screen, x, y, spanX, spanY, false);
- }
-
- /**
- * Adds the specified child in the specified screen. The position and dimension of
- * the child are defined by x, y, spanX and spanY.
- *
- * @param child The child to add in one of the workspace's screens.
- * @param screen The screen in which to add the child.
- * @param x The X position of the child in the screen's grid.
- * @param y The Y position of the child in the screen's grid.
- * @param spanX The number of cells spanned horizontally by the child.
- * @param spanY The number of cells spanned vertically by the child.
- * @param insert When true, the child is inserted at the beginning of the children list.
- */
- void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,
- boolean insert) {
- if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (screen < 0 || screen >= getChildCount()) {
- Log.e(TAG, "The screen must be >= 0 and < " + getChildCount()
- + " (was " + screen + "); skipping child");
- return;
- }
- }
-
- final CellLayout layout;
- if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- layout = mLauncher.getHotseat().getLayout();
- child.setOnKeyListener(null);
-
- // Hide folder title in the hotseat
- if (child instanceof FolderIcon) {
- ((FolderIcon) child).setTextVisible(false);
- }
-
- if (screen < 0) {
- screen = mLauncher.getHotseat().getOrderInHotseat(x, y);
- } else {
- // Note: We do this to ensure that the hotseat is always laid out in the orientation
- // of the hotseat in order regardless of which orientation they were added
- x = mLauncher.getHotseat().getCellXFromOrder(screen);
- y = mLauncher.getHotseat().getCellYFromOrder(screen);
- }
- } else {
- // Show folder title if not in the hotseat
- if (child instanceof FolderIcon) {
- ((FolderIcon) child).setTextVisible(true);
- }
-
- layout = (CellLayout) getChildAt(screen);
- child.setOnKeyListener(new IconKeyEventListener());
- }
-
- LayoutParams genericLp = child.getLayoutParams();
- CellLayout.LayoutParams lp;
- if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
- lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
- } else {
- lp = (CellLayout.LayoutParams) genericLp;
- lp.cellX = x;
- lp.cellY = y;
- lp.cellHSpan = spanX;
- lp.cellVSpan = spanY;
- }
-
- if (spanX < 0 && spanY < 0) {
- lp.isLockedToGrid = false;
- }
-
- // Get the canonical child id to uniquely represent this view in this screen
- int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);
- boolean markCellsAsOccupied = !(child instanceof Folder);
- if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
- // TODO: This branch occurs when the workspace is adding views
- // outside of the defined grid
- // maybe we should be deleting these items from the LauncherModel?
- Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
- }
-
- if (!(child instanceof Folder)) {
- child.setHapticFeedbackEnabled(false);
- child.setOnLongClickListener(mLongClickListener);
- }
- if (child instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget) child);
- }
- }
-
- /**
- * Check if the point (x, y) hits a given page.
- */
- private boolean hitsPage(int index, float x, float y) {
- final View page = getChildAt(index);
- if (page != null) {
- float[] localXY = { x, y };
- mapPointFromSelfToChild(page, localXY);
- return (localXY[0] >= 0 && localXY[0] < page.getWidth()
- && localXY[1] >= 0 && localXY[1] < page.getHeight());
- }
- return false;
- }
-
- @Override
- protected boolean hitsPreviousPage(float x, float y) {
- // mNextPage is set to INVALID_PAGE whenever we are stationary.
- // Calculating "next page" this way ensures that you scroll to whatever page you tap on
- final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
-
- // Only allow tap to next page on large devices, where there's significant margin outside
- // the active workspace
- return LauncherApplication.isScreenLarge() && hitsPage(current - 1, x, y);
- }
-
- @Override
- protected boolean hitsNextPage(float x, float y) {
- // mNextPage is set to INVALID_PAGE whenever we are stationary.
- // Calculating "next page" this way ensures that you scroll to whatever page you tap on
- final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
-
- // Only allow tap to next page on large devices, where there's significant margin outside
- // the active workspace
- return LauncherApplication.isScreenLarge() && hitsPage(current + 1, x, y);
- }
-
- /**
- * Called directly from a CellLayout (not by the framework), after we've been added as a
- * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
- * that it should intercept touch events, which is not something that is normally supported.
- */
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return (isSmall() || !isFinishedSwitchingState());
- }
-
- public boolean isSwitchingState() {
- return mIsSwitchingState;
- }
-
- /** This differs from isSwitchingState in that we take into account how far the transition
- * has completed. */
- public boolean isFinishedSwitchingState() {
- return !mIsSwitchingState || (mTransitionProgress > 0.5f);
- }
-
- protected void onWindowVisibilityChanged (int visibility) {
- mLauncher.onWindowVisibilityChanged(visibility);
- }
-
- @Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- if (isSmall() || !isFinishedSwitchingState()) {
- // when the home screens are shrunken, shouldn't allow side-scrolling
- return false;
- }
- return super.dispatchUnhandledMove(focused, direction);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- switch (ev.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- mXDown = ev.getX();
- mYDown = ev.getY();
- break;
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_REST) {
- final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
- if (!currentPage.lastDownOnOccupiedCell()) {
- onWallpaperTap(ev);
- }
- }
- }
- return super.onInterceptTouchEvent(ev);
- }
-
- protected void reinflateWidgetsIfNecessary() {
- final int clCount = getChildCount();
- for (int i = 0; i < clCount; i++) {
- CellLayout cl = (CellLayout) getChildAt(i);
- ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
- final int itemCount = swc.getChildCount();
- for (int j = 0; j < itemCount; j++) {
- View v = swc.getChildAt(j);
-
- if (v.getTag() instanceof LauncherAppWidgetInfo) {
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
- LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
- if (lahv != null && lahv.orientationChangedSincedInflation()) {
- mLauncher.removeAppWidget(info);
- // Remove the current widget which is inflated with the wrong orientation
- cl.removeView(lahv);
- mLauncher.bindAppWidget(info);
- }
- }
- }
- }
- }
-
- @Override
- protected void determineScrollingStart(MotionEvent ev) {
- if (isSmall()) return;
- if (!isFinishedSwitchingState()) return;
-
- float deltaX = Math.abs(ev.getX() - mXDown);
- float deltaY = Math.abs(ev.getY() - mYDown);
-
- if (Float.compare(deltaX, 0f) == 0) return;
-
- float slope = deltaY / deltaX;
- float theta = (float) Math.atan(slope);
-
- if (deltaX > mTouchSlop || deltaY > mTouchSlop) {
- cancelCurrentPageLongPress();
- }
-
- if (theta > MAX_SWIPE_ANGLE) {
- // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace
- return;
- } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
- // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to
- // increase the touch slop to make it harder to begin scrolling the workspace. This
- // results in vertically scrolling widgets to more easily. The higher the angle, the
- // more we increase touch slop.
- theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
- float extraRatio = (float)
- Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
- super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
- } else {
- // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special
- super.determineScrollingStart(ev);
- }
- }
-
- @Override
- protected boolean isScrollingIndicatorEnabled() {
- return super.isScrollingIndicatorEnabled() && (mState != State.SPRING_LOADED);
- }
-
- protected void onPageBeginMoving() {
- super.onPageBeginMoving();
-
- if (isHardwareAccelerated()) {
- updateChildrenLayersEnabled();
- } else {
- if (mNextPage != INVALID_PAGE) {
- // we're snapping to a particular screen
- enableChildrenCache(mCurrentPage, mNextPage);
- } else {
- // this is when user is actively dragging a particular screen, they might
- // swipe it either left or right (but we won't advance by more than one screen)
- enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
- }
- }
-
- // Only show page outlines as we pan if we are on large screen
- if (LauncherApplication.isScreenLarge()) {
- showOutlines();
- mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null;
- }
-
- // If we are not fading in adjacent screens, we still need to restore the alpha in case the
- // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
- if (!mWorkspaceFadeInAdjacentScreens) {
- for (int i = 0; i < getChildCount(); ++i) {
- ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);
- }
- }
-
- // Show the scroll indicator as you pan the page
- showScrollingIndicator(false);
- }
-
- protected void onPageEndMoving() {
- super.onPageEndMoving();
-
- if (isHardwareAccelerated()) {
- updateChildrenLayersEnabled();
- } else {
- clearChildrenCache();
- }
-
-
- if (mDragController.isDragging()) {
- if (isSmall()) {
- // If we are in springloaded mode, then force an event to check if the current touch
- // is under a new page (to scroll to)
- mDragController.forceMoveEvent();
- }
- } else {
- // If we are not mid-dragging, hide the page outlines if we are on a large screen
- if (LauncherApplication.isScreenLarge()) {
- hideOutlines();
- }
-
- // Hide the scroll indicator as you pan the page
- if (!mDragController.isDragging()) {
- hideScrollingIndicator(false);
- }
- }
- mOverScrollMaxBackgroundAlpha = 0.0f;
-
- if (mDelayedResizeRunnable != null) {
- mDelayedResizeRunnable.run();
- mDelayedResizeRunnable = null;
- }
-
- if (mDelayedSnapToPageRunnable != null) {
- mDelayedSnapToPageRunnable.run();
- mDelayedSnapToPageRunnable = null;
- }
- }
-
- @Override
- protected void notifyPageSwitchListener() {
- super.notifyPageSwitchListener();
- Launcher.setScreen(mCurrentPage);
- };
-
- // As a ratio of screen height, the total distance we want the parallax effect to span
- // horizontally
- private float wallpaperTravelToScreenWidthRatio(int width, int height) {
- float aspectRatio = width / (float) height;
-
- // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
- // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
- // We will use these two data points to extrapolate how much the wallpaper parallax effect
- // to span (ie travel) at any aspect ratio:
-
- final float ASPECT_RATIO_LANDSCAPE = 16/10f;
- final float ASPECT_RATIO_PORTRAIT = 10/16f;
- final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
- final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
-
- // To find out the desired width at different aspect ratios, we use the following two
- // formulas, where the coefficient on x is the aspect ratio (width/height):
- // (16/10)x + y = 1.5
- // (10/16)x + y = 1.2
- // We solve for x and y and end up with a final formula:
- final float x =
- (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
- (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
- final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
- return x * aspectRatio + y;
- }
-
- // The range of scroll values for Workspace
- private int getScrollRange() {
- return getChildOffset(getChildCount() - 1) - getChildOffset(0);
- }
-
- protected void setWallpaperDimension() {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- mLauncher.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
- final int maxDim = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
- final int minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels);
-
- // We need to ensure that there is enough extra space in the wallpaper for the intended
- // parallax effects
- if (LauncherApplication.isScreenLarge()) {
- mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
- mWallpaperHeight = maxDim;
- } else {
- mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
- mWallpaperHeight = maxDim;
- }
- new Thread("setWallpaperDimension") {
- public void run() {
- mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
- }
- }.start();
- }
-
- private float wallpaperOffsetForCurrentScroll() {
- // Set wallpaper offset steps (1 / (number of screens - 1))
- mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
-
- // For the purposes of computing the scrollRange and overScrollOffset, we assume
- // that mLayoutScale is 1. This means that when we're in spring-loaded mode,
- // there's no discrepancy between the wallpaper offset for a given page.
- float layoutScale = mLayoutScale;
- mLayoutScale = 1f;
- int scrollRange = getScrollRange();
-
- // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale
- float adjustedScrollX = Math.max(0, Math.min(getScrollX(), mMaxScrollX));
- adjustedScrollX *= mWallpaperScrollRatio;
- mLayoutScale = layoutScale;
-
- float scrollProgress =
- adjustedScrollX / (float) scrollRange;
-
- if (LauncherApplication.isScreenLarge() && mIsStaticWallpaper) {
- // The wallpaper travel width is how far, from left to right, the wallpaper will move
- // at this orientation. On tablets in portrait mode we don't move all the way to the
- // edges of the wallpaper, or otherwise the parallax effect would be too strong.
- int wallpaperTravelWidth = Math.min(mWallpaperTravelWidth, mWallpaperWidth);
-
- float offsetInDips = wallpaperTravelWidth * scrollProgress +
- (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
- float offset = offsetInDips / (float) mWallpaperWidth;
- return offset;
- } else {
- return scrollProgress;
- }
- }
-
- private void syncWallpaperOffsetWithScroll() {
- final boolean enableWallpaperEffects = isHardwareAccelerated();
- if (enableWallpaperEffects) {
- mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
- }
- }
-
- public void updateWallpaperOffsetImmediately() {
- mUpdateWallpaperOffsetImmediately = true;
- }
-
- private void updateWallpaperOffsets() {
- boolean updateNow = false;
- boolean keepUpdating = true;
- if (mUpdateWallpaperOffsetImmediately) {
- updateNow = true;
- keepUpdating = false;
- mWallpaperOffset.jumpToFinal();
- mUpdateWallpaperOffsetImmediately = false;
- } else {
- updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
- }
- if (updateNow) {
- if (mWindowToken != null) {
- mWallpaperManager.setWallpaperOffsets(mWindowToken,
- mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
- }
- }
- if (keepUpdating) {
- invalidate();
- }
- }
-
- @Override
- protected void updateCurrentPageScroll() {
- super.updateCurrentPageScroll();
- computeWallpaperScrollRatio(mCurrentPage);
- }
-
- @Override
- protected void snapToPage(int whichPage) {
- super.snapToPage(whichPage);
- computeWallpaperScrollRatio(whichPage);
- }
-
- @Override
- protected void snapToPage(int whichPage, int duration) {
- super.snapToPage(whichPage, duration);
- computeWallpaperScrollRatio(whichPage);
- }
-
- protected void snapToPage(int whichPage, Runnable r) {
- if (mDelayedSnapToPageRunnable != null) {
- mDelayedSnapToPageRunnable.run();
- }
- mDelayedSnapToPageRunnable = r;
- snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION);
- }
-
- private void computeWallpaperScrollRatio(int page) {
- // Here, we determine what the desired scroll would be with and without a layout scale,
- // and compute a ratio between the two. This allows us to adjust the wallpaper offset
- // as though there is no layout scale.
- float layoutScale = mLayoutScale;
- int scaled = getChildOffset(page) - getRelativeChildOffset(page);
- mLayoutScale = 1.0f;
- float unscaled = getChildOffset(page) - getRelativeChildOffset(page);
- mLayoutScale = layoutScale;
- if (scaled > 0) {
- mWallpaperScrollRatio = (1.0f * unscaled) / scaled;
- } else {
- mWallpaperScrollRatio = 1f;
- }
- }
-
- class WallpaperOffsetInterpolator {
- float mFinalHorizontalWallpaperOffset = 0.0f;
- float mFinalVerticalWallpaperOffset = 0.5f;
- float mHorizontalWallpaperOffset = 0.0f;
- float mVerticalWallpaperOffset = 0.5f;
- long mLastWallpaperOffsetUpdateTime;
- boolean mIsMovingFast;
- boolean mOverrideHorizontalCatchupConstant;
- float mHorizontalCatchupConstant = 0.35f;
- float mVerticalCatchupConstant = 0.35f;
-
- public WallpaperOffsetInterpolator() {
- }
-
- public void setOverrideHorizontalCatchupConstant(boolean override) {
- mOverrideHorizontalCatchupConstant = override;
- }
-
- public void setHorizontalCatchupConstant(float f) {
- mHorizontalCatchupConstant = f;
- }
-
- public void setVerticalCatchupConstant(float f) {
- mVerticalCatchupConstant = f;
- }
-
- public boolean computeScrollOffset() {
- if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 &&
- Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) {
- mIsMovingFast = false;
- return false;
- }
- boolean isLandscape = mDisplaySize.x > mDisplaySize.y;
-
- long currentTime = System.currentTimeMillis();
- long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime;
- timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate);
- timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate);
-
- float xdiff = Math.abs(mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset);
- if (!mIsMovingFast && xdiff > 0.07) {
- mIsMovingFast = true;
- }
-
- float fractionToCatchUpIn1MsHorizontal;
- if (mOverrideHorizontalCatchupConstant) {
- fractionToCatchUpIn1MsHorizontal = mHorizontalCatchupConstant;
- } else if (mIsMovingFast) {
- fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.5f : 0.75f;
- } else {
- // slow
- fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.27f : 0.5f;
- }
- float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
-
- fractionToCatchUpIn1MsHorizontal /= 33f;
- fractionToCatchUpIn1MsVertical /= 33f;
-
- final float UPDATE_THRESHOLD = 0.00001f;
- float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset;
- float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset;
- boolean jumpToFinalValue = Math.abs(hOffsetDelta) < UPDATE_THRESHOLD &&
- Math.abs(vOffsetDelta) < UPDATE_THRESHOLD;
-
- // Don't have any lag between workspace and wallpaper on non-large devices
- if (!LauncherApplication.isScreenLarge() || jumpToFinalValue) {
- mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
- mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
- } else {
- float percentToCatchUpVertical =
- Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsVertical);
- float percentToCatchUpHorizontal =
- Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal);
- mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta;
- mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta;
- }
-
- mLastWallpaperOffsetUpdateTime = System.currentTimeMillis();
- return true;
- }
-
- public float getCurrX() {
- return mHorizontalWallpaperOffset;
- }
-
- public float getFinalX() {
- return mFinalHorizontalWallpaperOffset;
- }
-
- public float getCurrY() {
- return mVerticalWallpaperOffset;
- }
-
- public float getFinalY() {
- return mFinalVerticalWallpaperOffset;
- }
-
- public void setFinalX(float x) {
- mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f));
- }
-
- public void setFinalY(float y) {
- mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f));
- }
-
- public void jumpToFinal() {
- mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
- mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
- }
- }
-
- @Override
- public void computeScroll() {
- super.computeScroll();
- syncWallpaperOffsetWithScroll();
- }
-
- void showOutlines() {
- if (!isSmall() && !mIsSwitchingState) {
- if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
- if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
- mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f);
- mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
- mChildrenOutlineFadeInAnimation.start();
- }
- }
-
- void hideOutlines() {
- if (!isSmall() && !mIsSwitchingState) {
- if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
- if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
- mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f);
- mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
- mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
- mChildrenOutlineFadeOutAnimation.start();
- }
- }
-
- public void showOutlinesTemporarily() {
- if (!mIsPageMoving && !isTouchActive()) {
- snapToPage(mCurrentPage);
- }
- }
-
- public void setChildrenOutlineAlpha(float alpha) {
- mChildrenOutlineAlpha = alpha;
- for (int i = 0; i < getChildCount(); i++) {
- CellLayout cl = (CellLayout) getChildAt(i);
- cl.setBackgroundAlpha(alpha);
- }
- }
-
- public float getChildrenOutlineAlpha() {
- return mChildrenOutlineAlpha;
- }
-
- void disableBackground() {
- mDrawBackground = false;
- }
- void enableBackground() {
- mDrawBackground = true;
- }
-
- private void animateBackgroundGradient(float finalAlpha, boolean animated) {
- if (mBackground == null) return;
- if (mBackgroundFadeInAnimation != null) {
- mBackgroundFadeInAnimation.cancel();
- mBackgroundFadeInAnimation = null;
- }
- if (mBackgroundFadeOutAnimation != null) {
- mBackgroundFadeOutAnimation.cancel();
- mBackgroundFadeOutAnimation = null;
- }
- float startAlpha = getBackgroundAlpha();
- if (finalAlpha != startAlpha) {
- if (animated) {
- mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(startAlpha, finalAlpha);
- mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
- }
- });
- mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
- mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
- mBackgroundFadeOutAnimation.start();
- } else {
- setBackgroundAlpha(finalAlpha);
- }
- }
- }
-
- public void setBackgroundAlpha(float alpha) {
- if (alpha != mBackgroundAlpha) {
- mBackgroundAlpha = alpha;
- invalidate();
- }
- }
-
- public float getBackgroundAlpha() {
- return mBackgroundAlpha;
- }
-
- /**
- * Due to 3D transformations, if two CellLayouts are theoretically touching each other,
- * on the xy plane, when one is rotated along the y-axis, the gap between them is perceived
- * as being larger. This method computes what offset the rotated view should be translated
- * in order to minimize this perceived gap.
- * @param degrees Angle of the view
- * @param width Width of the view
- * @param height Height of the view
- * @return Offset to be used in a View.setTranslationX() call
- */
- private float getOffsetXForRotation(float degrees, int width, int height) {
- mMatrix.reset();
- mCamera.save();
- mCamera.rotateY(Math.abs(degrees));
- mCamera.getMatrix(mMatrix);
- mCamera.restore();
-
- mMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
- mMatrix.postTranslate(width * 0.5f, height * 0.5f);
- mTempFloat2[0] = width;
- mTempFloat2[1] = height;
- mMatrix.mapPoints(mTempFloat2);
- return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
- }
-
- float backgroundAlphaInterpolator(float r) {
- float pivotA = 0.1f;
- float pivotB = 0.4f;
- if (r < pivotA) {
- return 0;
- } else if (r > pivotB) {
- return 1.0f;
- } else {
- return (r - pivotA)/(pivotB - pivotA);
- }
- }
-
- float overScrollBackgroundAlphaInterpolator(float r) {
- float threshold = 0.08f;
-
- if (r > mOverScrollMaxBackgroundAlpha) {
- mOverScrollMaxBackgroundAlpha = r;
- } else if (r < mOverScrollMaxBackgroundAlpha) {
- r = mOverScrollMaxBackgroundAlpha;
- }
-
- return Math.min(r / threshold, 1.0f);
- }
-
- private void updatePageAlphaValues(int screenCenter) {
- boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
- if (mWorkspaceFadeInAdjacentScreens &&
- mState == State.NORMAL &&
- !mIsSwitchingState &&
- !isInOverscroll) {
- for (int i = 0; i < getChildCount(); i++) {
- CellLayout child = (CellLayout) getChildAt(i);
- if (child != null) {
- float scrollProgress = getScrollProgress(screenCenter, child, i);
- float alpha = 1 - Math.abs(scrollProgress);
- child.getShortcutsAndWidgets().setAlpha(alpha);
- if (!mIsDragOccuring) {
- child.setBackgroundAlphaMultiplier(
- backgroundAlphaInterpolator(Math.abs(scrollProgress)));
- } else {
- child.setBackgroundAlphaMultiplier(1f);
- }
- }
- }
- }
- }
-
- private void setChildrenBackgroundAlphaMultipliers(float a) {
- for (int i = 0; i < getChildCount(); i++) {
- CellLayout child = (CellLayout) getChildAt(i);
- child.setBackgroundAlphaMultiplier(a);
- }
- }
-
- @Override
- protected void screenScrolled(int screenCenter) {
- super.screenScrolled(screenCenter);
-
- updatePageAlphaValues(screenCenter);
-
- if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
- int index = mOverScrollX < 0 ? 0 : getChildCount() - 1;
- CellLayout cl = (CellLayout) getChildAt(index);
- float scrollProgress = getScrollProgress(screenCenter, cl, index);
- cl.setOverScrollAmount(Math.abs(scrollProgress), index == 0);
- float rotation = - WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
- cl.setRotationY(rotation);
- setFadeForOverScroll(Math.abs(scrollProgress));
- if (!mOverscrollTransformsSet) {
- mOverscrollTransformsSet = true;
- cl.setCameraDistance(mDensity * mCameraDistance);
- cl.setPivotX(cl.getMeasuredWidth() * (index == 0 ? 0.75f : 0.25f));
- cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
- cl.setOverscrollTransformsDirty(true);
- }
- } else {
- if (mOverscrollFade != 0) {
- setFadeForOverScroll(0);
- }
- if (mOverscrollTransformsSet) {
- mOverscrollTransformsSet = false;
- ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
- ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
- }
- }
- }
-
- @Override
- protected void overScroll(float amount) {
- acceleratedOverScroll(amount);
- }
-
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mWindowToken = getWindowToken();
- computeScroll();
- mDragController.setWindowToken(mWindowToken);
- }
-
- protected void onDetachedFromWindow() {
- mWindowToken = null;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
- mUpdateWallpaperOffsetImmediately = true;
- }
- super.onLayout(changed, left, top, right, bottom);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- updateWallpaperOffsets();
-
- // Draw the background gradient if necessary
- if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
- int alpha = (int) (mBackgroundAlpha * 255);
- mBackground.setAlpha(alpha);
- mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),
- getMeasuredHeight());
- mBackground.draw(canvas);
- }
-
- super.onDraw(canvas);
- }
-
- boolean isDrawingBackgroundGradient() {
- return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
- }
-
- @Override
- protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- if (!mLauncher.isAllAppsVisible()) {
- final Folder openFolder = getOpenFolder();
- if (openFolder != null) {
- return openFolder.requestFocus(direction, previouslyFocusedRect);
- } else {
- return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
- }
- }
- return false;
- }
-
- @Override
- public int getDescendantFocusability() {
- if (isSmall()) {
- return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
- }
- return super.getDescendantFocusability();
- }
-
- @Override
- public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- if (!mLauncher.isAllAppsVisible()) {
- final Folder openFolder = getOpenFolder();
- if (openFolder != null) {
- openFolder.addFocusables(views, direction);
- } else {
- super.addFocusables(views, direction, focusableMode);
- }
- }
- }
-
- public boolean isSmall() {
- return mState == State.SMALL || mState == State.SPRING_LOADED;
- }
-
- void enableChildrenCache(int fromPage, int toPage) {
- if (fromPage > toPage) {
- final int temp = fromPage;
- fromPage = toPage;
- toPage = temp;
- }
-
- final int screenCount = getChildCount();
-
- fromPage = Math.max(fromPage, 0);
- toPage = Math.min(toPage, screenCount - 1);
-
- for (int i = fromPage; i <= toPage; i++) {
- final CellLayout layout = (CellLayout) getChildAt(i);
- layout.setChildrenDrawnWithCacheEnabled(true);
- layout.setChildrenDrawingCacheEnabled(true);
- }
- }
-
- void clearChildrenCache() {
- final int screenCount = getChildCount();
- for (int i = 0; i < screenCount; i++) {
- final CellLayout layout = (CellLayout) getChildAt(i);
- layout.setChildrenDrawnWithCacheEnabled(false);
- // In software mode, we don't want the items to continue to be drawn into bitmaps
- if (!isHardwareAccelerated()) {
- layout.setChildrenDrawingCacheEnabled(false);
- }
- }
- }
-
- private void updateChildrenLayersEnabled() {
- boolean small = mState == State.SMALL || mIsSwitchingState;
- boolean enableChildrenLayers = small || mAnimatingViewIntoPlace || isPageMoving();
-
- if (enableChildrenLayers != mChildrenLayersEnabled) {
- mChildrenLayersEnabled = enableChildrenLayers;
- for (int i = 0; i < getPageCount(); i++) {
- ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(mChildrenLayersEnabled);
- }
- }
- }
-
- protected void onWallpaperTap(MotionEvent ev) {
- final int[] position = mTempCell;
- getLocationOnScreen(position);
-
- int pointerIndex = ev.getActionIndex();
- position[0] += (int) ev.getX(pointerIndex);
- position[1] += (int) ev.getY(pointerIndex);
-
- mWallpaperManager.sendWallpaperCommand(getWindowToken(),
- ev.getAction() == MotionEvent.ACTION_UP
- ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
- position[0], position[1], 0, null);
- }
-
- /*
- * This interpolator emulates the rate at which the perceived scale of an object changes
- * as its distance from a camera increases. When this interpolator is applied to a scale
- * animation on a view, it evokes the sense that the object is shrinking due to moving away
- * from the camera.
- */
- static class ZInterpolator implements TimeInterpolator {
- private float focalLength;
-
- public ZInterpolator(float foc) {
- focalLength = foc;
- }
-
- public float getInterpolation(float input) {
- return (1.0f - focalLength / (focalLength + input)) /
- (1.0f - focalLength / (focalLength + 1.0f));
- }
- }
-
- /*
- * The exact reverse of ZInterpolator.
- */
- static class InverseZInterpolator implements TimeInterpolator {
- private ZInterpolator zInterpolator;
- public InverseZInterpolator(float foc) {
- zInterpolator = new ZInterpolator(foc);
- }
- public float getInterpolation(float input) {
- return 1 - zInterpolator.getInterpolation(1 - input);
- }
- }
-
- /*
- * ZInterpolator compounded with an ease-out.
- */
- static class ZoomOutInterpolator implements TimeInterpolator {
- private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
- private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
-
- public float getInterpolation(float input) {
- return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
- }
- }
-
- /*
- * InvereZInterpolator compounded with an ease-out.
- */
- static class ZoomInInterpolator implements TimeInterpolator {
- private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
- private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
-
- public float getInterpolation(float input) {
- return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
- }
- }
-
- private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
-
- /*
- *
- * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
- * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
- *
- * These methods mark the appropriate pages as accepting drops (which alters their visual
- * appearance).
- *
- */
- public void onDragStartedWithItem(View v) {
- final Canvas canvas = new Canvas();
-
- // The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
- }
-
- public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) {
- final Canvas canvas = new Canvas();
-
- int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
-
- // The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
- size[1], alphaClipPaint);
- }
-
- public void exitWidgetResizeMode() {
- DragLayer dragLayer = mLauncher.getDragLayer();
- dragLayer.clearAllResizeFrames();
- }
-
- private void initAnimationArrays() {
- final int childCount = getChildCount();
- if (mOldTranslationXs != null) return;
- mOldTranslationXs = new float[childCount];
- mOldTranslationYs = new float[childCount];
- mOldScaleXs = new float[childCount];
- mOldScaleYs = new float[childCount];
- mOldBackgroundAlphas = new float[childCount];
- mOldAlphas = new float[childCount];
- mNewTranslationXs = new float[childCount];
- mNewTranslationYs = new float[childCount];
- mNewScaleXs = new float[childCount];
- mNewScaleYs = new float[childCount];
- mNewBackgroundAlphas = new float[childCount];
- mNewAlphas = new float[childCount];
- mNewRotationYs = new float[childCount];
- }
-
- Animator getChangeStateAnimation(final State state, boolean animated) {
- return getChangeStateAnimation(state, animated, 0);
- }
-
- Animator getChangeStateAnimation(final State state, boolean animated, int delay) {
- if (mState == state) {
- return null;
- }
-
- // Initialize animation arrays for the first time if necessary
- initAnimationArrays();
-
- AnimatorSet anim = animated ? new AnimatorSet() : null;
-
- // Stop any scrolling, move to the current page right away
- setCurrentPage(getNextPage());
-
- final State oldState = mState;
- final boolean oldStateIsNormal = (oldState == State.NORMAL);
- final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
- final boolean oldStateIsSmall = (oldState == State.SMALL);
- mState = state;
- final boolean stateIsNormal = (state == State.NORMAL);
- final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
- final boolean stateIsSmall = (state == State.SMALL);
- float finalScaleFactor = 1.0f;
- float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
- float translationX = 0;
- float translationY = 0;
- boolean zoomIn = true;
-
- if (state != State.NORMAL) {
- finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0);
- setPageSpacing(mSpringLoadedPageSpacing);
- if (oldStateIsNormal && stateIsSmall) {
- zoomIn = false;
- setLayoutScale(finalScaleFactor);
- updateChildrenLayersEnabled();
- } else {
- finalBackgroundAlpha = 1.0f;
- setLayoutScale(finalScaleFactor);
- }
- } else {
- setPageSpacing(PagedView.AUTOMATIC_PAGE_SPACING);
- setLayoutScale(1.0f);
- }
-
- final int duration = zoomIn ?
- getResources().getInteger(R.integer.config_workspaceUnshrinkTime) :
- getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
- for (int i = 0; i < getChildCount(); i++) {
- final CellLayout cl = (CellLayout) getChildAt(i);
- float finalAlpha = (!mWorkspaceFadeInAdjacentScreens || stateIsSpringLoaded ||
- (i == mCurrentPage)) ? 1f : 0f;
- float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
- float initialAlpha = currentAlpha;
-
- // Determine the pages alpha during the state transition
- if ((oldStateIsSmall && stateIsNormal) ||
- (oldStateIsNormal && stateIsSmall)) {
- // To/from workspace - only show the current page unless the transition is not
- // animated and the animation end callback below doesn't run;
- // or, if we're in spring-loaded mode
- if (i == mCurrentPage || !animated || oldStateIsSpringLoaded) {
- finalAlpha = 1f;
- } else {
- initialAlpha = 0f;
- finalAlpha = 0f;
- }
- }
-
- mOldAlphas[i] = initialAlpha;
- mNewAlphas[i] = finalAlpha;
- if (animated) {
- mOldTranslationXs[i] = cl.getTranslationX();
- mOldTranslationYs[i] = cl.getTranslationY();
- mOldScaleXs[i] = cl.getScaleX();
- mOldScaleYs[i] = cl.getScaleY();
- mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
-
- mNewTranslationXs[i] = translationX;
- mNewTranslationYs[i] = translationY;
- mNewScaleXs[i] = finalScaleFactor;
- mNewScaleYs[i] = finalScaleFactor;
- mNewBackgroundAlphas[i] = finalBackgroundAlpha;
- } else {
- cl.setTranslationX(translationX);
- cl.setTranslationY(translationY);
- cl.setScaleX(finalScaleFactor);
- cl.setScaleY(finalScaleFactor);
- cl.setBackgroundAlpha(finalBackgroundAlpha);
- cl.setShortcutAndWidgetAlpha(finalAlpha);
- }
- }
-
- if (animated) {
- for (int index = 0; index < getChildCount(); index++) {
- final int i = index;
- final CellLayout cl = (CellLayout) getChildAt(i);
- float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
- if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
- cl.setTranslationX(mNewTranslationXs[i]);
- cl.setTranslationY(mNewTranslationYs[i]);
- cl.setScaleX(mNewScaleXs[i]);
- cl.setScaleY(mNewScaleYs[i]);
- cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
- cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
- cl.setRotationY(mNewRotationYs[i]);
- } else {
- LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl);
- a.translationX(mNewTranslationXs[i])
- .translationY(mNewTranslationYs[i])
- .scaleX(mNewScaleXs[i])
- .scaleY(mNewScaleYs[i])
- .setDuration(duration)
- .setInterpolator(mZoomInInterpolator);
- anim.play(a);
-
- if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
- LauncherViewPropertyAnimator alphaAnim =
- new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
- alphaAnim.alpha(mNewAlphas[i])
- .setDuration(duration)
- .setInterpolator(mZoomInInterpolator);
- anim.play(alphaAnim);
- }
- if (mOldBackgroundAlphas[i] != 0 ||
- mNewBackgroundAlphas[i] != 0) {
- ValueAnimator bgAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
- bgAnim.setInterpolator(mZoomInInterpolator);
- bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
- public void onAnimationUpdate(float a, float b) {
- cl.setBackgroundAlpha(
- a * mOldBackgroundAlphas[i] +
- b * mNewBackgroundAlphas[i]);
- }
- });
- anim.play(bgAnim);
- }
- }
- }
- buildPageHardwareLayers();
- anim.setStartDelay(delay);
- }
-
- if (stateIsSpringLoaded) {
- // Right now we're covered by Apps Customize
- // Show the background gradient immediately, so the gradient will
- // be showing once AppsCustomize disappears
- animateBackgroundGradient(getResources().getInteger(
- R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
- } else {
- // Fade the background gradient away
- animateBackgroundGradient(0f, true);
- }
- return anim;
- }
-
- @Override
- public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mIsSwitchingState = true;
- cancelScrollingIndicatorAnimations();
- }
-
- @Override
- public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- }
-
- @Override
- public void onLauncherTransitionStep(Launcher l, float t) {
- mTransitionProgress = t;
- }
-
- @Override
- public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mIsSwitchingState = false;
- mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
- updateChildrenLayersEnabled();
- // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
- // ensure that only the current page is visible during (and subsequently, after) the
- // transition animation. If fade adjacent pages is disabled, then re-enable the page
- // visibility after the transition animation.
- if (!mWorkspaceFadeInAdjacentScreens) {
- for (int i = 0; i < getChildCount(); i++) {
- final CellLayout cl = (CellLayout) getChildAt(i);
- cl.setShortcutAndWidgetAlpha(1f);
- }
- }
- }
-
- @Override
- public View getContent() {
- return this;
- }
-
- /**
- * Draw the View v into the given Canvas.
- *
- * @param v the view to draw
- * @param destCanvas the canvas to draw on
- * @param padding the horizontal and vertical padding to use when drawing
- */
- private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
- final Rect clipRect = mTempRect;
- v.getDrawingRect(clipRect);
-
- boolean textVisible = false;
-
- destCanvas.save();
- if (v instanceof TextView && pruneToDrawable) {
- Drawable d = ((TextView) v).getCompoundDrawables()[1];
- clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);
- destCanvas.translate(padding / 2, padding / 2);
- d.draw(destCanvas);
- } else {
- if (v instanceof FolderIcon) {
- // For FolderIcons the text can bleed into the icon area, and so we need to
- // hide the text completely (which can't be achieved by clipping).
- if (((FolderIcon) v).getTextVisible()) {
- ((FolderIcon) v).setTextVisible(false);
- textVisible = true;
- }
- } else if (v instanceof BubbleTextView) {
- final BubbleTextView tv = (BubbleTextView) v;
- clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
- tv.getLayout().getLineTop(0);
- } else if (v instanceof TextView) {
- final TextView tv = (TextView) v;
- clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
- tv.getLayout().getLineTop(0);
- }
- destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
- destCanvas.clipRect(clipRect, Op.REPLACE);
- v.draw(destCanvas);
-
- // Restore text visibility of FolderIcon if necessary
- if (textVisible) {
- ((FolderIcon) v).setTextVisible(true);
- }
- }
- destCanvas.restore();
- }
-
- /**
- * Returns a new bitmap to show when the given View is being dragged around.
- * Responsibility for the bitmap is transferred to the caller.
- */
- public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
- Bitmap b;
-
- if (v instanceof TextView) {
- Drawable d = ((TextView) v).getCompoundDrawables()[1];
- b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,
- d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);
- } else {
- b = Bitmap.createBitmap(
- v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
- }
-
- canvas.setBitmap(b);
- drawDragView(v, canvas, padding, true);
- canvas.setBitmap(null);
-
- return b;
- }
-
- /**
- * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
- * Responsibility for the bitmap is transferred to the caller.
- */
- private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
- final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
- final Bitmap b = Bitmap.createBitmap(
- v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
-
- canvas.setBitmap(b);
- drawDragView(v, canvas, padding, true);
- mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
- canvas.setBitmap(null);
- return b;
- }
-
- /**
- * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
- * Responsibility for the bitmap is transferred to the caller.
- */
- private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
- Paint alphaClipPaint) {
- final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
- final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- canvas.setBitmap(b);
-
- Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
- float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
- (h - padding) / (float) orig.getHeight());
- int scaledWidth = (int) (scaleFactor * orig.getWidth());
- int scaledHeight = (int) (scaleFactor * orig.getHeight());
- Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
-
- // center the image
- dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
-
- canvas.drawBitmap(orig, src, dst, null);
- mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
- alphaClipPaint);
- canvas.setBitmap(null);
-
- return b;
- }
-
- void startDrag(CellLayout.CellInfo cellInfo) {
- View child = cellInfo.cell;
-
- // Make sure the drag was started by a long press as opposed to a long click.
- if (!child.isInTouchMode()) {
- return;
- }
-
- mDragInfo = cellInfo;
- child.setVisibility(INVISIBLE);
- CellLayout layout = (CellLayout) child.getParent().getParent();
- layout.prepareChildForDrag(child);
-
- child.clearFocus();
- child.setPressed(false);
-
- final Canvas canvas = new Canvas();
-
- // The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
- beginDragShared(child, this);
- }
-
- public void beginDragShared(View child, DragSource source) {
- Resources r = getResources();
-
- // The drag bitmap follows the touch point around on the screen
- final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
-
- final int bmpWidth = b.getWidth();
- final int bmpHeight = b.getHeight();
-
- mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
- int dragLayerX =
- Math.round(mTempXY[0] - (bmpWidth - child.getScaleX() * child.getWidth()) / 2);
- int dragLayerY =
- Math.round(mTempXY[1] - (bmpHeight - child.getScaleY() * bmpHeight) / 2
- - DRAG_BITMAP_PADDING / 2);
-
- Point dragVisualizeOffset = null;
- Rect dragRect = null;
- if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
- int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
- int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top);
- int top = child.getPaddingTop();
- int left = (bmpWidth - iconSize) / 2;
- int right = left + iconSize;
- int bottom = top + iconSize;
- dragLayerY += top;
- // Note: The drag region is used to calculate drag layer offsets, but the
- // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
- dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2,
- iconPaddingTop - DRAG_BITMAP_PADDING / 2);
- dragRect = new Rect(left, top, right, bottom);
- } else if (child instanceof FolderIcon) {
- int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size);
- dragRect = new Rect(0, 0, child.getWidth(), previewSize);
- }
-
- // Clear the pressed state if necessary
- if (child instanceof BubbleTextView) {
- BubbleTextView icon = (BubbleTextView) child;
- icon.clearPressedOrFocusedBackground();
- }
-
- mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
- DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, child.getScaleX());
- b.recycle();
-
- // Show the scrolling indicator when you pick up an item
- showScrollingIndicator(false);
- }
-
- void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen,
- int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
- View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
-
- final int[] cellXY = new int[2];
- target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
- addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0],
- cellXY[1]);
- }
-
- public boolean transitionStateShouldAllowDrop() {
- return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean acceptDrop(DragObject d) {
- // If it's an external drop (e.g. from All Apps), check if it should be accepted
- CellLayout dropTargetLayout = mDropToLayout;
- if (d.dragSource != this) {
- // Don't accept the drop if we're not over a screen at time of drop
- if (dropTargetLayout == null) {
- return false;
- }
- if (!transitionStateShouldAllowDrop()) return false;
-
- mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
- d.dragView, mDragViewVisualCenter);
-
- // We want the point to be mapped to the dragTarget.
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
- }
-
- int spanX = 1;
- int spanY = 1;
- if (mDragInfo != null) {
- final CellLayout.CellInfo dragCellInfo = mDragInfo;
- spanX = dragCellInfo.spanX;
- spanY = dragCellInfo.spanY;
- } else {
- final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
- spanX = dragInfo.spanX;
- spanY = dragInfo.spanY;
- }
-
- int minSpanX = spanX;
- int minSpanY = spanY;
- if (d.dragInfo instanceof PendingAddWidgetInfo) {
- minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;
- minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;
- }
-
- mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,
- mTargetCell);
- float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
- mDragViewVisualCenter[1], mTargetCell);
- if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
- mTargetCell, distance, true)) {
- return true;
- }
- if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
- mTargetCell, distance)) {
- return true;
- }
-
- int[] resultSpan = new int[2];
- mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
- null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);
- boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
-
- // Don't accept the drop if there's no room for the item
- if (!foundCell) {
- // Don't show the message if we are dropping on the AllApps button and the hotseat
- // is full
- boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
- if (mTargetCell != null && isHotseat) {
- Hotseat hotseat = mLauncher.getHotseat();
- if (hotseat.isAllAppsButtonRank(
- hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {
- return false;
- }
- }
-
- mLauncher.showOutOfSpaceMessage(isHotseat);
- return false;
- }
- }
- return true;
- }
-
- boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float
- distance, boolean considerTimeout) {
- if (distance > mMaxDistanceForFolderCreation) return false;
- View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
-
- if (dropOverView != null) {
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
- if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
- return false;
- }
- }
-
- boolean hasntMoved = false;
- if (mDragInfo != null) {
- hasntMoved = dropOverView == mDragInfo.cell;
- }
-
- if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {
- return false;
- }
-
- boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
- boolean willBecomeShortcut =
- (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
-
- return (aboveShortcut && willBecomeShortcut);
- }
-
- boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,
- float distance) {
- if (distance > mMaxDistanceForFolderCreation) return false;
- View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
-
- if (dropOverView != null) {
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
- if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
- return false;
- }
- }
-
- if (dropOverView instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) dropOverView;
- if (fi.acceptDrop(dragInfo)) {
- return true;
- }
- }
- return false;
- }
-
- boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
- int[] targetCell, float distance, boolean external, DragView dragView,
- Runnable postAnimationRunnable) {
- if (distance > mMaxDistanceForFolderCreation) return false;
- View v = target.getChildAt(targetCell[0], targetCell[1]);
-
- boolean hasntMoved = false;
- if (mDragInfo != null) {
- CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);
- hasntMoved = (mDragInfo.cellX == targetCell[0] &&
- mDragInfo.cellY == targetCell[1]) && (cellParent == target);
- }
-
- if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
- mCreateUserFolderOnDrop = false;
- final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target);
-
- boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
- boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
-
- if (aboveShortcut && willBecomeShortcut) {
- ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
- ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
- // if the drag started here, we need to remove it from the workspace
- if (!external) {
- getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
- }
-
- Rect folderLocation = new Rect();
- float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
- target.removeView(v);
-
- FolderIcon fi =
- mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]);
- destInfo.cellX = -1;
- destInfo.cellY = -1;
- sourceInfo.cellX = -1;
- sourceInfo.cellY = -1;
-
- // If the dragView is null, we can't animate
- boolean animate = dragView != null;
- if (animate) {
- fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
- postAnimationRunnable);
- } else {
- fi.addItem(destInfo);
- fi.addItem(sourceInfo);
- }
- return true;
- }
- return false;
- }
-
- boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
- float distance, DragObject d, boolean external) {
- if (distance > mMaxDistanceForFolderCreation) return false;
-
- View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
- if (!mAddToExistingFolderOnDrop) return false;
- mAddToExistingFolderOnDrop = false;
-
- if (dropOverView instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) dropOverView;
- if (fi.acceptDrop(d.dragInfo)) {
- fi.onDrop(d);
-
- // if the drag started here, we need to remove it from the workspace
- if (!external) {
- getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
- }
- return true;
- }
- }
- return false;
- }
-
- public void onDrop(final DragObject d) {
- mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
- mDragViewVisualCenter);
-
- CellLayout dropTargetLayout = mDropToLayout;
-
- // We want the point to be mapped to the dragTarget.
- if (dropTargetLayout != null) {
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
- }
- }
-
- int snapScreen = -1;
- boolean resizeOnDrop = false;
- if (d.dragSource != this) {
- final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1] };
- onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
- } else if (mDragInfo != null) {
- final View cell = mDragInfo.cell;
-
- Runnable resizeRunnable = null;
- if (dropTargetLayout != null) {
- // Move internally
- boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
- boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
- long container = hasMovedIntoHotseat ?
- LauncherSettings.Favorites.CONTAINER_HOTSEAT :
- LauncherSettings.Favorites.CONTAINER_DESKTOP;
- int screen = (mTargetCell[0] < 0) ?
- mDragInfo.screen : indexOfChild(dropTargetLayout);
- int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
- int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
- // First we find the cell nearest to point at which the item is
- // dropped, without any consideration to whether there is an item there.
-
- mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
- mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
- float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
- mDragViewVisualCenter[1], mTargetCell);
-
- // If the item being dropped is a shortcut and the nearest drop
- // cell also contains a shortcut, then create a folder with the two shortcuts.
- if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
- dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
- return;
- }
-
- if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
- distance, d, false)) {
- return;
- }
-
- // Aside from the special case where we're dropping a shortcut onto a shortcut,
- // we need to find the nearest cell location that is vacant
- ItemInfo item = (ItemInfo) d.dragInfo;
- int minSpanX = item.spanX;
- int minSpanY = item.spanY;
- if (item.minSpanX > 0 && item.minSpanY > 0) {
- minSpanX = item.minSpanX;
- minSpanY = item.minSpanY;
- }
-
- int[] resultSpan = new int[2];
- mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
- mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
-
- boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
- if (foundCell && (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
- resizeOnDrop = true;
- item.spanX = resultSpan[0];
- item.spanY = resultSpan[1];
- AppWidgetHostView awhv = (AppWidgetHostView) cell;
- AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
- resultSpan[1]);
- }
-
- if (mCurrentPage != screen && !hasMovedIntoHotseat) {
- snapScreen = screen;
- snapToPage(screen);
- }
-
- if (foundCell) {
- final ItemInfo info = (ItemInfo) cell.getTag();
- if (hasMovedLayouts) {
- // Reparent the view
- getParentCellLayoutForView(cell).removeView(cell);
- addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1],
- info.spanX, info.spanY);
- }
-
- // update the item's position after drop
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
- lp.cellX = lp.tmpCellX = mTargetCell[0];
- lp.cellY = lp.tmpCellY = mTargetCell[1];
- lp.cellHSpan = item.spanX;
- lp.cellVSpan = item.spanY;
- lp.isLockedToGrid = true;
- cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen,
- mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
-
- if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
- cell instanceof LauncherAppWidgetHostView) {
- final CellLayout cellLayout = dropTargetLayout;
- // We post this call so that the widget has a chance to be placed
- // in its final location
-
- final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
- AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
- if (pinfo != null &&
- pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
- final Runnable addResizeFrame = new Runnable() {
- public void run() {
- DragLayer dragLayer = mLauncher.getDragLayer();
- dragLayer.addResizeFrame(info, hostView, cellLayout);
- }
- };
- resizeRunnable = (new Runnable() {
- public void run() {
- if (!isPageMoving()) {
- addResizeFrame.run();
- } else {
- mDelayedResizeRunnable = addResizeFrame;
- }
- }
- });
- }
- }
-
- LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX,
- lp.cellY);
- } else {
- // If we can't find a drop location, we return the item to its original position
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
- mTargetCell[0] = lp.cellX;
- mTargetCell[1] = lp.cellY;
- CellLayout layout = (CellLayout) cell.getParent().getParent();
- layout.markCellsAsOccupiedForView(cell);
- }
- }
-
- final CellLayout parent = (CellLayout) cell.getParent().getParent();
- final Runnable finalResizeRunnable = resizeRunnable;
- // Prepare it to be animated into its new position
- // This must be called after the view has been re-parented
- final Runnable onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- mAnimatingViewIntoPlace = false;
- updateChildrenLayersEnabled();
- if (finalResizeRunnable != null) {
- finalResizeRunnable.run();
- }
- }
- };
- mAnimatingViewIntoPlace = true;
- if (d.dragView.hasDrawn()) {
- final ItemInfo info = (ItemInfo) cell.getTag();
- if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
- int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
- ANIMATE_INTO_POSITION_AND_DISAPPEAR;
- animateWidgetDrop(info, parent, d.dragView,
- onCompleteRunnable, animationType, cell, false);
- } else {
- int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
- mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
- onCompleteRunnable, this);
- }
- } else {
- d.deferDragViewCleanupPostAnimation = false;
- cell.setVisibility(VISIBLE);
- }
- parent.onDropChild(cell);
- }
- }
-
- public void setFinalScrollForPageChange(int screen) {
- if (screen >= 0) {
- mSavedScrollX = getScrollX();
- CellLayout cl = (CellLayout) getChildAt(screen);
- mSavedTranslationX = cl.getTranslationX();
- mSavedRotationY = cl.getRotationY();
- final int newX = getChildOffset(screen) - getRelativeChildOffset(screen);
- setScrollX(newX);
- cl.setTranslationX(0f);
- cl.setRotationY(0f);
- }
- }
-
- public void resetFinalScrollForPageChange(int screen) {
- if (screen >= 0) {
- CellLayout cl = (CellLayout) getChildAt(screen);
- setScrollX(mSavedScrollX);
- cl.setTranslationX(mSavedTranslationX);
- cl.setRotationY(mSavedRotationY);
- }
- }
-
- public void getViewLocationRelativeToSelf(View v, int[] location) {
- getLocationInWindow(location);
- int x = location[0];
- int y = location[1];
-
- v.getLocationInWindow(location);
- int vX = location[0];
- int vY = location[1];
-
- location[0] = vX - x;
- location[1] = vY - y;
- }
-
- public void onDragEnter(DragObject d) {
- mDragEnforcer.onDragEnter();
- mCreateUserFolderOnDrop = false;
- mAddToExistingFolderOnDrop = false;
-
- mDropToLayout = null;
- CellLayout layout = getCurrentDropLayout();
- setCurrentDropLayout(layout);
- setCurrentDragOverlappingLayout(layout);
-
- // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
- // don't need to show the outlines
- if (LauncherApplication.isScreenLarge()) {
- showOutlines();
- }
- }
-
- static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
- Resources res = launcher.getResources();
- Display display = launcher.getWindowManager().getDefaultDisplay();
- Point smallestSize = new Point();
- Point largestSize = new Point();
- display.getCurrentSizeRange(smallestSize, largestSize);
- if (orientation == CellLayout.LANDSCAPE) {
- if (mLandscapeCellLayoutMetrics == null) {
- int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
- int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
- int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
- int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
- int width = largestSize.x - paddingLeft - paddingRight;
- int height = smallestSize.y - paddingTop - paddingBottom;
- mLandscapeCellLayoutMetrics = new Rect();
- CellLayout.getMetrics(mLandscapeCellLayoutMetrics, res,
- width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
- orientation);
- }
- return mLandscapeCellLayoutMetrics;
- } else if (orientation == CellLayout.PORTRAIT) {
- if (mPortraitCellLayoutMetrics == null) {
- int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
- int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
- int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
- int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
- int width = smallestSize.x - paddingLeft - paddingRight;
- int height = largestSize.y - paddingTop - paddingBottom;
- mPortraitCellLayoutMetrics = new Rect();
- CellLayout.getMetrics(mPortraitCellLayoutMetrics, res,
- width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
- orientation);
- }
- return mPortraitCellLayoutMetrics;
- }
- return null;
- }
-
- public void onDragExit(DragObject d) {
- mDragEnforcer.onDragExit();
-
- // Here we store the final page that will be dropped to, if the workspace in fact
- // receives the drop
- if (mInScrollArea) {
- mDropToLayout = mDragOverlappingLayout;
- } else {
- mDropToLayout = mDragTargetLayout;
- }
-
- if (mDragMode == DRAG_MODE_CREATE_FOLDER) {
- mCreateUserFolderOnDrop = true;
- } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {
- mAddToExistingFolderOnDrop = true;
- }
-
- // Reset the scroll area and previous drag target
- onResetScrollArea();
- setCurrentDropLayout(null);
- setCurrentDragOverlappingLayout(null);
-
- mSpringLoadedDragController.cancel();
-
- if (!mIsPageMoving) {
- hideOutlines();
- }
- }
-
- void setCurrentDropLayout(CellLayout layout) {
- if (mDragTargetLayout != null) {
- mDragTargetLayout.revertTempState();
- mDragTargetLayout.onDragExit();
- }
- mDragTargetLayout = layout;
- if (mDragTargetLayout != null) {
- mDragTargetLayout.onDragEnter();
- }
- cleanupReorder(true);
- cleanupFolderCreation();
- setCurrentDropOverCell(-1, -1);
- }
-
- void setCurrentDragOverlappingLayout(CellLayout layout) {
- if (mDragOverlappingLayout != null) {
- mDragOverlappingLayout.setIsDragOverlapping(false);
- }
- mDragOverlappingLayout = layout;
- if (mDragOverlappingLayout != null) {
- mDragOverlappingLayout.setIsDragOverlapping(true);
- }
- invalidate();
- }
-
- void setCurrentDropOverCell(int x, int y) {
- if (x != mDragOverX || y != mDragOverY) {
- mDragOverX = x;
- mDragOverY = y;
- setDragMode(DRAG_MODE_NONE);
- }
- }
-
- void setDragMode(int dragMode) {
- if (dragMode != mDragMode) {
- if (dragMode == DRAG_MODE_NONE) {
- cleanupAddToFolder();
- // We don't want to cancel the re-order alarm every time the target cell changes
- // as this feels to slow / unresponsive.
- cleanupReorder(false);
- cleanupFolderCreation();
- } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {
- cleanupReorder(true);
- cleanupFolderCreation();
- } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {
- cleanupAddToFolder();
- cleanupReorder(true);
- } else if (dragMode == DRAG_MODE_REORDER) {
- cleanupAddToFolder();
- cleanupFolderCreation();
- }
- mDragMode = dragMode;
- }
- }
-
- private void cleanupFolderCreation() {
- if (mDragFolderRingAnimator != null) {
- mDragFolderRingAnimator.animateToNaturalState();
- }
- mFolderCreationAlarm.cancelAlarm();
- }
-
- private void cleanupAddToFolder() {
- if (mDragOverFolderIcon != null) {
- mDragOverFolderIcon.onDragExit(null);
- mDragOverFolderIcon = null;
- }
- }
-
- private void cleanupReorder(boolean cancelAlarm) {
- // Any pending reorders are canceled
- if (cancelAlarm) {
- mReorderAlarm.cancelAlarm();
- }
- mLastReorderX = -1;
- mLastReorderY = -1;
- }
-
- public DropTarget getDropTargetDelegate(DragObject d) {
- return null;
- }
-
- /*
- *
- * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
- * coordinate space. The argument xy is modified with the return result.
- *
- */
- void mapPointFromSelfToChild(View v, float[] xy) {
- mapPointFromSelfToChild(v, xy, null);
- }
-
- /*
- *
- * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
- * coordinate space. The argument xy is modified with the return result.
- *
- * if cachedInverseMatrix is not null, this method will just use that matrix instead of
- * computing it itself; we use this to avoid redundant matrix inversions in
- * findMatchingPageForDragOver
- *
- */
- void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
- if (cachedInverseMatrix == null) {
- v.getMatrix().invert(mTempInverseMatrix);
- cachedInverseMatrix = mTempInverseMatrix;
- }
- int scrollX = getScrollX();
- if (mNextPage != INVALID_PAGE) {
- scrollX = mScroller.getFinalX();
- }
- xy[0] = xy[0] + scrollX - v.getLeft();
- xy[1] = xy[1] + getScrollY() - v.getTop();
- cachedInverseMatrix.mapPoints(xy);
- }
-
- /*
- * Maps a point from the Workspace's coordinate system to another sibling view's. (Workspace
- * covers the full screen)
- */
- void mapPointFromSelfToSibling(View v, float[] xy) {
- xy[0] = xy[0] - v.getLeft();
- xy[1] = xy[1] - v.getTop();
- }
-
- void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
- xy[0] = xy[0] - hotseat.getLeft() - hotseat.getLayout().getLeft();
- xy[1] = xy[1] - hotseat.getTop() - hotseat.getLayout().getTop();
- }
-
- /*
- *
- * Convert the 2D coordinate xy from this CellLayout's coordinate space to
- * the parent View's coordinate space. The argument xy is modified with the return result.
- *
- */
- void mapPointFromChildToSelf(View v, float[] xy) {
- v.getMatrix().mapPoints(xy);
- int scrollX = getScrollX();
- if (mNextPage != INVALID_PAGE) {
- scrollX = mScroller.getFinalX();
- }
- xy[0] -= (scrollX - v.getLeft());
- xy[1] -= (getScrollY() - v.getTop());
- }
-
- static private float squaredDistance(float[] point1, float[] point2) {
- float distanceX = point1[0] - point2[0];
- float distanceY = point2[1] - point2[1];
- return distanceX * distanceX + distanceY * distanceY;
- }
-
- /*
- *
- * Returns true if the passed CellLayout cl overlaps with dragView
- *
- */
- boolean overlaps(CellLayout cl, DragView dragView,
- int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
- // Transform the coordinates of the item being dragged to the CellLayout's coordinates
- final float[] draggedItemTopLeft = mTempDragCoordinates;
- draggedItemTopLeft[0] = dragViewX;
- draggedItemTopLeft[1] = dragViewY;
- final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
- draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth();
- draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight();
-
- // Transform the dragged item's top left coordinates
- // to the CellLayout's local coordinates
- mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
- float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
- float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
-
- if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
- // Transform the dragged item's bottom right coordinates
- // to the CellLayout's local coordinates
- mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
- float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
- float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
-
- if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
- float overlap = (overlapRegionRight - overlapRegionLeft) *
- (overlapRegionBottom - overlapRegionTop);
- if (overlap > 0) {
- return true;
- }
- }
- }
- return false;
- }
-
- /*
- *
- * This method returns the CellLayout that is currently being dragged to. In order to drag
- * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
- * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
- *
- * Return null if no CellLayout is currently being dragged over
- *
- */
- private CellLayout findMatchingPageForDragOver(
- DragView dragView, float originX, float originY, boolean exact) {
- // We loop through all the screens (ie CellLayouts) and see which ones overlap
- // with the item being dragged and then choose the one that's closest to the touch point
- final int screenCount = getChildCount();
- CellLayout bestMatchingScreen = null;
- float smallestDistSoFar = Float.MAX_VALUE;
-
- for (int i = 0; i < screenCount; i++) {
- CellLayout cl = (CellLayout) getChildAt(i);
-
- final float[] touchXy = {originX, originY};
- // Transform the touch coordinates to the CellLayout's local coordinates
- // If the touch point is within the bounds of the cell layout, we can return immediately
- cl.getMatrix().invert(mTempInverseMatrix);
- mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
-
- if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
- touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
- return cl;
- }
-
- if (!exact) {
- // Get the center of the cell layout in screen coordinates
- final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
- cellLayoutCenter[0] = cl.getWidth()/2;
- cellLayoutCenter[1] = cl.getHeight()/2;
- mapPointFromChildToSelf(cl, cellLayoutCenter);
-
- touchXy[0] = originX;
- touchXy[1] = originY;
-
- // Calculate the distance between the center of the CellLayout
- // and the touch point
- float dist = squaredDistance(touchXy, cellLayoutCenter);
-
- if (dist < smallestDistSoFar) {
- smallestDistSoFar = dist;
- bestMatchingScreen = cl;
- }
- }
- }
- return bestMatchingScreen;
- }
-
- // This is used to compute the visual center of the dragView. This point is then
- // used to visualize drop locations and determine where to drop an item. The idea is that
- // the visual center represents the user's interpretation of where the item is, and hence
- // is the appropriate point to use when determining drop location.
- private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
- DragView dragView, float[] recycle) {
- float res[];
- if (recycle == null) {
- res = new float[2];
- } else {
- res = recycle;
- }
-
- // First off, the drag view has been shifted in a way that is not represented in the
- // x and y values or the x/yOffsets. Here we account for that shift.
- x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
- y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
-
- // These represent the visual top and left of drag view if a dragRect was provided.
- // If a dragRect was not provided, then they correspond to the actual view left and
- // top, as the dragRect is in that case taken to be the entire dragView.
- // R.dimen.dragViewOffsetY.
- int left = x - xOffset;
- int top = y - yOffset;
-
- // In order to find the visual center, we shift by half the dragRect
- res[0] = left + dragView.getDragRegion().width() / 2;
- res[1] = top + dragView.getDragRegion().height() / 2;
-
- return res;
- }
-
- private boolean isDragWidget(DragObject d) {
- return (d.dragInfo instanceof LauncherAppWidgetInfo ||
- d.dragInfo instanceof PendingAddWidgetInfo);
- }
- private boolean isExternalDragWidget(DragObject d) {
- return d.dragSource != this && isDragWidget(d);
- }
-
- public void onDragOver(DragObject d) {
- // Skip drag over events while we are dragging over side pages
- if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
-
- Rect r = new Rect();
- CellLayout layout = null;
- ItemInfo item = (ItemInfo) d.dragInfo;
-
- // Ensure that we have proper spans for the item that we are dropping
- if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
- mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
- d.dragView, mDragViewVisualCenter);
-
- final View child = (mDragInfo == null) ? null : mDragInfo.cell;
- // Identify whether we have dragged over a side page
- if (isSmall()) {
- if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
- mLauncher.getHotseat().getHitRect(r);
- if (r.contains(d.x, d.y)) {
- layout = mLauncher.getHotseat().getLayout();
- }
- }
- if (layout == null) {
- layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);
- }
- if (layout != mDragTargetLayout) {
-
- setCurrentDropLayout(layout);
- setCurrentDragOverlappingLayout(layout);
-
- boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);
- if (isInSpringLoadedMode) {
- if (mLauncher.isHotseatLayout(layout)) {
- mSpringLoadedDragController.cancel();
- } else {
- mSpringLoadedDragController.setAlarm(mDragTargetLayout);
- }
- }
- }
- } else {
- // Test to see if we are over the hotseat otherwise just use the current page
- if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
- mLauncher.getHotseat().getHitRect(r);
- if (r.contains(d.x, d.y)) {
- layout = mLauncher.getHotseat().getLayout();
- }
- }
- if (layout == null) {
- layout = getCurrentDropLayout();
- }
- if (layout != mDragTargetLayout) {
- setCurrentDropLayout(layout);
- setCurrentDragOverlappingLayout(layout);
- }
- }
-
- // Handle the drag over
- if (mDragTargetLayout != null) {
- // We want the point to be mapped to the dragTarget.
- if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
- mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
- } else {
- mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
- }
-
- ItemInfo info = (ItemInfo) d.dragInfo;
-
- mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
- mDragTargetLayout, mTargetCell);
-
- setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
-
- float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
- mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
-
- final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
- mTargetCell[1]);
-
- manageFolderFeedback(info, mDragTargetLayout, mTargetCell,
- targetCellDistance, dragOverView);
-
- int minSpanX = item.spanX;
- int minSpanY = item.spanY;
- if (item.minSpanX > 0 && item.minSpanY > 0) {
- minSpanX = item.minSpanX;
- minSpanY = item.minSpanY;
- }
-
- boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
- mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
- item.spanY, child, mTargetCell);
-
- if (!nearestDropOccupied) {
- mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
- (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
- mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,
- d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
- } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
- && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
- mLastReorderY != mTargetCell[1])) {
-
- // Otherwise, if we aren't adding to or creating a folder and there's no pending
- // reorder, then we schedule a reorder
- ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
- minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);
- mReorderAlarm.setOnAlarmListener(listener);
- mReorderAlarm.setAlarm(REORDER_TIMEOUT);
- }
-
- if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
- !nearestDropOccupied) {
- if (mDragTargetLayout != null) {
- mDragTargetLayout.revertTempState();
- }
- }
- }
- }
-
- private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,
- int[] targetCell, float distance, View dragOverView) {
- boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
- false);
-
- if (mDragMode == DRAG_MODE_NONE && userFolderPending &&
- !mFolderCreationAlarm.alarmPending()) {
- mFolderCreationAlarm.setOnAlarmListener(new
- FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
- mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
- return;
- }
-
- boolean willAddToFolder =
- willAddToExistingUserFolder(info, targetLayout, targetCell, distance);
-
- if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
- mDragOverFolderIcon = ((FolderIcon) dragOverView);
- mDragOverFolderIcon.onDragEnter(info);
- if (targetLayout != null) {
- targetLayout.clearDragOutlines();
- }
- setDragMode(DRAG_MODE_ADD_TO_FOLDER);
- return;
- }
-
- if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {
- setDragMode(DRAG_MODE_NONE);
- }
- if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {
- setDragMode(DRAG_MODE_NONE);
- }
-
- return;
- }
-
- class FolderCreationAlarmListener implements OnAlarmListener {
- CellLayout layout;
- int cellX;
- int cellY;
-
- public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
- this.layout = layout;
- this.cellX = cellX;
- this.cellY = cellY;
- }
-
- public void onAlarm(Alarm alarm) {
- if (mDragFolderRingAnimator == null) {
- mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
- }
- mDragFolderRingAnimator.setCell(cellX, cellY);
- mDragFolderRingAnimator.setCellLayout(layout);
- mDragFolderRingAnimator.animateToAcceptState();
- layout.showFolderAccept(mDragFolderRingAnimator);
- layout.clearDragOutlines();
- setDragMode(DRAG_MODE_CREATE_FOLDER);
- }
- }
-
- class ReorderAlarmListener implements OnAlarmListener {
- float[] dragViewCenter;
- int minSpanX, minSpanY, spanX, spanY;
- DragView dragView;
- View child;
-
- public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,
- int spanY, DragView dragView, View child) {
- this.dragViewCenter = dragViewCenter;
- this.minSpanX = minSpanX;
- this.minSpanY = minSpanY;
- this.spanX = spanX;
- this.spanY = spanY;
- this.child = child;
- this.dragView = dragView;
- }
-
- public void onAlarm(Alarm alarm) {
- int[] resultSpan = new int[2];
- mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
- mLastReorderX = mTargetCell[0];
- mLastReorderY = mTargetCell[1];
-
- mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
- child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);
-
- if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {
- mDragTargetLayout.revertTempState();
- } else {
- setDragMode(DRAG_MODE_REORDER);
- }
-
- boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
- mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
- (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
- mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
- dragView.getDragVisualizeOffset(), dragView.getDragRegion());
- }
- }
-
- @Override
- public void getHitRect(Rect outRect) {
- // We want the workspace to have the whole area of the display (it will find the correct
- // cell layout to drop to in the existing drag/drop logic.
- outRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
- }
-
- /**
- * Add the item specified by dragInfo to the given layout.
- * @return true if successful
- */
- public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
- if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
- onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
- return true;
- }
- mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));
- return false;
- }
-
- private void onDropExternal(int[] touchXY, Object dragInfo,
- CellLayout cellLayout, boolean insertAtFirst) {
- onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
- }
-
- /**
- * Drop an item that didn't originate on one of the workspace screens.
- * It may have come from Launcher (e.g. from all apps or customize), or it may have
- * come from another app altogether.
- *
- * NOTE: This can also be called when we are outside of a drag event, when we want
- * to add an item to one of the workspace screens.
- */
- private void onDropExternal(final int[] touchXY, final Object dragInfo,
- final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
- final Runnable exitSpringLoadedRunnable = new Runnable() {
- @Override
- public void run() {
- mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
- }
- };
-
- ItemInfo info = (ItemInfo) dragInfo;
- int spanX = info.spanX;
- int spanY = info.spanY;
- if (mDragInfo != null) {
- spanX = mDragInfo.spanX;
- spanY = mDragInfo.spanY;
- }
-
- final long container = mLauncher.isHotseatLayout(cellLayout) ?
- LauncherSettings.Favorites.CONTAINER_HOTSEAT :
- LauncherSettings.Favorites.CONTAINER_DESKTOP;
- final int screen = indexOfChild(cellLayout);
- if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage
- && mState != State.SPRING_LOADED) {
- snapToPage(screen);
- }
-
- if (info instanceof PendingAddItemInfo) {
- final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
-
- boolean findNearestVacantCell = true;
- if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
- cellLayout, mTargetCell);
- float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
- mDragViewVisualCenter[1], mTargetCell);
- if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,
- distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,
- cellLayout, mTargetCell, distance)) {
- findNearestVacantCell = false;
- }
- }
-
- final ItemInfo item = (ItemInfo) d.dragInfo;
- if (findNearestVacantCell) {
- int minSpanX = item.spanX;
- int minSpanY = item.spanY;
- if (item.minSpanX > 0 && item.minSpanY > 0) {
- minSpanX = item.minSpanX;
- minSpanY = item.minSpanY;
- }
- int[] resultSpan = new int[2];
- mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,
- null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);
- item.spanX = resultSpan[0];
- item.spanY = resultSpan[1];
- }
-
- Runnable onAnimationCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- // When dragging and dropping from customization tray, we deal with creating
- // widgets/shortcuts/folders in a slightly different way
- switch (pendingInfo.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- int span[] = new int[2];
- span[0] = item.spanX;
- span[1] = item.spanY;
- mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
- container, screen, mTargetCell, span, null);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- mLauncher.processShortcutFromDrop(pendingInfo.componentName,
- container, screen, mTargetCell, null);
- break;
- default:
- throw new IllegalStateException("Unknown item type: " +
- pendingInfo.itemType);
- }
- }
- };
- View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
- ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
- int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
- if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
- ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
- animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
- }
- animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,
- animationStyle, finalView, true);
- } else {
- // This is for other drag/drop cases, like dragging from All Apps
- View view = null;
-
- switch (info.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- if (info.container == NO_ID && info instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- info = new ShortcutInfo((ApplicationInfo) info);
- }
- view = mLauncher.createShortcut(R.layout.application, cellLayout,
- (ShortcutInfo) info);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
- (FolderInfo) info, mIconCache);
- break;
- default:
- throw new IllegalStateException("Unknown item type: " + info.itemType);
- }
-
- // First we find the cell nearest to point at which the item is
- // dropped, without any consideration to whether there is an item there.
- if (touchXY != null) {
- mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
- cellLayout, mTargetCell);
- float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
- mDragViewVisualCenter[1], mTargetCell);
- d.postAnimationRunnable = exitSpringLoadedRunnable;
- if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
- true, d.dragView, d.postAnimationRunnable)) {
- return;
- }
- if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
- true)) {
- return;
- }
- }
-
- if (touchXY != null) {
- // when dragging and dropping, just find the closest free spot
- mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
- (int) mDragViewVisualCenter[1], 1, 1, 1, 1,
- null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);
- } else {
- cellLayout.findCellForSpan(mTargetCell, 1, 1);
- }
- addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX,
- info.spanY, insertAtFirst);
- cellLayout.onDropChild(view);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
- cellLayout.getShortcutsAndWidgets().measureChild(view);
-
-
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen,
- lp.cellX, lp.cellY);
-
- if (d.dragView != null) {
- // We wrap the animation call in the temporary set and reset of the current
- // cellLayout to its final transform -- this means we animate the drag view to
- // the correct final location.
- setFinalTransitionTransform(cellLayout);
- mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
- exitSpringLoadedRunnable);
- resetTransitionTransform(cellLayout);
- }
- }
- }
-
- public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
- int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
- widgetInfo.spanY, widgetInfo, false);
- int visibility = layout.getVisibility();
- layout.setVisibility(VISIBLE);
-
- int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
- int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
- Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
-
- layout.measure(width, height);
- layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
- layout.draw(c);
- c.setBitmap(null);
- layout.setVisibility(visibility);
- return b;
- }
-
- private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,
- DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,
- boolean external, boolean scale) {
- // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
- // location and size on the home screen.
- int spanX = info.spanX;
- int spanY = info.spanY;
-
- Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);
- loc[0] = r.left;
- loc[1] = r.top;
-
- setFinalTransitionTransform(layout);
- float cellLayoutScale =
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc);
- resetTransitionTransform(layout);
-
- float dragViewScaleX;
- float dragViewScaleY;
- if (scale) {
- dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
- dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
- } else {
- dragViewScaleX = 1f;
- dragViewScaleY = 1f;
- }
-
- // The animation will scale the dragView about its center, so we need to center about
- // the final location.
- loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
- loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
-
- scaleXY[0] = dragViewScaleX * cellLayoutScale;
- scaleXY[1] = dragViewScaleY * cellLayoutScale;
- }
-
- public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,
- final Runnable onCompleteRunnable, int animationType, final View finalView,
- boolean external) {
- Rect from = new Rect();
- mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
-
- int[] finalPos = new int[2];
- float scaleXY[] = new float[2];
- boolean scalePreview = !(info instanceof PendingAddShortcutInfo);
- getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,
- external, scalePreview);
-
- Resources res = mLauncher.getResources();
- int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
-
- // In the case where we've prebound the widget, we remove it from the DragLayer
- if (finalView instanceof AppWidgetHostView && external) {
- Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
- mLauncher.getDragLayer().removeView(finalView);
- }
- if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
- Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
- dragView.setCrossFadeBitmap(crossFadeBitmap);
- dragView.crossFade((int) (duration * 0.8f));
- } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
- scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]);
- }
-
- DragLayer dragLayer = mLauncher.getDragLayer();
- if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
- mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,
- DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
- } else {
- int endStyle;
- if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {
- endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
- } else {
- endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;
- }
-
- Runnable onComplete = new Runnable() {
- @Override
- public void run() {
- if (finalView != null) {
- finalView.setVisibility(VISIBLE);
- }
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- }
- };
- dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
- finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
- duration, this);
- }
- }
-
- public void setFinalTransitionTransform(CellLayout layout) {
- if (isSwitchingState()) {
- int index = indexOfChild(layout);
- mCurrentScaleX = layout.getScaleX();
- mCurrentScaleY = layout.getScaleY();
- mCurrentTranslationX = layout.getTranslationX();
- mCurrentTranslationY = layout.getTranslationY();
- mCurrentRotationY = layout.getRotationY();
- layout.setScaleX(mNewScaleXs[index]);
- layout.setScaleY(mNewScaleYs[index]);
- layout.setTranslationX(mNewTranslationXs[index]);
- layout.setTranslationY(mNewTranslationYs[index]);
- layout.setRotationY(mNewRotationYs[index]);
- }
- }
- public void resetTransitionTransform(CellLayout layout) {
- if (isSwitchingState()) {
- mCurrentScaleX = layout.getScaleX();
- mCurrentScaleY = layout.getScaleY();
- mCurrentTranslationX = layout.getTranslationX();
- mCurrentTranslationY = layout.getTranslationY();
- mCurrentRotationY = layout.getRotationY();
- layout.setScaleX(mCurrentScaleX);
- layout.setScaleY(mCurrentScaleY);
- layout.setTranslationX(mCurrentTranslationX);
- layout.setTranslationY(mCurrentTranslationY);
- layout.setRotationY(mCurrentRotationY);
- }
- }
-
- /**
- * Return the current {@link CellLayout}, correctly picking the destination
- * screen while a scroll is in progress.
- */
- public CellLayout getCurrentDropLayout() {
- return (CellLayout) getChildAt(getNextPage());
- }
-
- /**
- * Return the current CellInfo describing our current drag; this method exists
- * so that Launcher can sync this object with the correct info when the activity is created/
- * destroyed
- *
- */
- public CellLayout.CellInfo getDragInfo() {
- return mDragInfo;
- }
-
- /**
- * Calculate the nearest cell where the given object would be dropped.
- *
- * pixelX and pixelY should be in the coordinate system of layout
- */
- private int[] findNearestArea(int pixelX, int pixelY,
- int spanX, int spanY, CellLayout layout, int[] recycle) {
- return layout.findNearestArea(
- pixelX, pixelY, spanX, spanY, recycle);
- }
-
- void setup(DragController dragController) {
- mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
- mDragController = dragController;
-
- // hardware layers on children are enabled on startup, but should be disabled until
- // needed
- updateChildrenLayersEnabled();
- setWallpaperDimension();
- }
-
- /**
- * Called at the end of a drag which originated on the workspace.
- */
- public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
- boolean success) {
- if (success) {
- if (target != this) {
- if (mDragInfo != null) {
- getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
- if (mDragInfo.cell instanceof DropTarget) {
- mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
- }
- }
- }
- } else if (mDragInfo != null) {
- CellLayout cellLayout;
- if (mLauncher.isHotseatLayout(target)) {
- cellLayout = mLauncher.getHotseat().getLayout();
- } else {
- cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
- }
- cellLayout.onDropChild(mDragInfo.cell);
- }
- if (d.cancelled && mDragInfo.cell != null) {
- mDragInfo.cell.setVisibility(VISIBLE);
- }
- mDragOutline = null;
- mDragInfo = null;
-
- // Hide the scrolling indicator after you pick up an item
- hideScrollingIndicator(false);
- }
-
- void updateItemLocationsInDatabase(CellLayout cl) {
- int count = cl.getShortcutsAndWidgets().getChildCount();
-
- int screen = indexOfChild(cl);
- int container = Favorites.CONTAINER_DESKTOP;
-
- if (mLauncher.isHotseatLayout(cl)) {
- screen = -1;
- container = Favorites.CONTAINER_HOTSEAT;
- }
-
- for (int i = 0; i < count; i++) {
- View v = cl.getShortcutsAndWidgets().getChildAt(i);
- ItemInfo info = (ItemInfo) v.getTag();
- // Null check required as the AllApps button doesn't have an item info
- if (info != null) {
- LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX,
- info.cellY, info.spanX, info.spanY);
- }
- }
- }
-
- @Override
- public boolean supportsFlingToDelete() {
- return true;
- }
-
- @Override
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
- // Do nothing
- }
-
- @Override
- public void onFlingToDeleteCompleted() {
- // Do nothing
- }
-
- public boolean isDropEnabled() {
- return true;
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- super.onRestoreInstanceState(state);
- Launcher.setScreen(mCurrentPage);
- }
-
- @Override
- public void scrollLeft() {
- if (!isSmall() && !mIsSwitchingState) {
- super.scrollLeft();
- }
- Folder openFolder = getOpenFolder();
- if (openFolder != null) {
- openFolder.completeDragExit();
- }
- }
-
- @Override
- public void scrollRight() {
- if (!isSmall() && !mIsSwitchingState) {
- super.scrollRight();
- }
- Folder openFolder = getOpenFolder();
- if (openFolder != null) {
- openFolder.completeDragExit();
- }
- }
-
- @Override
- public boolean onEnterScrollArea(int x, int y, int direction) {
- // Ignore the scroll area if we are dragging over the hot seat
- boolean isPortrait = !LauncherApplication.isScreenLandscape(getContext());
- if (mLauncher.getHotseat() != null && isPortrait) {
- Rect r = new Rect();
- mLauncher.getHotseat().getHitRect(r);
- if (r.contains(x, y)) {
- return false;
- }
- }
-
- boolean result = false;
- if (!isSmall() && !mIsSwitchingState) {
- mInScrollArea = true;
-
- final int page = getNextPage() +
- (direction == DragController.SCROLL_LEFT ? -1 : 1);
-
- // We always want to exit the current layout to ensure parity of enter / exit
- setCurrentDropLayout(null);
-
- if (0 <= page && page < getChildCount()) {
- CellLayout layout = (CellLayout) getChildAt(page);
- setCurrentDragOverlappingLayout(layout);
-
- // Workspace is responsible for drawing the edge glow on adjacent pages,
- // so we need to redraw the workspace when this may have changed.
- invalidate();
- result = true;
- }
- }
- return result;
- }
-
- @Override
- public boolean onExitScrollArea() {
- boolean result = false;
- if (mInScrollArea) {
- invalidate();
- CellLayout layout = getCurrentDropLayout();
- setCurrentDropLayout(layout);
- setCurrentDragOverlappingLayout(layout);
-
- result = true;
- mInScrollArea = false;
- }
- return result;
- }
-
- private void onResetScrollArea() {
- setCurrentDragOverlappingLayout(null);
- mInScrollArea = false;
- }
-
- /**
- * Returns a specific CellLayout
- */
- CellLayout getParentCellLayoutForView(View v) {
- ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
- for (CellLayout layout : layouts) {
- if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
- return layout;
- }
- }
- return null;
- }
-
- /**
- * Returns a list of all the CellLayouts in the workspace.
- */
- ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
- ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();
- int screenCount = getChildCount();
- for (int screen = 0; screen < screenCount; screen++) {
- layouts.add(((CellLayout) getChildAt(screen)));
- }
- if (mLauncher.getHotseat() != null) {
- layouts.add(mLauncher.getHotseat().getLayout());
- }
- return layouts;
- }
-
- /**
- * We should only use this to search for specific children. Do not use this method to modify
- * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
- * the hotseat and workspace pages
- */
- ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
- new ArrayList<ShortcutAndWidgetContainer>();
- int screenCount = getChildCount();
- for (int screen = 0; screen < screenCount; screen++) {
- childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
- }
- if (mLauncher.getHotseat() != null) {
- childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
- }
- return childrenLayouts;
- }
-
- public Folder getFolderForTag(Object tag) {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
- getAllShortcutAndWidgetContainers();
- for (ShortcutAndWidgetContainer layout: childrenLayouts) {
- int count = layout.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = layout.getChildAt(i);
- if (child instanceof Folder) {
- Folder f = (Folder) child;
- if (f.getInfo() == tag && f.getInfo().opened) {
- return f;
- }
- }
- }
- }
- return null;
- }
-
- public View getViewForTag(Object tag) {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
- getAllShortcutAndWidgetContainers();
- for (ShortcutAndWidgetContainer layout: childrenLayouts) {
- int count = layout.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = layout.getChildAt(i);
- if (child.getTag() == tag) {
- return child;
- }
- }
- }
- return null;
- }
-
- void clearDropTargets() {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
- getAllShortcutAndWidgetContainers();
- for (ShortcutAndWidgetContainer layout: childrenLayouts) {
- int childCount = layout.getChildCount();
- for (int j = 0; j < childCount; j++) {
- View v = layout.getChildAt(j);
- if (v instanceof DropTarget) {
- mDragController.removeDropTarget((DropTarget) v);
- }
- }
- }
- }
-
- void removeItems(final ArrayList<ApplicationInfo> apps) {
- final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
-
- final HashSet<String> packageNames = new HashSet<String>();
- final int appCount = apps.size();
- for (int i = 0; i < appCount; i++) {
- packageNames.add(apps.get(i).componentName.getPackageName());
- }
-
- ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
- for (final CellLayout layoutParent: cellLayouts) {
- final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
-
- // Avoid ANRs by treating each screen separately
- post(new Runnable() {
- public void run() {
- final ArrayList<View> childrenToRemove = new ArrayList<View>();
- childrenToRemove.clear();
-
- int childCount = layout.getChildCount();
- for (int j = 0; j < childCount; j++) {
- final View view = layout.getChildAt(j);
- Object tag = view.getTag();
-
- if (tag instanceof ShortcutInfo) {
- final ShortcutInfo info = (ShortcutInfo) tag;
- final Intent intent = info.intent;
- final ComponentName name = intent.getComponent();
-
- if (name != null) {
- if (packageNames.contains(name.getPackageName())) {
- LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
- }
- }
- } else if (tag instanceof FolderInfo) {
- final FolderInfo info = (FolderInfo) tag;
- final ArrayList<ShortcutInfo> contents = info.contents;
- final int contentsCount = contents.size();
- final ArrayList<ShortcutInfo> appsToRemoveFromFolder =
- new ArrayList<ShortcutInfo>();
-
- for (int k = 0; k < contentsCount; k++) {
- final ShortcutInfo appInfo = contents.get(k);
- final Intent intent = appInfo.intent;
- final ComponentName name = intent.getComponent();
-
- if (name != null) {
- if (packageNames.contains(name.getPackageName())) {
- appsToRemoveFromFolder.add(appInfo);
- }
- }
- }
- for (ShortcutInfo item: appsToRemoveFromFolder) {
- info.remove(item);
- LauncherModel.deleteItemFromDatabase(mLauncher, item);
- }
- } else if (tag instanceof LauncherAppWidgetInfo) {
- final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
- final ComponentName provider = info.providerName;
- if (provider != null) {
- if (packageNames.contains(provider.getPackageName())) {
- LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
- }
- }
- }
- }
-
- childCount = childrenToRemove.size();
- for (int j = 0; j < childCount; j++) {
- View child = childrenToRemove.get(j);
- // Note: We can not remove the view directly from CellLayoutChildren as this
- // does not re-mark the spaces as unoccupied.
- layoutParent.removeViewInLayout(child);
- if (child instanceof DropTarget) {
- mDragController.removeDropTarget((DropTarget)child);
- }
- }
-
- if (childCount > 0) {
- layout.requestLayout();
- layout.invalidate();
- }
- }
- });
- }
-
- // It is no longer the case the BubbleTextViews correspond 1:1 with the workspace items in
- // the database (and LauncherModel) since shortcuts are not added and animated in until
- // the user returns to launcher. As a result, we really should be cleaning up the Db
- // regardless of whether the item was added or not (unlike the logic above). This is only
- // relevant for direct workspace items.
- post(new Runnable() {
- @Override
- public void run() {
- String spKey = LauncherApplication.getSharedPreferencesKey();
- SharedPreferences sp = getContext().getSharedPreferences(spKey,
- Context.MODE_PRIVATE);
- Set<String> newApps = sp.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
- null);
-
- for (String packageName: packageNames) {
- // Remove all items that have the same package, but were not removed above
- ArrayList<ShortcutInfo> infos =
- mLauncher.getModel().getShortcutInfosForPackage(packageName);
- for (ShortcutInfo info : infos) {
- LauncherModel.deleteItemFromDatabase(mLauncher, info);
- }
- // Remove all queued items that match the same package
- if (newApps != null) {
- synchronized (newApps) {
- Iterator<String> iter = newApps.iterator();
- while (iter.hasNext()) {
- try {
- Intent intent = Intent.parseUri(iter.next(), 0);
- String pn = ItemInfo.getPackageName(intent);
- if (packageNames.contains(pn)) {
- iter.remove();
- }
- } catch (URISyntaxException e) {}
- }
- }
- }
- }
- }
- });
- }
-
- void updateShortcuts(ArrayList<ApplicationInfo> apps) {
- ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();
- for (ShortcutAndWidgetContainer layout: childrenLayouts) {
- int childCount = layout.getChildCount();
- for (int j = 0; j < childCount; j++) {
- final View view = layout.getChildAt(j);
- Object tag = view.getTag();
- if (tag instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) tag;
- // We need to check for ACTION_MAIN otherwise getComponent() might
- // return null for some shortcuts (for instance, for shortcuts to
- // web pages.)
- final Intent intent = info.intent;
- final ComponentName name = intent.getComponent();
- if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
- Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
- final int appCount = apps.size();
- for (int k = 0; k < appCount; k++) {
- ApplicationInfo app = apps.get(k);
- if (app.componentName.equals(name)) {
- BubbleTextView shortcut = (BubbleTextView) view;
- info.updateIcon(mIconCache);
- info.title = app.title.toString();
- shortcut.applyFromShortcutInfo(info, mIconCache);
- }
- }
- }
- }
- }
- }
- }
-
- void moveToDefaultScreen(boolean animate) {
- if (!isSmall()) {
- if (animate) {
- snapToPage(mDefaultPage);
- } else {
- setCurrentPage(mDefaultPage);
- }
- }
- getChildAt(mDefaultPage).requestFocus();
- }
-
- @Override
- public void syncPages() {
- }
-
- @Override
- public void syncPageItems(int page, boolean immediate) {
- }
-
- @Override
- protected String getCurrentPageDescription() {
- int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
- return String.format(getContext().getString(R.string.workspace_scroll_format),
- page + 1, getChildCount());
- }
-
- public void getLocationInDragLayer(int[] loc) {
- mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
- }
-
- void setFadeForOverScroll(float fade) {
- if (!isScrollingIndicatorEnabled()) return;
-
- mOverscrollFade = fade;
- float reducedFade = 0.5f + 0.5f * (1 - fade);
- final ViewGroup parent = (ViewGroup) getParent();
- final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider));
- final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider));
- final View scrollIndicator = getScrollingIndicator();
-
- cancelScrollingIndicatorAnimations();
- if (qsbDivider != null) qsbDivider.setAlpha(reducedFade);
- if (dockDivider != null) dockDivider.setAlpha(reducedFade);
- scrollIndicator.setAlpha(1 - fade);
- }
-}