blob: a32b0a32f7ab21fd9b448c9c3e1b24516cef7db7 [file] [log] [blame]
Andy Huang632721e2012-04-11 16:57:26 -07001/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.browse;
19
20import android.app.Fragment;
21import android.app.FragmentManager;
Andy Huang22ecc772012-05-16 16:11:54 -070022import android.content.res.Resources;
Andy Huang632721e2012-04-11 16:57:26 -070023import android.database.Cursor;
24import android.database.DataSetObserver;
25import android.os.Bundle;
26import android.os.Parcelable;
Andy Huang22ecc772012-05-16 16:11:54 -070027import android.support.v4.view.ViewPager;
Andy Huang632721e2012-04-11 16:57:26 -070028import android.view.ViewGroup;
29
Andy Huang22ecc772012-05-16 16:11:54 -070030import com.android.mail.R;
Andy Huang632721e2012-04-11 16:57:26 -070031import com.android.mail.providers.Account;
32import com.android.mail.providers.Conversation;
33import com.android.mail.providers.Folder;
34import com.android.mail.providers.UIProvider;
mindypf4fce122012-09-14 15:55:33 -070035import com.android.mail.ui.AbstractConversationViewFragment;
Andy Huang090db1e2012-07-25 13:25:28 -070036import com.android.mail.ui.ActivityController;
Andy Huang632721e2012-04-11 16:57:26 -070037import com.android.mail.ui.ConversationViewFragment;
Andy Huang351ad4e2012-12-06 16:04:58 -080038import com.android.mail.ui.SecureConversationViewFragment;
Andy Huang632721e2012-04-11 16:57:26 -070039import com.android.mail.utils.FragmentStatePagerAdapter2;
Paul Westbrookb334c902012-06-25 11:42:46 -070040import com.android.mail.utils.LogTag;
Andy Huang632721e2012-04-11 16:57:26 -070041import com.android.mail.utils.LogUtils;
42
Andy Huang7d646122012-09-05 19:41:44 -070043public class ConversationPagerAdapter extends FragmentStatePagerAdapter2
44 implements ViewPager.OnPageChangeListener {
Andy Huang632721e2012-04-11 16:57:26 -070045
46 private final DataSetObserver mListObserver = new ListObserver();
Andy Huang090db1e2012-07-25 13:25:28 -070047 private final DataSetObserver mFolderObserver = new FolderObserver();
48 private ActivityController mController;
Andy Huang632721e2012-04-11 16:57:26 -070049 private final Bundle mCommonFragmentArgs;
50 private final Conversation mInitialConversation;
Andy Huangb373e3e2012-06-29 19:18:47 -070051 private final Account mAccount;
52 private final Folder mFolder;
Andy Huang632721e2012-04-11 16:57:26 -070053 /**
54 * In singleton mode, this adapter ignores the cursor contents and size, and acts as if the
Andy Huang1ee96b22012-08-24 20:19:53 -070055 * data set size is exactly size=1, with {@link #getDefaultConversation()} at position 0.
Andy Huang632721e2012-04-11 16:57:26 -070056 */
57 private boolean mSingletonMode = true;
58 /**
Andy Huang1ee96b22012-08-24 20:19:53 -070059 * Similar to singleton mode, but once enabled, detached mode is permanent for this adapter.
60 */
61 private boolean mDetachedMode = false;
62 /**
Andy Huang632721e2012-04-11 16:57:26 -070063 * Adapter methods may trigger a data set change notification in the middle of a ViewPager
64 * update, but they are not safe to handle, so we have to ignore them. This will not ignore
65 * pager-external updates; it's impossible to be notified of an external change during
66 * an update.
67 *
68 * TODO: Queue up changes like this, if there ever are any that actually modify the data set.
69 * Right now there are none. Such a change would have to be of the form: instantiation or
70 * setPrimary somehow adds or removes items from the conversation cursor. Crazy!
71 */
72 private boolean mSafeToNotify;
Andy Huang22ecc772012-05-16 16:11:54 -070073 /**
74 * Need to keep this around to look up pager title strings.
75 */
76 private Resources mResources;
77 /**
78 * This isn't great to create a circular dependency, but our usage of {@link #getPageTitle(int)}
79 * requires knowing which page is the currently visible to dynamically name offscreen pages
80 * "newer" and "older". And {@link #setPrimaryItem(ViewGroup, int, Object)} does not work well
81 * because it isn't updated as often as {@link ViewPager#getCurrentItem()} is.
82 * <p>
83 * We must be careful to null out this reference when the pager and adapter are decoupled to
84 * minimize dangling references.
85 */
86 private ViewPager mPager;
mindypf4fce122012-09-14 15:55:33 -070087 private boolean mSanitizedHtml;
Andy Huang632721e2012-04-11 16:57:26 -070088
Paul Westbrookb334c902012-06-25 11:42:46 -070089 private static final String LOG_TAG = LogTag.getLogTag();
Andy Huang632721e2012-04-11 16:57:26 -070090
Andy Huang1ee96b22012-08-24 20:19:53 -070091 private static final String BUNDLE_DETACHED_MODE =
92 ConversationPagerAdapter.class.getName() + "-detachedmode";
93
Andy Huang22ecc772012-05-16 16:11:54 -070094 public ConversationPagerAdapter(Resources res, FragmentManager fm, Account account,
95 Folder folder, Conversation initialConversation) {
Andy Huang632721e2012-04-11 16:57:26 -070096 super(fm, false /* enableSavedStates */);
Andy Huang22ecc772012-05-16 16:11:54 -070097 mResources = res;
mindypf4fce122012-09-14 15:55:33 -070098 mCommonFragmentArgs = AbstractConversationViewFragment.makeBasicArgs(account, folder);
Andy Huang632721e2012-04-11 16:57:26 -070099 mInitialConversation = initialConversation;
Andy Huangb373e3e2012-06-29 19:18:47 -0700100 mAccount = account;
101 mFolder = folder;
mindypf4fce122012-09-14 15:55:33 -0700102 mSanitizedHtml = mAccount.supportsCapability
103 (UIProvider.AccountCapabilities.SANITIZED_HTML);
Andy Huangb373e3e2012-06-29 19:18:47 -0700104 }
105
106 public boolean matches(Account account, Folder folder) {
107 return mAccount != null && mFolder != null && mAccount.matches(account)
108 && mFolder.equals(folder);
Andy Huang632721e2012-04-11 16:57:26 -0700109 }
110
111 public void setSingletonMode(boolean enabled) {
112 if (mSingletonMode != enabled) {
113 mSingletonMode = enabled;
114 notifyDataSetChanged();
115 }
116 }
117
118 public boolean isSingletonMode() {
Andy Huang1ee96b22012-08-24 20:19:53 -0700119 return mSingletonMode;
120 }
121
mindyp77fb5be2012-09-26 15:43:40 -0700122 public boolean isDetached() {
123 return mDetachedMode;
124 }
125
Andy Huang1ee96b22012-08-24 20:19:53 -0700126 public boolean isPagingDisabled() {
127 return mSingletonMode || mDetachedMode || getCursor() == null;
Andy Huange3df1ad2012-04-24 17:15:23 -0700128 }
129
Paul Westbrook4de145b2012-12-19 16:43:25 -0800130 private ConversationCursor getCursor() {
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800131 if (mDetachedMode) {
132 // In detached mode, the pager is decoupled from the cursor. Nothing should rely on the
133 // cursor at this point.
134 return null;
135 }
Andy Huang090db1e2012-07-25 13:25:28 -0700136 if (mController == null) {
Vikram Aggarwal192fac12012-07-25 16:44:55 -0700137 // Happens when someone calls setActivityController(null) on us. This is done in
138 // ConversationPagerController.stopListening() to indicate that the Conversation View
139 // is going away *very* soon.
Andy Huang3825f3d2012-08-29 16:44:12 -0700140 LogUtils.i(LOG_TAG, "Pager adapter has a null controller. If the conversation view"
Vikram Aggarwal192fac12012-07-25 16:44:55 -0700141 + " is going away, this is fine. Otherwise, the state is inconsistent");
Andy Huang8775ffa2012-06-27 16:40:04 -0700142 return null;
Andy Huange3df1ad2012-04-24 17:15:23 -0700143 }
144
Andy Huang090db1e2012-07-25 13:25:28 -0700145 return mController.getConversationListCursor();
Andy Huang632721e2012-04-11 16:57:26 -0700146 }
147
148 @Override
149 public Fragment getItem(int position) {
150 final Conversation c;
151
Andy Huang1ee96b22012-08-24 20:19:53 -0700152 if (isPagingDisabled()) {
Andy Huang632721e2012-04-11 16:57:26 -0700153 // cursor-less adapter is a size-1 cursor that points to mInitialConversation.
154 // sanity-check
155 if (position != 0) {
156 LogUtils.wtf(LOG_TAG, "pager cursor is null and position is non-zero: %d",
157 position);
158 }
Andy Huang1ee96b22012-08-24 20:19:53 -0700159 c = getDefaultConversation();
Vikram Aggarwalc7694222012-04-23 13:37:01 -0700160 c.position = 0;
Andy Huang632721e2012-04-11 16:57:26 -0700161 } else {
Andy Huange3df1ad2012-04-24 17:15:23 -0700162 final Cursor cursor = getCursor();
Andy Huang8775ffa2012-06-27 16:40:04 -0700163 if (cursor == null) {
164 LogUtils.wtf(LOG_TAG, "unable to get ConversationCursor, pos=%d", position);
165 return null;
166 }
Andy Huange3df1ad2012-04-24 17:15:23 -0700167 if (!cursor.moveToPosition(position)) {
Andy Huang632721e2012-04-11 16:57:26 -0700168 LogUtils.wtf(LOG_TAG, "unable to seek to ConversationCursor pos=%d (%s)", position,
Andy Huange3df1ad2012-04-24 17:15:23 -0700169 cursor);
Andy Huang632721e2012-04-11 16:57:26 -0700170 return null;
171 }
172 // TODO: switch to something like MessageCursor or AttachmentCursor
173 // to re-use these models
Andy Huange3df1ad2012-04-24 17:15:23 -0700174 c = new Conversation(cursor);
Vikram Aggarwalc7694222012-04-23 13:37:01 -0700175 c.position = position;
Andy Huang632721e2012-04-11 16:57:26 -0700176 }
mindypf4fce122012-09-14 15:55:33 -0700177 final Fragment f = getConversationViewFragment(c);
Andy Huang632721e2012-04-11 16:57:26 -0700178 LogUtils.d(LOG_TAG, "IN PagerAdapter.getItem, frag=%s subj=%s", f, c.subject);
179 return f;
180 }
181
mindypf4fce122012-09-14 15:55:33 -0700182 private AbstractConversationViewFragment getConversationViewFragment(Conversation c) {
183 if (mSanitizedHtml) {
184 return ConversationViewFragment.newInstance(mCommonFragmentArgs, c);
185 } else {
186 return SecureConversationViewFragment.newInstance(mCommonFragmentArgs, c);
187 }
188 }
189
Andy Huang632721e2012-04-11 16:57:26 -0700190 @Override
191 public int getCount() {
Andy Huang1ee96b22012-08-24 20:19:53 -0700192 if (isPagingDisabled()) {
Andy Huang3825f3d2012-08-29 16:44:12 -0700193 LogUtils.d(LOG_TAG, "IN CPA.getCount, returning 1 (effective singleton). cursor=%s",
194 getCursor());
Andy Huang8775ffa2012-06-27 16:40:04 -0700195 return 1;
196 }
197 final Cursor cursor = getCursor();
198 if (cursor == null) {
199 return 0;
200 }
201 return cursor.getCount();
Andy Huang632721e2012-04-11 16:57:26 -0700202 }
203
204 @Override
205 public int getItemPosition(Object item) {
mindypf4fce122012-09-14 15:55:33 -0700206 if (!(item instanceof AbstractConversationViewFragment)) {
Andy Huang632721e2012-04-11 16:57:26 -0700207 LogUtils.wtf(LOG_TAG, "getItemPosition received unexpected item: %s", item);
208 }
209
mindypf4fce122012-09-14 15:55:33 -0700210 final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item;
Andy Huang632721e2012-04-11 16:57:26 -0700211 return getConversationPosition(fragment.getConversation());
212 }
213
214 @Override
215 public void setPrimaryItem(ViewGroup container, int position, Object object) {
216 LogUtils.d(LOG_TAG, "IN PagerAdapter.setPrimaryItem, pos=%d, frag=%s", position,
217 object);
218 super.setPrimaryItem(container, position, object);
219 }
220
221 @Override
222 public CharSequence getPageTitle(int position) {
Andy Huang22ecc772012-05-16 16:11:54 -0700223 final String title;
224 final int currentPosition = mPager.getCurrentItem();
Andy Huang632721e2012-04-11 16:57:26 -0700225
Andy Huang1ee96b22012-08-24 20:19:53 -0700226 if (isPagingDisabled()) {
Andy Huang68459a72012-08-09 19:09:38 -0700227 title = null;
228 } else if (position == currentPosition) {
Andy Huang090db1e2012-07-25 13:25:28 -0700229 int total = getCount();
230 if (mController != null) {
231 final Folder f = mController.getFolder();
232 if (f != null && f.totalCount > total) {
233 total = f.totalCount;
234 }
235 }
236 title = mResources.getString(R.string.conversation_count, position + 1, total);
Andy Huang22ecc772012-05-16 16:11:54 -0700237 } else {
Andy Huang68459a72012-08-09 19:09:38 -0700238 title = mResources.getString(position < currentPosition ?
Andy Huang22ecc772012-05-16 16:11:54 -0700239 R.string.conversation_newer : R.string.conversation_older);
240 }
241 return title;
Andy Huang632721e2012-04-11 16:57:26 -0700242 }
243
244 @Override
245 public Parcelable saveState() {
Andy Huang1ee96b22012-08-24 20:19:53 -0700246 LogUtils.d(LOG_TAG, "IN PagerAdapter.saveState. this=%s", this);
247 Bundle state = (Bundle) super.saveState(); // superclass uses a Bundle
248 if (state == null) {
249 state = new Bundle();
250 }
251 state.putBoolean(BUNDLE_DETACHED_MODE, mDetachedMode);
252 return state;
Andy Huang632721e2012-04-11 16:57:26 -0700253 }
254
255 @Override
256 public void restoreState(Parcelable state, ClassLoader loader) {
Andy Huang1ee96b22012-08-24 20:19:53 -0700257 LogUtils.d(LOG_TAG, "IN PagerAdapter.restoreState. this=%s", this);
Andy Huang632721e2012-04-11 16:57:26 -0700258 super.restoreState(state, loader);
Andy Huang1ee96b22012-08-24 20:19:53 -0700259 if (state != null) {
260 Bundle b = (Bundle) state;
261 b.setClassLoader(loader);
262 mDetachedMode = b.getBoolean(BUNDLE_DETACHED_MODE);
263 }
Andy Huang632721e2012-04-11 16:57:26 -0700264 }
265
266 @Override
267 public void startUpdate(ViewGroup container) {
268 mSafeToNotify = false;
269 super.startUpdate(container);
270 }
271
272 @Override
273 public void finishUpdate(ViewGroup container) {
274 super.finishUpdate(container);
275 mSafeToNotify = true;
276 }
277
278 @Override
279 public void notifyDataSetChanged() {
280 if (!mSafeToNotify) {
281 LogUtils.d(LOG_TAG, "IN PagerAdapter.notifyDataSetChanged, ignoring unsafe update");
282 return;
283 }
Andy Huang1ee96b22012-08-24 20:19:53 -0700284
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800285 // If we are in detached mode, changes to the cursor are of no interest to us, but they may
286 // be to parent classes.
287
Andy Huang1ee96b22012-08-24 20:19:53 -0700288 // when the currently visible item disappears from the dataset:
289 // if the new version of the currently visible item has zero messages:
290 // notify the list controller so it can handle this 'current conversation gone' case
291 // (by backing out of conversation mode)
292 // else
293 // 'detach' the conversation view from the cursor, keeping the current item as-is but
294 // disabling swipe (effectively the same as singleton mode)
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800295 if (mController != null && !mDetachedMode) {
Andy Huang1ee96b22012-08-24 20:19:53 -0700296 final Conversation currConversation = mController.getCurrentConversation();
297 final int pos = getConversationPosition(currConversation);
Vikram Aggarwal49e0e992012-09-21 13:53:15 -0700298 if (pos == POSITION_NONE && getCursor() != null && currConversation != null) {
Andy Huang1ee96b22012-08-24 20:19:53 -0700299 // enable detached mode and do no more here. the fragment itself will figure out
300 // if the conversation is empty (using message list cursor) and back out if needed.
301 mDetachedMode = true;
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800302 mController.setDetachedMode();
Andy Huang1ee96b22012-08-24 20:19:53 -0700303 LogUtils.i(LOG_TAG, "CPA: current conv is gone, reverting to detached mode. c=%s",
304 currConversation.uri);
mindyp36280f32012-09-09 16:11:23 -0700305 } else {
mindyp89955542012-09-13 09:58:16 -0700306 // notify unaffected fragment items of the change, so they can
307 // re-render
308 // (the change may have been to the labels for a single
309 // conversation, for example)
mindyp26d4d2d2012-09-18 17:30:32 -0700310 final AbstractConversationViewFragment frag =
311 (AbstractConversationViewFragment) getFragmentAt(pos);
mindyp16982472012-09-18 16:13:51 -0700312 final Cursor cursor = getCursor();
Andy Huang9d3fd922012-09-26 22:23:58 -0700313 if (frag != null && cursor.moveToPosition(pos) && frag.isUserVisible()) {
mindyp16982472012-09-18 16:13:51 -0700314 // reload what we think is in the current position.
mindypb2b98ba2012-09-24 14:13:58 -0700315 Conversation conv = new Conversation(cursor);
mindypa825aae2012-09-25 10:12:53 -0700316 conv.position = pos;
mindypb2b98ba2012-09-24 14:13:58 -0700317 frag.onConversationUpdated(conv);
318 mController.setCurrentConversation(conv);
mindyp16982472012-09-18 16:13:51 -0700319 }
Andy Huang1ee96b22012-08-24 20:19:53 -0700320 }
321 }
322
Andy Huang632721e2012-04-11 16:57:26 -0700323 super.notifyDataSetChanged();
324 }
325
326 @Override
327 public void setItemVisible(Fragment item, boolean visible) {
328 super.setItemVisible(item, visible);
mindypf4fce122012-09-14 15:55:33 -0700329 final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item;
Andy Huang632721e2012-04-11 16:57:26 -0700330 fragment.setExtraUserVisibleHint(visible);
Andy Huang632721e2012-04-11 16:57:26 -0700331 }
332
Andy Huang1ee96b22012-08-24 20:19:53 -0700333 private Conversation getDefaultConversation() {
334 Conversation c = (mController != null) ? mController.getCurrentConversation() : null;
335 if (c == null) {
336 c = mInitialConversation;
337 }
338 return c;
339 }
340
Andy Huang632721e2012-04-11 16:57:26 -0700341 public int getConversationPosition(Conversation conv) {
Andy Huang1ee96b22012-08-24 20:19:53 -0700342 if (isPagingDisabled()) {
Andy Huang1ee96b22012-08-24 20:19:53 -0700343 if (conv != getDefaultConversation()) {
Vikram Aggarwal49e0e992012-09-21 13:53:15 -0700344 LogUtils.d(LOG_TAG, "unable to find conversation in singleton mode. c=%s", conv);
Andy Huang632721e2012-04-11 16:57:26 -0700345 return POSITION_NONE;
346 }
347 return 0;
348 }
349
Paul Westbrook4de145b2012-12-19 16:43:25 -0800350 final ConversationCursor cursor = getCursor();
Vikram Aggarwal49e0e992012-09-21 13:53:15 -0700351 if (cursor == null || conv == null) {
Andy Huang8775ffa2012-06-27 16:40:04 -0700352 return POSITION_NONE;
353 }
Andy Huange3df1ad2012-04-24 17:15:23 -0700354
Andy Huangca854412012-04-20 19:55:38 -0700355 int result = POSITION_NONE;
Paul Westbrookc8f2a3c2013-01-08 13:57:24 -0800356 final int pos = cursor.getConversationPosition(conv.id);
357 if (pos >= 0) {
358 LogUtils.d(LOG_TAG, "pager adapter found repositioned convo '%s' at pos=%d",
359 conv.subject, pos);
360 result = pos;
Andy Huangca854412012-04-20 19:55:38 -0700361 }
362
363 return result;
Andy Huang632721e2012-04-11 16:57:26 -0700364 }
365
Andy Huang22ecc772012-05-16 16:11:54 -0700366 public void setPager(ViewPager pager) {
Andy Huang7d646122012-09-05 19:41:44 -0700367 if (mPager != null) {
368 mPager.setOnPageChangeListener(null);
369 }
Andy Huang22ecc772012-05-16 16:11:54 -0700370 mPager = pager;
Andy Huang7d646122012-09-05 19:41:44 -0700371 if (mPager != null) {
372 mPager.setOnPageChangeListener(this);
373 }
Andy Huang22ecc772012-05-16 16:11:54 -0700374 }
375
Andy Huang090db1e2012-07-25 13:25:28 -0700376 public void setActivityController(ActivityController controller) {
377 if (mController != null) {
378 mController.unregisterConversationListObserver(mListObserver);
Andy Huang86016442012-08-29 16:58:24 -0700379 mController.unregisterFolderObserver(mFolderObserver);
Andy Huang632721e2012-04-11 16:57:26 -0700380 }
Andy Huang090db1e2012-07-25 13:25:28 -0700381 mController = controller;
382 if (mController != null) {
383 mController.registerConversationListObserver(mListObserver);
Andy Huang86016442012-08-29 16:58:24 -0700384 mController.registerFolderObserver(mFolderObserver);
Andy Huang632721e2012-04-11 16:57:26 -0700385
Andy Huange3df1ad2012-04-24 17:15:23 -0700386 notifyDataSetChanged();
Andy Huang632721e2012-04-11 16:57:26 -0700387 } else {
Andy Huange3df1ad2012-04-24 17:15:23 -0700388 // We're being torn down; do not notify.
389 // Let the pager controller manage pager lifecycle.
Andy Huang632721e2012-04-11 16:57:26 -0700390 }
391 }
392
Andy Huang7d646122012-09-05 19:41:44 -0700393 @Override
394 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
395 // no-op
396 }
397
398 @Override
399 public void onPageSelected(int position) {
Vikram Aggarwal66db04c2012-10-04 16:04:04 -0700400 if (mController == null) {
401 return;
Andy Huang7d646122012-09-05 19:41:44 -0700402 }
Vikram Aggarwal66db04c2012-10-04 16:04:04 -0700403 final Cursor cursor = getCursor();
404 if (cursor == null || !cursor.moveToPosition(position)) {
405 // No valid cursor or it doesn't have the position we want. Bail.
406 return;
407 }
408 final Conversation c = new Conversation(cursor);
409 c.position = position;
410 LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s", c.subject);
411 mController.setCurrentConversation(c);
Andy Huang7d646122012-09-05 19:41:44 -0700412 }
413
414 @Override
415 public void onPageScrollStateChanged(int state) {
416 // no-op
417 }
418
Andy Huang090db1e2012-07-25 13:25:28 -0700419 // update the pager title strip as the Folder's conversation count changes
420 private class FolderObserver extends DataSetObserver {
421 @Override
422 public void onChanged() {
423 notifyDataSetChanged();
424 }
425 }
426
Andy Huang632721e2012-04-11 16:57:26 -0700427 // update the pager dataset as the Controller's cursor changes
428 private class ListObserver extends DataSetObserver {
429 @Override
430 public void onChanged() {
Andy Huange3df1ad2012-04-24 17:15:23 -0700431 notifyDataSetChanged();
Andy Huang632721e2012-04-11 16:57:26 -0700432 }
433 @Override
434 public void onInvalidated() {
435 }
436 }
437
438}