18

I would like to know if it's possible to create an Intent that makes the gallery cropper show wallpaper highlighting. This feature has been introduced in Honeycomb. To get an idea of what I'm looking for have a look at the tablet on the image (the three blue rectangles).

I had a look at the source code of the ICS gallery app, but I couldn't find what I'm looking for.

this

Thomas
  • 1,508
  • 2
  • 22
  • 35

6 Answers6

8

I would like to know if it's possible to create an Intent that makes the gallery cropper show wallpaper highlighting.

Assuming you want your app to behave properly across all Android devices, the answer is no. Neither the cropping activity nor the highlighted crop-view is part of the public API; both are internal to the Gallery 3D app. In other words, you could spend all the time in the world trying to find an Intent action to get this to magically work for you, but the fact is that some devices simply won't support it. For example, many devices, such as the HTC Sense and Samsung Galaxy, have customized Android versions that have their own gallery app. Since these Gallery apps are specific to the companies that designed them, these devices won't necessarily have a CropImage class for you to launch.

That being said, in order to guarantee that your application works across all devices, you'll have to incorporate the cropping code directly into your project. And if for some reason you find a way to launch the crop activity with an Intent, you should test to see whether the com.android.gallery3d package exists at the very least, and handle it somehow.

I have included below a work-around that might help you incorporate the Android code into your project. I don't currently have access to a tablet running Honeycomb/ICS so I can't be more specific with regards to how to get it working on newer versions of Android, but I imagine it involves similar analysis and a bit of copying and pasting from the com.android.gallery3d package.


Reusing the "Crop Activity" on Android 2.x

I tested this on my Nexus One and just before the soft "crop-rectangle" popped up, I got the following logcat output:

I/ActivityManager(   94): Starting: Intent { 
    act=android.intent.action.CHOOSER 
    cmp=android/com.android.internal.app.ChooserActivity (has extras) } from pid 558
I/ActivityManager(   94): Starting: Intent { 
    act=android.intent.action.ATTACH_DATA 
    dat=content://media/external/images/media/648 
    typ=image/jpeg 
    flg=0x3000001 
    cmp=com.google.android.gallery3d/com.cooliris.media.Photographs (has extras) } from pid 558
I/ActivityManager(   94): Starting: Intent { 
    dat=content://media/external/images/media/648 
    cmp=com.google.android.gallery3d/com.cooliris.media.CropImage (has extras) } from pid 558

So from what I can tell, the sequence of events that occurs when you perform this action is as follows:

  1. You navigate to an image in the gallery and select "set as...". An ActivityChooser pops up and you select "Wallpaper".
  2. This selection fires an Intent with action ATTACH_DATA and component com.cooliris.media.Photographs, which is a class in the Android framework that serves as a "wallpaper picker" for the camera application; it just redirects to the standard pick action. Since we have given the Intent a URI that specifies the image to set as the wallpaper, this class will inevitably execute the following code (see the class's onResume method):

    Intent intent = new Intent();   
    intent.setClass(this, CropImage.class);
    intent.setData(imageToUse);
    formatIntent(intent);
    startActivityForResult(intent, CROP_DONE);
    
  3. This fires another Intent that starts the CropImage Activity... this is where you specify the cropped area using the soft-rectangle. When you specify the crop, the result is set to RESULT_OK with requestCode = CROP_DONE. The Photographs Activity switch-cases over these two constants and then sets the wallpaper accordingly (see the Photographs class's onActivityResult method).

Unfortunately, for whatever reason the Android team decided to removed these functionalities from the SDK beginning with API 4 (Android v1.6)... so if you wanted to fire an Intent to perform these exact sequence of events, it would require you to sift through the com.cooliris.media package, and to copy and paste the relevant classes into your project. In my past experience, doing this is often more trouble than it is worth (unless it is to perform a relatively simple action) but it is definitely possible.

Here is a nice tutorial on how you might go about simplifying the process... it requires you to copy and paste 12 Java classes into your project as opposed to the entire com.cooliris.media package. These classes together should be enough to correctly fire up the CropImage Activity, but you will have to set the wallpaper manually upon the CropImage Activity's result.

Also note that the sample code provided assumes that you want to crop immediately after a picture is taken by the camera. In order to, for example, start the CropImage Activity with a pre-selected image from the gallery, you'd call,

Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, ACTIVITY_SELECT_IMAGE);

and then in onActivityResult, (if requestCode == ACTIVITY_SELECT_IMAGE and resultCode == RESULT_OK), launch the CropImage Activity with the Uri data given in the onActivityResult's third argument (see the sample code for an example on how to launch the Activity).

If anything, hopefully this will help point you in the right direction. Let me know how it goes and leave a comment if you want me to clarify anything.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
2

I this will help:

public class CropSelectedImageActivity extends Activity {

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
            photoPickerIntent.setType("image/*");
            startActivityForResult(photoPickerIntent, 1);
}

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK) {
                    final Bundle extras = data.getExtras();
                    Uri photoUri = data.getData();
                    if (photoUri != null) {
                            Intent intent = new Intent("com.android.camera.action.CROP");
                    //intent.setClassName("com.android.camera", "com.android.camera.CropImage");

                    intent.setData(photoUri);
                    intent.putExtra("outputX", 96);
                    intent.putExtra("outputY", 96);
                    intent.putExtra("aspectX", 1);
                    intent.putExtra("aspectY", 1);
                    intent.putExtra("scale", true);
                    intent.putExtra("return-data", true);            
                    startActivityForResult(intent, 1);
                    }
            }
    }
}

taken from: ImageCropper

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
TryTryAgain
  • 7,632
  • 11
  • 46
  • 82
1

Just Do this!

Intent intent = new Intent(Intent.ACTION_ATTACH_DATA).setDataAndType(contentUri,  "image/jpeg")
    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    .putExtra("mimeType", "image/jpeg");
startActivity(Intent.createChooser(intent, getString(R.string.set_as)));

which "image/jpeg" is the image mimeType, contentUri is the image uri

01.sunlit
  • 305
  • 1
  • 2
  • 8
1

There is a nice library that's based on ICS's cropping screen (from the gallery app) , here .

You could modify it to your needs, to select the part to be cropped.

The code is based on Android's Gallery app (link here), under "/com/android/camera/gallery" , while the most important class is "CropImage" in "/com/android/camera/" . It's available for all even in case the library will be missing (Google's code is always available), as such:

git clone https://android.googlesource.com/platform/packages/apps/Gallery3D/

(and even if this won't be available, I'm sure there will be others)

Advantages over the other solutions here:

  • independent
  • customizable
  • cannot crash due the changes in the ROM. Other solutions assume the existance of exact classes and apps.
  • open source.
  • a real implementation, and not starting an intent to another app.
  • other solutions are highly non-recommended, just because of the usage of non-official intents, as written here . This is written by a very well known StackOverflow user called "CommonsWare" , who is very respectable user that you can count on in a lot of Android-related topics.

Again, the most recommended thing for cropping images is still a third party library. Not using workarounds of intents.

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Christian Garbin Feb 16 '15 at 00:02
  • @chr sometimes, since the code is too huge and complex and has other kinds of files except for Java, it's impossible to post it here, and it's better to provide a real github link. The code is open source and based on the code of Android. The other solutions here, even though they are quite short, are dangerous, as they have assumptions about the existing apps on the device. If the device doesn't have them, it won't allow to crop. The solutions here actually have the implementation on an app that might not exist. They didn't even check if it exists, so the app can crash. – android developer Feb 16 '15 at 00:11
  • @chr So, between something that could crash and isn't customizable at all, and something that works, open sourced and based on Google's code, I think my solution is better. Maybe if StackOverflow would have allowed me to upload a full project, I would, but I can't – android developer Feb 16 '15 at 00:15
1

I haven't tried this but if you have a look here

         Bundle newExtras = new Bundle();
         // maybe that here - for more options see your source code link
         newExtras.putString("circleCrop", "true");
         Intent cropIntent = new Intent();
         // Uri would be something from MediaStore.Images.Media.EXTERNAL_CONTENT_URI
         cropIntent.setData(img.fullSizeImageUri());
         // edit: it's inside com.android.gallery in case that is even installed.
         // should work if you replace that with setClassName("com.android.gallery", "com.android.camera.CropImage")
         cropIntent.setClass(this, CropImage.class);
         cropIntent.putExtras(newExtras);
         startActivityForResult(cropIntent, CROP_MSG);

Then this might work for you.

Via pick intent maybe that way:

Intent i = new Intent(Intent.ACTION_PICK);
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivity(i);
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
zapl
  • 63,179
  • 10
  • 123
  • 154
  • When using `cropIntent.setClassName("com.android.camera", "com.android.camera.CropImage");`, I get an ActivityNotFoundException. Also, I was looking for an adaption of a normal image picking intent (Intent.ACTION_PICK), although I now realise that the question was not clear in that regard. – Thomas Mar 13 '12 at 23:47
  • The code you found is from the "Gallery" app. There is also a "Gallery2" and a closed source version from Google. So maybe it is entirely the wrong sourcecode we were looking at. Besides it should be `cropIntent.setClassName("com.android.gallery", "com.android.camera.CropImage")` as far as I can see. For `Intent.ACTION_PICK` see updated answer. Untested but it might work. – zapl Mar 14 '12 at 10:34
0

Try this

    // Set Home wallpaper the image
public void setHomeWallpaper () {
                BitmapDrawable bitmapDrawable = ((BitmapDrawable) imageView.getDrawable());
                Bitmap bitmap = bitmapDrawable.getBitmap();
                String bitmapPath = Images.Media.insertImage(getContentResolver(), bitmap, "", null);
                Uri bitmapUri = Uri.parse(bitmapPath);
                Intent intent = new Intent(Intent.ACTION_ATTACH_DATA).setDataAndType(bitmapUri,  "image/jpeg")
                        .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                        .putExtra("mimeType", "image/jpeg");
                startActivity(Intent.createChooser(intent, getString(R.string.background)));
                Toast.makeText(PicassoDisplayImageAdapter.this, "قم بإختيار التطبيق المناسب لتعيين الصورة", Toast.LENGTH_SHORT).show();
}
Moataz
  • 495
  • 3
  • 20