0

I am using folowing code below to share images to wanted apps, which works well for most of the apps, except viber. Whenever I am trying to share image to viber, viber crashes with folliwng error:

FATAL EXCEPTION: ThreadManager::idleTasksHandler
                                 Process: com.viber.voip, PID: 16668
                                 java.lang.IllegalArgumentException: column '_data' does not exist
                                     at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:303)
                                     at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:78)
                                     at com.viber.voip.util.aw.a(SourceFile:238)
                                     at com.viber.voip.util.aw.b(SourceFile:206)
                                     at com.viber.voip.util.aw.a(SourceFile:141)
                                     at com.viber.voip.util.b.n.a(SourceFile:1204)
                                     at com.viber.voip.util.bm.run(SourceFile:207)
                                     at android.os.Handler.handleCallback(Handler.java:739)
                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                     at com.viber.voip.be.dispatchMessage(SourceFile:32)
                                     at android.os.Looper.loop(Looper.java:135)
                                     at android.os.HandlerThread.run(HandlerThread.java:61)
                                     at com.viber.voip.cj.run(SourceFile:100)

My Uriess looks like content://com.myapp.fileprovider/share_images/nxt_emoji_26.png
code

public class ShareSmile {
  public static void share(Context context, int id, String selectedPackage) {
    String name = context.getResources().getResourceEntryName(id);
    try{
    if (name.contains("ic_")) {
      name = name.replace("ic_", "");
      File imagePath = new File(context.getFilesDir(), "image_assets/smiles");
      File newFile = new File(imagePath, name + ".png");
      Uri contentUri =
          FileProvider.getUriForFile(context, "com.myapp.fileprovider", newFile);
      Intent shareIntent = shareImage(contentUri,context);
      shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

      if (TextUtils.isEmpty(selectedPackage)) {
        //create chooser
       Intent sendIntent= Intent.createChooser(shareIntent, context.getString(R.string.send_via));
        sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(sendIntent);
      } else {
        //send to specific app
        shareIntent.setPackage(selectedPackage);
        context.startActivity(shareIntent);
      }
    }}catch (Exception e){
      HashMap<String,Boolean> map = MyPrefs.getSupportedApss(context);
      map.put(selectedPackage,false);

      Toast.makeText(context, R.string.share_smile_error,Toast.LENGTH_LONG).show();
    }
  }

  public static Intent shareImage(Uri uri,Context context) {
    Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
      shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    } else {
      shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
    }
    shareIntent.setType("image/png");
    ArrayList<Uri> streamUris = new ArrayList<>();
    streamUris.add(uri);
    shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, streamUris);
    //grant permission to access fileprovider
    List<ResolveInfo> resInfoList = context.getPackageManager()
        .queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
    for (ResolveInfo resolveInfo : resInfoList) {
      String packageName = resolveInfo.activityInfo.packageName;
      context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
    return shareIntent;
  }
}
Yarh
  • 4,459
  • 5
  • 45
  • 95

1 Answers1

1

The authors of Viber are inexperienced and think that all content Uri values come from the MediaStore, and so they are querying for a _data column that does not exist.

My LegacyCompatCursorWrapper can be used with FileProvider to try to improve compatibility with buggy apps like Viber, based off of the approach shown in this Stack Overflow answer. This sample app demonstrates the use of LegacyCompatCursorWrapper. You subclass FileProvider, override query(), and wrap the Cursor returned by super.query() in a LegacyCompatCursorWrapper:

/***
 Copyright (c) 2015 CommonsWare, LLC
 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.

 From _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.cp.v4file;

import android.database.Cursor;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import com.commonsware.cwac.provider.LegacyCompatCursorWrapper;

public class LegacyCompatFileProvider extends FileProvider {
  @Override
  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    return(new LegacyCompatCursorWrapper(super.query(uri, projection, selection, selectionArgs, sortOrder)));
  }
}

Then, register your FileProvider subclass in the manifest and otherwise use it like you would FileProvider.

Community
  • 1
  • 1
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I have try this solution for PDF and it won't work. Do you have some solution for PDF share via viber, PDF file is stored on my internal memory. – eJoe Feb 01 '17 at 14:08