Capture screen shot of GoogleMap Android API V2

AndroidAndroid MapviewGoogle Maps-Android-Api-2

Android Problem Overview


Final Update

The feature request has been fulfilled by Google. Please see this answer below.

Original Question

Using the old version of the Google Maps Android API, I was able to capture a screenshot of the google map to share via social media. I used the following code to capture the screenshot and save the image to a file and it worked great:

public String captureScreen()
{
	String storageState = Environment.getExternalStorageState();
	Log.d("StorageState", "Storage state is: " + storageState);
	
	// image naming and path  to include sd card  appending name you choose for file
	String mPath = this.getFilesDir().getAbsolutePath();
	
	// create bitmap screen capture
	Bitmap bitmap;
	View v1 = this.mapView.getRootView();
	v1.setDrawingCacheEnabled(true);
	bitmap = Bitmap.createBitmap(v1.getDrawingCache());
	v1.setDrawingCacheEnabled(false);

	OutputStream fout = null;

	String filePath = System.currentTimeMillis() + ".jpeg";

	try 
	{
        fout = openFileOutput(filePath,
                MODE_WORLD_READABLE);
		
		// Write the string to the file
		bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
	    fout.flush();
	    fout.close();
	} 
	catch (FileNotFoundException e) 
	{
	    // TODO Auto-generated catch block
		Log.d("ImageCapture", "FileNotFoundException");
		Log.d("ImageCapture", e.getMessage());
	    filePath = "";
	} 
	catch (IOException e) 
	{
	    // TODO Auto-generated catch block
		Log.d("ImageCapture", "IOException");
		Log.d("ImageCapture", e.getMessage());
	    filePath = "";
	}
	
	return filePath;
}

However, the new GoogleMap object used by V2 of the api does not have a "getRootView()" method like MapView does.

I tried to do this:

	SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.basicMap);
	
	View v1 = mapFragment.getView();

But the screenshot that I get does not have any map content and looks like this: Blank Map Screenshot

Has anyone figured out how to take a screenshot of the new Google Maps Android API V2?

Update

I also tried to get the rootView this way:

View v1 = getWindow().getDecorView().getRootView();

This results in a screenshot that includes the action bar at the top of the screen, but the map is still blank like the screenshot I attached.

Update

A feature request has been submitted to Google. Please go star the feature request if this is something you want google to add in the future: Add screenshot ability to Google Maps API V2

Android Solutions


Solution 1 - Android

Update - Google has added a snapshot method**!:

The feature request for a method to take a screen shot of the Android Google Map API V2 OpenGL layer has been fulfilled.

To take a screenshot, simply implement the following interface:

public abstract void onSnapshotReady (Bitmap snapshot)

and call:

public final void snapshot (GoogleMap.SnapshotReadyCallback callback)

Example that takes a screenshot, then presents the standard "Image Sharing" options:

public void captureScreen()
	{
		SnapshotReadyCallback callback = new SnapshotReadyCallback() 
		{

            @Override
            public void onSnapshotReady(Bitmap snapshot) 
            {
                // TODO Auto-generated method stub
                bitmap = snapshot;
                
        		OutputStream fout = null;
        		 
        		String filePath = System.currentTimeMillis() + ".jpeg";

        		try 
        		{
        	        fout = openFileOutput(filePath,
                            MODE_WORLD_READABLE);
        			
        			// Write the string to the file
        			bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
        		    fout.flush();
        		    fout.close();
        		} 
        		catch (FileNotFoundException e) 
        		{
        		    // TODO Auto-generated catch block
        			Log.d("ImageCapture", "FileNotFoundException");
        			Log.d("ImageCapture", e.getMessage());
        		    filePath = "";
        		} 
        		catch (IOException e) 
        		{
        		    // TODO Auto-generated catch block
        			Log.d("ImageCapture", "IOException");
        			Log.d("ImageCapture", e.getMessage());
        		    filePath = "";
        		}
        		
        		openShareImageDialog(filePath);
            }
        };

        mMap.snapshot(callback);
	}

Once the image is finished being captured, it will trigger the standard "Share Image" dialog so the user can pick how they'd like to share it:

public void openShareImageDialog(String filePath) 
{
File file = this.getFileStreamPath(filePath);

if(!filePath.equals(""))
{
	final ContentValues values = new ContentValues(2);
	values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
	values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
	final Uri contentUriFile = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
	
	final Intent intent = new Intent(android.content.Intent.ACTION_SEND);
	intent.setType("image/jpeg");
	intent.putExtra(android.content.Intent.EXTRA_STREAM, contentUriFile);
	startActivity(Intent.createChooser(intent, "Share Image"));
}
else
{
            //This is a custom class I use to show dialogs...simply replace this with whatever you want to show an error message, Toast, etc.
	DialogUtilities.showOkDialogWithText(this, R.string.shareImageFailed);
}
}

Documentation is here

Solution 2 - Android

Below are the steps to capture screen shot of Google Map V2 with example

Step 1. open Android Sdk Manager (Window > Android Sdk Manager) then Expand Extras now update/install Google Play Services to Revision 10 ignore this step if already installed

Read Notes here https://developers.google.com/maps/documentation/android/releases#august_2013

Step 2. Restart Eclipse

Step 3. import com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback;

Step 4. Make Method to Capture/Store Screen/image of Map like below

public void CaptureMapScreen() 
{
SnapshotReadyCallback callback = new SnapshotReadyCallback() {
			Bitmap bitmap;

			@Override
			public void onSnapshotReady(Bitmap snapshot) {
				// TODO Auto-generated method stub
				bitmap = snapshot;
				try {
					FileOutputStream out = new FileOutputStream("/mnt/sdcard/"
						+ "MyMapScreen" + System.currentTimeMillis()
						+ ".png");

                    // above "/mnt ..... png" => is a storage path (where image will be stored) + name of image you can customize as per your Requirement

					bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};

		myMap.snapshot(callback);

        // myMap is object of GoogleMap +> GoogleMap myMap;
        // which is initialized in onCreate() => 
        // myMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_pass_home_call)).getMap();
}

Step 5. Now call this CaptureMapScreen() method where you want to capture the image

in my case i am calling this method on Button click in my onCreate() which is working fine

like:

Button btnCap = (Button) findViewById(R.id.btnTakeScreenshot);
	btnCap.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			try {
				CaptureMapScreen();
			} catch (Exception e) {
				// TODO: handle exception
                e.printStackTrace();
			}

		}
	});

Check Doc here and here

Solution 3 - Android

I capctured Map screenshot.It will be helpful

  private GoogleMap map;
 private static LatLng latLong;

`

public void onMapReady(GoogleMap googleMap) {
           map = googleMap;
           setMap(this.map);
           animateCamera();
            map.moveCamera (CameraUpdateFactory.newLatLng (latLong));
            map.setOnMapLoadedCallback (new GoogleMap.OnMapLoadedCallback () {
                @Override
                public void onMapLoaded() {
                    snapShot();
                }
            });
        }

`

snapShot() method for taking screenshot of map

 public void snapShot(){
    GoogleMap.SnapshotReadyCallback callback=new GoogleMap.SnapshotReadyCallback () {
        Bitmap bitmap;
        @Override
        public void onSnapshotReady(Bitmap snapshot) {
            bitmap=snapshot;
   
            try{
                file=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"map.png");
                FileOutputStream fout=new FileOutputStream (file);
                bitmap.compress (Bitmap.CompressFormat.PNG,90,fout);
                Toast.makeText (PastValuations.this, "Capture", Toast.LENGTH_SHORT).show ();
               
            }catch (Exception e){
                e.printStackTrace ();
                Toast.makeText (PastValuations.this, "Not Capture", Toast.LENGTH_SHORT).show ();
            }


        }
    };map.snapshot (callback);
}

My output is belowenter image description here

Solution 4 - Android

Edit: this answer is no longer valid - the feature request for screenshots on Google Maps Android API V2 has been fulfilled. See this answer for an example.

Original Accepted Answer

Since the new Android API v2 Maps are displayed using OpenGL, there are no possibilities to create a screenshot.

Solution 5 - Android

Since the top voted answer doesnt work with polylines and other overlays on top of the map fragment (What I was looking for), I want to share this solution.

public void captureScreen()
        {
            GoogleMap.SnapshotReadyCallback callback = new GoogleMap.SnapshotReadyCallback()
            {

             
                @Override
                public void onSnapshotReady(Bitmap snapshot) {
                    try {
                        getWindow().getDecorView().findViewById(android.R.id.content).setDrawingCacheEnabled(true);
                        Bitmap backBitmap = getWindow().getDecorView().findViewById(android.R.id.content).getDrawingCache();
                        Bitmap bmOverlay = Bitmap.createBitmap(
                                backBitmap.getWidth(), backBitmap.getHeight(),
                                backBitmap.getConfig());
                        Canvas canvas = new Canvas(bmOverlay);
                        canvas.drawBitmap(snapshot, new Matrix(), null);
                        canvas.drawBitmap(backBitmap, 0, 0, null);

                        OutputStream fout = null;

                        String filePath = System.currentTimeMillis() + ".jpeg";

                        try
                        {
                            fout = openFileOutput(filePath,
                                    MODE_WORLD_READABLE);

                            // Write the string to the file
                            bmOverlay.compress(Bitmap.CompressFormat.JPEG, 90, fout);
                            fout.flush();
                            fout.close();
                        }
                        catch (FileNotFoundException e)
                        {
                            // TODO Auto-generated catch block
                            Log.d("ImageCapture", "FileNotFoundException");
                            Log.d("ImageCapture", e.getMessage());
                            filePath = "";
                        }
                        catch (IOException e)
                        {
                            // TODO Auto-generated catch block
                            Log.d("ImageCapture", "IOException");
                            Log.d("ImageCapture", e.getMessage());
                            filePath = "";
                        }

                        openShareImageDialog(filePath);


                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };

           ;


            map.snapshot(callback);
        }

Solution 6 - Android

private GoogleMap mMap;
SupportMapFragment mapFragment;
LinearLayout linearLayout;
String jobId="1";

File file;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate (savedInstanceState);
    setContentView (R.layout.activity_maps);

    linearLayout=(LinearLayout)findViewById (R.id.linearlayout);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
     mapFragment = (SupportMapFragment)getSupportFragmentManager ()
            .findFragmentById (R.id.map);
    mapFragment.getMapAsync (this);
    //Taking Snapshot of Google Map


}



/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng (-26.888033, 75.802754);
    mMap.addMarker (new MarkerOptions ().position (sydney).title ("Kailash Tower"));
    mMap.moveCamera (CameraUpdateFactory.newLatLng (sydney));
    mMap.setOnMapLoadedCallback (new GoogleMap.OnMapLoadedCallback () {
        @Override
        public void onMapLoaded() {
            snapShot();
        }
    });
}

// Initializing Snapshot Method
public void snapShot(){
    GoogleMap.SnapshotReadyCallback callback=new GoogleMap.SnapshotReadyCallback () {
        Bitmap bitmap;
        @Override
        public void onSnapshotReady(Bitmap snapshot) {
            bitmap=snapshot;
            bitmap=getBitmapFromView(linearLayout);
            try{
               file=new File (getExternalCacheDir (),"map.png");
                FileOutputStream fout=new FileOutputStream (file);
                bitmap.compress (Bitmap.CompressFormat.PNG,90,fout);
                Toast.makeText (MapsActivity.this, "Capture", Toast.LENGTH_SHORT).show ();
                sendSceenShot (file);
            }catch (Exception e){
                e.printStackTrace ();
                Toast.makeText (MapsActivity.this, "Not Capture", Toast.LENGTH_SHORT).show ();
            }


        }
    };mMap.snapshot (callback);
}
private Bitmap getBitmapFromView(View view) {
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas (returnedBitmap);
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null) {
        //has background drawable, then draw it on the canvas
        bgDrawable.draw(canvas);
    }   else{
        //does not have background drawable, then draw white background on the canvas
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);
    return returnedBitmap;
}

//Implementing Api using Retrofit
private void sendSceenShot(File file) {
    RequestBody job=null;

    Gson gson = new GsonBuilder ()
            .setLenient ()
            .create ();

    Retrofit retrofit = new Retrofit.Builder ()
            .baseUrl (BaseUrl.url)
            .addConverterFactory (GsonConverterFactory.create (gson))
            .build ();

    final RequestBody requestBody = RequestBody.create (MediaType.parse ("image/*"),file);
    job=RequestBody.create (MediaType.parse ("text"),jobId);


    MultipartBody.Part  fileToUpload = MultipartBody.Part.createFormData ("name",file.getName (), requestBody);

    API service = retrofit.create (API.class);
    Call<ScreenCapture_Pojo> call=service.sendScreen (job,fileToUpload);
    call.enqueue (new Callback<ScreenCapture_Pojo> () {
        @Override
        public void onResponse(Call <ScreenCapture_Pojo> call, Response<ScreenCapture_Pojo> response) {
            if (response.body ().getMessage ().equalsIgnoreCase ("Success")){
                Toast.makeText (MapsActivity.this, "success", Toast.LENGTH_SHORT).show ();
            }
        }

        @Override
        public void onFailure(Call <ScreenCapture_Pojo> call, Throwable t) {

        }
    });

}

}

Solution 7 - Android

I hope this would help to capture the screenshot of your map

Method call:

gmap.setOnMapLoadedCallback(mapLoadedCallback);

Method declaration:

final SnapshotReadyCallback snapReadyCallback = new SnapshotReadyCallback() {
        Bitmap bitmap;
        @Override
        public void onSnapshotReady(Bitmap snapshot) {
            bitmap = snapshot;

            try {

                //do something with your snapshot
                 
                imageview.setImageBitmap(bitmap);

            } catch (Exception e) {
                e.printStackTrace();
            }


        }
    };

GoogleMap.OnMapLoadedCallback mapLoadedCallback = new GoogleMap.OnMapLoadedCallback() {
        @Override
        public void onMapLoaded() {
            gmap.snapshot(snapReadyCallback);
        }
};

Solution 8 - Android

Use mapcalback for get screenshot of map

 GoogleMap.SnapshotReadyCallback callback = new GoogleMap.SnapshotReadyCallback() {
                    Bitmap bitmap=null;
                    @Override
                    public void onSnapshotReady(Bitmap snapshot) {
                        // TODO Auto-generated method stub
                        bitmap = snapshot;
                        try {
                            saveImage(bitmap);
                            Toast.makeText(getActivity().getApplicationContext(), "Successful.Screenshot Saved.", Toast.LENGTH_LONG).show();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    private void saveImage(Bitmap bitmap) throws IOException {
                        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);

                        Date date = new Date();
                        CharSequence format = android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", date);
                        String dirpath = Environment.getExternalStorageDirectory() + "";
                        File file = new File(dirpath);
                        if (!file.exists()) {
                            boolean mkdir = file.mkdir();
                        }
                        String path1 = dirpath + "/Documents/SCREENSHOT/";
                        File imageurl1 = new File(path1);
                        imageurl1.mkdirs();
                        File f = new File(path1 +"/"+ format + ".png");
                        f.createNewFile();
                        FileOutputStream fo = new FileOutputStream(f);
                        fo.write(bytes.toByteArray());
                        fo.close();
                    }
                };
                mMap.snapshot(callback);

Solution 9 - Android

Eclipse DDMS can capture the screen even it's google map V2.

Try to call /system/bin/screencap or /system/bin/screenshot if you have the "root". I learned that from https://stackoverflow.com/questions/14684081/how-eclipse-android-ddms-implement-screen-capture

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDiscDevView Question on Stackoverflow
Solution 1 - AndroidDiscDevView Answer on Stackoverflow
Solution 2 - AndroidTarsem SinghView Answer on Stackoverflow
Solution 3 - AndroidNarendra.krView Answer on Stackoverflow
Solution 4 - AndroidGreenyView Answer on Stackoverflow
Solution 5 - AndroiddanielroseroView Answer on Stackoverflow
Solution 6 - AndroidAndroHelperView Answer on Stackoverflow
Solution 7 - AndroidMahendran CandyView Answer on Stackoverflow
Solution 8 - Androidsadegh salehiView Answer on Stackoverflow
Solution 9 - Androidandrewwang1TWView Answer on Stackoverflow