1

I am having some trouble trying to share a custom view in one of my activities via social media (Facebook etc...) by button click, however when I press the button nothing happens and Logcat is not showing any errors. The custom view is of a canvas drawing. Below is my code:

public class GraphActivity extends AppCompatActivity {
    DrawGraphTest drawGraphTest;

    private Button shareImage;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_graph);
        drawGraphTest = (DrawGraphTest)findViewById(R.id.drawGraphTest);

        shareImage = (Button) findViewById(R.id.btnShare);
        shareImage.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                share(drawGraphTest);
            }
        });
    }

    @SuppressLint("SetWorldReadable")
    public void share(View view){
        Bitmap bitmap =getBitmapFromView(drawGraphTest);
        try {
            File file = new File(this.getExternalCacheDir(),"myImage.png");
            FileOutputStream fOut = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();
            file.setReadable(true, false);
            final Intent intent = new Intent(Intent.ACTION_SEND);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
            intent.setType("image/png");
            startActivity(Intent.createChooser(intent, "Share image via"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    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;
    }

}

My XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".GraphActivity">

    <g.myPackage.DrawGraphTest
        android:id="@+id/drawGraphTest"
        android:layout_width="wrap_content"
        android:layout_height="400dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <Button
        android:id="@+id/btnShare"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.982" />

I have also enabled these permissions in my Manifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

On the button click, Logcat Verbose shows:

2019-03-21 04:30:26.147 19176-19176/g.companieshouse.companieshouse D/errortag1: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/g.companieshouse.companieshouse/cache/companieshouse.png exposed beyond app through ClipData.Item.getUri()

For reference, the code that I am trying to implement is in the link below and as I am new to Android Studio I am struggling to see where I went wrong in my implementation and could really use some help! The only difference that I can see is that in the link they are sharing an Image View whereas I am sharing a custom view.

https://www.logicchip.com/share-image-without-saving/

Sean
  • 157
  • 1
  • 2
  • 14
  • Remove the try-catch block and check which error occurred. – aslamhossin Mar 21 '19 at 04:17
  • @Aslam Hossin So I removed the try catch block and it says "Unhandled exception: java.io.FileNotFoundException" when I highlight "new FileOutputStream(file)" and also "fOut.flush()" says "Unhandled exception java.io.IOException". – Sean Mar 21 '19 at 04:24
  • @Aslam Hossin I updated the post to show the stacktrace on the button clicked in Logcat under Verbose, I don't know if this will help at all. – Sean Mar 21 '19 at 04:34

2 Answers2

1

The exception that is thrown when an application exposes a file:// Uri to another app.

This exposure is discouraged since the receiving app may not have access to the shared path. For example, the receiving app may not have requested the Manifest.permission.READ_EXTERNAL_STORAGE runtime permission or the platform may be sharing the Uri across user profile boundaries.

Instead, apps should use content:// Uris so the platform can extend temporary permission for the receiving app to access the resource.

This is only thrown for applications targeting Build.VERSION_CODES#N or higher. Applications targeting earlier SDK versions are allowed to share file:// Uri, but it's strongly discouraged.

Possible solution : android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData()

aslamhossin
  • 1,217
  • 12
  • 22
  • thank you for pointing me in the right direction with your link. Managed to find a solution! – Sean Mar 21 '19 at 20:08
0

if android version > m, get URI must through FileProvider, like this

fun getUri(file: File): Uri? {
     try {
         return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
         FileProvider.getUriForFile(MyApp.instance, MyApp.instance.packageName, file)
     } else {
         Uri.fromFile(file)
     }
     } catch (e: Exception) {
        e.printStackTrace()
     }
     return null
}
wanbo
  • 868
  • 9
  • 24