Merge change 2768 into donut
* changes:
Add an API demo that shows the effets of setting Bitmaps as being purgeable.
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index d353d31..fb34afa 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -1612,6 +1612,20 @@
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
+
+ <activity android:name=".graphics.PurgeableBitmap" android:label="Graphics/PurgeableBitmap/NonPurgeable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity-alias android:targetActivity=".graphics.PurgeableBitmap" android:name="Purgeable" android:label="Graphics/PurgeableBitmap/Purgeable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity-alias>
<!-- ************************************* -->
<!-- MEDIA SAMPLES -->
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmap.java b/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmap.java
new file mode 100644
index 0000000..14ec8c4
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmap.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 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.example.android.apis.graphics;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+
+/**
+ * PurgeableBitmap demonstrates the effects of setting Bitmaps as being
+ * purgeable.
+ *
+ * In the NonPurgeable case, an encoded bitstream is decoded to a different
+ * Bitmap over and over again up to 200 times until out-of-memory occurs.
+ * In contrast, the Purgeable case shows that the system can complete decoding
+ * the encoded bitstream 200 times without hitting the out-of-memory case.
+ */
+public class PurgeableBitmap extends GraphicsActivity {
+
+ private PurgeableBitmapView mView;
+ private final RefreshHandler mRedrawHandler = new RefreshHandler();
+
+ class RefreshHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message msg) {
+ int index = mView.update(this);
+ if (index > 0) {
+ showAlertDialog(getDialogMessage(true, index));
+ } else if (index < 0){
+ mView.invalidate();
+ showAlertDialog(getDialogMessage(false, -index));
+ } else {
+ mView.invalidate();
+ }
+ }
+
+ public void sleep(long delayMillis) {
+ this.removeMessages(0);
+ sendMessageDelayed(obtainMessage(0), delayMillis);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mView = new PurgeableBitmapView(this, detectIfPurgeableRequest());
+ mRedrawHandler.sleep(0);
+ setContentView(mView);
+ }
+
+ private boolean detectIfPurgeableRequest() {
+ PackageManager pm = getPackageManager();
+ CharSequence labelSeq = null;
+ try {
+ ActivityInfo info = pm.getActivityInfo(this.getComponentName(),
+ PackageManager.GET_META_DATA);
+ labelSeq = info.loadLabel(pm);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ String[] components = labelSeq.toString().split("/");
+ if (components[components.length - 1].equals("Purgeable")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private String getDialogMessage(boolean isOutOfMemory, int index) {
+ StringBuilder sb = new StringBuilder();
+ if (isOutOfMemory) {
+ sb.append("Out of memery occurs when the ");
+ sb.append(index);
+ sb.append("th Bitmap is decoded.");
+ } else {
+ sb.append("Complete decoding ")
+ .append(index)
+ .append(" bitmaps without running out of memory.");
+ }
+ return sb.toString();
+ }
+
+ private void showAlertDialog(String message) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage(message)
+ .setCancelable(false)
+ .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmapView.java b/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmapView.java
new file mode 100644
index 0000000..2105628
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/PurgeableBitmapView.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 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.example.android.apis.graphics;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.BitmapFactory.Options;
+import android.view.View;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * PurgeableBitmapView works with PurgeableBitmap to demonstrate the effects of setting
+ * Bitmaps as being purgeable.
+ *
+ * PurgeableBitmapView decodes an encoded bitstream to a Bitmap each time update()
+ * is invoked(), and its onDraw() draws the Bitmap and a number to screen.
+ * The number is used to indicate the number of Bitmaps that has been decoded.
+ */
+public class PurgeableBitmapView extends View {
+ private final byte[] bitstream;
+
+ private Bitmap mBitmap;
+ private final int mArraySize = 200;
+ private final Bitmap[] mBitmapArray = new Bitmap [mArraySize];
+ private final Options mOptions = new Options();
+ private static final int WIDTH = 150;
+ private static final int HEIGHT = 450;
+ private static final int STRIDE = 320; // must be >= WIDTH
+ private int mDecodingCount = 0;
+ private final Paint mPaint = new Paint();
+ private final int textSize = 32;
+ private static int delay = 100;
+
+ public PurgeableBitmapView(Context context, boolean isPurgeable) {
+ super(context);
+ setFocusable(true);
+ mOptions.inPurgeable = isPurgeable;
+
+ int[] colors = createColors();
+ Bitmap src = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
+ Bitmap.Config.ARGB_8888);
+ bitstream = generateBitstream(src, Bitmap.CompressFormat.JPEG, 80);
+
+ mPaint.setTextSize(textSize);
+ mPaint.setColor(Color.GRAY);
+ }
+
+ private int[] createColors() {
+ int[] colors = new int[STRIDE * HEIGHT];
+ for (int y = 0; y < HEIGHT; y++) {
+ for (int x = 0; x < WIDTH; x++) {
+ int r = x * 255 / (WIDTH - 1);
+ int g = y * 255 / (HEIGHT - 1);
+ int b = 255 - Math.min(r, g);
+ int a = Math.max(r, g);
+ colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+ }
+ return colors;
+ }
+
+ public int update(PurgeableBitmap.RefreshHandler handler) {
+ try {
+ mBitmapArray[mDecodingCount] = BitmapFactory.decodeByteArray(
+ bitstream, 0, bitstream.length, mOptions);
+ mBitmap = mBitmapArray[mDecodingCount];
+ mDecodingCount++;
+ if (mDecodingCount < mArraySize) {
+ handler.sleep(delay);
+ return 0;
+ } else {
+ return -mDecodingCount;
+ }
+
+ } catch (OutOfMemoryError error) {
+ for (int i = 0; i < mDecodingCount; i++) {
+ mBitmapArray[i].recycle();
+ }
+ return mDecodingCount + 1;
+ }
+ }
+
+ @Override protected void onDraw(Canvas canvas) {
+ canvas.drawColor(Color.WHITE);
+ canvas.drawBitmap(mBitmap, 0, 0, null);
+ canvas.drawText(String.valueOf(mDecodingCount), WIDTH / 2 - 20,
+ HEIGHT / 2, mPaint);
+ }
+
+ private byte[] generateBitstream(Bitmap src, Bitmap.CompressFormat format,
+ int quality) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ src.compress(format, quality, os);
+ return os.toByteArray();
+ }
+
+}