summaryrefslogtreecommitdiffstats
path: root/src/com/cyanogenmod/trebuchet
diff options
context:
space:
mode:
authorDanesh M <daneshm90@gmail.com>2013-08-01 18:12:51 -0700
committerDanesh M <daneshm90@gmail.com>2013-08-07 17:01:00 -0700
commitf5c472b2a90e1f153efe2f778d95c41e3ab54e0a (patch)
treedcb389f936e02509cd88dfd7cc897f987dc3d71b /src/com/cyanogenmod/trebuchet
parent840a01498d04247f05f0d2c0319fd223c915400e (diff)
downloadandroid_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.java10
-rw-r--r--src/com/cyanogenmod/trebuchet/DragController.java2
-rw-r--r--src/com/cyanogenmod/trebuchet/Folder.java60
-rw-r--r--src/com/cyanogenmod/trebuchet/FolderIcon.java2
-rw-r--r--src/com/cyanogenmod/trebuchet/IconCache.java4
-rw-r--r--src/com/cyanogenmod/trebuchet/Launcher.java101
-rw-r--r--src/com/cyanogenmod/trebuchet/LauncherModel.java44
-rw-r--r--src/com/cyanogenmod/trebuchet/LauncherProvider.java10
-rw-r--r--src/com/cyanogenmod/trebuchet/LauncherSettings.java13
-rw-r--r--src/com/cyanogenmod/trebuchet/LiveFolderInfo.java76
-rw-r--r--src/com/cyanogenmod/trebuchet/LiveFolderItemInfo.java12
-rw-r--r--src/com/cyanogenmod/trebuchet/LiveFoldersReceiver.java105
-rw-r--r--src/com/cyanogenmod/trebuchet/Workspace.java12
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;