Add a new FolderUri

This will allow us to add query parameters such that Uris will still
appear to be equal, regardless of differences in the parameters.

Bug: 9780067
Change-Id: Iafe39763b3ee448cf02536df89caa736500dfdaf
diff --git a/src/com/android/mail/MailIntentService.java b/src/com/android/mail/MailIntentService.java
index 2fa0717..daca7a7 100644
--- a/src/com/android/mail/MailIntentService.java
+++ b/src/com/android/mail/MailIntentService.java
@@ -16,6 +16,7 @@
 package com.android.mail;
 
 import android.net.Uri;
+
 import com.android.mail.utils.StorageLowState;
 
 import android.app.IntentService;
@@ -24,6 +25,7 @@
 
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Folder;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.NotificationUtils;
@@ -71,7 +73,8 @@
             final Uri accountUri = intent.getParcelableExtra(Utils.EXTRA_ACCOUNT_URI);
             final Uri folderUri = intent.getParcelableExtra(Utils.EXTRA_FOLDER_URI);
 
-            NotificationUtils.resendNotifications(this, false, accountUri, folderUri);
+            NotificationUtils.resendNotifications(this, false, accountUri,
+                    new FolderUri(folderUri));
         } else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
             // The storage_low state is recorded centrally even though
             // no handler might be present to change application state
diff --git a/src/com/android/mail/adapter/DrawerItem.java b/src/com/android/mail/adapter/DrawerItem.java
index 00f76f3..f8a819b 100644
--- a/src/com/android/mail/adapter/DrawerItem.java
+++ b/src/com/android/mail/adapter/DrawerItem.java
@@ -313,7 +313,7 @@
             case VIEW_FOLDER:
                 // True if folder types and URIs are the same
                 if (currentFolder != null && mFolder != null) {
-                    return (mFolderType == currentType) && mFolder.uri.equals(currentFolder.uri);
+                    return (mFolderType == currentType) && mFolder.equals(currentFolder);
                 }
                 return false;
             case VIEW_ACCOUNT:
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index cf15909..60c1133 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -100,6 +100,7 @@
 import com.android.mail.ui.SwipeableItemView;
 import com.android.mail.ui.SwipeableListView;
 import com.android.mail.ui.ViewMode;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.HardwareLayerEnabler;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
@@ -281,7 +282,7 @@
         }
 
         @Override
-        public void loadConversationFolders(Conversation conv, final Uri ignoreFolderUri,
+        public void loadConversationFolders(Conversation conv, final FolderUri ignoreFolderUri,
                 final int ignoreFolderType) {
             super.loadConversationFolders(conv, ignoreFolderUri, ignoreFolderType);
             mFoldersCount = mFoldersSortedSet.size();
@@ -623,8 +624,8 @@
             ignoreFolderType = -1;
         }
 
-        mHeader.folderDisplayer.loadConversationFolders(mHeader.conversation, mDisplayedFolder.uri,
-                ignoreFolderType);
+        mHeader.folderDisplayer.loadConversationFolders(mHeader.conversation,
+                mDisplayedFolder.folderUri, ignoreFolderType);
 
         mHeader.dateText = DateUtils.getRelativeTimeSpanString(mContext,
                 mHeader.conversation.dateMs);
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index ad6c0d8..10a0b6c 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -19,7 +19,6 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.net.Uri;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.StaticLayout;
@@ -34,6 +33,7 @@
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.MessageInfo;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.FolderUri;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
@@ -360,8 +360,9 @@
      * Clear cached header model objects when the folder changes.
      */
     public static void onFolderUpdated(Folder folder) {
-        Uri old = sCachedModelsFolder != null ? sCachedModelsFolder.uri : Uri.EMPTY;
-        Uri newUri = folder != null ? folder.uri : Uri.EMPTY;
+        final FolderUri old = sCachedModelsFolder != null
+                ? sCachedModelsFolder.folderUri : FolderUri.EMPTY;
+        final FolderUri newUri = folder != null ? folder.folderUri : FolderUri.EMPTY;
         if (!old.equals(newUri)) {
             sCachedModelsFolder = folder;
             sConversationHeaderMap.evictAll();
diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java
index 77c69ae..8ab88ca 100644
--- a/src/com/android/mail/providers/Folder.java
+++ b/src/com/android/mail/providers/Folder.java
@@ -31,6 +31,7 @@
 import com.android.mail.content.CursorCreator;
 import com.android.mail.content.ObjectCursorLoader;
 import com.android.mail.providers.UIProvider.FolderType;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
@@ -79,7 +80,7 @@
     /**
      * The content provider URI that returns this folder for this account.
      */
-    public Uri uri;
+    public FolderUri folderUri;
 
     /**
      * The human visible name for this folder.
@@ -201,7 +202,7 @@
             final long lastMessageTimestamp) {
         this.id = id;
         this.persistentId = persistentId;
-        this.uri = uri;
+        this.folderUri = new FolderUri(uri);
         this.name = name;
         this.capabilities = capabilities;
         this.hasChildren = hasChildren;
@@ -234,7 +235,8 @@
     public Folder(Cursor cursor) {
         id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN);
         persistentId = cursor.getString(UIProvider.FOLDER_PERSISTENT_ID_COLUMN);
-        uri = Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN));
+        folderUri =
+                new FolderUri(Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN)));
         name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
         capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN);
         // 1 for true, 0 for false.
@@ -290,7 +292,7 @@
     public Folder(Parcel in, ClassLoader loader) {
         id = in.readInt();
         persistentId = in.readString();
-        uri = in.readParcelable(loader);
+        folderUri = new FolderUri((Uri) in.readParcelable(loader));
         name = in.readString();
         capabilities = in.readInt();
         // 1 for true, 0 for false.
@@ -326,7 +328,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(id);
         dest.writeString(persistentId);
-        dest.writeParcelable(uri, 0);
+        dest.writeParcelable(folderUri.fullUri, 0);
         dest.writeString(name);
         dest.writeInt(capabilities);
         // 1 for true, 0 for false.
@@ -371,7 +373,7 @@
     public static HashMap<Uri, Folder> hashMapForFolders(List<Folder> rawFolders) {
         final HashMap<Uri, Folder> folders = new HashMap<Uri, Folder>();
         for (Folder f : rawFolders) {
-            folders.put(f.uri, f);
+            folders.put(f.folderUri.comparisonUri, f);
         }
         return folders;
     }
@@ -421,12 +423,12 @@
         if (o == null || !(o instanceof Folder)) {
             return false;
         }
-        return Objects.equal(uri, ((Folder) o).uri);
+        return Objects.equal(folderUri, ((Folder) o).folderUri);
     }
 
     @Override
     public int hashCode() {
-        return uri == null ? 0 : uri.hashCode();
+        return folderUri == null ? 0 : folderUri.hashCode();
     }
 
     @Override
@@ -436,7 +438,7 @@
         sb.append(id);
         if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
             sb.append(", uri=");
-            sb.append(uri);
+            sb.append(folderUri);
             sb.append(", name=");
             sb.append(name);
         }
@@ -521,7 +523,7 @@
         final String[] folderUris = new String[folders.size()];
         int i = 0;
         for (Folder folder : folders) {
-            folderUris[i] = folder.uri.toString();
+            folderUris[i] = folder.folderUri.toString();
             i++;
         }
         return folderUris;
@@ -621,7 +623,7 @@
          }
          f.id = id;
          int index = 1;
-         f.uri = Folder.getValidUri(split[index++]);
+         f.folderUri = new FolderUri(Folder.getValidUri(split[index++]));
          f.name = split[index++];
          f.hasChildren = Integer.parseInt(split[index++]) != 0;
          f.capabilities = Integer.parseInt(split[index++]);
diff --git a/src/com/android/mail/providers/FolderWatcher.java b/src/com/android/mail/providers/FolderWatcher.java
index 8c0b1d3..3bddcb1 100644
--- a/src/com/android/mail/providers/FolderWatcher.java
+++ b/src/com/android/mail/providers/FolderWatcher.java
@@ -220,7 +220,7 @@
                 return;
             }
             final Folder f = data.getModel();
-            final Uri uri = f.uri;
+            final Uri uri = f.folderUri.comparisonUri;
             final int unreadCount = f.unreadCount;
             final Folder previousFolder = mInbox.get(uri);
             final boolean unreadCountChanged = previousFolder == null
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index d8f9972..52c8361 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -99,7 +99,6 @@
 import com.android.mail.utils.Observable;
 import com.android.mail.utils.Utils;
 import com.android.mail.utils.VeiledAddressMatcher;
-
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -941,7 +940,7 @@
         }
         // If the previous folder was null, or if the two folders represent different data, then we
         // consider that the folder has changed.
-        if (mFolder == null || !newFolder.uri.equals(mFolder.uri)) {
+        if (mFolder == null || !newFolder.equals(mFolder)) {
             mFolderChanged = true;
         }
     }
@@ -2285,7 +2284,7 @@
             } else if (intent.hasExtra(Utils.EXTRA_FOLDER)) {
                 final Folder folder =
                         Folder.fromString(intent.getStringExtra(Utils.EXTRA_FOLDER));
-                folderUri = folder.uri;
+                folderUri = folder.folderUri.fullUri;
             } else {
                 final Bundle extras = intent.getExtras();
                 LogUtils.d(LOG_TAG, "Couldn't find a folder URI in the extras: %s",
@@ -3128,7 +3127,7 @@
                     (UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)
                 && folder.supportsCapability
                     (UIProvider.FolderCapabilities.CAN_HOLD_MAIL)
-                && !mFolder.uri.equals(folder.uri));
+                && !mFolder.equals(folder));
     }
 
     /**
@@ -3187,11 +3186,11 @@
             for (Conversation target : conversations) {
                 folderUris = new ArrayList<Uri>();
                 adds = new ArrayList<Boolean>();
-                folderUris.add(folder.uri);
+                folderUris.add(folder.folderUri.fullUri);
                 adds.add(Boolean.TRUE);
                 final HashMap<Uri, Folder> targetFolders =
                         Folder.hashMapForFolders(target.getRawFolders());
-                targetFolders.put(folder.uri, folder);
+                targetFolders.put(folder.folderUri.fullUri, folder);
                 ops.add(mConversationListCursor.getConversationFolderOperation(target,
                         folderUris, adds, targetFolders.values()));
             }
@@ -3243,14 +3242,14 @@
             for (Conversation target : mConversations) {
                 folderUris = new ArrayList<Uri>();
                 adds = new ArrayList<Boolean>();
-                folderUris.add(mStarred.uri);
+                folderUris.add(mStarred.folderUri.fullUri);
                 adds.add(Boolean.TRUE);
-                folderUris.add(mInitialFolder.uri);
+                folderUris.add(mInitialFolder.folderUri.fullUri);
                 adds.add(Boolean.FALSE);
                 final HashMap<Uri, Folder> targetFolders =
                         Folder.hashMapForFolders(target.getRawFolders());
-                targetFolders.put(mStarred.uri, mStarred);
-                targetFolders.remove(mInitialFolder.uri);
+                targetFolders.put(mStarred.folderUri.fullUri, mStarred);
+                targetFolders.remove(mInitialFolder.folderUri.fullUri);
                 values.put(ConversationColumns.STARRED, true);
                 operation = mConversationListCursor.getConversationFolderOperation(target,
                         folderUris, adds, targetFolders.values(), values);
@@ -3374,7 +3373,7 @@
                     LogUtils.d(LOG_TAG, "LOADER_FOLDER_CURSOR created");
                     final ObjectCursorLoader<Folder> loader = new
                             ObjectCursorLoader<Folder>(
-                            mContext, mFolder.uri, everything, Folder.FACTORY);
+                            mContext, mFolder.folderUri.fullUri, everything, Folder.FACTORY);
                     loader.setUpdateThrottle(mFolderItemUpdateDelayMs);
                     return loader;
                 case LOADER_RECENT_FOLDERS:
@@ -3753,12 +3752,12 @@
                     target.localDeleteOnUpdate = true;
                 }
                 for (FolderOperation op : mFolderOps) {
-                    folderUris.add(op.mFolder.uri);
+                    folderUris.add(op.mFolder.folderUri.fullUri);
                     adds.add(op.mAdd ? Boolean.TRUE : Boolean.FALSE);
                     if (op.mAdd) {
-                        targetFolders.put(op.mFolder.uri, op.mFolder);
+                        targetFolders.put(op.mFolder.folderUri.fullUri, op.mFolder);
                     } else {
-                        targetFolders.remove(op.mFolder.uri);
+                        targetFolders.remove(op.mFolder.folderUri.fullUri);
                     }
                 }
                 ops.add(mConversationListCursor.getConversationFolderOperation(target,
diff --git a/src/com/android/mail/ui/FolderDisplayer.java b/src/com/android/mail/ui/FolderDisplayer.java
index 2e12074..019c662 100644
--- a/src/com/android/mail/ui/FolderDisplayer.java
+++ b/src/com/android/mail/ui/FolderDisplayer.java
@@ -17,11 +17,11 @@
 
 package com.android.mail.ui;
 
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogTag;
 import com.google.common.collect.Sets;
 
 import android.content.Context;
-import android.net.Uri;
 
 import com.android.mail.R;
 import com.android.mail.providers.Conversation;
@@ -57,7 +57,7 @@
      * @param ignoreFolderUri (optional) folder to omit from the displayed set
      * @param ignoreFolderType -1, or the {@link FolderType} to omit from the displayed set
      */
-    public void loadConversationFolders(Conversation conv, final Uri ignoreFolderUri,
+    public void loadConversationFolders(Conversation conv, final FolderUri ignoreFolderUri,
             final int ignoreFolderType) {
         mFoldersSortedSet.clear();
         for (Folder folder : conv.getRawFolders()) {
@@ -66,7 +66,7 @@
                 continue;
             }
             // skip the ignoreFolder
-            if (ignoreFolderUri != null && ignoreFolderUri.equals(folder.uri)) {
+            if (ignoreFolderUri != null && ignoreFolderUri.equals(folder.folderUri)) {
                 continue;
             }
             mFoldersSortedSet.add(folder);
diff --git a/src/com/android/mail/ui/FolderItemView.java b/src/com/android/mail/ui/FolderItemView.java
index ef0cfee..1a4cf75 100644
--- a/src/com/android/mail/ui/FolderItemView.java
+++ b/src/com/android/mail/ui/FolderItemView.java
@@ -103,7 +103,7 @@
             // a is not null because it would have returned above.
             return false;
         }
-        return (a == b || (a.uri.equals(b.uri)
+        return (a == b || (a.folderUri.equals(b.folderUri)
                 && a.name.equals(b.name)
                 && a.hasChildren == b.hasChildren
                 && a.unseenCount == b.unseenCount
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
index 55a0924..b153715 100644
--- a/src/com/android/mail/ui/FolderListFragment.java
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -46,6 +46,7 @@
 import com.android.mail.providers.RecentFolderObserver;
 import com.android.mail.providers.UIProvider;
 import com.android.mail.providers.UIProvider.FolderType;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
 
@@ -109,7 +110,7 @@
     private AccountController mAccountController;
 
     /** The currently selected folder (the folder being viewed).  This is never null. */
-    private Uri mSelectedFolderUri = Uri.EMPTY;
+    private FolderUri mSelectedFolderUri = FolderUri.EMPTY;
     /**
      * The current folder from the controller.  This is meant only to check when the unread count
      * goes out of sync and fixing it.
@@ -268,7 +269,8 @@
             selectedFolder = currentFolder;
         }
         // Is the selected folder fresher than the one we have restored from a bundle?
-        if (selectedFolder != null && !selectedFolder.uri.equals(mSelectedFolderUri)) {
+        if (selectedFolder != null
+                && !selectedFolder.folderUri.equals(mSelectedFolderUri)) {
             setSelectedFolder(selectedFolder);
         }
 
@@ -352,10 +354,11 @@
             mListView.onRestoreInstanceState(savedState.getParcelable(BUNDLE_LIST_STATE));
         }
         if (savedState != null && savedState.containsKey(BUNDLE_SELECTED_FOLDER)) {
-            mSelectedFolderUri = Uri.parse(savedState.getString(BUNDLE_SELECTED_FOLDER));
+            mSelectedFolderUri =
+                    new FolderUri(Uri.parse(savedState.getString(BUNDLE_SELECTED_FOLDER)));
             mSelectedFolderType = savedState.getInt(BUNDLE_SELECTED_TYPE);
         } else if (mParentFolder != null) {
-            mSelectedFolderUri = mParentFolder.uri;
+            mSelectedFolderUri = mParentFolder.folderUri;
             // No selected folder type required for hierarchical lists.
         }
 
@@ -486,7 +489,7 @@
             // Not changing the account.
             final Account nextAccount = null;
             // Go to the conversation list for this folder.
-            if (!folder.uri.equals(mSelectedFolderUri)) {
+            if (!folder.folderUri.equals(mSelectedFolderUri)) {
                 mNextFolder = folder;
                 mAccountController.closeDrawer(true, nextAccount, folder);
             } else {
@@ -942,7 +945,7 @@
 
         private static final int PARENT = 0;
         private static final int CHILD = 1;
-        private final Uri mParentUri;
+        private final FolderUri mParentUri;
         private final Folder mParent;
         private final FolderItemView.DropHandler mDropHandler;
 
@@ -950,7 +953,7 @@
             super(mActivity.getActivityContext(), R.layout.folder_item);
             mDropHandler = mActivity;
             mParent = parentFolder;
-            mParentUri = parentFolder.uri;
+            mParentUri = parentFolder.folderUri;
             setCursor(c);
         }
 
@@ -963,14 +966,14 @@
         @Override
         public int getItemViewType(int position) {
             final Folder f = getItem(position);
-            return f.uri.equals(mParentUri) ? PARENT : CHILD;
+            return f.folderUri.equals(mParentUri) ? PARENT : CHILD;
         }
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             final FolderItemView folderItemView;
             final Folder folder = getItem(position);
-            boolean isParent = folder.uri.equals(mParentUri);
+            boolean isParent = folder.folderUri.equals(mParentUri);
             if (convertView != null) {
                 folderItemView = (FolderItemView) convertView;
             } else {
@@ -979,7 +982,7 @@
                         mActivity.getActivityContext()).inflate(resId, null);
             }
             folderItemView.bind(folder, mDropHandler);
-            if (folder.uri.equals(mSelectedFolderUri)) {
+            if (folder.folderUri.equals(mSelectedFolderUri)) {
                 getListView().setItemChecked(position, true);
                 // If this is the current folder, also check to verify that the unread count
                 // matches what the action bar shows.
@@ -1045,7 +1048,7 @@
      */
     private void setSelectedFolder(Folder folder) {
         if (folder == null) {
-            mSelectedFolderUri = Uri.EMPTY;
+            mSelectedFolderUri = FolderUri.EMPTY;
             mCurrentFolderForUnreadCheck = null;
             LogUtils.e(LOG_TAG, "FolderListFragment.setSelectedFolder(null) called!");
             return;
@@ -1062,13 +1065,13 @@
         //    default inbox already, back exits the app.)
         // In both these cases, the selected folder type is not set, and must be set.
         if (mSelectedFolderType == DrawerItem.UNSET || (mCurrentAccount != null
-                && folder.uri.equals(mCurrentAccount.settings.defaultInbox))) {
+                && folder.folderUri.equals(mCurrentAccount.settings.defaultInbox))) {
             mSelectedFolderType =
                     folder.isInbox() ? DrawerItem.FOLDER_INBOX : DrawerItem.FOLDER_OTHER;
         }
 
         mCurrentFolderForUnreadCheck = folder;
-        mSelectedFolderUri = folder.uri;
+        mSelectedFolderUri = folder.folderUri;
         if (mCursorAdapter != null && viewChanged) {
             mCursorAdapter.notifyDataSetChanged();
         }
diff --git a/src/com/android/mail/ui/FolderOperation.java b/src/com/android/mail/ui/FolderOperation.java
index 28fef50..3dc61b8 100644
--- a/src/com/android/mail/ui/FolderOperation.java
+++ b/src/com/android/mail/ui/FolderOperation.java
@@ -68,7 +68,7 @@
      */
     public static boolean isDestructive(Collection<FolderOperation> folderOps, Folder folder) {
         for (FolderOperation op : folderOps) {
-            if (Objects.equal(op.mFolder.uri, folder.uri) && !op.mAdd) {
+            if (Objects.equal(op.mFolder, folder) && !op.mAdd) {
                 return true;
             }
             if (folder.isTrash() && op.mFolder.isInbox()) {
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index 743afc7..93c3f08 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -248,8 +248,9 @@
      * Create a widget for the specified account and folder
      */
     protected void createWidget(int id, Account account, Folder selectedFolder) {
-        WidgetProvider.updateWidget(this, id, account, selectedFolder.type, selectedFolder.uri,
-                selectedFolder.conversationListUri, selectedFolder.name);
+        WidgetProvider.updateWidget(this, id, account, selectedFolder.type,
+                selectedFolder.folderUri.fullUri, selectedFolder.conversationListUri,
+                selectedFolder.name);
         final Intent result = new Intent();
         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id);
         setResult(RESULT_OK, result);
@@ -279,8 +280,8 @@
                  * account, calculate the human readable name of the folder and
                  * use it as the shortcut name, etc...
                  */
-                final Intent clickIntent = Utils.createViewFolderIntent(this, mSelectedFolder.uri,
-                        mAccount);
+                final Intent clickIntent = Utils.createViewFolderIntent(this,
+                        mSelectedFolder.folderUri.fullUri, mAccount);
                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, clickIntent);
                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
                         Intent.ShortcutIconResource.fromContext(this,
diff --git a/src/com/android/mail/ui/FolderSelectorAdapter.java b/src/com/android/mail/ui/FolderSelectorAdapter.java
index 96e1d56..4cd9e91 100644
--- a/src/com/android/mail/ui/FolderSelectorAdapter.java
+++ b/src/com/android/mail/ui/FolderSelectorAdapter.java
@@ -115,7 +115,8 @@
             do {
                 final Folder folder = new Folder(folders);
                 final boolean isSelected = initiallySelected != null
-                        && initiallySelected.contains(folder.uri.toString());
+                        && initiallySelected.contains(
+                                folder.folderUri.comparisonUri.toString());
                 if (meetsRequirements(folder) && !Objects.equal(folder, mExcludedFolder)) {
                     final FolderRow row = new FolderRow(folder, isSelected);
                     // Add the currently selected first.
diff --git a/src/com/android/mail/ui/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index 8df8320..dee716b 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -770,7 +770,7 @@
             return;
         }
         /** True if we are changing folders. */
-        final boolean changingFolders = (mFolder == null || !mFolder.uri.equals(folder.uri));
+        final boolean changingFolders = (mFolder == null || !mFolder.equals(folder));
         mFolder = folder;
         setFolderAndAccount(changingFolders);
         final ConversationListContext listContext = mController == null ? null :
diff --git a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
index b1b9059..3fb378b 100644
--- a/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
+++ b/src/com/android/mail/ui/MultiFoldersSelectionDialog.java
@@ -88,7 +88,7 @@
                 } else {
                     // There are no folders for this conversation, so it must
                     // belong to the folder we are currently looking at.
-                    checked.add(mCurrentFolder.uri.toString());
+                    checked.add(mCurrentFolder.folderUri.fullUri.toString());
                 }
             }
             // TODO(mindyp) : bring this back in UR8 when Email providers
@@ -142,14 +142,15 @@
                 if (item instanceof FolderRow) {
                    ((FolderRow)item).setIsPresent(false);
                    final Folder folder = ((FolderRow)item).getFolder();
-                   mOperations.put(folder.uri, new FolderOperation(folder, false));
+                   mOperations.put(folder.folderUri.fullUri,
+                           new FolderOperation(folder, false));
                 }
             }
         }
         row.setIsPresent(add);
         mAdapter.notifyDataSetChanged();
         final Folder folder = row.getFolder();
-        mOperations.put(folder.uri, new FolderOperation(folder, add));
+        mOperations.put(folder.folderUri.fullUri, new FolderOperation(folder, add));
     }
 
     @Override
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index df198ae..e68d64f 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -34,6 +34,7 @@
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.Utils;
 
@@ -117,7 +118,7 @@
      * @param account the account whose default Inbox the candidate might be
      * @return true if the candidate is indeed the default inbox for the given account.
      */
-    private static boolean isDefaultInbox(Uri candidate, Account account) {
+    private static boolean isDefaultInbox(FolderUri candidate, Account account) {
         return (candidate != null && account != null)
                 && candidate.equals(account.settings.defaultInbox);
     }
@@ -131,7 +132,7 @@
         // If we don't have valid state, then we are not in the inbox.
         return !(account == null || context == null || context.folder == null
                 || account.settings == null) && !ConversationListContext.isSearchResult(context)
-                && isDefaultInbox(context.folder.uri, account);
+                && isDefaultInbox(context.folder.folderUri, account);
     }
 
     /**
@@ -441,7 +442,7 @@
      */
     private void transitionToInbox() {
         // The inbox could have changed, in which case we should load it again.
-        if (mInbox == null || !isDefaultInbox(mInbox.uri, mAccount)) {
+        if (mInbox == null || !isDefaultInbox(mInbox.folderUri, mAccount)) {
             loadAccountInbox();
         } else {
             onFolderChanged(mInbox);
diff --git a/src/com/android/mail/ui/RecentFolderList.java b/src/com/android/mail/ui/RecentFolderList.java
index e09b08a..25f3568 100644
--- a/src/com/android/mail/ui/RecentFolderList.java
+++ b/src/com/android/mail/ui/RecentFolderList.java
@@ -26,6 +26,7 @@
 import com.android.mail.providers.AccountObserver;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.Settings;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.LogUtils;
 import com.android.mail.utils.LruCache;
 import com.android.mail.utils.Utils;
@@ -112,7 +113,7 @@
                 ContentValues values = new ContentValues();
                 // Only the folder URIs are provided. Providers are free to update their specific
                 // information, though most will probably write the current timestamp.
-                values.put(mFolder.uri.toString(), 0);
+                values.put(mFolder.folderUri.fullUri.toString(), 0);
                 LogUtils.i(TAG, "Save: %s", mFolder.name);
                 mContext.getContentResolver().update(uri, values, null, null);
             }
@@ -176,7 +177,7 @@
         do {
             final Folder folder = c.getModel();
             final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
-            mFolderCache.putElement(folder.uri.toString(), entry);
+            mFolderCache.putElement(folder.folderUri.fullUri.toString(), entry);
             LogUtils.v(TAG, "Account %s, Recent: %s", mAccount.name, folder.name);
         } while (c.moveToPrevious());
     }
@@ -205,7 +206,7 @@
         }
 
         final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
-        mFolderCache.putElement(folder.uri.toString(), entry);
+        mFolderCache.putElement(folder.folderUri.fullUri.toString(), entry);
         new StoreRecent(mAccount, folder).execute();
     }
 
@@ -216,14 +217,15 @@
      * Returns a list of size {@value #MAX_RECENT_FOLDERS} or smaller.
      * @param excludedFolderUri the uri of folder to be excluded (typically the current folder)
      */
-    public ArrayList<Folder> getRecentFolderList(Uri excludedFolderUri) {
-        final ArrayList<Uri> excludedUris = new ArrayList<Uri>();
+    public ArrayList<Folder> getRecentFolderList(final FolderUri excludedFolderUri) {
+        final ArrayList<FolderUri> excludedUris = new ArrayList<FolderUri>();
         if (excludedFolderUri != null) {
             excludedUris.add(excludedFolderUri);
         }
-        final Uri defaultInbox = (mAccount == null) ?
-                Uri.EMPTY : Settings.getDefaultInboxUri(mAccount.settings);
-        if (!defaultInbox.equals(Uri.EMPTY)) {
+        final FolderUri defaultInbox = (mAccount == null)
+                ? FolderUri.EMPTY
+                : new FolderUri(Settings.getDefaultInboxUri(mAccount.settings));
+        if (!defaultInbox.equals(FolderUri.EMPTY)) {
             excludedUris.add(defaultInbox);
         }
         final List<RecentFolderListEntry> recent = Lists.newArrayList();
@@ -232,7 +234,7 @@
 
         final ArrayList<Folder> recentFolders = Lists.newArrayList();
         for (final RecentFolderListEntry entry : recent) {
-            if (!excludedUris.contains(entry.mFolder.uri)) {
+            if (!excludedUris.contains(entry.mFolder.folderUri)) {
                 recentFolders.add(entry.mFolder);
             }
             if (recentFolders.size() == MAX_RECENT_FOLDERS) {
diff --git a/src/com/android/mail/ui/SuppressNotificationReceiver.java b/src/com/android/mail/ui/SuppressNotificationReceiver.java
index a2d94e7..685edd0 100644
--- a/src/com/android/mail/ui/SuppressNotificationReceiver.java
+++ b/src/com/android/mail/ui/SuppressNotificationReceiver.java
@@ -146,7 +146,7 @@
         final Uri intentFolderUri =
                 (Uri)intent.getParcelableExtra(UIProvider.UpdateNotificationExtras.EXTRA_FOLDER);
 
-        if (!listContextFolder.uri.equals(intentFolderUri)) {
+        if (!listContextFolder.folderUri.equals(intentFolderUri)) {
             return;
         }
         final int count = intent.getIntExtra(
diff --git a/src/com/android/mail/ui/SwipeableListView.java b/src/com/android/mail/ui/SwipeableListView.java
index 24189fd..6523654 100644
--- a/src/com/android/mail/ui/SwipeableListView.java
+++ b/src/com/android/mail/ui/SwipeableListView.java
@@ -224,12 +224,12 @@
                 FolderOperation folderOp = new FolderOperation(mFolder, false);
                 HashMap<Uri, Folder> targetFolders = Folder
                         .hashMapForFolders(conv.getRawFolders());
-                targetFolders.remove(folderOp.mFolder.uri);
+                targetFolders.remove(folderOp.mFolder.folderUri.fullUri);
                 final FolderList folders = FolderList.copyOf(targetFolders.values());
                 conv.setRawFolders(folders);
                 final ContentValues values = new ContentValues();
                 folderUris = new ArrayList<Uri>();
-                folderUris.add(mFolder.uri);
+                folderUris.add(mFolder.folderUri.fullUri);
                 adds = new ArrayList<Boolean>();
                 adds.add(Boolean.FALSE);
                 ConversationCursor.addFolderUpdates(folderUris, adds, values);
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index e579292..91a3ccf 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -423,7 +423,7 @@
                 }
                 final boolean shouldLoadInbox = mode == ViewMode.CONVERSATION_LIST &&
                         mAccount != null && mFolder != null &&
-                        !mAccount.settings.defaultInbox.equals(mFolder.uri) &&
+                        !mFolder.folderUri.equals(mAccount.settings.defaultInbox) &&
                         mLayout != null && !mLayout.isExpansiveLayout();
                 if (shouldLoadInbox) {
                     loadAccountInbox();
diff --git a/src/com/android/mail/utils/FolderUri.java b/src/com/android/mail/utils/FolderUri.java
new file mode 100644
index 0000000..3de8913
--- /dev/null
+++ b/src/com/android/mail/utils/FolderUri.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.utils;
+
+import android.net.Uri;
+
+/**
+ * A holder for a Folder {@link Uri} that can be compared, ignoring any query parameters.
+ */
+public class FolderUri {
+    public static final FolderUri EMPTY = new FolderUri(Uri.EMPTY);
+
+    /**
+     * The full {@link Uri}. This should be used for any queries.
+     */
+    public final Uri fullUri;
+    /**
+     * Equivalent to {@link #fullUri}, but without any query parameters, and can safely be used in
+     * comparisons to determine if two {@link Uri}s point to the same object.
+     */
+    public final Uri comparisonUri;
+
+    public FolderUri(final Uri uri) {
+        fullUri = uri;
+        comparisonUri = buildComparisonUri(uri);
+    }
+
+    private static Uri buildComparisonUri(final Uri fullUri) {
+        final Uri.Builder builder = new Uri.Builder();
+        builder.scheme(fullUri .getScheme());
+        builder.path(fullUri.getPath());
+
+        return builder.build();
+    }
+
+    @Override
+    public int hashCode() {
+        return comparisonUri.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (o instanceof FolderUri) {
+            return comparisonUri.equals(((FolderUri) o).comparisonUri);
+        }
+
+        return comparisonUri.equals(o);
+    }
+
+    @Override
+    public String toString() {
+        return fullUri.toString();
+    }
+}
diff --git a/src/com/android/mail/utils/NotificationActionUtils.java b/src/com/android/mail/utils/NotificationActionUtils.java
index f3246f9..3c0e42a 100644
--- a/src/com/android/mail/utils/NotificationActionUtils.java
+++ b/src/com/android/mail/utils/NotificationActionUtils.java
@@ -632,8 +632,8 @@
                     // Not inbox, so remove label
                     final ContentValues values = new ContentValues(1);
 
-                    final String removeFolderUri =
-                            folder.uri.buildUpon().appendPath(Boolean.FALSE.toString()).toString();
+                    final String removeFolderUri = folder.folderUri.fullUri.buildUpon()
+                            .appendPath(Boolean.FALSE.toString()).toString();
                     values.put(ConversationOperations.FOLDERS_UPDATED, removeFolderUri);
 
                     contentResolver.update(uri, values, null, null);
@@ -729,7 +729,7 @@
         final Intent intent = new Intent(MailIntentService.ACTION_RESEND_NOTIFICATIONS);
         intent.setPackage(context.getPackageName()); // Make sure we only deliver this to ourself
         intent.putExtra(Utils.EXTRA_ACCOUNT_URI, account.uri);
-        intent.putExtra(Utils.EXTRA_FOLDER_URI, folder.uri);
+        intent.putExtra(Utils.EXTRA_FOLDER_URI, folder.folderUri.fullUri);
         context.startService(intent);
     }
 
diff --git a/src/com/android/mail/utils/NotificationUtils.java b/src/com/android/mail/utils/NotificationUtils.java
index e38a64e..4889651 100644
--- a/src/com/android/mail/utils/NotificationUtils.java
+++ b/src/com/android/mail/utils/NotificationUtils.java
@@ -218,7 +218,7 @@
                 final Integer unseenCount = value.second;
                 if (unreadCount != null && unseenCount != null) {
                     final String[] partValues = new String[] {
-                            key.account.uri.toString(), key.folder.uri.toString(),
+                            key.account.uri.toString(), key.folder.folderUri.fullUri.toString(),
                             unreadCount.toString(), unseenCount.toString()};
                     notificationSet.add(TextUtils.join(NOTIFICATION_PART_SEPARATOR, partValues));
                 }
@@ -291,7 +291,7 @@
      *                  upon which an action occurred.
      */
     public static void resendNotifications(Context context, final boolean cancelExisting,
-            final Uri accountUri, final Uri folderUri) {
+            final Uri accountUri, final FolderUri folderUri) {
         LogUtils.d(LOG_TAG, "NotificationUtils: resendNotifications ");
 
         if (cancelExisting) {
@@ -311,15 +311,15 @@
             // Only resend notifications if the notifications are from the same folder
             // and same account as the undo notification that was previously displayed.
             if (accountUri != null && !Objects.equal(accountUri, notification.account.uri) &&
-                    folderUri != null && !Objects.equal(folderUri, folder.uri)) {
+                    folderUri != null && !Objects.equal(folderUri, folder.folderUri)) {
                 LogUtils.d(LOG_TAG, "NotificationUtils: resendNotifications - not resending %s / %s"
                         + " because it doesn't match %s / %s",
-                        notification.account.uri, folder.uri, accountUri, folderUri);
+                        notification.account.uri, folder.folderUri, accountUri, folderUri);
                 continue;
             }
 
             LogUtils.d(LOG_TAG, "NotificationUtils: resendNotifications - resending %s / %s",
-                    notification.account.uri, folder.uri);
+                    notification.account.uri, folder.folderUri);
 
             final NotificationAction undoableAction =
                     NotificationActionUtils.sUndoNotifications.get(notificationId);
@@ -361,8 +361,8 @@
                     // If notification is not enabled for this label, remember this NotificationKey
                     // to later cancel the notification, and remove the entry from the map
                     final Folder folder = notification.folder;
-                    final boolean isInbox =
-                            notification.account.settings.defaultInbox.equals(folder.uri);
+                    final boolean isInbox = folder.folderUri.equals(
+                            notification.account.settings.defaultInbox);
                     final FolderPreferences folderPreferences = new FolderPreferences(
                             context, notification.account.name, folder, isInbox);
 
@@ -400,7 +400,7 @@
             final boolean getAttention) {
         LogUtils.d(LOG_TAG, "NotificationUtils: setNewEmailIndicator unreadCount = %d, "
             + "unseenCount = %d, account = %s, folder = %s, getAttention = %b", unreadCount,
-            unseenCount, account.name, folder.uri, getAttention);
+            unseenCount, account.name, folder.folderUri, getAttention);
 
         boolean ignoreUnobtrusiveSetting = false;
 
@@ -535,7 +535,7 @@
                     new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
             cancelNotificationIntent.setPackage(context.getPackageName());
             cancelNotificationIntent.setData(Utils.appendVersionQueryParameter(context,
-                    folder.uri));
+                    folder.folderUri.fullUri));
             cancelNotificationIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
             cancelNotificationIntent.putExtra(Utils.EXTRA_FOLDER, folder);
 
@@ -547,7 +547,7 @@
 
             boolean eventInfoConfigured = false;
 
-            final boolean isInbox = account.settings.defaultInbox.equals(folder.uri);
+            final boolean isInbox = folder.folderUri.equals(account.settings.defaultInbox);
             final FolderPreferences folderPreferences =
                     new FolderPreferences(context, account.name, folder, isInbox);
 
@@ -659,15 +659,15 @@
         final Intent intent;
 
         if (cursor == null) {
-            intent = Utils.createViewFolderIntent(context, folder.uri, account);
+            intent = Utils.createViewFolderIntent(context, folder.folderUri.fullUri, account);
         } else {
             // A conversation cursor has been specified, so this intent is intended to be go
             // directly to the one new conversation
 
             // Get the Conversation object
             final Conversation conversation = new Conversation(cursor);
-            intent = Utils.createViewConversationIntent(context, conversation, folder.uri,
-                    account);
+            intent = Utils.createViewConversationIntent(context, conversation,
+                    folder.folderUri.fullUri, account);
         }
 
         return intent;
@@ -719,7 +719,7 @@
         String notificationTicker = null;
 
         // Boolean indicating that this notification is for a non-inbox label.
-        final boolean isInbox = account.settings.defaultInbox.equals(folder.uri);
+        final boolean isInbox = folder.folderUri.fullUri.equals(account.settings.defaultInbox);
 
         // Notification label name for user label notifications.
         final String notificationLabelName = isInbox ? null : folder.name;
@@ -1376,7 +1376,7 @@
     }
 
     public static void markSeen(final Context context, final Folder folder) {
-        final Uri uri = folder.uri;
+        final Uri uri = folder.folderUri.fullUri;
 
         final ContentValues values = new ContentValues(1);
         values.put(UIProvider.ConversationColumns.SEEN, 1);
diff --git a/src/com/android/mail/widget/WidgetConversationViewBuilder.java b/src/com/android/mail/widget/WidgetConversationViewBuilder.java
index 45c4cd9..77c1992 100644
--- a/src/com/android/mail/widget/WidgetConversationViewBuilder.java
+++ b/src/com/android/mail/widget/WidgetConversationViewBuilder.java
@@ -20,13 +20,13 @@
 import com.android.mail.providers.Conversation;
 import com.android.mail.providers.Folder;
 import com.android.mail.ui.FolderDisplayer;
+import com.android.mail.utils.FolderUri;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Typeface;
-import android.net.Uri;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.style.AbsoluteSizeSpan;
@@ -66,7 +66,7 @@
          * Load Conversation Labels
          */
         @Override
-        public void loadConversationFolders(Conversation conv, final Uri ignoreFolderUri,
+        public void loadConversationFolders(Conversation conv, final FolderUri ignoreFolderUri,
                 final int ignoreFolderType) {
             super.loadConversationFolders(conv, ignoreFolderUri, ignoreFolderType);
         }
@@ -147,8 +147,8 @@
      * Return the full View
      */
     public RemoteViews getStyledView(CharSequence date, Conversation conversation,
-            final Uri folderUri, final int ignoreFolderType, SpannableStringBuilder senders,
-            String filteredSubject) {
+            final FolderUri folderUri, final int ignoreFolderType,
+            SpannableStringBuilder senders, String filteredSubject) {
 
         final boolean isUnread = !conversation.read;
         String snippet = conversation.getSnippet();
diff --git a/src/com/android/mail/widget/WidgetService.java b/src/com/android/mail/widget/WidgetService.java
index 7d19c68..a8a45f3 100644
--- a/src/com/android/mail/widget/WidgetService.java
+++ b/src/com/android/mail/widget/WidgetService.java
@@ -48,6 +48,7 @@
 import com.android.mail.providers.UIProvider.ConversationListQueryParameters;
 import com.android.mail.providers.UIProvider.FolderType;
 import com.android.mail.utils.AccountUtils;
+import com.android.mail.utils.FolderUri;
 import com.android.mail.utils.DelayedTaskHandler;
 import com.android.mail.utils.LogTag;
 import com.android.mail.utils.LogUtils;
@@ -241,7 +242,7 @@
                 String folderString = intent.getStringExtra(Utils.EXTRA_FOLDER);
                 Folder folder = Folder.fromString(folderString);
                 if (folder != null) {
-                    mFolderUri = folder.uri;
+                    mFolderUri = folder.folderUri.fullUri;
                     mFolderConversationListUri = folder.conversationListUri;
                 } else {
                     mFolderUri = Uri.EMPTY;
@@ -414,8 +415,8 @@
 
                 // Load up our remote view.
                 RemoteViews remoteViews = mWidgetConversationViewBuilder.getStyledView(date,
-                        conversation, mFolderUri, ignoreFolderType, senderBuilder,
-                                filterTag(conversation.subject));
+                        conversation, new FolderUri(mFolderUri), ignoreFolderType,
+                        senderBuilder, filterTag(conversation.subject));
 
                 // On click intent.
                 remoteViews.setOnClickFillInIntent(R.id.widget_conversation,