Add onContentDirty notification to MediaSet.
Change-Id: Id89f73fb468463565cade75a6b3628318dbaf597
diff --git a/new3d/src/com/android/gallery3d/data/ComboAlbumSet.java b/new3d/src/com/android/gallery3d/data/ComboAlbumSet.java
index 5918a69..f4a4c0c 100644
--- a/new3d/src/com/android/gallery3d/data/ComboAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/ComboAlbumSet.java
@@ -32,6 +32,7 @@
}
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
@@ -55,6 +56,7 @@
return count;
}
+ @Override
public String getName() {
return TAG;
}
@@ -67,6 +69,7 @@
return count;
}
+ @Override
public void reload() {
for (MediaSet set : mSets) {
set.reload();
@@ -78,4 +81,10 @@
mListener.onContentChanged();
}
}
+
+ public void onContentDirty() {
+ if (mListener != null) {
+ mListener.onContentDirty();
+ }
+ }
}
diff --git a/new3d/src/com/android/gallery3d/data/DatabaseMediaSet.java b/new3d/src/com/android/gallery3d/data/DatabaseMediaSet.java
index 707ecb3..6d05df0 100644
--- a/new3d/src/com/android/gallery3d/data/DatabaseMediaSet.java
+++ b/new3d/src/com/android/gallery3d/data/DatabaseMediaSet.java
@@ -42,6 +42,7 @@
protected final Handler mDbHandler;
protected final GalleryContext mContext;
protected final ContentResolver mResolver;
+ protected boolean mIsDirty = true;
// How many times do we need to reload: 1 means we are reloading,
// 2 means after current reloading, we need to do another one.
@@ -77,7 +78,10 @@
};
}
+ @Override
public synchronized void reload() {
+ if (!mIsDirty) return;
+ mIsDirty = false;
// If we already have reload pending, just return.
if (mReloadCount >= 2) return;
// If this is the first reload, start it.
@@ -86,6 +90,11 @@
}
}
+ protected void notifyContentDirty() {
+ mIsDirty = true;
+ if (mListener != null) mListener.onContentDirty();
+ }
+
abstract protected void onLoadFromDatabase();
abstract protected void onUpdateContent();
}
diff --git a/new3d/src/com/android/gallery3d/data/LocalAlbum.java b/new3d/src/com/android/gallery3d/data/LocalAlbum.java
index 4e56750..ed76a92 100644
--- a/new3d/src/com/android/gallery3d/data/LocalAlbum.java
+++ b/new3d/src/com/android/gallery3d/data/LocalAlbum.java
@@ -17,8 +17,10 @@
package com.android.gallery3d.data;
import android.content.ContentResolver;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Handler;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.provider.MediaStore.Images.ImageColumns;
@@ -50,6 +52,7 @@
private final String mBucketName;
private boolean mIsImage;
private long mUniqueId;
+ private boolean mIsDirty = true;
public LocalAlbum(GalleryContext context, int bucketId, String name, boolean isImage) {
mContext = context;
@@ -75,12 +78,16 @@
mUniqueId = DataManager.makeId(
DataManager.ID_LOCAL_VIDEO_ALBUM, bucketId);
}
+
+ mResolver.registerContentObserver(mBaseUri, true, new MyContentObserver());
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
+ @Override
public ArrayList<MediaItem> getMediaItem(int start, int count) {
ImageService imageService = mContext.getImageService();
DataManager dataManager = mContext.getDataManager();
@@ -107,6 +114,7 @@
return list;
}
+ @Override
public int getMediaItemCount() {
Cursor cursor = mResolver.query(
mBaseUri, COUNT_PROJECTION, mWhereClause,
@@ -119,10 +127,12 @@
}
}
+ @Override
public String getName() {
return mBucketName;
}
+ @Override
public int getTotalMediaItemCount() {
return getMediaItemCount();
}
@@ -155,7 +165,23 @@
}
}
+ @Override
public void reload() {
- // do nothing
+ if (mIsDirty) {
+ mIsDirty = false;
+ if (mListener != null) mListener.onContentChanged();
+ }
+ }
+
+ private class MyContentObserver extends ContentObserver {
+ public MyContentObserver() {
+ super(new Handler(mContext.getMainLooper()));
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mIsDirty = true;
+ if (mListener != null) mListener.onContentDirty();
+ }
}
}
diff --git a/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java b/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
index e18cd4c..9485fc9 100644
--- a/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/LocalAlbumSet.java
@@ -16,8 +16,10 @@
package com.android.gallery3d.data;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Handler;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.provider.MediaStore.Images.ImageColumns;
@@ -66,8 +68,11 @@
mBaseUri = Video.Media.EXTERNAL_CONTENT_URI;
mUniqueId = DataManager.makeId(DataManager.ID_LOCAL_VIDEO_ALBUM_SET, 0);
}
+ context.getContentResolver().registerContentObserver(
+ mBaseUri, true, new MyContentObserver());
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
@@ -80,6 +85,7 @@
return mAlbums.size();
}
+ @Override
public String getName() {
return TAG;
}
@@ -125,4 +131,15 @@
Collections.sort(mAlbums, LocalAlbum.sBucketNameComparator);
}
+
+ private class MyContentObserver extends ContentObserver {
+ public MyContentObserver() {
+ super(new Handler(mContext.getMainLooper()));
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ notifyContentDirty();
+ }
+ }
}
diff --git a/new3d/src/com/android/gallery3d/data/MediaSet.java b/new3d/src/com/android/gallery3d/data/MediaSet.java
index b51cf27..282e00c 100644
--- a/new3d/src/com/android/gallery3d/data/MediaSet.java
+++ b/new3d/src/com/android/gallery3d/data/MediaSet.java
@@ -30,6 +30,7 @@
public abstract class MediaSet {
public interface MediaSetListener {
+ public void onContentDirty();
public void onContentChanged();
}
diff --git a/new3d/src/com/android/gallery3d/data/MergeAlbum.java b/new3d/src/com/android/gallery3d/data/MergeAlbum.java
index c4e4b3b..b4cf364 100644
--- a/new3d/src/com/android/gallery3d/data/MergeAlbum.java
+++ b/new3d/src/com/android/gallery3d/data/MergeAlbum.java
@@ -18,10 +18,10 @@
import android.util.Log;
-import java.util.Comparator;
-import java.util.TreeMap;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.SortedMap;
+import java.util.TreeMap;
// MergeAlbum merges items from two or more MediaSets. It uses a Comparator to
// determine the order of items. The items are assumed to be sorted in the input
@@ -99,24 +99,28 @@
mIndex.put(0, new int[mSize]);
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
+ @Override
public String getName() {
return TAG;
}
+ @Override
public int getMediaItemCount() {
return getTotalMediaItemCount();
}
+ @Override
public ArrayList<MediaItem> getMediaItem(int start, int count) {
// First find the nearest mark position <= start.
SortedMap<Integer, int[]> head = mIndex.headMap(start + 1);
int markPos = head.lastKey();
- int[] subPos = (int []) head.get(markPos).clone();
+ int[] subPos = head.get(markPos).clone();
MediaItem[] slot = new MediaItem[mSize];
// fill all slots
@@ -148,13 +152,14 @@
// Periodically leave a mark in the index, so we can come back later.
if ((i + 1) % mPageSize == 0) {
- mIndex.put(i + 1, (int[]) subPos.clone());
+ mIndex.put(i + 1, subPos.clone());
}
}
return result;
}
+ @Override
public int getTotalMediaItemCount() {
int count = 0;
for (MediaSet set : mSets) {
@@ -163,6 +168,7 @@
return count;
}
+ @Override
public void reload() {
for (MediaSet set : mSets) {
set.reload();
@@ -176,6 +182,10 @@
mListener.onContentChanged();
}
}
+
+ public void onContentDirty() {
+ if (mListener != null) mListener.onContentDirty();
+ }
}
class FetchCache {
diff --git a/new3d/src/com/android/gallery3d/data/MergeAlbumSet.java b/new3d/src/com/android/gallery3d/data/MergeAlbumSet.java
index 052df14..d04e29b 100644
--- a/new3d/src/com/android/gallery3d/data/MergeAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/MergeAlbumSet.java
@@ -16,8 +16,6 @@
package com.android.gallery3d.data;
-import android.util.Log;
-
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
@@ -46,6 +44,7 @@
}
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
@@ -78,18 +77,22 @@
}
}
+ @Override
public MediaSet getSubMediaSet(int index) {
return mAlbums.get(index);
}
+ @Override
public int getSubMediaSetCount() {
return mAlbums.size();
}
+ @Override
public String getName() {
return TAG;
}
+ @Override
public int getTotalMediaItemCount() {
int count = 0;
for (MediaSet set : mSets) {
@@ -98,6 +101,7 @@
return count;
}
+ @Override
public void reload() {
for (MediaSet set : mSets) {
set.reload();
@@ -110,4 +114,8 @@
mListener.onContentChanged();
}
}
+
+ public void onContentDirty() {
+ if (mListener != null) mListener.onContentDirty();
+ }
}
diff --git a/new3d/src/com/android/gallery3d/data/PicasaAlbum.java b/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
index f82c923..625e474 100644
--- a/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
+++ b/new3d/src/com/android/gallery3d/data/PicasaAlbum.java
@@ -17,8 +17,10 @@
package com.android.gallery3d.data;
import android.content.ContentResolver;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Handler;
import com.android.gallery3d.app.GalleryContext;
import com.android.gallery3d.picasa.AlbumEntry;
@@ -41,6 +43,7 @@
private final ContentResolver mResolver;
private long mUniqueId;
private GalleryContext mContext;
+ private boolean mIsDirty = true;
public PicasaAlbum(GalleryContext context, AlbumEntry entry) {
mContext = context;
@@ -48,12 +51,16 @@
mData = entry;
mUniqueId = DataManager.makeId(
DataManager.ID_PICASA_ALBUM, (int) entry.id);
+ mResolver.registerContentObserver(
+ PicasaContentProvider.PHOTOS_URI, true, new MyContentObserver());
}
+ @Override
public long getUniqueId() {
return mUniqueId;
}
+ @Override
public ArrayList<MediaItem> getMediaItem(int start, int count) {
Uri uri = PicasaContentProvider.PHOTOS_URI.buildUpon()
.appendQueryParameter("limit", start + "," + count).build();
@@ -83,6 +90,7 @@
return list;
}
+ @Override
public int getMediaItemCount() {
Cursor cursor = mResolver.query(
PicasaContentProvider.PHOTOS_URI,
@@ -96,15 +104,33 @@
}
}
+ @Override
public String getName() {
return TAG;
}
+ @Override
public int getTotalMediaItemCount() {
return getMediaItemCount();
}
+ @Override
public void reload() {
- // do nothing
+ if (mIsDirty) {
+ mIsDirty = false;
+ if (mListener != null) mListener.onContentChanged();
+ }
+ }
+
+ private class MyContentObserver extends ContentObserver {
+ public MyContentObserver() {
+ super(new Handler(mContext.getMainLooper()));
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mIsDirty = true;
+ if (mListener != null) mListener.onContentDirty();
+ }
}
}
diff --git a/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java b/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
index d7c839e..ec6b4b9 100644
--- a/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
+++ b/new3d/src/com/android/gallery3d/data/PicasaAlbumSet.java
@@ -16,7 +16,9 @@
package com.android.gallery3d.data;
+import android.database.ContentObserver;
import android.database.Cursor;
+import android.os.Handler;
import com.android.gallery3d.app.GalleryContext;
import com.android.gallery3d.picasa.AlbumEntry;
@@ -35,8 +37,11 @@
public PicasaAlbumSet(GalleryContext context) {
super(context);
+ context.getContentResolver().registerContentObserver(
+ PicasaContentProvider.ALBUMS_URI, true, new MyContentObserver());
}
+ @Override
public MediaSet getSubMediaSet(int index) {
return mAlbums.get(index);
}
@@ -45,10 +50,12 @@
return mAlbums.size();
}
+ @Override
public String getName() {
return TAG;
}
+ @Override
public long getUniqueId() {
return DataManager.makeId(DataManager.ID_PICASA_ALBUM_SET, 0);
}
@@ -83,4 +90,15 @@
mAlbums.addAll(mLoadBuffer);
mLoadBuffer.clear();
}
+
+ private class MyContentObserver extends ContentObserver {
+ public MyContentObserver() {
+ super(new Handler(mContext.getMainLooper()));
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ notifyContentDirty();
+ }
+ }
}
diff --git a/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java b/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
index 9b771cf..7347e92 100644
--- a/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
+++ b/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
@@ -192,6 +192,10 @@
public void onContentChanged() {
GridSlotAdapter.this.onContentChanged();
}
+
+ public void onContentDirty() {
+ //TODO: reload the album
+ }
}
public void updateVisibleRange(int start, int end) {
diff --git a/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java b/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
index 23ed738..de01dce 100644
--- a/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
+++ b/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
@@ -298,6 +298,10 @@
mSlotView.invalidate();
}
}
+
+ public void onContentDirty() {
+ // TODO Reload the album set
+ }
}
private class MyContentListener implements MediaSet.MediaSetListener {
@@ -305,6 +309,10 @@
public void onContentChanged() {
MediaSetSlotAdapter.this.onContentChanged();
}
+
+ public void onContentDirty() {
+ // TODO Reload the album set
+ }
}
public void updateVisibleRange(int start, int end) {
diff --git a/new3d/tests/src/com/android/gallery3d/data/GalleryContextMock.java b/new3d/tests/src/com/android/gallery3d/data/GalleryContextMock.java
index dc4774e..534aa7c 100644
--- a/new3d/tests/src/com/android/gallery3d/data/GalleryContextMock.java
+++ b/new3d/tests/src/com/android/gallery3d/data/GalleryContextMock.java
@@ -1,24 +1,34 @@
package com.android.gallery3d.data;
-import com.android.gallery3d.ui.GLRoot;
-import com.android.gallery3d.ui.GLRootStub;
-
import android.content.ContentResolver;
import android.content.Context;
+import android.os.Looper;
+
+import com.android.gallery3d.ui.GLRoot;
+import com.android.gallery3d.ui.GLRootStub;
class GalleryContextMock extends GalleryContextStub {
GLRoot mGLRoot = new GLRootStub();
DataManager mDataManager = new DataManager(this);
ContentResolver mResolver;
Context mContext;
+ Looper mMainLooper;
- GalleryContextMock(Context context, ContentResolver resolver) {
+ GalleryContextMock(Context context,
+ ContentResolver resolver, Looper mainLooper) {
mContext = context;
mResolver = resolver;
+ mMainLooper = mainLooper;
}
+ @Override
public GLRoot getGLRoot() { return mGLRoot; }
+ @Override
public DataManager getDataManager() { return mDataManager; }
+ @Override
public Context getAndroidContext() { return mContext; }
+ @Override
public ContentResolver getContentResolver() { return mResolver; }
+ @Override
+ public Looper getMainLooper() { return mMainLooper; }
}
diff --git a/new3d/tests/src/com/android/gallery3d/data/LocalDataTest.java b/new3d/tests/src/com/android/gallery3d/data/LocalDataTest.java
index 4d551df..f3a0425 100644
--- a/new3d/tests/src/com/android/gallery3d/data/LocalDataTest.java
+++ b/new3d/tests/src/com/android/gallery3d/data/LocalDataTest.java
@@ -17,9 +17,6 @@
package com.android.gallery3d.data;
import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.IContentProvider;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
@@ -28,13 +25,9 @@
import android.test.AndroidTestCase;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
-import java.util.ArrayList;
-
public class LocalDataTest extends AndroidTestCase {
private static final String TAG = "LocalDataTest";
@@ -64,13 +57,14 @@
mIsImage = isImage;
}
+ @Override
public void run() {
Looper.prepare();
SQLiteDatabase db = SQLiteDatabase.create(null);
prepareData(db);
- GalleryContextStub context = newGalleryContext(db);
+ GalleryContextStub context = newGalleryContext(db, Looper.myLooper());
LocalAlbumSet albumSet = new LocalAlbumSet(context, mIsImage);
MyListener listener = new MyListener();
albumSet.setContentListener(listener);
@@ -98,10 +92,12 @@
}
class TestZeroImage extends TestLocalImageAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
createImageTable(db);
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(0, albumSet.getSubMediaSetCount());
@@ -112,11 +108,13 @@
}
class TestOneImage extends TestLocalImageAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
createImageTable(db);
insertImageData(db);
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(1, albumSet.getSubMediaSetCount());
@@ -142,6 +140,7 @@
}
class TestMoreImages extends TestLocalImageAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
// Albums are sorted by names, and items are sorted by
// dateTimeTaken (descending)
@@ -153,6 +152,7 @@
insertImageData(db, 3000, 0xB001, "first"); // id 3
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(2, albumSet.getSubMediaSetCount());
@@ -220,10 +220,12 @@
}
class TestZeroVideo extends TestLocalVideoAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
createVideoTable(db);
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(0, albumSet.getSubMediaSetCount());
@@ -234,11 +236,13 @@
}
class TestOneVideo extends TestLocalVideoAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
createVideoTable(db);
insertVideoData(db);
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(1, albumSet.getSubMediaSetCount());
@@ -265,6 +269,7 @@
}
class TestMoreVideos extends TestLocalVideoAlbum {
+ @Override
public void prepareData(SQLiteDatabase db) {
// Albums are sorted by names, and items are sorted by
// dateTimeTaken (descending)
@@ -276,6 +281,7 @@
insertVideoData(db, 3000, 0xB001, "first"); // id 3
}
+ @Override
public void verifyResult(LocalAlbumSet albumSet) {
assertEquals(0, albumSet.getMediaItemCount());
assertEquals(2, albumSet.getSubMediaSetCount());
@@ -347,19 +353,23 @@
+ "'/mnt/sdcard/DCIM/Camera/VID_20100811_051413.3gp', 2964)");
}
- static GalleryContextStub newGalleryContext(SQLiteDatabase db) {
+ static GalleryContextStub newGalleryContext(SQLiteDatabase db, Looper mainLooper) {
ContentProvider cp = new DbContentProvider(db);
MockContentResolver cr = new MockContentResolver();
cr.addProvider("media", cp);
- return new GalleryContextMock(null, cr);
+ return new GalleryContextMock(null, cr, mainLooper);
}
static class MyListener implements MediaSet.MediaSetListener {
int count;
+
public void onContentChanged() {
count++;
Looper.myLooper().quit();
}
+
+ public void onContentDirty() {
+ }
}
}
diff --git a/new3d/tests/src/com/android/gallery3d/data/RealDataTest.java b/new3d/tests/src/com/android/gallery3d/data/RealDataTest.java
index 93ffef5..fff82a0 100644
--- a/new3d/tests/src/com/android/gallery3d/data/RealDataTest.java
+++ b/new3d/tests/src/com/android/gallery3d/data/RealDataTest.java
@@ -16,18 +16,13 @@
package com.android.gallery3d.data;
-import com.android.gallery3d.app.GalleryContext;
-import com.android.gallery3d.ui.GLRoot;
-import com.android.gallery3d.ui.GLRootStub;
-
-import android.content.ContentResolver;
import android.os.Looper;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import com.android.gallery3d.app.GalleryContext;
+
import java.util.ArrayList;
import java.util.HashSet;
@@ -54,11 +49,13 @@
}
class TestLocalImageThread extends Thread {
+ @Override
public void run() {
Looper.prepare();
GalleryContext context = new GalleryContextMock(
mContext,
- mContext.getContentResolver());
+ mContext.getContentResolver(),
+ Looper.myLooper());
LocalAlbumSet albumSet = new LocalAlbumSet(context, true);
MyListener listener = new MyListener();
@@ -73,11 +70,14 @@
}
class TestLocalVideoThread extends Thread {
+ @Override
public void run() {
Looper.prepare();
+
GalleryContext context = new GalleryContextMock(
mContext,
- mContext.getContentResolver());
+ mContext.getContentResolver(),
+ Looper.myLooper());
LocalAlbumSet albumSet = new LocalAlbumSet(context, false);
MyListener listener = new MyListener();
@@ -92,11 +92,13 @@
}
class TestPicasaThread extends Thread {
+ @Override
public void run() {
Looper.prepare();
GalleryContext context = new GalleryContextMock(
mContext,
- mContext.getContentResolver());
+ mContext.getContentResolver(),
+ Looper.myLooper());
PicasaAlbumSet albumSet = new PicasaAlbumSet(context);
MyListener listener = new MyListener();
@@ -144,9 +146,13 @@
static class MyListener implements MediaSet.MediaSetListener {
int count;
+
public void onContentChanged() {
count++;
Looper.myLooper().quit();
}
+
+ public void onContentDirty() {
+ }
}
}