summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTyson Miller <tmiller@cyngn.com>2015-11-10 08:59:15 -0800
committerTyson Miller <tmiller@cyngn.com>2015-12-01 17:16:59 -0800
commit719deb83a0ac84422b68605f4d5c782865766aef (patch)
treefd3db92c9e10fa1665c2bb5c7f2e0b059ba79d5d /src
parentb0bc788a4fc3d6d7a86ff3f286d8524e3fa2787c (diff)
downloadandroid_packages_apps_Trebuchet-719deb83a0ac84422b68605f4d5c782865766aef.tar.gz
android_packages_apps_Trebuchet-719deb83a0ac84422b68605f4d5c782865766aef.tar.bz2
android_packages_apps_Trebuchet-719deb83a0ac84422b68605f4d5c782865766aef.zip
Trebuchet: dynamic folder type added
Issue-Id: CYNGNOS-1328 Change-Id: I09bf7bec119307f54836fedee8a1532627035d9a
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher3/AutoInstallsLayout.java47
-rw-r--r--src/com/android/launcher3/DefaultLayoutParser.java32
-rw-r--r--src/com/android/launcher3/Folder.java134
-rw-r--r--src/com/android/launcher3/FolderIcon.java19
-rw-r--r--src/com/android/launcher3/FolderInfo.java3
-rw-r--r--src/com/android/launcher3/Launcher.java19
-rw-r--r--src/com/android/launcher3/LauncherModel.java70
-rw-r--r--src/com/android/launcher3/RemoteFolder.java260
-rw-r--r--src/com/android/launcher3/Workspace.java2
9 files changed, 536 insertions, 50 deletions
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index a5d22286d..b7a6d9ae9 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -82,6 +82,7 @@ public class AutoInstallsLayout {
private static final String TAG_APP_ICON = "appicon";
private static final String TAG_AUTO_INSTALL = "autoinstall";
private static final String TAG_FOLDER = "folder";
+ private static final String TAG_REMOTE_FOLDER = "remote-folder";
private static final String TAG_APPWIDGET = "appwidget";
private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_EXTRA = "extra";
@@ -257,6 +258,7 @@ public class AutoInstallsLayout {
parsers.put(TAG_APP_ICON, new AppShortcutParser());
parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
parsers.put(TAG_FOLDER, new FolderParser());
+ parsers.put(TAG_REMOTE_FOLDER, new RemoteFolderParser());
parsers.put(TAG_APPWIDGET, new AppWidgetParser());
parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
return parsers;
@@ -269,6 +271,8 @@ public class AutoInstallsLayout {
*/
long parseAndAdd(XmlResourceParser parser)
throws XmlPullParserException, IOException;
+
+ boolean isRemoteFolder();
}
/**
@@ -311,6 +315,11 @@ public class AutoInstallsLayout {
}
}
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
+
/**
* Helper method to allow extending the parser capabilities
*/
@@ -343,6 +352,11 @@ public class AutoInstallsLayout {
return addShortcut(mContext.getString(R.string.package_state_unknown), intent,
Favorites.ITEM_TYPE_APPLICATION);
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
/**
@@ -396,6 +410,11 @@ public class AutoInstallsLayout {
}
return new Intent(Intent.ACTION_VIEW, null).setData(Uri.parse(url));
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
/**
@@ -488,6 +507,11 @@ public class AutoInstallsLayout {
}
return insertedId;
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
protected class FolderParser implements TagParser {
@@ -517,6 +541,11 @@ public class AutoInstallsLayout {
mValues.put(Favorites.SPANX, 1);
mValues.put(Favorites.SPANY, 1);
mValues.put(Favorites._ID, mCallback.generateNewItemId());
+
+ if (isRemoteFolder()) {
+ mValues.put("subType", 1);
+ }
+
long folderId = mCallback.insertAndCheck(mDb, mValues);
if (folderId < 0) {
if (LOGD) Log.e(TAG, "Unable to add folder");
@@ -575,6 +604,11 @@ public class AutoInstallsLayout {
}
return addedId;
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
protected static final void beginDocument(XmlPullParser parser, String firstElementName)
@@ -630,4 +664,17 @@ public class AutoInstallsLayout {
private static void copyInteger(ContentValues from, ContentValues to, String key) {
to.put(key, from.getAsInteger(key));
}
+
+ protected class RemoteFolderParser extends FolderParser {
+
+ @Override
+ public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException, IOException {
+ return super.parseAndAdd(parser);
+ }
+
+ @Override
+ public boolean isRemoteFolder() {
+ return true;
+ }
+ }
}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index e3ea40ebb..d9c400b3a 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -243,6 +243,11 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
}
return addedId;
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
/**
@@ -269,6 +274,11 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
}
return -1;
}
+
+ @Override
+ public boolean isRemoteFolder() {
+ return false;
+ }
}
/**
@@ -287,4 +297,26 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
return super.parseAndAdd(parser);
}
}
+
+ protected class RemoteFolderParser extends FolderParser {
+ public RemoteFolderParser() {
+ super();
+ }
+
+ @Override
+ public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
+ IOException {
+ final int resId = getAttributeResourceValue(parser, ATTR_FOLDER_ITEMS, 0);
+ if (resId != 0) {
+ parser = mSourceRes.getXml(resId);
+ beginDocument(parser, TAG_REMOTE_FOLDER);
+ }
+ return super.parseAndAdd(parser);
+ }
+
+ @Override
+ public boolean isRemoteFolder() {
+ return true;
+ }
+ }
}
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index d10be4efc..4cc328c5a 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -62,7 +62,9 @@ import android.widget.ScrollView;
import android.widget.TextView;
import com.android.launcher3.FolderInfo.FolderListener;
+import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.settings.SettingsProvider;
+import com.cyngn.RemoteFolder.RemoteFolderUpdater;
import java.util.ArrayList;
import java.util.Collections;
@@ -232,7 +234,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mContent.setGridSize(0, 0);
mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
mContent.setInvertIfRtl(true);
- mFolderNameLockContainer = findViewById(R.id.folder_name_lock_container);
+
mFolderName = (FolderEditText) findViewById(R.id.folder_name);
mFolderName.setFolder(this);
mFolderName.setOnFocusChangeListener(this);
@@ -257,11 +259,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.setVisibility(View.GONE);
}
+ mFolderNameLockContainer = findViewById(R.id.folder_name_lock_container);
mFolderLock = (ImageView) findViewById(R.id.folder_lock);
- mFolderLock.measure(measureSpec, measureSpec);
- mFolderLock.setOnClickListener(this);
- mFolderLockHeight = mFolderLock.getMeasuredHeight();
+ // Could be null if this Folder an instance of the RemoteFolder subclass
+ if (mFolderLock != null) {
+ mFolderLock.measure(measureSpec, measureSpec);
+ mFolderLock.setOnClickListener(this);
+ mFolderLockHeight = mFolderLock.getMeasuredHeight();
+ }
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
mScreenWidth = displayMetrics.widthPixels;
}
@@ -476,39 +482,73 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
}
- void bind(FolderInfo info) {
+ void bind(final 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) == null) {
- overflow.add(child);
- } else {
- count++;
+ final ArrayList<ShortcutInfo> children = info.contents;
+
+ if (info.subType == FolderInfo.REMOTE_SUBTYPE && children.isEmpty()) {
+ final int count = 6;
+ RemoteFolderUpdater updater = mLauncher.getRemoteFolderUpdaterInstance();
+ updater.requestSync(getContext(), count, new RemoteFolderUpdater.RemoteFolderUpdateListener() {
+ @Override
+ public void onSuccess(List<RemoteFolderUpdater.RemoteFolderInfo> remoteFolderInfoList) {
+ children.clear();
+ for (RemoteFolderUpdater.RemoteFolderInfo remoteFolderInfo : remoteFolderInfoList) {
+ ShortcutInfo shortcutInfo = new ShortcutInfo(remoteFolderInfo.getIntent(),
+ remoteFolderInfo.getTitle(),
+ remoteFolderInfo.getTitle(),
+ remoteFolderInfo.getIcon(),
+ UserHandleCompat.myUserHandle());
+ children.add(shortcutInfo);
+
+ View child = mLauncher.createShortcut(R.layout.application, mContent,
+ shortcutInfo);
+ remoteFolderInfo.setRecommendationData(child);
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, shortcutInfo, info.container,
+ info.screenId, info.cellX, info.cellY);
+ }
+ info.contents = children;
+ bind(info);
+ }
+
+ @Override
+ public void onFailure(String error) {
+ Log.e(TAG, "Failed to sync data for the remote folder's shortcuts. Reason: " + error);
+ setupContentForNumItems(count);
+ }
+ });
+ } else {
+ 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) == null) {
+ overflow.add(child);
+ } else {
+ count++;
+ }
}
- }
- // We rearrange the items in case there are any empty gaps
- setupContentForNumItems(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);
- }
+ // 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);
+ mItemsInvalidated = true;
+ updateTextViewFocus();
+ mInfo.addListener(this);
- setFolderName();
- updateItemLocationsInDatabase();
+ setFolderName();
+ updateItemLocationsInDatabase();
+ }
}
public void setFolderName() {
@@ -658,12 +698,19 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
Animator circReveal = LauncherAnimUtils.createCircularReveal(this,
circX, circY, 0, mScreenWidth);
- final View[] alphaViewSet = new View[] { mFolderNameLockContainer,
- mContent, mFolderName, mFolderLock };
+ final View[] alphaViewSet;
+ if (mInfo.subType == FolderInfo.REMOTE_SUBTYPE) {
+ alphaViewSet = new View[] { mContent, mFolderName };
+ } else {
+ alphaViewSet = new View[] { mFolderNameLockContainer,
+ mContent, mFolderName, mFolderLock };
+ }
+
for (View view : alphaViewSet) {
view.setAlpha(0f);
}
+
circReveal.setDuration(150);
circReveal.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1371,15 +1418,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
centerAboutIcon();
}
- private int getContentAreaHeight() {
+ protected int getContentAreaHeight() {
return Math.max(mContent.getDesiredHeight(), MIN_CONTENT_DIMEN);
}
- private int getContentAreaWidth() {
+ protected int getContentAreaWidth() {
return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
}
- private int getFolderHeight() {
+ protected int getFolderHeight() {
int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight
+ getContentAreaHeight();
return height;
@@ -1405,8 +1452,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
mFolderNameHeight, MeasureSpec.EXACTLY));
}
+
mFolderNameLockContainer.measure(contentAreaWidthSpec,
- MeasureSpec.makeMeasureSpec(mFolderNameHeight,MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
+
setMeasuredDimension(width, height);
}
@@ -1468,6 +1517,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
private void replaceFolderWithFinalItem() {
+ if (mInfo.subType == FolderInfo.REMOTE_SUBTYPE) {
+ return;
+ }
+
if (mInfo.hidden && getItemCount() >= 1) {
return;
}
@@ -1626,6 +1679,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
createAndAddShortcut(item);
LauncherModel.addOrMoveItemInDatabase(
mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+
+ // If this is a Remote Folder, we need to register each view with our updater for click handling.
+ if (mInfo.subType == FolderInfo.REMOTE_SUBTYPE) {
+ RemoteFolderUpdater updater = mLauncher.getModel().getRemoteFolderUpdaterInstance();
+ updater.registerViewForInteraction(getViewForInfo(item), item.getIntent());
+ }
+
}
public void onRemove(ShortcutInfo item) {
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 214ec3241..b66d5b70d 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -170,12 +170,19 @@ public class FolderIcon extends FrameLayout implements FolderListener {
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;
-
+ if (folderInfo.subType == FolderInfo.REMOTE_SUBTYPE) {
+ RemoteFolder folder = RemoteFolder.fromXml(launcher);
+ folder.setDragController(launcher.getDragController());
+ folder.setFolderIcon(icon);
+ folder.bind(folderInfo);
+ icon.mFolder = folder;
+ } else {
+ 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);
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 104bd6cc1..12b3032ec 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
* Represents a folder containing shortcuts or apps.
*/
public class FolderInfo extends ItemInfo {
+ public static final int REMOTE_SUBTYPE = 1;
/**
* Whether this folder has been opened
@@ -118,7 +119,7 @@ public class FolderInfo extends ItemInfo {
@Override
public String toString() {
- return "FolderInfo(id=" + this.id + " type=" + this.itemType
+ return "FolderInfo(id=" + this.id + " type=" + this.itemType + " subtype=" + this.subType
+ " container=" + this.container + " screen=" + screenId
+ " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
+ " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")";
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index bada6ba13..b734ad032 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -125,6 +125,7 @@ import com.android.launcher3.PagedView.TransitionEffect;
import com.android.launcher3.settings.SettingsProvider;
import com.android.launcher3.stats.LauncherStats;
import com.android.launcher3.stats.internal.service.AggregationIntentService;
+import com.cyngn.RemoteFolder.RemoteFolderUpdater;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -403,6 +404,9 @@ public class Launcher extends Activity
private BubbleTextView mWaitingForResume;
+ // Remote Folder Updater, used in Workspace and Folder
+ private RemoteFolderUpdater remoteFolderUpdater;
+
// Search widget
int mSearchWidgetId;
AppWidgetProviderInfo mSearchWidgetInfo;
@@ -3225,6 +3229,10 @@ public class Launcher extends Activity
closeFolder();
// Open the requested folder
openFolder(folderIcon, folderTouchXYOffset);
+
+ if (info.subType == FolderInfo.REMOTE_SUBTYPE) {
+ mModel.syncRemoteFolder(info, this);
+ }
} else {
// Find the open folder...
int folderScreen;
@@ -4883,7 +4891,7 @@ public class Launcher extends Activity
final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection<Animator> bounceAnims = new ArrayList<Animator>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
- Workspace workspace = mWorkspace;
+ final Workspace workspace = mWorkspace;
long newShortcutsScreenId = -1;
for (int i = start; i < end; i++) {
final ItemInfo item = shortcuts.get(i);
@@ -4934,7 +4942,7 @@ public class Launcher extends Activity
}
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
+ final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item, mIconCache);
newFolder.setTextVisible(!mHideIconLabels);
@@ -5938,6 +5946,13 @@ public class Launcher extends Activity
SettingsProvider.SETTINGS_UI_HOMESCREEN_SEARCH,
R.bool.preferences_interface_homescreen_search_default);
}
+
+ public RemoteFolderUpdater getRemoteFolderUpdaterInstance() {
+ if (remoteFolderUpdater == null) {
+ remoteFolderUpdater = new RemoteFolderUpdater();
+ }
+ return remoteFolderUpdater;
+ }
}
interface LauncherTransitionable {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index dae2c180f..724fa3227 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -116,6 +116,8 @@ public class LauncherModel extends BroadcastReceiver
private boolean mIsLoaderTaskRunning;
private volatile boolean mFlushingWorkerThread;
+ private static RemoteFolderUpdater remoteFolderUpdater;
+
/**
* Maintain a set of packages per user, for which we added a shortcut on the workspace.
*/
@@ -933,10 +935,10 @@ public class LauncherModel extends BroadcastReceiver
String userSerial = Long.toString(UserManagerCompat.getInstance(context)
.getSerialNumberForUser(user));
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent", "profileId" },
- "title=? and (intent=? or intent=?) and profileId=?",
- new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },
- null);
+ new String[]{"title", "intent", "profileId"},
+ "title=? and (intent=? or intent=?) and profileId=?",
+ new String[]{title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial},
+ null);
try {
return c.moveToFirst();
} finally {
@@ -2384,6 +2386,11 @@ public class LauncherModel extends BroadcastReceiver
sBgItemsIdMap.put(folderInfo.id, folderInfo);
sBgFolders.put(folderInfo.id, folderInfo);
+
+ if (folderInfo.subType == FolderInfo.REMOTE_SUBTYPE) {
+ syncRemoteFolder(folderInfo, mContext);
+ }
+
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -4245,4 +4252,59 @@ public class LauncherModel extends BroadcastReceiver
public Callbacks getCallback() {
return mCallbacks != null ? mCallbacks.get() : null;
}
+
+ public static RemoteFolderUpdater getRemoteFolderUpdaterInstance() {
+ if (remoteFolderUpdater == null) {
+ remoteFolderUpdater = new RemoteFolderUpdater();
+ }
+ return remoteFolderUpdater;
+ }
+
+ protected synchronized void syncRemoteFolder(final FolderInfo folderInfo, final Context context) {
+
+ String spKey = LauncherAppState.getSharedPreferencesKey();
+ SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ boolean isEnabled = sp.getBoolean(RemoteFolder.REMOTE_FOLDER_ENABLED, true);
+
+ if (!isEnabled) {
+ Log.e(TAG, "Prevented remote folder sync, since it has been explicitly disabled.");
+ return;
+ }
+
+ RemoteFolderUpdater updater = getRemoteFolderUpdaterInstance();
+ final int count = 6;
+
+ updater.requestSync(context, count, new RemoteFolderUpdater.RemoteFolderUpdateListener() {
+ @Override
+ public void onSuccess(List<RemoteFolderUpdater.RemoteFolderInfo> remoteFolderInfoList) {
+
+ synchronized (mLock) {
+
+ // Clear contents to prevent any duplicates
+ if (folderInfo.contents != null && !folderInfo.contents.isEmpty()) {
+ deleteItemsFromDatabase(context, folderInfo.contents);
+ folderInfo.contents.clear();
+ }
+
+ // Add each remote folder item, update the DB, and notify listeners
+ for (RemoteFolderUpdater.RemoteFolderInfo remoteFolderInfo : remoteFolderInfoList) {
+ ShortcutInfo shortcutInfo = new ShortcutInfo(remoteFolderInfo.getIntent(),
+ remoteFolderInfo.getTitle(),
+ remoteFolderInfo.getTitle(),
+ remoteFolderInfo.getIcon(),
+ UserHandleCompat.myUserHandle());
+ folderInfo.add(shortcutInfo);
+ }
+
+ updateItemInDatabase(context, folderInfo);
+ folderInfo.itemsChanged();
+ }
+ }
+
+ @Override
+ public void onFailure(String error) {
+ Log.e(TAG, "Failed to sync data for the remote folder's shortcuts. Reason: " + error);
+ }
+ });
+ }
}
diff --git a/src/com/android/launcher3/RemoteFolder.java b/src/com/android/launcher3/RemoteFolder.java
new file mode 100644
index 000000000..0d33a5536
--- /dev/null
+++ b/src/com/android/launcher3/RemoteFolder.java
@@ -0,0 +1,260 @@
+package com.android.launcher3;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * Created by tmiller on 11/24/15.
+ */
+public class RemoteFolder extends Folder {
+
+ public static final String TAG = "RemoteFolder";
+ public static final String REMOTE_FOLDER_ENABLED = "remote_folder_enabled";
+ private ScrollView mContentScrollView;
+ private ImageView mFolderInfo;
+ private TextView mFolderHelpText;
+ private Button mCloseInfoButton;
+ private Button mDisableFolderButton;
+ private View mFolderInfoContainer;
+
+ private int mFolderInfoContainerHeight;
+ private int mHelpTextHeight;
+ private int mHelpTextWidth;
+ private int mButtonHeight;
+ private int mFolderInfoIconHeight;
+ /**
+ * 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 RemoteFolder(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Creates a new UserFolder, inflated from R.layout.remote_folder.
+ *
+ * @param context The application's context.
+ *
+ * @return A new UserFolder.
+ */
+ static RemoteFolder fromXml(Context context) {
+ return (RemoteFolder) LayoutInflater.from(context).inflate(R.layout.remote_folder, null);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ int measureSpec = MeasureSpec.UNSPECIFIED;
+
+ mContentScrollView = (ScrollView) findViewById(R.id.scroll_view);
+
+ mFolderInfoContainer = findViewById(R.id.folder_info_container);
+ mFolderInfoContainer.measure(measureSpec, measureSpec);
+ mFolderInfoContainerHeight = mFolderInfoContainer.getMeasuredHeight();
+
+ mFolderInfo = (ImageView) findViewById(R.id.folder_info);
+ mFolderInfo.measure(measureSpec, measureSpec);
+ mFolderInfoIconHeight = mFolderInfo.getMeasuredHeight();
+ mFolderInfo.setOnClickListener(this);
+
+ mFolderHelpText = (TextView) findViewById(R.id.help_text_view);
+ mFolderHelpText.setText(getResources().getString(R.string.recommendations_help_text));
+ mFolderHelpText.measure(measureSpec, measureSpec);
+ mHelpTextHeight = (mFolderHelpText.getLineHeight() * mFolderHelpText.getLineCount()) +
+ mFolderHelpText.getPaddingTop() + mFolderHelpText.getPaddingBottom();
+ mHelpTextWidth = mFolderHelpText.getMeasuredWidth();
+ mFolderHelpText.setVisibility(GONE);
+
+ mCloseInfoButton = (Button) findViewById(R.id.close_info_button);
+ mCloseInfoButton.setText(getResources().getString(R.string.close));
+ mCloseInfoButton.measure(measureSpec, measureSpec);
+ mButtonHeight = mCloseInfoButton.getMeasuredHeight();
+ mCloseInfoButton.setOnClickListener(this);
+
+ mDisableFolderButton = (Button) findViewById(R.id.disable_remote_folder_button);
+ mDisableFolderButton.setText(getResources().getString(R.string.disable));
+ mDisableFolderButton.measure(measureSpec, measureSpec);
+ mDisableFolderButton.setOnClickListener(this);
+ }
+
+ protected int getFolderHeight() {
+ if (mFolderHelpText.getVisibility() == VISIBLE) {
+ mHelpTextHeight = (mFolderHelpText.getLineHeight() * mFolderHelpText.getLineCount()) +
+ mFolderHelpText.getPaddingTop() + mFolderHelpText.getPaddingBottom();
+
+ int height = getPaddingTop() + getPaddingBottom() + mFolderInfoIconHeight
+ + mHelpTextHeight + mButtonHeight;
+ return height;
+ } else {
+ int height = getPaddingTop() + getPaddingBottom() + mFolderInfoIconHeight
+ + getContentAreaHeight();
+ return height;
+
+ }
+ }
+
+ private int getFolderWidth() {
+ if (mFolderHelpText.getVisibility() == VISIBLE) {
+ DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
+ int screenWidth = displayMetrics.widthPixels;
+ int width = Math.min(mHelpTextWidth, screenWidth - getPaddingLeft() - getPaddingRight());
+ return width;
+ } else {
+ int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
+ return width;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // TODO (Tyson): clean this up before merging into main CM branch
+ int width = getFolderWidth();
+ int height = getFolderHeight();
+ int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
+ MeasureSpec.EXACTLY);
+ int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
+ MeasureSpec.EXACTLY);
+
+ if (LauncherAppState.isDisableAllApps()) {
+ // Don't cap the height of the content to allow scrolling.
+ mContent.setFixedSize(getContentAreaWidth(), mContent.getDesiredHeight());
+ } else {
+ mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
+ }
+ mContentScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
+
+ if (mFolderHelpText.getVisibility() == VISIBLE) {
+ mHelpTextHeight = (mFolderHelpText.getLineHeight() * mFolderHelpText.getLineCount()) +
+ mFolderHelpText.getPaddingTop() + mFolderHelpText.getPaddingBottom();
+
+ mFolderHelpText.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
+ mHelpTextHeight, MeasureSpec.EXACTLY));
+ mFolderInfoContainer.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(
+ mFolderInfoIconHeight + mHelpTextHeight + mButtonHeight, MeasureSpec.EXACTLY));
+ mCloseInfoButton.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(mButtonHeight, MeasureSpec.EXACTLY));
+ mDisableFolderButton.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(mButtonHeight, MeasureSpec.EXACTLY));
+ } else {
+ mHelpTextHeight = 0;
+ mFolderHelpText.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
+ mHelpTextHeight, MeasureSpec.EXACTLY));
+ mFolderInfoContainer.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(mFolderInfoIconHeight, MeasureSpec.EXACTLY));
+ mCloseInfoButton.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
+ mDisableFolderButton.measure(contentAreaWidthSpec,
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
+ }
+
+ Log.e(TAG, "onMeasure(), width: " + width + ", height:" + height);
+
+ setMeasuredDimension(width, height);
+ }
+
+ public void onClick(View v) {
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ mLauncher.onClick(v);
+ }
+
+ switch (v.getId()) {
+ case R.id.folder_info:
+ toggleInfoPane();
+ break;
+ case R.id.close_info_button:
+ mLauncher.closeFolder();
+ break;
+ case R.id.disable_remote_folder_button:
+ disableRemoteFolder();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void toggleInfoPane() {
+ if (mFolderHelpText.getVisibility() == VISIBLE) {
+ // info ImageView becomes a close "X" when the help text is showing, handle accordingly
+ mContentScrollView.setVisibility(VISIBLE);
+ mContent.setVisibility(VISIBLE);
+
+ mFolderHelpText.setVisibility(GONE);
+
+ mCloseInfoButton.setVisibility(GONE);
+ mDisableFolderButton.setVisibility(GONE);
+
+ mFolderInfo.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_info_normal_holo));
+
+ } else {
+ // show the info to the user about remote folders, including the option to disable it
+ mContentScrollView.setVisibility(GONE);
+ mContent.setVisibility(GONE);
+
+ mFolderHelpText.setVisibility(VISIBLE);
+
+ mCloseInfoButton.setVisibility(VISIBLE);
+ mDisableFolderButton.setVisibility(VISIBLE);
+
+ mFolderInfo.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_clear_normal_holo));
+ }
+ this.invalidate();
+
+ }
+
+ private void disableRemoteFolder() {
+ // close the folder UX & disable remote folders.
+ mLauncher.closeFolder();
+
+ if (mContext != null) {
+ String spKey = LauncherAppState.getSharedPreferencesKey();
+ SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ sp.edit().putBoolean(REMOTE_FOLDER_ENABLED, false).commit();
+ Log.e(TAG, "Set preference to disable remote folder. Requesting sync to remove existing folder");
+
+ LauncherModel.deleteFolderContentsFromDatabase(mContext, mInfo);
+ LauncherModel.deleteItemFromDatabase(mContext, mInfo);
+ mLauncher.getWorkspace().removeView(this);
+ mLauncher.removeFolder(mInfo);
+
+ mLauncher.getWorkspace().refreshDrawableState();
+ }
+ }
+
+ @Override
+ public void animateClosed(boolean animate) {
+ super.animateClosed(animate);
+ mFolderHelpText.setVisibility(GONE);
+ mCloseInfoButton.setVisibility(GONE);
+ mDisableFolderButton.setVisibility(GONE);
+ mContentScrollView.setVisibility(VISIBLE);
+ mFolderInfo.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_info_normal_holo));
+ }
+
+ @Override
+ public void animateOpen(Workspace workspace, int[] folderTouch) {
+ super.animateOpen(workspace, folderTouch);
+
+ mFolderHelpText.setText(getResources().getString(R.string.recommendations_help_text));
+ mFolderHelpText.setVisibility(GONE);
+ mCloseInfoButton.setVisibility(GONE);
+ mDisableFolderButton.setVisibility(GONE);
+ mContentScrollView.setVisibility(VISIBLE);
+ mContent.setVisibility(VISIBLE);
+ mFolderInfo.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher_info_normal_holo));
+ this.invalidate();
+ }
+}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 71407b9fc..197c09a77 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -76,11 +76,13 @@ import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.settings.SettingsProvider;
+import com.cyngn.RemoteFolder.RemoteFolderUpdater;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;