0

UPDATE I added the following code:

        v1.setDrawingCacheEnabled(true);
    v1.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    v1.layout(0, 0, v1.getMeasuredWidth(), v1.getMeasuredHeight()); 
    v1.buildDrawingCache(true);

Now I'm getting screenshots, but they're not what I need. For instance, one screen I need to capture consists of an LinearLayout containing an ImageView and a ListView. When the Activity loads during app execution, the list shows 10 items. The capture I'm getting only shows the top imageview and about 1.5 of the listitems. Is there something I can do to capture exactly what the screen shows? (I would post the shots I'm getting, but due to IP issues I'd have to redact basically everything, and posting a filled black rectangle is not super useful)

/update

I'm targeting Android 2.2 and trying to develop a class that be called from any activity to capture the current screen and store the image on the SD card (preferably as a PNG). I've found similar questions but there is an important difference here: I can't create a new View, and I can't build this code into every Activity (I can get away with adding one function call in each Activity).
So I need to 1) obtain the current Activity's View (which I'm doing with ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0)) and 2) passing that View to a function in another class (defined below). I've tried combining this and this but the bitmap I get is null after the .getDrawingCache() call so .compress bombs.

Here's the code:

public static void captureScreen(View v1){
                View v1= v;
        v1.setDrawingCacheEnabled(true);
        Bitmap bm = v1.getDrawingCache();
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try {
            bm.compress(Bitmap.CompressFormat.PNG, 100, bytes);
        } catch (Exception e1) {
            Log.e("BM.Compress", e1.getMessage());
        }

        //create a new file name "test.jpg" in sdcard folder.
        File f = new File(Environment.getExternalStorageDirectory()
                                + File.separator + context.getPackageName().replace(".", File.separator) 
                                + File.separator + "screenshots" + File.separator +  "test.jpg");
        //Log.d("CF", context.getPackageName());
        try {
            f.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //write the bytes in file
        try {
            FileOutputStream fo = new FileOutputStream(f);
            fo.write(bytes.toByteArray());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
}

LogCat:

06-06 16:37:14.613: D/AndroidRuntime(284): Shutting down VM
06-06 16:37:14.613: W/dalvikvm(284): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
06-06 16:37:14.768: E/AndroidRuntime(284): FATAL EXCEPTION: main
06-06 16:37:14.768: E/AndroidRuntime(284): java.lang.RuntimeException: Unable to start activity ComponentInfo{pkgname.pkgnameExpo/pkgname.pkgnameExpo.SplashActivity}: java.lang.NullPointerException: println needs a message
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread.access$2300(ActivityThread.java:125)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.os.Looper.loop(Looper.java:123)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread.main(ActivityThread.java:4627)
06-06 16:37:14.768: E/AndroidRuntime(284):  at java.lang.reflect.Method.invokeNative(Native Method)
06-06 16:37:14.768: E/AndroidRuntime(284):  at java.lang.reflect.Method.invoke(Method.java:521)
06-06 16:37:14.768: E/AndroidRuntime(284):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
06-06 16:37:14.768: E/AndroidRuntime(284):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
06-06 16:37:14.768: E/AndroidRuntime(284):  at dalvik.system.NativeStart.main(Native Method)
06-06 16:37:14.768: E/AndroidRuntime(284): Caused by: java.lang.NullPointerException: println needs a message
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.util.Log.println_native(Native Method)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.util.Log.e(Log.java:215)
06-06 16:37:14.768: E/AndroidRuntime(284):  at pkgname.pkgnameExpo.Classes.CFunctions.captureScreen(CFunctions.java:432)
06-06 16:37:14.768: E/AndroidRuntime(284):  at pkgname.pkgnameExpo.SplashActivity.onCreate(SplashActivity.java:38)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
06-06 16:37:14.768: E/AndroidRuntime(284):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
06-06 16:37:14.768: E/AndroidRuntime(284):  ... 11 more

All I can tell from debug is that, before bm.compress is called, bm is null while v1 is not. Any ideas?

UPDATE Here's the new LogCat, which I think is telling me that it can't create the file?

06-06 22:13:55.975: I/System.out(12244): debugger has settled (1400)
06-06 22:13:58.351: E/BM.Compress(12244): nullfixnull
06-06 22:13:58.411: W/System.err(12244): java.io.IOException: No such file or directory
06-06 22:13:58.421: W/System.err(12244):    at java.io.File.createNewFileImpl(Native Method)
06-06 22:13:58.432: W/System.err(12244):    at java.io.File.createNewFile(File.java:1160)
06-06 22:13:58.432: W/System.err(12244):    at pkgname.pkgnameExpo.Classes.CFunctions.captureScreen(CFunctions.java:441)
06-06 22:13:58.441: W/System.err(12244):    at pkgname.pkgnameExpo.SplashActivity.onCreate(SplashActivity.java:38)
06-06 22:13:58.451: W/System.err(12244):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
06-06 22:13:58.451: W/System.err(12244):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
06-06 22:13:58.461: W/System.err(12244):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
06-06 22:13:58.461: W/System.err(12244):    at android.app.ActivityThread.access$2300(ActivityThread.java:125)
06-06 22:13:58.471: W/System.err(12244):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
06-06 22:13:58.471: W/System.err(12244):    at android.os.Handler.dispatchMessage(Handler.java:99)
06-06 22:13:58.491: W/System.err(12244):    at android.os.Looper.loop(Looper.java:123)
06-06 22:13:58.491: W/System.err(12244):    at android.app.ActivityThread.main(ActivityThread.java:4627)
06-06 22:13:58.501: W/System.err(12244):    at java.lang.reflect.Method.invokeNative(Native Method)
06-06 22:13:58.511: W/System.err(12244):    at java.lang.reflect.Method.invoke(Method.java:521)
06-06 22:13:58.511: W/System.err(12244):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
06-06 22:13:58.522: W/System.err(12244):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
06-06 22:13:58.522: W/System.err(12244):    at dalvik.system.NativeStart.main(Native Method)
06-06 22:13:58.531: W/System.err(12244): java.io.FileNotFoundException: /mnt/sdcard/pkgname/pkgnameExpo/screenshots/test.jpg (No such file or directory)
06-06 22:13:58.541: W/System.err(12244):    at org.apache.harmony.luni.platform.OSFileSystem.openImpl(Native Method)
06-06 22:13:58.551: W/System.err(12244):    at org.apache.harmony.luni.platform.OSFileSystem.open(OSFileSystem.java:152)
06-06 22:13:58.551: W/System.err(12244):    at java.io.FileOutputStream.<init>(FileOutputStream.java:97)
06-06 22:13:58.561: W/System.err(12244):    at java.io.FileOutputStream.<init>(FileOutputStream.java:69)
06-06 22:13:58.561: W/System.err(12244):    at pkgname.pkgnameExpo.Classes.CFunctions.captureScreen(CFunctions.java:447)
06-06 22:13:58.571: W/System.err(12244):    at pkgname.pkgnameExpo.SplashActivity.onCreate(SplashActivity.java:38)
06-06 22:13:58.571: W/System.err(12244):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
06-06 22:13:58.581: W/System.err(12244):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
06-06 22:13:58.581: W/System.err(12244):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
06-06 22:13:58.591: W/System.err(12244):    at android.app.ActivityThread.access$2300(ActivityThread.java:125)
06-06 22:13:58.591: W/System.err(12244):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
06-06 22:13:58.601: W/System.err(12244):    at android.os.Handler.dispatchMessage(Handler.java:99)
06-06 22:13:58.601: W/System.err(12244):    at android.os.Looper.loop(Looper.java:123)
06-06 22:13:58.612: W/System.err(12244):    at android.app.ActivityThread.main(ActivityThread.java:4627)
06-06 22:13:58.612: W/System.err(12244):    at java.lang.reflect.Method.invokeNative(Native Method)
06-06 22:13:58.621: W/System.err(12244):    at java.lang.reflect.Method.invoke(Method.java:521)
06-06 22:13:58.631: W/System.err(12244):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
06-06 22:13:58.631: W/System.err(12244):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
06-06 22:13:58.641: W/System.err(12244):    at dalvik.system.NativeStart.main(Native Method)
Community
  • 1
  • 1
cschryer
  • 25
  • 1
  • 7
  • For your error of the moment, it should be enough to append the object which might be null to a string indicating what you expect it to be, ie Log.e("your tag", "something="+mightBeNull()) That way you will get a string representation of the concept of null, rather than a null string which is the complaint causing your current crash. – Chris Stratton Jun 06 '12 at 18:09
  • But bypassing the null bitmap won't help. Saving the bitmap is the point of the whole thing, so I need to know why it's null. Maybe I don't understand what you're saying. – cschryer Jun 06 '12 at 19:26
  • Although it may also be the case, the crash is not actually because the bitmap is null, but rather because the return of getMessage() on the exception is. That may not be an appropriate thing to do with an exception. You should fix this first - you really don't want your exception handler to be having internal crashes. – Chris Stratton Jun 06 '12 at 20:20
  • Noooww I get it. Thanks for that. Crash is gone now, but I still can't figure out why my bitmap is null. – cschryer Jun 06 '12 at 21:11

1 Answers1

0

You seem to be constructing a rather deep pathname for your file. If all of those directories do no not already exist, you need to call mkdirs() on a file object representing the directory into which you want to write the file.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
  • ...Huzzah! now I'm creating empty files! One step closer. Now how can I figure out what's wrong with my bitmap creation? – cschryer Jun 06 '12 at 22:49
  • I use myBitmap.compress(Bitmap.CompressFormat.PNG, 90, myFileOutputStream) in a project skipping the intermediate buffer. Or maybe you have an empty bitmap. I create a bitmap matching the view, create a canvas for it, and then call onDraw on the view passing the canvas as the parameter, I think I pulled that all out of example code somewhere. – Chris Stratton Jun 06 '12 at 23:10
  • OK, changed my code to use a FileOutputStream in .compress (since it works for you I'll assume it'll work for me when I get that far). In debug, the View (v1)'s drawingcache is null, so it makes sense that making that into a bitmap makes a null bitmap, but I just don't know enough about Views -- so why would the drawingcache be null? – cschryer Jun 07 '12 at 12:53
  • added code from [here](http://stackoverflow.com/a/4618030/1396596), but cache is still null. I'd be grateful for any further advice. – cschryer Jun 08 '12 at 15:00
  • I added some code (see update above) and now I'm getting screenshots, but they're not what I need. For instance, one screen I need to capture consists of an LinearLayout containing an ImageView and a ListView. When the Activity loads during app execution, the list shows 10 items. The capture I'm getting only shows the top imageview and about 1.5 of the listitems. Is there something I can do to capture exactly what the screen shows? – cschryer Jun 08 '12 at 21:35
  • Does anyone know how to do this? Can I automate the DDMS screencapture function? That doesn't meet my requirement, but it would get the job done, sort of. – cschryer Jun 12 '12 at 20:20