Search code examples
androidfile-managerpuz

.puz file picker- Android


I am developing a crossword application which accepts .puz file as input. I tried the following code in which the application doesn't accept .puz file from default file manager while it accepts the and begins the game when it is sent through third-party file-managers like ES file manager. Is there a way to make it accept the input through default file manager?

 public void loadFile(View view){
    Intent intent = new Intent(MediaStore.Files.FileColumns.DATA);
    intent.setType("*/*");
    intent.putExtra("CONTENT_TYPE", "*/*");
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, "Select PUZ file"), 1);
}

//selected file will be processed here
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(requestCode == 1){
        if(resultCode == RESULT_OK){
            String path = getPath(data.getData());
            if(path!=null&&path.endsWith("puz")) {
                try {
                    PuzzleDatabaseHelper dbHelper = WordsWithCrossesApplication.getDatabaseHelper();
                    Intent intent = new Intent(Intent.ACTION_EDIT, null, this, PlayActivity.class);
                    intent.putExtra(PlayActivity.EXTRA_PUZZLE_ID, dbHelper.addPuzzle(new File(path),"dilip","",0));
                    this.startActivity(intent);
                } catch (Exception e) {
                }
            }
            else
                Toast.makeText(this, "Invalid Format  or Try different File Manager to select file", Toast.LENGTH_SHORT).show();
        }
    }
}

Solution

  • Add the following intent-filter to the relevant activity tag in your AndroidManifest:

    <intent-filter>
      <action android:name="android.intent.action.VIEW"/>
    
      <category android:name="android.intent.category.DEFAULT"/>
    
      <data
          android:host="*"
          android:mimeType="*/*"
          android:scheme="file"/>
    
      <data android:pathPattern="/.*\\.puz"/>
      <data android:pathPattern="/.*\\.PUZ"/>
    </intent-filter>
    

    Add the following code in onCreate(Bundle) to check if the Activity was started from another app:

    if (getIntent().getData() != null) {
      String path = getIntent().getData().getPath();
      if (path != null && path.toLowerCase(Locale.ENGLISH).endsWith(".puz")) {
        File puz = new File(path);
        // TODO: do stuff with puz
      }
    }
    

    Note: File managers might use different methods for finding apps that can handle a certain intent/file. If your app doesn't show in a certain file manager, try tweaking your intent-filter. For example, you might need to add:

    <data android:pathPattern="/.*\\..*\\.puz"/>
    <data android:pathPattern="/.*\\..*\\..*\\.puz"/>
    <data android:pathPattern="/.*\\..*\\..*\\..*\\.puz"/>
    <data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.puz"/>
    <data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.puz"/>
    

    For paths that include more dots or are in hidden directories. (see here)