Implement state transition. The change handles a user's enter input.
Add StateView, which represents a state about the GLRootView's content pane.
Add StateManager, which stacks the StateView transitions.
Add DataManager, which manages the access of a retrieved data set.
Change-Id: Ife26d92e692120084f1b6d3907483f7d7cbbf09d
diff --git a/new3d/src/com/android/gallery3d/app/Gallery.java b/new3d/src/com/android/gallery3d/app/Gallery.java
index 74d5cc7..e44b3f6 100644
--- a/new3d/src/com/android/gallery3d/app/Gallery.java
+++ b/new3d/src/com/android/gallery3d/app/Gallery.java
@@ -19,31 +19,21 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Message;
import android.util.Log;
import com.android.gallery3d.R;
+import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.ImageService;
import com.android.gallery3d.data.MediaDbAccessor;
-import com.android.gallery3d.data.MediaSet;
-import com.android.gallery3d.ui.Compositor;
+import com.android.gallery3d.ui.GalleryView;
import com.android.gallery3d.ui.GLRootView;
-import com.android.gallery3d.ui.GridSlotAdapter;
-import com.android.gallery3d.ui.MediaSetSlotAdapter;
-import com.android.gallery3d.ui.SlotView;
-import com.android.gallery3d.ui.SynchronizedHandler;
+import com.android.gallery3d.ui.StateManager;
-public final class Gallery extends Activity implements SlotView.SlotTapListener {
+public final class Gallery extends Activity {
public static final String REVIEW_ACTION = "com.android.gallery3d.app.REVIEW";
- private static final int CHANGE_BACKGROUND = 1;
-
private static final String TAG = "Gallery";
private GLRootView mGLRootView;
- private SynchronizedHandler mHandler;
- private Compositor mCompositor;
- private MediaSet mRootSet;
- private SlotView mSlotView;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -51,32 +41,14 @@
setContentView(R.layout.main);
mGLRootView = (GLRootView) findViewById(R.id.gl_root_view);
+ // Initialize various managers.
+ StateManager.initialize(this, mGLRootView);
ImageService.initialize(this);
MediaDbAccessor.initialize(this, mGLRootView);
+ DataManager.initialize(this);
- mRootSet = MediaDbAccessor.getInstance().getRootMediaSets();
- mCompositor = new Compositor(this);
- mSlotView = mCompositor.getSlotView();
- mSlotView.setModel(new MediaSetSlotAdapter(this, mRootSet, mSlotView));
- mSlotView.setSlotTapListener(this);
- mGLRootView.setContentPane(mCompositor);
-
- mHandler = new SynchronizedHandler(mGLRootView) {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case CHANGE_BACKGROUND:
- mCompositor.changeBackground();
- mHandler.sendEmptyMessageDelayed(CHANGE_BACKGROUND, 3000);
- break;
- }
- }
- };
- }
-
- public void onSingleTapUp(int slotIndex) {
- mCompositor.getSlotView().setModel(new GridSlotAdapter(
- this, mRootSet.getSubMediaSet(slotIndex), mSlotView));
+ StateManager.getInstance().startStateView(
+ GalleryView.class, new Bundle());
}
@Override
@@ -93,14 +65,12 @@
public void onResume() {
super.onResume();
mGLRootView.onResume();
- mHandler.sendEmptyMessageDelayed(CHANGE_BACKGROUND, 3000);
}
@Override
public void onPause() {
super.onPause();
mGLRootView.onPause();
- mHandler.removeMessages(CHANGE_BACKGROUND);
}
@Override
diff --git a/new3d/src/com/android/gallery3d/data/DataManager.java b/new3d/src/com/android/gallery3d/data/DataManager.java
new file mode 100644
index 0000000..732f33b
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/data/DataManager.java
@@ -0,0 +1,38 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.data;
+
+import android.content.Context;
+
+public class DataManager {
+ private static DataManager mInstance;
+ private MediaSet mRootSet;
+ private Context mContext;
+
+ public DataManager(Context context) {
+ mContext = context;
+ }
+
+ public static void initialize(Context context) {
+ mInstance = new DataManager(context);
+ }
+
+ public static synchronized DataManager getInstance() {
+ if (mInstance == null) throw new IllegalStateException();
+ return mInstance;
+ }
+
+ public MediaSet getRootSet() {
+ if (mRootSet == null) {
+ mRootSet = MediaDbAccessor.getInstance().getRootMediaSets();
+ }
+ return mRootSet;
+ }
+
+ public MediaSet getSubMediaSet(int subSetIndex) {
+ if (mRootSet == null) {
+ mRootSet = MediaDbAccessor.getInstance().getRootMediaSets();
+ }
+ return mRootSet.getSubMediaSet(subSetIndex);
+ }
+}
diff --git a/new3d/src/com/android/gallery3d/data/ImageMediaItem.java b/new3d/src/com/android/gallery3d/data/ImageMediaItem.java
index 1c0e0a3..28e8cc0 100644
--- a/new3d/src/com/android/gallery3d/data/ImageMediaItem.java
+++ b/new3d/src/com/android/gallery3d/data/ImageMediaItem.java
@@ -6,6 +6,7 @@
import android.graphics.BitmapFactory;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
+import android.util.Log;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
@@ -14,10 +15,11 @@
public class ImageMediaItem extends DatabaseMediaItem {
private static final int MICRO_TARGET_PIXELS = 128 * 128;
- private static final int JPEG_MARK_POSITION = 10 * 1024;
+ private static final int JPEG_MARK_POSITION = 60 * 1024;
private static final int FULLIMAGE_TARGET_SIZE = 1024;
private static final int FULLIMAGE_MAX_NUM_PIXELS = 2 * 1024 * 1024;
+ private static final String TAG = "ImageMediaItem";
// Must preserve order between these indices and the order of the terms in
// PROJECTION_IMAGES.
@@ -49,6 +51,7 @@
private final BitmapFactory.Options mOptions = new BitmapFactory.Options();
protected Bitmap decodeImage(String path) throws IOException {
+ // TODO: need to figure out why simply setting JPEG_MARK_POSITION doesn't work!
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(path), JPEG_MARK_POSITION);
try {
@@ -57,13 +60,14 @@
options.inJustDecodeBounds = true;
bis.mark(JPEG_MARK_POSITION);
BitmapFactory.decodeStream(bis, null, options);
-
if (options.mCancel) return null;
try {
bis.reset();
} catch (IOException e) {
- throw new AssertionError();
+ Log.w(TAG, "failed in resetting the buffer after reading the jpeg header", e);
+ bis.close();
+ bis = new BufferedInputStream(new FileInputStream(path));
}
options.inSampleSize = Utils.computeSampleSize(options,
diff --git a/new3d/src/com/android/gallery3d/ui/AlbumView.java b/new3d/src/com/android/gallery3d/ui/AlbumView.java
new file mode 100644
index 0000000..e8a7216
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/ui/AlbumView.java
@@ -0,0 +1,125 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.ui;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.DataManager;
+import com.android.gallery3d.data.MediaSet;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Message;
+
+public class AlbumView extends StateView implements SlotView.SlotTapListener {
+ public static final String KEY_BUCKET_INDEX = "keyBucketIndex";
+ private static final int CHANGE_BACKGROUND = 1;
+ private static final int MARGIN_HUD_SLOTVIEW = 5;
+ private static final int HORIZONTAL_GAP_SLOTS = 5;
+ private static final int VERTICAL_GAP_SLOTS = 5;
+
+ private AdaptiveBackground mBackground;
+ private SlotView mSlotView;
+ private HeadUpDisplay mHud;
+ private SynchronizedHandler mHandler;
+ private Bitmap mBgImages[];
+ private int mBgIndex = 0;
+ private int mBucketIndex;
+
+ public AlbumView() {}
+
+ @Override
+ public void onStart(Bundle data) {
+ initializeViews();
+ intializeData(data);
+
+ mHandler = new SynchronizedHandler(getGLRootView()) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case CHANGE_BACKGROUND:
+ changeBackground();
+ mHandler.sendEmptyMessageDelayed(
+ CHANGE_BACKGROUND, 3000);
+ break;
+ }
+ }
+ };
+ mHandler.sendEmptyMessage(CHANGE_BACKGROUND);
+ }
+
+ @Override
+ public void onPause() {
+ mHandler.removeMessages(CHANGE_BACKGROUND);
+ }
+
+ private void initializeViews() {
+ mBackground = new AdaptiveBackground();
+ addComponent(mBackground);
+ mSlotView = new SlotView(mContext);
+ addComponent(mSlotView);
+ mHud = new HeadUpDisplay(mContext);
+ addComponent(mHud);
+ mSlotView.setGaps(HORIZONTAL_GAP_SLOTS, VERTICAL_GAP_SLOTS);
+ mSlotView.setSlotTapListener(this);
+
+ loadBackgroundBitmap(R.drawable.square,
+ R.drawable.potrait, R.drawable.landscape);
+ mBackground.setImage(mBgImages[mBgIndex]);
+ }
+
+ private void intializeData(Bundle data) {
+ mBucketIndex = data.getInt(KEY_BUCKET_INDEX);
+ MediaSet mediaSet = DataManager.getInstance()
+ .getSubMediaSet(mBucketIndex);
+ mSlotView.setModel(new GridSlotAdapter(mContext, mediaSet, mSlotView));
+ }
+
+ public SlotView getSlotView() {
+ return mSlotView;
+ }
+
+ @Override
+ protected void onLayout(
+ boolean changed, int left, int top, int right, int bottom) {
+ mBackground.layout(0, 0, right - left, bottom - top);
+ mHud.layout(0, 0, right - left, bottom - top);
+
+ int slotViewTop = mHud.getTopBarBottomPosition() + MARGIN_HUD_SLOTVIEW;
+ int slotViewBottom = mHud.getBottomBarTopPosition()
+ - MARGIN_HUD_SLOTVIEW;
+
+ mSlotView.layout(0, slotViewTop, right - left, slotViewBottom);
+ }
+
+ public void changeBackground() {
+ mBackground.setImage(mBgImages[mBgIndex]);
+ if (++mBgIndex == mBgImages.length) mBgIndex = 0;
+ }
+
+ private void loadBackgroundBitmap(int ... ids) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.RGB_565;
+ mBgImages = new Bitmap[ids.length];
+ Resources res = mContext.getResources();
+ for (int i = 0, n = ids.length; i < n; ++i) {
+ Bitmap bitmap = BitmapFactory.decodeResource(res, ids[i], options);
+ mBgImages[i] = mBackground.getAdaptiveBitmap(bitmap);
+ bitmap.recycle();
+ }
+ }
+
+ public void onSingleTapUp(int slotIndex) {
+ Bundle data = new Bundle();
+ data.putInt(PhotoView.KEY_SET_INDEX, mBucketIndex);
+ data.putInt(PhotoView.KEY_PHOTO_INDEX, slotIndex);
+
+ StateManager.getInstance().startStateView(PhotoView.class, data);
+ }
+
+ @Override
+ public void onResume() {
+ mHandler.sendEmptyMessage(CHANGE_BACKGROUND);
+ }
+}
\ No newline at end of file
diff --git a/new3d/src/com/android/gallery3d/ui/GalleryView.java b/new3d/src/com/android/gallery3d/ui/GalleryView.java
new file mode 100644
index 0000000..9654202
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/ui/GalleryView.java
@@ -0,0 +1,122 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.ui;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.DataManager;
+import com.android.gallery3d.data.MediaSet;
+
+public class GalleryView extends StateView implements SlotView.SlotTapListener {
+ private static final int CHANGE_BACKGROUND = 1;
+
+ private static final int MARGIN_HUD_SLOTVIEW = 5;
+ private static final int HORIZONTAL_GAP_SLOTS = 5;
+ private static final int VERTICAL_GAP_SLOTS = 5;
+
+ private AdaptiveBackground mBackground;
+ private SlotView mSlotView;
+ private HeadUpDisplay mHud;
+ private SynchronizedHandler mHandler;
+
+ private Bitmap mBgImages[];
+ private int mBgIndex = 0;
+
+ public GalleryView() {}
+
+ @Override
+ public void onStart(Bundle data) {
+ initializeViews();
+ intializeData();
+ mHandler = new SynchronizedHandler(getGLRootView()) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case CHANGE_BACKGROUND:
+ changeBackground();
+ mHandler.sendEmptyMessageDelayed(
+ CHANGE_BACKGROUND, 3000);
+ break;
+ }
+ }
+ };
+ mHandler.sendEmptyMessage(CHANGE_BACKGROUND);
+ }
+
+ @Override
+ public void onPause() {
+ mHandler.removeMessages(CHANGE_BACKGROUND);
+ }
+
+ @Override
+ public void onResume() {
+ mHandler.sendEmptyMessage(CHANGE_BACKGROUND);
+ }
+
+ private void intializeData() {
+ MediaSet mediaSet = DataManager.getInstance().getRootSet();
+ mSlotView.setModel(new MediaSetSlotAdapter(
+ mContext, mediaSet, mSlotView));
+ }
+
+ private void initializeViews() {
+ mBackground = new AdaptiveBackground();
+ addComponent(mBackground);
+ mSlotView = new SlotView(mContext);
+ addComponent(mSlotView);
+ mHud = new HeadUpDisplay(mContext);
+ addComponent(mHud);
+ mSlotView.setGaps(HORIZONTAL_GAP_SLOTS, VERTICAL_GAP_SLOTS);
+ mSlotView.setSlotTapListener(this);
+
+ loadBackgroundBitmap(R.drawable.square,
+ R.drawable.potrait, R.drawable.landscape);
+ mBackground.setImage(mBgImages[mBgIndex]);
+ }
+
+ public SlotView getSlotView() {
+ return mSlotView;
+ }
+
+ @Override
+ protected void onLayout(
+ boolean changed, int left, int top, int right, int bottom) {
+ mBackground.layout(0, 0, right - left, bottom - top);
+ mHud.layout(0, 0, right - left, bottom - top);
+
+ int slotViewTop = mHud.getTopBarBottomPosition() + MARGIN_HUD_SLOTVIEW;
+ int slotViewBottom = mHud.getBottomBarTopPosition()
+ - MARGIN_HUD_SLOTVIEW;
+
+ mSlotView.layout(0, slotViewTop, right - left, slotViewBottom);
+ }
+
+ public void changeBackground() {
+ mBackground.setImage(mBgImages[mBgIndex]);
+ if (++mBgIndex == mBgImages.length) mBgIndex = 0;
+ }
+
+ private void loadBackgroundBitmap(int ... ids) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.RGB_565;
+ mBgImages = new Bitmap[ids.length];
+ Resources res = mContext.getResources();
+ for (int i = 0, n = ids.length; i < n; ++i) {
+ Bitmap bitmap = BitmapFactory.decodeResource(res, ids[i], options);
+ mBgImages[i] = mBackground.getAdaptiveBitmap(bitmap);
+ bitmap.recycle();
+ }
+ }
+
+ public void onSingleTapUp(int slotIndex) {
+ Bundle data = new Bundle();
+ data.putInt(AlbumView.KEY_BUCKET_INDEX, slotIndex);
+ StateManager.getInstance().startStateView(AlbumView.class, data);
+ }
+}
\ No newline at end of file
diff --git a/new3d/src/com/android/gallery3d/ui/PhotoView.java b/new3d/src/com/android/gallery3d/ui/PhotoView.java
new file mode 100644
index 0000000..49068be
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/ui/PhotoView.java
@@ -0,0 +1,144 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.ui;
+
+import com.android.gallery3d.data.DataManager;
+import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaSet;
+
+import java.util.ArrayList;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Bitmap.Config;
+import android.os.Bundle;
+import android.os.Message;
+
+public class PhotoView extends StateView implements SlotView.SlotTapListener {
+ public static final String KEY_SET_INDEX = "keySetIndex";
+ public static final String KEY_PHOTO_INDEX = "keyPhotoIndex";
+
+ private static final int ON_IMAGE_READY = 1;
+
+ private SynchronizedHandler mHandler;
+ private ImageViewer mImageViewer;
+ private Bitmap mScaledBitmaps[];
+ private Bitmap mBackupBitmap;
+
+ private int mSetIndex;
+ private int mPhotoIndex;
+
+ public PhotoView() {}
+
+ @Override
+ public void onStart(Bundle data) {
+ mHandler = new SynchronizedHandler(getGLRootView()) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case ON_IMAGE_READY:
+ setImageViewer(new ImageViewer(
+ mContext, mScaledBitmaps,
+ mBackupBitmap));
+ break;
+ }
+ }
+ };
+ initializeData(data);
+ }
+
+ @Override
+ public void onPause() {
+ synchronized (getGLRootView()) {
+ mImageViewer.close();
+ }
+ }
+
+ private void initializeData(Bundle data) {
+ mSetIndex = data.getInt(KEY_SET_INDEX);
+ mPhotoIndex = data.getInt(KEY_PHOTO_INDEX);
+ MediaSet set = DataManager.getInstance().getSubMediaSet(mSetIndex);
+ MediaItem item = set.getMediaItem(mPhotoIndex);
+ item.setListener(new MyMediaItemListener());
+ item.requestImage(MediaItem.TYPE_FULL_IMAGE);
+ }
+
+ @Override
+ protected void onLayout(
+ boolean changed, int left, int top, int right, int bottom) {
+ if (mImageViewer != null) {
+ mImageViewer.layout(0, 0, right - left, bottom - top);
+ }
+ }
+
+ public void onSingleTapUp(int slotIndex) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setImageViewer(ImageViewer imageViewer) {
+ // TODO modify ImageViewer to accepting a data model
+ removeComponent(mImageViewer);
+ mImageViewer = imageViewer;
+ addComponent(mImageViewer);
+ requestLayout();
+ }
+
+ private class MyMediaItemListener implements MediaItem.MediaItemListener {
+ private static final int BACKUP_SIZE = 512;
+ public MyMediaItemListener() {}
+
+ public void onImageCanceled(MediaItem abstractMediaItem, int type) {
+ // Do nothing
+ }
+
+ public void onImageError(MediaItem item, int type, Throwable error) {
+ // Do nothing
+ }
+
+ public void onImageReady(MediaItem item, int type, Bitmap bitmap) {
+ mScaledBitmaps = getScaledBitmaps(bitmap);
+ mBackupBitmap = getBackupBitmap(bitmap);
+ mHandler.sendEmptyMessage(ON_IMAGE_READY);
+ }
+
+ private Bitmap getBackupBitmap(Bitmap bitmap) {
+ Config config = bitmap.hasAlpha()
+ ? Config.ARGB_8888 : Config.RGB_565;
+
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ float scale = (float) BACKUP_SIZE / (width > height ? width : height);
+ width = (int) (width * scale + 0.5f);
+ height = (int) (height * scale + 0.5f);
+ Bitmap result = Bitmap.createBitmap(width, height, config);
+ Canvas canvas = new Canvas(result);
+ canvas.scale(scale, scale);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ return result;
+ }
+
+ private Bitmap[] getScaledBitmaps(Bitmap bitmap) {
+ Config config = bitmap.hasAlpha()
+ ? Config.ARGB_8888 : Config.RGB_565;
+
+ int width = bitmap.getWidth() / 2;
+ int height = bitmap.getHeight() / 2;
+
+ ArrayList<Bitmap> list = new ArrayList<Bitmap>();
+ list.add(bitmap);
+ while (width > BACKUP_SIZE || height > BACKUP_SIZE) {
+ Bitmap half = Bitmap.createBitmap(width, height, config);
+ Canvas canvas = new Canvas(half);
+ canvas.scale(0.5f, 0.5f);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ width /= 2;
+ height /= 2;
+ bitmap = half;
+ list.add(bitmap);
+ }
+ return list.toArray(new Bitmap[list.size()]);
+ }
+
+ }
+}
diff --git a/new3d/src/com/android/gallery3d/ui/StateManager.java b/new3d/src/com/android/gallery3d/ui/StateManager.java
new file mode 100644
index 0000000..708ec21
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/ui/StateManager.java
@@ -0,0 +1,59 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.ui;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import java.util.Stack;
+
+public class StateManager {
+ private static StateManager mInstance;
+ private Context mContext;
+ private GLRootView mRootView;
+ private Stack<StateView> mStateStack = new Stack<StateView>();
+ private Stack<Bundle> mBundleStack = new Stack<Bundle>();
+
+ public StateManager(Context context, GLRootView rootView) {
+ mContext = context;
+ mRootView = rootView;
+ }
+
+ public static void initialize(Context context, GLRootView rootView) {
+ mInstance = new StateManager(context, rootView);
+ }
+
+ public static synchronized StateManager getInstance() {
+ if (mInstance == null) throw new IllegalStateException();
+ return mInstance;
+ }
+
+ public void startStateView(Class<? extends StateView> stateClass,
+ Bundle data) {
+ StateView stateView = null;
+ try {
+ stateView = stateClass.newInstance();
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ }
+ stateView.setContext(mContext);
+
+ if (!mStateStack.isEmpty()) {
+ mStateStack.peek().onPause();
+ }
+
+ mRootView.setContentPane(stateView);
+ mStateStack.push(stateView);
+ mBundleStack.push(data);
+ stateView.onStart(data);
+ }
+
+ void popState() {
+ if (!mStateStack.isEmpty()) {
+ mStateStack.pop();
+ mBundleStack.pop();
+ }
+ }
+}
diff --git a/new3d/src/com/android/gallery3d/ui/StateView.java b/new3d/src/com/android/gallery3d/ui/StateView.java
new file mode 100644
index 0000000..85edb56
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/ui/StateView.java
@@ -0,0 +1,25 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.ui;
+
+import android.content.Context;
+import android.os.Bundle;
+
+abstract public class StateView extends GLView {
+ protected Context mContext;
+
+ public StateView() {
+ }
+
+ void setContext(Context context) {
+ mContext = context;
+ }
+
+ abstract public void onStart(Bundle data);
+
+ public void onPause() {}
+
+ public void onResume() {}
+
+ public void onDestroy() {}
+}