Merge "Adding workaround for crashes (5087036, 4556344) now that widget previews are loaded asynchronously."
diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace.xml
index 0e96a67..d509490 100644
--- a/res/xml/default_workspace.xml
+++ b/res/xml/default_workspace.xml
@@ -61,5 +61,4 @@
launcher:screen="3"
launcher:x="3"
launcher:y="0" />
-
</favorites>
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 014356b..780d0ed 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -100,6 +100,10 @@
private Rect mTempRect = new Rect();
private boolean mFirstOpen = true;
+ // Internal variable to track whether the folder was destroyed due to only a single
+ // item remaining
+ private boolean mDestroyed = false;
+
private boolean mIsEditingName = false;
private InputMethodManager mInputMethodManager;
@@ -514,7 +518,8 @@
// by another item. If it is, we need to find the next available slot and assign
// it that position. This is an issue when upgrading from the old Folders implementation
// which could contain an unlimited number of items.
- if (mContent.getChildAt(item.cellX, item.cellY) != null) {
+ if (mContent.getChildAt(item.cellX, item.cellY) != null ||
+ item.cellX < 0 || item.cellY < 0) {
if (!findAndSetEmptyCells(item)) {
return false;
}
@@ -658,17 +663,16 @@
mCurrentDragInfo = null;
mCurrentDragView = null;
mSuppressOnAdd = false;
+ if (target != this) {
+ mOnExitAlarm.cancelAlarm();
+ completeDragExit();
+ }
+
if (!success) {
- if (d.dragView != null) {
- if (target instanceof CellLayout) {
- // TODO: we should animate the item back to the folder in this case
- }
- }
- // TODO: if the drag fails, we need to re-add the item
- } else {
- if (target != this) {
- mOnExitAlarm.cancelAlarm();
- completeDragExit();
+ if (!mDestroyed) {
+ mFolderIcon.onDrop(d);
+ } else {
+ // TODO: if the folder was removed, recreate it
}
}
}
@@ -842,6 +846,7 @@
private void replaceFolderWithFinalItem() {
ItemInfo finalItem = null;
+ mDestroyed = true;
if (getItemCount() == 1) {
finalItem = mInfo.contents.get(0);
}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 0f302a0..cd62ee1 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -51,6 +51,7 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -212,12 +213,6 @@
private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
- // Hotseats (quick-launch icons next to AllApps)
- private String[] mHotseatConfig = null;
- private Intent[] mHotseats = null;
- private Drawable[] mHotseatIcons = null;
- private CharSequence[] mHotseatLabels = null;
-
private Intent mAppMarketIntent = null;
// Related to the auto-advancing of widgets
@@ -436,16 +431,6 @@
}
}
- // Note: This doesn't do all the client-id magic that BrowserProvider does
- // in Browser. (http://b/2425179)
- private Uri getDefaultBrowserUri() {
- String url = getString(R.string.default_browser_url);
- if (url.indexOf("{CID}") != -1) {
- url = url.replace("{CID}", "android-google");
- }
- return Uri.parse(url);
- }
-
/**
* 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.
@@ -657,7 +642,6 @@
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;
@@ -1922,27 +1906,6 @@
showDialog(DIALOG_CREATE_SHORTCUT);
}
- private void pickShortcut() {
- // Insert extra item to handle picking application
- Bundle bundle = new Bundle();
-
- ArrayList<String> shortcutNames = new ArrayList<String>();
- shortcutNames.add(getString(R.string.group_applications));
- bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
-
- ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
- shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
- R.drawable.ic_launcher_application));
- bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
- pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_shortcut));
- pickIntent.putExtras(bundle);
-
- startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
- }
-
private class RenameFolder {
private EditText mInput;
diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java
index 96cc63c..6ca16de 100644
--- a/src/com/android/launcher2/LauncherProvider.java
+++ b/src/com/android/launcher2/LauncherProvider.java
@@ -20,46 +20,45 @@
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ContentProvider;
-import android.content.Context;
-import android.content.ContentValues;
-import android.content.Intent;
import android.content.ComponentName;
-import android.content.ContentUris;
+import android.content.ContentProvider;
import android.content.ContentResolver;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.content.res.TypedArray;
-import android.content.pm.PackageManager;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.SharedPreferences;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteStatement;
-import android.database.sqlite.SQLiteQueryBuilder;
+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.provider.Settings;
+import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
-import android.util.AttributeSet;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.provider.Settings;
+
+import com.android.internal.util.XmlUtils;
+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;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParser;
-
-import com.android.internal.util.XmlUtils;
-import com.android.launcher2.LauncherSettings.Favorites;
-
-import com.android.launcher.R;
-
public class LauncherProvider extends ContentProvider {
private static final String TAG = "Launcher.LauncherProvider";
private static final boolean LOGD = false;
@@ -123,6 +122,12 @@
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);
@@ -199,6 +204,7 @@
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 final Context mContext;
private final AppWidgetHost mAppWidgetHost;
@@ -741,10 +747,9 @@
values.put(LauncherSettings.Favorites.CELLX, x);
values.put(LauncherSettings.Favorites.CELLY, y);
- System.out.println("Adding item to container: " + container);
-
if (TAG_FAVORITE.equals(name)) {
- added = addAppShortcut(db, values, a, packageManager, intent);
+ 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)) {
@@ -752,12 +757,66 @@
} else if (TAG_APPWIDGET.equals(name)) {
added = addAppWidget(db, values, a, packageManager);
} else if (TAG_SHORTCUT.equals(name)) {
- added = addUriShortcut(db, values, a);
+ 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) {
@@ -771,9 +830,9 @@
return i;
}
- private boolean addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
+ 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);
@@ -788,7 +847,7 @@
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);
@@ -798,13 +857,27 @@
values.put(Favorites.SPANX, 1);
values.put(Favorites.SPANY, 1);
values.put(Favorites._ID, generateNewId());
- dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
+ 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 false;
}
- return true;
+ 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() {
@@ -843,7 +916,7 @@
"com.android.alarmclock.AnalogAppWidgetProvider");
return addAppWidget(db, values, cn, 2, 2);
}
-
+
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, TypedArray a,
PackageManager packageManager) {
@@ -902,8 +975,8 @@
return allocatedAppWidgets;
}
-
- private boolean addUriShortcut(SQLiteDatabase db, ContentValues values,
+
+ private long addUriShortcut(SQLiteDatabase db, ContentValues values,
TypedArray a) {
Resources r = mContext.getResources();
@@ -917,14 +990,15 @@
intent = Intent.parseUri(uri, 0);
} catch (URISyntaxException e) {
Log.w(TAG, "Shortcut has malformed uri: " + uri);
- return false; // Oh well
+ return -1; // Oh well
}
if (iconResId == 0 || titleResId == 0) {
Log.w(TAG, "Shortcut is missing title or icon resource ID");
- return false;
+ 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));
@@ -934,10 +1008,12 @@
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, generateNewId());
- dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
+ values.put(Favorites._ID, id);
- return true;
+ if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
+ return -1;
+ }
+ return id;
}
}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index e4865c2..10b218a 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -142,7 +142,6 @@
private int[] mTempEstimate = new int[2];
private float[] mDragViewVisualCenter = new float[2];
private float[] mTempDragCoordinates = new float[2];
- private float[] mTempTouchCoordinates = new float[2];
private float[] mTempCellLayoutCenterCoordinates = new float[2];
private float[] mTempDragBottomRightCoordinates = new float[2];
private Matrix mTempInverseMatrix = new Matrix();
@@ -1290,12 +1289,6 @@
}
}
- private boolean childLayersEnabled() {
- boolean isSmallOrSpringloaded =
- isSmall() || mIsSwitchingState || mState == State.SPRING_LOADED;
- return isSmallOrSpringloaded || isPageMoving() || mIsDragOccuring;
- }
-
private void updateChildrenLayersEnabled() {
boolean small =
isSmall() || mIsSwitchingState || mState == State.SPRING_LOADED;
@@ -1713,6 +1706,14 @@
}
void unshrink(boolean animated, boolean springLoaded) {
+ if (mFirstLayout) {
+ // (mFirstLayout == "first layout has not happened yet")
+ // cancel any pending shrinks that were set earlier
+ mSwitchStateAfterFirstLayout = false;
+ mStateAfterFirstLayout = State.NORMAL;
+ return;
+ }
+
if (isSmall()) {
float finalScaleFactor = 1.0f;
float finalBackgroundAlpha = 0.0f;
@@ -2058,7 +2059,6 @@
final Bitmap b = createDragBitmap(child, new Canvas(), bitmapPadding);
final int bmpWidth = b.getWidth();
- final int bmpHeight = b.getHeight();
mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
final int dragLayerX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2;
@@ -2778,8 +2778,6 @@
// Identify whether we have dragged over a side page
if (isSmall()) {
- int left = d.x - d.xOffset;
- int top = d.y - d.yOffset;
layout = findMatchingPageForDragOver(d.dragView, mDragViewVisualCenter[0],
mDragViewVisualCenter[1], true);
if (layout != mDragTargetLayout) {
@@ -3109,7 +3107,6 @@
}
public void resetTransitionTransform(CellLayout layout) {
if (isSwitchingState()) {
- int index = indexOfChild(layout);
mCurrentScaleX = layout.getScaleX();
mCurrentScaleY = layout.getScaleY();
mCurrentTranslationX = layout.getTranslationX();
@@ -3340,7 +3337,6 @@
int count = layout.getChildCount();
for (int i = 0; i < count; i++) {
View child = layout.getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (child instanceof Folder) {
Folder f = (Folder) child;
if (f.getInfo() == tag && f.getInfo().opened) {
@@ -3380,7 +3376,6 @@
}
void removeItems(final ArrayList<ApplicationInfo> apps) {
- final int screenCount = getChildCount();
final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
final HashSet<String> packageNames = new HashSet<String>();