Search code examples
androidshareandroid-permissionsandroid-version

Receive .vcf file from Files app in Nougat and Oreo versions to my app


I've an Android App, which works fine in Jelly Bean and Kitkat versions. The app will receive .vcf file as Intent from File Manager app using Complete Action Using option.

Now in Android Nougat and Oreo versions, Using Files app, there is an option Open with or Share will not list my App.

How to solve this? Thanks in advance.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app" >

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.CustomOrange"
        >
        <activity>
        ...
        ...
        </activity>
        <activity
            android:name=".ViewContactActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/title_activity_vcf" >

            <intent-filter> <!-- Handle http https requests without mimeTypes: -->
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="http" />
                <data android:scheme="https" />
                <data android:host="*" />
                <data android:pathPattern="/.*\\.vcf" />
            </intent-filter>
            <intent-filter> <!-- Handle with mimeTypes, where the suffix is irrelevant: -->
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="http" />
                <data android:scheme="https" />
                <data android:host="*" />
                <data android:mimeType="text/x-vcard" />
            </intent-filter>
            <intent-filter> <!-- Handle intent from a file browser app: -->
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSERT_OR_EDIT" />

                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="file" />
                <data android:host="*" />
                <data android:mimeType="text/x-vcard" />
            </intent-filter>
        </activity>
    </application>

</manifest>

ViewContactActivity.java

public  class       ViewContactActivity
        extends     AppCompatActivity {

    private static final String TAG = ViewContactActivity.class.getSimpleName();

    public static final String  VIEW_CONTACT_BY_ID      = "viewContactById";

    private static final int    MODE_VIEW_BY_ID     = 0;
    private static final int    MODE_VIEW_BY_FILE   = 1;
    private int                 viewContactMode;

    private ActionBar mActionBar;
    ContactDetails contactDetails;
    String mFilePath;
    private GroupInfoPickerAlertDialog mGroupInfoPickerAD;

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


        contactDetails = new ContactDetails(this);
        Intent intent = getIntent();
        Long id = intent.getLongExtra(VIEW_CONTACT_BY_ID, -1L);
        Bitmap bitmap = null;
        if (id != -1L) {
            viewContactMode = MODE_VIEW_BY_ID;
            contactDetails.collectContactDetail(id);
            bitmap = BitmapFactory.decodeStream(new BufferedInputStream(contactDetails.getDisplayPhoto()));
        } else {
            viewContactMode = MODE_VIEW_BY_FILE;
            Uri fileUri = intent.getData();
            mFilePath = fileUri.getPath();
            Log.d(TAG, "onCreate() - file path: " + mFilePath);
            //onCreate() - file path: /path/to/file.vcf

            contactDetails.readVCard2_1(fileUri);
        }


        setSupportActionBar((Toolbar)findViewById(R.id.toolbar));
        mActionBar = getSupportActionBar();

        if(mActionBar == null) {
            Log.d(TAG, "onCreate() mActionBar == null");
        } else {
            Log.d(TAG, "onCreate() mActionBar != null");
        }
        mActionBar.setCustomView(null);
        mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);


        contactDetails.displayContact(bitmap);
        if (viewContactMode == MODE_VIEW_BY_FILE) {
            TextView textView = (TextView) findViewById(R.id.message_text_view);
            textView.setText(mFilePath);// + "\n\n" + stringBuilder);
        } else {
            View v = (View) findViewById(R.id.message_text_view).getParent();
            v.setVisibility(View.GONE);
        }
    }

    // ....
    // ....
    // Other codes...
    // ....
    // ....

}

Solution

  • Your <intent-filter> elements support http, https, and file. Few "file manager" apps will use any of those on Android 7.0+, in part because the file scheme is banned.

    Replace:

            <intent-filter> <!-- Handle intent from a file browser app: -->
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSERT_OR_EDIT" />
    
                <category android:name="android.intent.category.DEFAULT" />
    
                <data android:scheme="file" />
                <data android:host="*" />
                <data android:mimeType="text/x-vcard" />
            </intent-filter>
    

    with:

            <intent-filter> <!-- Handle intent from a file browser app: -->
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSERT_OR_EDIT" />
    
                <category android:name="android.intent.category.DEFAULT" />
    
                <data android:scheme="file" />
                <data android:scheme="content" />
                <data android:mimeType="text/x-vcard" />
            </intent-filter>
    

    Then, make sure that readVCard2_1() handles file and content Uri schemes, such as by calling openInputStream() on a ContentResolver to access the stream.