diff options
author | Danesh M <daneshm90@gmail.com> | 2013-08-01 18:12:51 -0700 |
---|---|---|
committer | Danesh M <daneshm90@gmail.com> | 2013-08-07 17:01:00 -0700 |
commit | f5c472b2a90e1f153efe2f778d95c41e3ab54e0a (patch) | |
tree | dcb389f936e02509cd88dfd7cc897f987dc3d71b /src/com/cyanogenmod/trebuchet | |
parent | 840a01498d04247f05f0d2c0319fd223c915400e (diff) | |
download | android_packages_apps_Trebuchet-f5c472b2a90e1f153efe2f778d95c41e3ab54e0a.tar.gz android_packages_apps_Trebuchet-f5c472b2a90e1f153efe2f778d95c41e3ab54e0a.tar.bz2 android_packages_apps_Trebuchet-f5c472b2a90e1f153efe2f778d95c41e3ab54e0a.zip |
Initial base for live folders
Change-Id: I76b8065b88e4a51d33e802fc8b80911f703f025a
Diffstat (limited to 'src/com/cyanogenmod/trebuchet')
-rw-r--r-- | src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java | 10 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/DragController.java | 2 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/Folder.java | 60 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/FolderIcon.java | 2 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/IconCache.java | 4 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/Launcher.java | 101 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherModel.java | 44 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherProvider.java | 10 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherSettings.java | 13 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LiveFolderInfo.java | 76 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LiveFolderItemInfo.java | 12 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LiveFoldersReceiver.java | 105 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/Workspace.java | 12 |
13 files changed, 427 insertions, 24 deletions
diff --git a/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java b/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java index 9098d194d..bf497001f 100644 --- a/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java +++ b/src/com/cyanogenmod/trebuchet/AppsCustomizePagedView.java @@ -59,6 +59,7 @@ import android.widget.GridLayout; import android.widget.ImageView; import android.widget.Toast; +import org.cyanogenmod.support.ui.LiveFolder; import com.cyanogenmod.trebuchet.DropTarget.DragObject; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; @@ -679,6 +680,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } mWidgets.addAll(shortcuts); + + Intent createLiveFolder = new Intent(LiveFolder.Constants.CREATE_LIVE_FOLDER); + List<ResolveInfo> lst = mPackageManager.queryIntentActivities(createLiveFolder, + PackageManager.GET_RESOLVED_FILTER); + mWidgets.addAll(lst); + Collections.sort(mWidgets, new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager)); updatePageCounts(); @@ -1614,6 +1621,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen ResolveInfo info = (ResolveInfo) rawInfo; createItemInfo = new PendingAddShortcutInfo(info.activityInfo); createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + if (info.filter != null && info.filter.hasAction(LiveFolder.Constants.CREATE_LIVE_FOLDER)) { + createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER; + } createItemInfo.componentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); widget.applyFromResolveInfo(mPackageManager, info); diff --git a/src/com/cyanogenmod/trebuchet/DragController.java b/src/com/cyanogenmod/trebuchet/DragController.java index 2a0569585..68b11416a 100644 --- a/src/com/cyanogenmod/trebuchet/DragController.java +++ b/src/com/cyanogenmod/trebuchet/DragController.java @@ -49,7 +49,7 @@ public class DragController { private static final int SCROLL_DELAY = 500; private static final int RESCROLL_DELAY = 750; - private static final int VIBRATE_DURATION = 15; + static final int VIBRATE_DURATION = 15; private static final boolean PROFILE_DRAWING_DURING_DRAG = false; diff --git a/src/com/cyanogenmod/trebuchet/Folder.java b/src/com/cyanogenmod/trebuchet/Folder.java index 28a9aefdf..b46a3d0e5 100644 --- a/src/com/cyanogenmod/trebuchet/Folder.java +++ b/src/com/cyanogenmod/trebuchet/Folder.java @@ -25,6 +25,7 @@ import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Vibrator; import android.text.InputType; import android.text.Selection; import android.text.Spannable; @@ -43,6 +44,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import com.cyanogenmod.trebuchet.FolderInfo.FolderListener; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; @@ -206,6 +208,16 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (tag instanceof ShortcutInfo) { // refactor this code from Folder ShortcutInfo item = (ShortcutInfo) tag; + + if (item instanceof LiveFolderItemInfo && item.intent == null) { + LiveFolderItemInfo fItem = (LiveFolderItemInfo) item; + if (fItem.item_id > 0) { + LiveFoldersReceiver.alertItemOpened(mContext, (LiveFolderInfo) getInfo(), + (LiveFolderItemInfo) item); + } + return; + } + int[] pos = new int[2]; v.getLocationOnScreen(pos); item.intent.setSourceBounds(new Rect(pos[0], pos[1], @@ -216,19 +228,36 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } public boolean onLongClick(View v) { - // Only if workspace is not locked - if (mLauncher.getLockWorkspace()) return false; // Return if global dragging is not enabled if (!mLauncher.isDraggingEnabled()) return true; - Object tag = v.getTag(); - if (tag instanceof ShortcutInfo) { - ShortcutInfo item = (ShortcutInfo) tag; + ShortcutInfo item = v.getTag() instanceof ShortcutInfo ? + (ShortcutInfo) v.getTag() : null; + + if (item != null) { if (!v.isInTouchMode()) { return false; } + if (item instanceof LiveFolderItemInfo) { + mLauncher.dismissFolderCling(null); + getInfo().remove(item); + Vibrator vibr = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + vibr.vibrate(DragController.VIBRATE_DURATION); + LiveFoldersReceiver.alertItemRemoved(mContext, + (LiveFolderInfo) getInfo(), (LiveFolderItemInfo) item); + return true; + } + } + + // Only if workspace is not locked + if (mLauncher.getLockWorkspace()) { + Toast.makeText(mContext, getResources().getString(R.string.workspace_locked), Toast.LENGTH_SHORT).show(); + return false; + } + + if (item != null) { mLauncher.dismissFolderCling(null); mLauncher.getWorkspace().onDragStartedWithItem(v); @@ -399,6 +428,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } else { mFolderName.setText(""); } + + if (getInfo() instanceof LiveFolderInfo) { + mFolderName.setEnabled(false); + } updateItemLocationsInDatabase(); } @@ -917,8 +950,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList 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); + if (!(getInfo() instanceof LiveFolderInfo)) { + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0, + info.cellX, info.cellY); + } } mContent.addViewToCellLayout(v, 0, (int) info.id, lp, true); } @@ -957,6 +992,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } private void replaceFolderWithFinalItem() { + + if (mInfo instanceof LiveFolderInfo) { + return; + } + // Add the last remaining child to the workspace in place of the folder Runnable onCompleteRunnable = new Runnable() { @Override @@ -1067,8 +1107,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList findAndSetEmptyCells(item); } createAndAddShortcut(item); - LauncherModel.addOrMoveItemInDatabase( - mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); + if (item instanceof LiveFolderItemInfo) { + LauncherModel.addOrMoveItemInDatabase( + mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); + } } public void onRemove(ShortcutInfo item) { diff --git a/src/com/cyanogenmod/trebuchet/FolderIcon.java b/src/com/cyanogenmod/trebuchet/FolderIcon.java index 882757694..7d0a7115c 100644 --- a/src/com/cyanogenmod/trebuchet/FolderIcon.java +++ b/src/com/cyanogenmod/trebuchet/FolderIcon.java @@ -286,7 +286,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT || itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) && - !mFolder.isFull() && item != mInfo && !mInfo.opened); + !mFolder.isFull() && item != mInfo && !mInfo.opened && !(mFolder.getInfo() instanceof LiveFolderInfo)); } public boolean acceptDrop(ItemInfo dragInfo) { diff --git a/src/com/cyanogenmod/trebuchet/IconCache.java b/src/com/cyanogenmod/trebuchet/IconCache.java index 7005e1208..2715a784d 100644 --- a/src/com/cyanogenmod/trebuchet/IconCache.java +++ b/src/com/cyanogenmod/trebuchet/IconCache.java @@ -161,6 +161,10 @@ public class IconCache { public Bitmap getIcon(Intent intent) { synchronized (mCache) { + if (intent == null) { + return mDefaultIcon; + } + final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); ComponentName component = intent.getComponent(); diff --git a/src/com/cyanogenmod/trebuchet/Launcher.java b/src/com/cyanogenmod/trebuchet/Launcher.java index 7569573e7..d49a95f06 100644 --- a/src/com/cyanogenmod/trebuchet/Launcher.java +++ b/src/com/cyanogenmod/trebuchet/Launcher.java @@ -67,6 +67,7 @@ import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.speech.RecognizerIntent; import android.text.Selection; @@ -103,6 +104,9 @@ import android.widget.TextView; import android.widget.Toast; import com.android.common.Search; + +import org.cyanogenmod.support.ui.LiveFolder; + import com.cyanogenmod.trebuchet.DropTarget.DragObject; import com.cyanogenmod.trebuchet.preference.*; @@ -119,6 +123,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -147,6 +152,7 @@ public final class Launcher extends Activity 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_CREATE_LIVE_FOLDER = 12; private static final int REQUEST_BIND_APPWIDGET = 11; @@ -229,7 +235,7 @@ public final class Launcher extends Activity private AppWidgetManager mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; - private ItemInfo mPendingAddInfo = new ItemInfo(); + private PendingAddItemInfo mPendingAddInfo = new PendingAddItemInfo(); private AppWidgetProviderInfo mPendingAddWidgetInfo; private int[] mTmpAddItemCellCoordinates = new int[2]; @@ -633,6 +639,25 @@ public final class Launcher extends Activity case REQUEST_PICK_WALLPAPER: // We just wanted the activity result here so we can clear mWaitingForResult break; + case REQUEST_CREATE_LIVE_FOLDER: + if (args.intent.hasExtra(LiveFolder.Constants.FOLDER_RECEIVER_EXTRA)) { + ComponentName receiver = args.intent.getParcelableExtra( + LiveFolder.Constants.FOLDER_RECEIVER_EXTRA); + try { + // Verify that the receiver sent by the intent is from the same package + if (receiver != null && getPackageManager().getReceiverInfo(receiver, 0).packageName + .equals(mPendingAddInfo.componentName.getPackageName())) { + completeLiveFolder(receiver, args.container, args.screen, args.cellX, + args.cellY, args.intent.getStringExtra(LiveFolder.Constants.FOLDER_TITLE_EXTRA)); + result = true; + } else { + Log.d(TAG, "Receiver not valid in returning package"); + } + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + } + 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 @@ -1189,6 +1214,14 @@ public final class Launcher extends Activity info.mFolderInfo = null; } + private void completeLiveFolder(ComponentName receiver, long container, int screen, int cellX, + int cellY, String title) { + CellLayout layout = getCellLayout(container, screen); + + FolderIcon liveFolder = addLiveFolder(receiver, layout, container, screen, + mPendingAddInfo.cellX, mPendingAddInfo.cellY, title); + } + /** * Add a shortcut to the workspace. * @@ -1881,6 +1914,7 @@ public final class Launcher extends Activity mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1; mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = -1; mPendingAddInfo.dropPos = null; + mPendingAddInfo.componentName = null; } void addAppWidgetImpl(final int appWidgetId, ItemInfo info, AppWidgetHostView boundWidget, @@ -1902,6 +1936,23 @@ public final class Launcher extends Activity } } + void processLiveFolderFromDrop(ComponentName componentName, long container, int screen, + int[] cell, int[] loc) { + resetAddInfo(); + mPendingAddInfo.container = container; + mPendingAddInfo.screen = screen; + mPendingAddInfo.dropPos = loc; + mPendingAddInfo.componentName = componentName; + if (cell != null) { + mPendingAddInfo.cellX = cell[0]; + mPendingAddInfo.cellY = cell[1]; + } + + Intent createLiveFolderIntent = new Intent(LiveFolder.Constants.CREATE_LIVE_FOLDER); + createLiveFolderIntent.setComponent(componentName); + startActivityForResultSafely(createLiveFolderIntent, REQUEST_CREATE_LIVE_FOLDER); + } + /** * Process a shortcut drop. * @@ -2008,6 +2059,39 @@ public final class Launcher extends Activity startActivityForResult(intent, REQUEST_PICK_WALLPAPER); } + FolderIcon addLiveFolder(ComponentName receiver, CellLayout layout, long container, final int screen, int cellX, + int cellY, String title) { + final LiveFolderInfo folderInfo = new LiveFolderInfo(title); + folderInfo.receiver = receiver; + // 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); + int x = cellX, y = cellY; + if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + newFolder.setTextVisible(!mHideDockIconLabels); + } else { + newFolder.setTextVisible(!mHideIconLabels); + } + + if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT && + getHotseat().hasVerticalHotseat()) { + // Note: If the destination of the new folder is the hotseat and + // the hotseat is in vertical mode, then we need to invert the xy position, + // so the addInScreen method will use the correct values to draw the new folder + // in the correct position + // We use the y in both case to determine the new position + x = getHotseat().getInverterCellXFromOrder(y); + y = getHotseat().getInverterCellYFromOrder(y); + } + mWorkspace.addInScreen(newFolder, container, screen, x, y, 1, 1, isWorkspaceLocked()); + return newFolder; + } + FolderIcon addFolder(CellLayout layout, long container, final int screen, int cellX, int cellY) { final FolderInfo folderInfo = new FolderInfo(); @@ -2044,6 +2128,9 @@ public final class Launcher extends Activity void removeFolder(FolderInfo folder) { sFolders.remove(folder.id); + if (folder instanceof LiveFolderInfo) { + LiveFoldersReceiver.alertFolderModified(this, (LiveFolderInfo) folder, true); + } } private void startWallpaper() { @@ -3655,6 +3742,7 @@ public final class Launcher extends Activity } } break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()), @@ -3774,6 +3862,17 @@ public final class Launcher extends Activity } mWorkspaceLoading = false; + + // Alert live folder receivers + Intent intent = new Intent(LiveFolder.Constants.LIVE_FOLDER_UPDATES); + intent.putExtra(LiveFolder.Constants.FOLDER_UPDATE_TYPE_EXTRA, + LiveFolder.Constants.EXISTING_FOLDERS_CREATED); + for (FolderInfo i : getModel().sBgFolders.values()) { + if (i instanceof LiveFolderInfo) { + intent.setComponent(((LiveFolderInfo) i).receiver); + sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF); + } + } } private boolean canRunNewAppsAnimation() { diff --git a/src/com/cyanogenmod/trebuchet/LauncherModel.java b/src/com/cyanogenmod/trebuchet/LauncherModel.java index 6aa109ae9..482632c45 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherModel.java +++ b/src/com/cyanogenmod/trebuchet/LauncherModel.java @@ -348,6 +348,7 @@ public class LauncherModel extends BroadcastReceiver { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_ALLAPPS: if (!sBgWorkspaceItems.contains(modelItem)) { sBgWorkspaceItems.add(modelItem); @@ -532,11 +533,13 @@ public class LauncherModel extends BroadcastReceiver { 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 receiverPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RECEIVER_COMPONENT); FolderInfo folderInfo = null; switch (c.getInt(itemTypeIndex)) { + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - folderInfo = findOrMakeFolder(folderList, id); + folderInfo = findOrMakeFolder(folderList, id, c.getInt(itemTypeIndex)); break; } @@ -549,6 +552,11 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.cellY = c.getInt(cellYIndex); } + if (folderInfo instanceof LiveFolderInfo) { + LiveFolderInfo info = (LiveFolderInfo) folderInfo; + info.receiver = ComponentName.unflattenFromString(c.getString(receiverPackageIndex)); + } + return folderInfo; } } finally { @@ -562,7 +570,7 @@ public class LauncherModel extends BroadcastReceiver { * 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, + static void addItemToDatabase(final Context context, final ItemInfo item, final long container, final int screen, final int cellX, final int cellY, final boolean notify) { // We store hotseat items in canonical form which is this orientation invariant position @@ -609,8 +617,12 @@ public class LauncherModel extends BroadcastReceiver { checkItemInfoLocked(item.id, item, null); sBgItemsIdMap.put(item.id, item); switch (item.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: sBgFolders.put(item.id, (FolderInfo) item); + if (item instanceof LiveFolderInfo) { + LiveFoldersReceiver.alertFolderModified(context, (LiveFolderInfo) item, false); + } // Fall through case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: @@ -697,6 +709,7 @@ public class LauncherModel extends BroadcastReceiver { // Lock on mBgLock *after* the db operation synchronized (sBgLock) { switch (item.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: sBgFolders.remove(item.id); for (ItemInfo info: sBgItemsIdMap.values()) { @@ -1308,6 +1321,8 @@ public class LauncherModel extends BroadcastReceiver { (LauncherSettings.Favorites.SPANX); final int spanYIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.SPANY); + final int receiverPackageIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.RECEIVER_COMPONENT); ShortcutInfo info; String intentDescription; @@ -1390,7 +1405,7 @@ public class LauncherModel extends BroadcastReceiver { default: // Item is in a user folder FolderInfo folderInfo = - findOrMakeFolder(sBgFolders, container); + findOrMakeFolder(sBgFolders, container, LauncherSettings.Favorites.ITEM_TYPE_FOLDER); folderInfo.add(info); break; } @@ -1410,11 +1425,11 @@ public class LauncherModel extends BroadcastReceiver { id, false), null, null); } break; - + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: id = c.getLong(idIndex); - FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id); - + FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id, itemType); + folderInfo.itemType = itemType; folderInfo.title = c.getString(titleIndex); folderInfo.id = id; container = c.getInt(containerIndex); @@ -1423,6 +1438,11 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.cellX = c.getInt(cellXIndex); folderInfo.cellY = c.getInt(cellYIndex); + if (folderInfo instanceof LiveFolderInfo) { + LiveFolderInfo fInfo = (LiveFolderInfo) folderInfo; + fInfo.receiver = ComponentName.unflattenFromString(c.getString(receiverPackageIndex)); + } + // check & update map of what's occupied if (!checkItemPlacement(occupied, folderInfo)) { break; @@ -1693,7 +1713,7 @@ public class LauncherModel extends BroadcastReceiver { } } - if (folder.contents.size() == 1) { + if (folder.contents.size() == 1 && !(folder instanceof LiveFolderInfo)) { ShortcutInfo finalItem = folder.contents.get(0); finalItem.container = folder.container; LauncherModel.deleteItemFromDatabase(mContext, folder); @@ -1702,7 +1722,7 @@ public class LauncherModel extends BroadcastReceiver { workspaceItems.remove(i); workspaceItems.add(finalItem); folders.remove(Long.valueOf(item.id)); - } else if (folder.contents.size() == 0) { + } else if (folder.contents.size() == 0 && !(folder instanceof LiveFolderInfo)) { LauncherModel.deleteFolderContentsFromDatabase(mContext, folder); workspaceItems.remove(i); folders.remove(Long.valueOf(item.id)); @@ -2469,12 +2489,16 @@ public class LauncherModel extends BroadcastReceiver { * 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) { + private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id, int folderType) { // 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(); + if (folderType == LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) { + folderInfo = new LiveFolderInfo(); + } else { + folderInfo = new FolderInfo(); + } folders.put(id, folderInfo); } return folderInfo; diff --git a/src/com/cyanogenmod/trebuchet/LauncherProvider.java b/src/com/cyanogenmod/trebuchet/LauncherProvider.java index 9f450389a..4805962aa 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherProvider.java +++ b/src/com/cyanogenmod/trebuchet/LauncherProvider.java @@ -62,7 +62,7 @@ public class LauncherProvider extends ContentProvider { private static final String DATABASE_NAME = "launcher.db"; - private static final int DATABASE_VERSION = 14; + private static final int DATABASE_VERSION = 15; static final String AUTHORITY = "com.cyanogenmod.trebuchet.settings"; @@ -289,7 +289,8 @@ public class LauncherProvider extends ContentProvider { "iconType INTEGER," + "iconPackage TEXT," + "iconResource TEXT," + - "icon BLOB" + + "icon BLOB," + + "receiverComponent TEXT" + ");"); // Database was just created, so wipe any previous widgets @@ -433,6 +434,11 @@ public class LauncherProvider extends ContentProvider { version = 14; } + if (oldVersion < 15) { + db.execSQL("ALTER TABLE favorites ADD receiverComponent TEXT;"); + version = 15; + } + if (version != DATABASE_VERSION) { Log.w(TAG, "Destroying all old data."); db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); diff --git a/src/com/cyanogenmod/trebuchet/LauncherSettings.java b/src/com/cyanogenmod/trebuchet/LauncherSettings.java index 425d84f6c..f855139b1 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherSettings.java +++ b/src/com/cyanogenmod/trebuchet/LauncherSettings.java @@ -31,6 +31,12 @@ class LauncherSettings { static final String TITLE = "title"; /** + * Flattened component name of the package bound to receive + * updates for live folder + */ + static final String RECEIVER_COMPONENT = "receiverComponent"; + + /** * 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. @@ -183,6 +189,13 @@ class LauncherSettings { static final int ITEM_TYPE_APPWIDGET = 4; /** + * The favorite is a user created live folder + * It's contents are non persistent, and the + * receiver is responsible for populating its contents + */ + static final int ITEM_TYPE_LIVE_FOLDER = 6; + + /** * The appWidgetId of the widget * * <P>Type: INTEGER</P> diff --git a/src/com/cyanogenmod/trebuchet/LiveFolderInfo.java b/src/com/cyanogenmod/trebuchet/LiveFolderInfo.java new file mode 100644 index 000000000..f377d70d0 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/LiveFolderInfo.java @@ -0,0 +1,76 @@ +package com.cyanogenmod.trebuchet; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.cyanogenmod.support.ui.LiveFolder; + +import android.content.ComponentName; +import android.content.ContentValues; +import android.content.Intent; +import android.text.TextUtils; + +/** + * Extension of regular folders with different characteristics + * User cannot drag items to/from the folder. + * Allows deletion of items when workspace is locked + * Long press to delete items + * Contents of this folder are non-persistent, and populated + * by an accompanying receiver in the 3rd party application + * Folder continues to exist even when its empty + */ +class LiveFolderInfo extends FolderInfo { + + ComponentName receiver; + long lastUpdate; + Intent.ShortcutIconResource iconResource; + + LiveFolderInfo() { + this("LiveFolder"); + } + + LiveFolderInfo(String lblMsg) { + itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER; + title = TextUtils.isEmpty(lblMsg) ? "LiveFolder" : lblMsg; + } + + @Override + void onAddToDatabase(ContentValues values) { + super.onAddToDatabase(values); + values.put(LauncherSettings.Favorites.TITLE, title.toString()); + values.put(LauncherSettings.Favorites.RECEIVER_COMPONENT, receiver.flattenToString()); + } + + public void removeAll() { + Iterator<ShortcutInfo> iter = contents.iterator(); + while (iter.hasNext()) { + ShortcutInfo info = iter.next(); + iter.remove(); + for (FolderListener listener : listeners) { + listener.onRemove(info); + } + } + itemsChanged(); + } + + public boolean isOwner(String packageName) { + return packageName.equals(receiver.getPackageName()); + } + + public void populateWithItems(ArrayList<LiveFolder.Item> items) { + lastUpdate = System.currentTimeMillis(); + removeAll(); + for (LiveFolder.Item item : items) { + LiveFolderItemInfo cInfo = new LiveFolderItemInfo(); + cInfo.title = item.getLabel(); + cInfo.intent = item.getIntent(); + cInfo.setIcon(item.getIcon()); + cInfo.item_id = item.getId(); + cInfo.container = id; + add(cInfo); + if (contents.size() == LiveFolder.Constants.MAX_ITEMS) { + break; + } + } + } +} diff --git a/src/com/cyanogenmod/trebuchet/LiveFolderItemInfo.java b/src/com/cyanogenmod/trebuchet/LiveFolderItemInfo.java new file mode 100644 index 000000000..dd68b66b5 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/LiveFolderItemInfo.java @@ -0,0 +1,12 @@ +package com.cyanogenmod.trebuchet; + + +public class LiveFolderItemInfo extends ShortcutInfo { + + int item_id; + + LiveFolderItemInfo() { + super(); + requiresDbUpdate = false; + } +} diff --git a/src/com/cyanogenmod/trebuchet/LiveFoldersReceiver.java b/src/com/cyanogenmod/trebuchet/LiveFoldersReceiver.java new file mode 100644 index 000000000..6c1eb03c5 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/LiveFoldersReceiver.java @@ -0,0 +1,105 @@ +package com.cyanogenmod.trebuchet; + +import java.util.ArrayList; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.util.Log; + +import org.cyanogenmod.support.ui.LiveFolder; +import static org.cyanogenmod.support.ui.LiveFolder.Constants.*; + +public class LiveFoldersReceiver extends BroadcastReceiver { + + private static final String TAG = LiveFoldersReceiver.class.getName(); + + static void alertFolderModified(Context ctx, LiveFolderInfo info, boolean deleted) { + Intent i = new Intent(LIVE_FOLDER_UPDATES); + i.putExtra(FOLDER_UPDATE_TYPE_EXTRA, deleted ? FOLDER_DELETED : NEW_FOLDER_CREATED); + i.putExtra(FOLDER_ID_EXTRA, info.id); + i.setComponent(info.receiver); + ctx.sendBroadcastAsUser(i, UserHandle.CURRENT_OR_SELF); + } + + static void alertItemOpened(Context ctx, LiveFolderInfo info, LiveFolderItemInfo item) { + Intent i = new Intent(LIVE_FOLDER_UPDATES); + i.putExtra(FOLDER_UPDATE_TYPE_EXTRA, FOLDER_ITEM_SELECTED); + i.putExtra(FOLDER_ID_EXTRA, info.id); + i.putExtra(FOLDER_ITEM_TITLE_EXTRA, item.title); + i.putExtra(FOLDER_ITEM_ID_EXTRA, item.item_id); + i.setComponent(info.receiver); + ctx.sendBroadcastAsUser(i, UserHandle.CURRENT_OR_SELF); + } + + static void alertItemRemoved(Context ctx, LiveFolderInfo info, LiveFolderItemInfo item) { + Intent i = new Intent(LIVE_FOLDER_UPDATES); + i.putExtra(FOLDER_UPDATE_TYPE_EXTRA, FOLDER_ITEM_REMOVED); + i.putExtra(FOLDER_ID_EXTRA, info.id); + i.putExtra(FOLDER_ITEM_TITLE_EXTRA, item.title); + i.putExtra(FOLDER_ITEM_ID_EXTRA, item.item_id); + i.setComponent(info.receiver); + ctx.sendBroadcastAsUser(i, UserHandle.CURRENT_OR_SELF); + } + + @Override + public void onReceive(Context context, Intent intent) { + + // Verify item list + ArrayList<LiveFolder.Item> items = intent.getParcelableArrayListExtra( + FOLDER_ENTRIES_EXTRA); + if (items == null || items.isEmpty()) { + Log.e(TAG, "Cannot populate with empty items"); + return; + } + + if (intent.hasExtra(FOLDER_ID_EXTRA)) { + + long id = intent.getLongExtra(FOLDER_ID_EXTRA, 0); + if (id != 0) { + synchronized (LauncherModel.sBgLock) { + FolderInfo folder = LauncherModel.sBgFolders.get(id); + + if (folder == null || !(folder instanceof LiveFolderInfo)) { + Log.e(TAG, "No live folder found with id " + id); + return; + } + + LiveFolderInfo fInfo = (LiveFolderInfo) folder; + + if (!fInfo.isOwner(getSendingPackage(intent))) { + Log.e(TAG, "Cannot modify a folder that belongs to another package"); + return; + } + + fInfo.populateWithItems(items); + + // Update folder title provided + if (intent.hasExtra(LiveFolder.Constants.FOLDER_TITLE_EXTRA)) { + String title = intent.getStringExtra( + LiveFolder.Constants.FOLDER_TITLE_EXTRA); + fInfo.title = title; + } + } + } + + } else if (intent.getBooleanExtra(FOLDER_UPDATE_ALL, false)) { + + synchronized (LauncherModel.sBgLock) { + for (FolderInfo info : LauncherModel.sBgFolders.values()) { + if (info instanceof LiveFolderInfo) { + LiveFolderInfo fInfo = (LiveFolderInfo) info; + + if (fInfo.isOwner(getSendingPackage(intent))) { + fInfo.populateWithItems(items); + } + } + } + } + + } else { + Log.d(TAG, "No folder id specified"); + } + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/trebuchet/Workspace.java b/src/com/cyanogenmod/trebuchet/Workspace.java index 20b995395..27cd01e9d 100644 --- a/src/com/cyanogenmod/trebuchet/Workspace.java +++ b/src/com/cyanogenmod/trebuchet/Workspace.java @@ -3770,6 +3770,10 @@ public class Workspace extends PagedView mLauncher.processShortcutFromDrop(pendingInfo.componentName, container, screen, mTargetCell, null); break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + mLauncher.processLiveFolderFromDrop(pendingInfo.componentName, + container, screen, mTargetCell, null); + break; default: throw new IllegalStateException("Unknown item type: " + pendingInfo.itemType); @@ -3807,6 +3811,7 @@ public class Workspace extends PagedView view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) info); break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout, (FolderInfo) info); @@ -4351,6 +4356,13 @@ public class Workspace extends PagedView childrenToRemove.add(view); } } + } else if (tag instanceof LiveFolderInfo) { + final LiveFolderInfo info = (LiveFolderInfo) tag; + String folderPkg = info.receiver.getPackageName(); + if (packageNames.contains(folderPkg)) { + LauncherModel.deleteItemFromDatabase(mLauncher, info); + childrenToRemove.add(view); + } } else if (tag instanceof FolderInfo) { final FolderInfo info = (FolderInfo) tag; final ArrayList<ShortcutInfo> contents = info.contents; |