The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

910 lines
43KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. //==============================================================================
  22. // This byte-code is generated from native/javacore/app/com/roli/juce/JuceSharingContentProvider.java with min sdk version 16
  23. // See juce_core/native/java/README.txt on how to generate this byte-code.
  24. static const uint8 javaJuceSharingContentProvider[] =
  25. {100,101,120,10,48,51,53,0,66,68,79,209,68,153,2,8,5,37,136,73,129,38,235,114,135,129,180,66,79,170,89,247,100,13,0,0,112,0,0,
  26. 0,120,86,52,18,0,0,0,0,0,0,0,0,160,12,0,0,77,0,0,0,112,0,0,0,21,0,0,0,164,1,0,0,18,0,0,0,248,1,0,0,5,0,0,0,208,2,0,0,25,0,0,0,
  27. 248,2,0,0,3,0,0,0,192,3,0,0,68,9,0,0,32,4,0,0,226,6,0,0,234,6,0,0,237,6,0,0,243,6,0,0,250,6,0,0,253,6,0,0,30,7,0,0,33,7,0,0,37,
  28. 7,0,0,42,7,0,0,50,7,0,0,85,7,0,0,118,7,0,0,161,7,0,0,188,7,0,0,221,7,0,0,240,7,0,0,11,8,0,0,46,8,0,0,105,8,0,0,170,8,0,0,214,
  29. 8,0,0,250,8,0,0,26,9,0,0,61,9,0,0,81,9,0,0,101,9,0,0,117,9,0,0,139,9,0,0,142,9,0,0,147,9,0,0,151,9,0,0,157,9,0,0,161,9,0,0,166,
  30. 9,0,0,172,9,0,0,179,9,0,0,182,9,0,0,203,9,0,0,216,9,0,0,223,9,0,0,236,9,0,0,7,10,0,0,39,10,0,0,68,10,0,0,91,10,0,0,111,10,0,
  31. 0,119,10,0,0,126,10,0,0,151,10,0,0,167,10,0,0,176,10,0,0,182,10,0,0,193,10,0,0,201,10,0,0,207,10,0,0,213,10,0,0,229,10,0,0,235,
  32. 10,0,0,241,10,0,0,251,10,0,0,4,11,0,0,19,11,0,0,29,11,0,0,35,11,0,0,47,11,0,0,54,11,0,0,62,11,0,0,73,11,0,0,88,11,0,0,99,11,
  33. 0,0,105,11,0,0,113,11,0,0,121,11,0,0,126,11,0,0,131,11,0,0,138,11,0,0,1,0,0,0,4,0,0,0,10,0,0,0,11,0,0,0,12,0,0,0,13,0,0,0,14,
  34. 0,0,0,15,0,0,0,16,0,0,0,17,0,0,0,18,0,0,0,19,0,0,0,20,0,0,0,21,0,0,0,22,0,0,0,23,0,0,0,24,0,0,0,25,0,0,0,28,0,0,0,36,0,0,0,37,
  35. 0,0,0,3,0,0,0,0,0,0,0,96,6,0,0,2,0,0,0,0,0,0,0,108,6,0,0,8,0,0,0,4,0,0,0,120,6,0,0,9,0,0,0,5,0,0,0,128,6,0,0,8,0,0,0,7,0,0,0,
  36. 144,6,0,0,6,0,0,0,9,0,0,0,0,0,0,0,8,0,0,0,9,0,0,0,120,6,0,0,7,0,0,0,17,0,0,0,152,6,0,0,28,0,0,0,18,0,0,0,0,0,0,0,29,0,0,0,18,
  37. 0,0,0,160,6,0,0,30,0,0,0,18,0,0,0,168,6,0,0,31,0,0,0,18,0,0,0,176,6,0,0,35,0,0,0,18,0,0,0,188,6,0,0,34,0,0,0,18,0,0,0,200,6,
  38. 0,0,33,0,0,0,18,0,0,0,212,6,0,0,32,0,0,0,18,0,0,0,220,6,0,0,36,0,0,0,19,0,0,0,0,0,0,0,8,0,0,0,20,0,0,0,120,6,0,0,10,0,1,0,51,0,
  39. 0,0,10,0,12,0,71,0,0,0,11,0,1,0,51,0,0,0,11,0,12,0,71,0,0,0,12,0,16,0,54,0,0,0,2,0,8,0,0,0,0,0,4,0,5,0,48,0,0,0,6,0,15,0,0,0,
  40. 0,0,6,0,8,0,39,0,0,0,8,0,14,0,0,0,0,0,10,0,13,0,0,0,0,0,10,0,8,0,39,0,0,0,10,0,10,0,41,0,0,0,11,0,12,0,0,0,0,0,11,0,11,0,42,0,
  41. 0,0,11,0,9,0,60,0,0,0,12,0,8,0,0,0,0,0,12,0,17,0,43,0,0,0,12,0,2,0,44,0,0,0,12,0,3,0,45,0,0,0,12,0,1,0,46,0,0,0,12,0,17,0,49,0,
  42. 0,0,12,0,7,0,50,0,0,0,12,0,4,0,53,0,0,0,12,0,16,0,59,0,0,0,12,0,2,0,61,0,0,0,12,0,6,0,62,0,0,0,12,0,3,0,65,0,0,0,12,0,0,0,72,
  43. 0,0,0,16,0,8,0,0,0,0,0,10,0,0,0,17,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,48,6,0,0,52,12,0,0,0,0,0,0,11,0,0,0,17,0,0,0,8,0,0,0,0,0,0,0,
  44. 5,0,0,0,64,6,0,0,75,12,0,0,0,0,0,0,12,0,0,0,17,0,0,0,2,0,0,0,0,0,0,0,5,0,0,0,80,6,0,0,98,12,0,0,0,0,0,0,2,0,0,0,18,12,0,0,24,
  45. 12,0,0,2,0,0,0,18,12,0,0,33,12,0,0,1,0,0,0,42,12,0,0,5,0,5,0,2,0,0,0,146,11,0,0,8,0,0,0,91,1,1,0,112,32,2,0,64,0,90,2,0,0,14,
  46. 0,3,0,1,0,3,0,0,0,157,11,0,0,9,0,0,0,111,16,3,0,2,0,83,32,0,0,112,48,7,0,2,1,14,0,0,0,6,0,6,0,3,0,0,0,164,11,0,0,8,0,0,0,91,1,
  47. 3,0,112,48,4,0,64,5,90,2,2,0,14,0,5,0,3,0,5,0,0,0,176,11,0,0,6,0,0,0,83,32,2,0,112,84,9,0,2,49,14,0,2,0,1,0,1,0,0,0,184,11,0,
  48. 0,11,0,0,0,112,16,0,0,1,0,34,0,16,0,112,16,24,0,0,0,91,16,4,0,14,0,0,0,5,0,4,0,0,0,0,0,190,11,0,0,2,0,0,0,18,0,15,0,5,0,3,0,3,
  49. 0,1,0,198,11,0,0,12,0,0,0,84,33,4,0,29,1,112,48,12,0,50,4,12,0,30,1,17,0,13,0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,3,0,2,0,0,0,0,
  50. 0,208,11,0,0,2,0,0,0,18,0,17,0,4,0,3,0,0,0,0,0,214,11,0,0,2,0,0,0,18,0,17,0,2,0,1,0,0,0,0,0,221,11,0,0,2,0,0,0,18,16,15,0,5,
  51. 0,3,0,3,0,1,0,226,11,0,0,12,0,0,0,84,33,4,0,29,1,112,48,13,0,50,4,12,0,30,1,17,0,13,0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,6,0,3,
  52. 0,3,0,1,0,235,11,0,0,21,0,0,0,84,50,4,0,29,2,112,48,13,0,67,5,12,0,56,0,8,0,110,16,1,0,0,0,12,1,30,2,17,1,18,1,30,2,40,253,13,
  53. 1,30,2,39,1,0,0,3,0,0,0,17,0,1,0,1,0,18,0,8,0,6,0,6,0,1,0,253,11,0,0,12,0,0,0,84,33,4,0,29,1,118,6,14,0,2,0,12,0,30,1,17,0,13,
  54. 0,30,1,39,0,3,0,0,0,8,0,1,0,1,0,9,0,6,0,5,0,0,0,0,0,9,12,0,0,2,0,0,0,18,0,15,0,32,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,4,0,0,0,0,
  55. 0,0,0,0,0,0,0,0,0,0,56,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,3,0,17,0,20,0,3,0,0,0,7,0,17,0,20,0,0,0,2,0,0,0,7,0,17,0,5,0,
  56. 0,0,7,0,20,0,17,0,20,0,17,0,0,0,2,0,0,0,7,0,3,0,1,0,0,0,7,0,0,0,2,0,0,0,0,0,17,0,1,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,17,0,0,0,4,
  57. 0,0,0,12,0,1,0,17,0,0,0,3,0,0,0,12,0,1,0,20,0,0,0,2,0,0,0,17,0,0,0,1,0,0,0,20,0,6,60,105,110,105,116,62,0,1,73,0,4,73,76,76,76,
  58. 0,5,73,76,76,76,76,0,1,74,0,31,74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,
  59. 114,46,106,97,118,97,0,1,76,0,2,76,76,0,3,76,76,76,0,6,76,76,76,76,76,76,0,33,76,97,110,100,114,111,105,100,47,99,111,110,116,
  60. 101,110,116,47,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,59,0,31,76,97,110,100,114,111,105,100,47,99,111,110,
  61. 116,101,110,116,47,67,111,110,116,101,110,116,86,97,108,117,101,115,59,0,41,76,97,110,100,114,111,105,100,47,99,111,110,116,
  62. 101,110,116,47,114,101,115,47,65,115,115,101,116,70,105,108,101,68,101,115,99,114,105,112,116,111,114,59,0,25,76,97,110,100,114,
  63. 111,105,100,47,100,97,116,97,98,97,115,101,47,67,117,114,115,111,114,59,0,31,76,97,110,100,114,111,105,100,47,100,97,116,97,98,
  64. 97,115,101,47,77,97,116,114,105,120,67,117,114,115,111,114,59,0,17,76,97,110,100,114,111,105,100,47,110,101,116,47,85,114,105,
  65. 59,0,25,76,97,110,100,114,111,105,100,47,111,115,47,70,105,108,101,79,98,115,101,114,118,101,114,59,0,33,76,97,110,100,114,111,
  66. 105,100,47,111,115,47,80,97,114,99,101,108,70,105,108,101,68,101,115,99,114,105,112,116,111,114,59,0,57,76,99,111,109,47,114,
  67. 111,108,105,47,106,117,99,101,47,74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,
  68. 114,36,80,114,111,118,105,100,101,114,67,117,114,115,111,114,59,0,63,76,99,111,109,47,114,111,108,105,47,106,117,99,101,47,
  69. 74,117,99,101,83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,36,80,114,111,118,105,100,101,
  70. 114,70,105,108,101,79,98,115,101,114,118,101,114,59,0,42,76,99,111,109,47,114,111,108,105,47,106,117,99,101,47,74,117,99,101,
  71. 83,104,97,114,105,110,103,67,111,110,116,101,110,116,80,114,111,118,105,100,101,114,59,0,34,76,100,97,108,118,105,107,47,97,
  72. 110,110,111,116,97,116,105,111,110,47,69,110,99,108,111,115,105,110,103,67,108,97,115,115,59,0,30,76,100,97,108,118,105,107,47,
  73. 97,110,110,111,116,97,116,105,111,110,47,73,110,110,101,114,67,108,97,115,115,59,0,33,76,100,97,108,118,105,107,47,97,110,110,
  74. 111,116,97,116,105,111,110,47,77,101,109,98,101,114,67,108,97,115,115,101,115,59,0,18,76,106,97,118,97,47,108,97,110,103,47,
  75. 79,98,106,101,99,116,59,0,18,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,0,14,80,114,111,118,105,100,101,
  76. 114,67,117,114,115,111,114,0,20,80,114,111,118,105,100,101,114,70,105,108,101,79,98,115,101,114,118,101,114,0,1,86,0,3,86,73,
  77. 76,0,2,86,74,0,4,86,74,73,76,0,2,86,76,0,3,86,76,73,0,4,86,76,74,76,0,5,86,76,74,76,73,0,1,90,0,19,91,76,106,97,118,97,47,108,
  78. 97,110,103,47,83,116,114,105,110,103,59,0,11,97,99,99,101,115,115,70,108,97,103,115,0,5,99,108,111,115,101,0,11,99,111,108,117,
  79. 109,110,78,97,109,101,115,0,25,99,111,110,116,101,110,116,83,104,97,114,101,114,67,117,114,115,111,114,67,108,111,115,101,100,
  80. 0,30,99,111,110,116,101,110,116,83,104,97,114,101,114,70,105,108,101,79,98,115,101,114,118,101,114,69,118,101,110,116,0,27,99,
  81. 111,110,116,101,110,116,83,104,97,114,101,114,71,101,116,83,116,114,101,97,109,84,121,112,101,115,0,21,99,111,110,116,101,110,
  82. 116,83,104,97,114,101,114,79,112,101,110,70,105,108,101,0,18,99,111,110,116,101,110,116,83,104,97,114,101,114,81,117,101,114,
  83. 121,0,6,100,101,108,101,116,101,0,5,101,118,101,110,116,0,23,103,101,116,80,97,114,99,101,108,70,105,108,101,68,101,115,99,114,
  84. 105,112,116,111,114,0,14,103,101,116,83,116,114,101,97,109,84,121,112,101,115,0,7,103,101,116,84,121,112,101,0,4,104,111,115,
  85. 116,0,9,104,111,115,116,84,111,85,115,101,0,6,105,110,115,101,114,116,0,4,108,111,99,107,0,4,109,97,115,107,0,14,109,105,109,
  86. 101,84,121,112,101,70,105,108,116,101,114,0,4,109,111,100,101,0,4,110,97,109,101,0,8,111,110,67,114,101,97,116,101,0,7,111,110,
  87. 69,118,101,110,116,0,13,111,112,101,110,65,115,115,101,116,70,105,108,101,0,8,111,112,101,110,70,105,108,101,0,4,112,97,116,
  88. 104,0,10,112,114,111,106,101,99,116,105,111,110,0,5,113,117,101,114,121,0,6,114,101,115,117,108,116,0,9,115,101,108,101,99,116,
  89. 105,111,110,0,13,115,101,108,101,99,116,105,111,110,65,114,103,115,0,9,115,111,114,116,79,114,100,101,114,0,4,116,104,105,115,
  90. 0,6,116,104,105,115,36,48,0,6,117,112,100,97,116,101,0,3,117,114,105,0,3,117,114,108,0,5,118,97,108,117,101,0,6,118,97,108,117,
  91. 101,115,0,46,3,72,53,41,7,14,45,61,45,0,55,0,7,14,61,90,0,27,4,72,53,64,56,7,14,45,61,45,0,35,2,48,64,7,14,90,0,15,0,7,14,61,0,
  92. 97,3,74,68,69,7,14,0,131,1,2,74,57,7,14,61,105,0,103,1,74,7,14,0,84,2,74,77,7,14,0,68,0,7,14,0,109,2,74,58,7,14,61,105,0,118,
  93. 2,74,58,7,14,61,76,3,0,67,5,45,91,75,5,0,0,75,5,75,65,68,69,70,7,14,61,105,0,91,4,74,77,68,69,7,14,0,2,13,1,75,24,12,2,14,2,38,
  94. 4,17,58,23,26,2,14,2,38,4,17,58,23,27,2,15,1,75,28,2,24,10,24,11,0,2,2,1,0,2,1,144,32,5,128,128,4,192,8,2,130,2,0,6,1,224,8,
  95. 0,2,2,1,2,2,1,144,32,8,129,128,4,132,9,1,130,2,0,10,1,164,9,0,1,4,9,4,2,11,129,128,4,192,9,1,130,2,0,1,130,2,0,1,130,2,0,15,1,
  96. 232,9,1,1,252,9,1,1,176,10,1,1,196,10,1,1,216,10,1,1,236,10,1,1,160,11,1,1,232,11,1,1,156,12,0,0,16,0,0,0,0,0,0,0,1,0,0,0,0,
  97. 0,0,0,1,0,0,0,77,0,0,0,112,0,0,0,2,0,0,0,21,0,0,0,164,1,0,0,3,0,0,0,18,0,0,0,248,1,0,0,4,0,0,0,5,0,0,0,208,2,0,0,5,0,0,0,25,0,
  98. 0,0,248,2,0,0,6,0,0,0,3,0,0,0,192,3,0,0,3,16,0,0,3,0,0,0,32,4,0,0,1,32,0,0,14,0,0,0,64,4,0,0,6,32,0,0,3,0,0,0,48,6,0,0,1,16,
  99. 0,0,13,0,0,0,96,6,0,0,2,32,0,0,77,0,0,0,226,6,0,0,3,32,0,0,14,0,0,0,146,11,0,0,4,32,0,0,4,0,0,0,18,12,0,0,0,32,0,0,3,0,0,0,52,
  100. 12,0,0,0,16,0,0,1,0,0,0,160,12,0,0,0,0};
  101. //==============================================================================
  102. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  103. FIELD (authority, "authority", "Ljava/lang/String;")
  104. DECLARE_JNI_CLASS (AndroidProviderInfo, "android/content/pm/ProviderInfo")
  105. #undef JNI_CLASS_MEMBERS
  106. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  107. METHOD (constructor, "<init>", "(Landroid/os/ParcelFileDescriptor;JJ)V") \
  108. METHOD (createInputStream, "createInputStream", "()Ljava/io/FileInputStream;") \
  109. METHOD (getLength, "getLength", "()J")
  110. DECLARE_JNI_CLASS (AssetFileDescriptor, "android/content/res/AssetFileDescriptor")
  111. #undef JNI_CLASS_MEMBERS
  112. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  113. METHOD (close, "close", "()V")
  114. DECLARE_JNI_CLASS (JavaCloseable, "java/io/Closeable")
  115. #undef JNI_CLASS_MEMBERS
  116. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  117. STATICMETHOD (open, "open", "(Ljava/io/File;I)Landroid/os/ParcelFileDescriptor;")
  118. DECLARE_JNI_CLASS (ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
  119. #undef JNI_CLASS_MEMBERS
  120. //==============================================================================
  121. class AndroidContentSharerCursor
  122. {
  123. public:
  124. class Owner
  125. {
  126. public:
  127. virtual ~Owner() {}
  128. virtual void cursorClosed (const AndroidContentSharerCursor&) = 0;
  129. };
  130. AndroidContentSharerCursor (Owner& ownerToUse, JNIEnv* env,
  131. const LocalRef<jobject>& contentProvider,
  132. const LocalRef<jobjectArray>& resultColumns)
  133. : owner (ownerToUse),
  134. cursor (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderCursor,
  135. JuceContentProviderCursor.constructor,
  136. contentProvider.get(),
  137. reinterpret_cast<jlong> (this),
  138. resultColumns.get()))))
  139. {
  140. // the content provider must be created first
  141. jassert (contentProvider.get() != nullptr);
  142. }
  143. jobject getNativeCursor() { return cursor.get(); }
  144. void cursorClosed()
  145. {
  146. MessageManager::callAsync ([this] { owner.cursorClosed (*this); });
  147. }
  148. void addRow (LocalRef<jobjectArray>& values)
  149. {
  150. auto* env = getEnv();
  151. env->CallVoidMethod (cursor.get(), JuceContentProviderCursor.addRow, values.get());
  152. }
  153. private:
  154. Owner& owner;
  155. GlobalRef cursor;
  156. //==============================================================================
  157. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  158. METHOD (addRow, "addRow", "([Ljava/lang/Object;)V") \
  159. METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;J[Ljava/lang/String;)V") \
  160. CALLBACK (contentSharerCursorClosed, "contentSharerCursorClosed", "(J)V") \
  161. DECLARE_JNI_CLASS (JuceContentProviderCursor, "com/roli/juce/JuceSharingContentProvider$ProviderCursor")
  162. #undef JNI_CLASS_MEMBERS
  163. static void JNICALL contentSharerCursorClosed(JNIEnv*, jobject, jlong host)
  164. {
  165. if (auto* myself = reinterpret_cast<AndroidContentSharerCursor*> (host))
  166. myself->cursorClosed();
  167. }
  168. };
  169. AndroidContentSharerCursor::JuceContentProviderCursor_Class AndroidContentSharerCursor::JuceContentProviderCursor;
  170. //==============================================================================
  171. class AndroidContentSharerFileObserver
  172. {
  173. public:
  174. class Owner
  175. {
  176. public:
  177. virtual ~Owner() {}
  178. virtual void fileHandleClosed (const AndroidContentSharerFileObserver&) = 0;
  179. };
  180. AndroidContentSharerFileObserver (Owner& ownerToUse, JNIEnv* env,
  181. const LocalRef<jobject>& contentProvider,
  182. const String& filepathToUse)
  183. : owner (ownerToUse),
  184. filepath (filepathToUse),
  185. fileObserver (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderFileObserver,
  186. JuceContentProviderFileObserver.constructor,
  187. contentProvider.get(),
  188. reinterpret_cast<jlong> (this),
  189. javaString (filepath).get(),
  190. open | access | closeWrite | closeNoWrite))))
  191. {
  192. // the content provider must be created first
  193. jassert (contentProvider.get() != nullptr);
  194. env->CallVoidMethod (fileObserver, JuceContentProviderFileObserver.startWatching);
  195. }
  196. void onFileEvent (int event, const LocalRef<jstring>& path)
  197. {
  198. ignoreUnused (path);
  199. if (event == open)
  200. {
  201. ++numOpenedHandles;
  202. }
  203. else if (event == access)
  204. {
  205. fileWasRead = true;
  206. }
  207. else if (event == closeNoWrite || event == closeWrite)
  208. {
  209. --numOpenedHandles;
  210. // numOpenedHandles may get negative if we don't receive open handle event.
  211. if (fileWasRead && numOpenedHandles <= 0)
  212. {
  213. MessageManager::callAsync ([this]
  214. {
  215. getEnv()->CallVoidMethod (fileObserver, JuceContentProviderFileObserver.stopWatching);
  216. owner.fileHandleClosed (*this);
  217. });
  218. }
  219. }
  220. }
  221. private:
  222. static constexpr int open = 32;
  223. static constexpr int access = 1;
  224. static constexpr int closeWrite = 8;
  225. static constexpr int closeNoWrite = 16;
  226. bool fileWasRead = false;
  227. int numOpenedHandles = 0;
  228. Owner& owner;
  229. String filepath;
  230. GlobalRef fileObserver;
  231. //==============================================================================
  232. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  233. METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;JLjava/lang/String;I)V") \
  234. METHOD (startWatching, "startWatching", "()V") \
  235. METHOD (stopWatching, "stopWatching", "()V") \
  236. CALLBACK (contentSharerFileObserverEvent, "contentSharerFileObserverEvent", "(JILjava/lang/String;)V") \
  237. DECLARE_JNI_CLASS (JuceContentProviderFileObserver, "com/roli/juce/JuceSharingContentProvider$ProviderFileObserver")
  238. #undef JNI_CLASS_MEMBERS
  239. static void JNICALL contentSharerFileObserverEvent (JNIEnv*, jobject /*fileObserver*/, jlong host, int event, jstring path)
  240. {
  241. if (auto* myself = reinterpret_cast<AndroidContentSharerFileObserver*> (host))
  242. myself->onFileEvent (event, LocalRef<jstring> (path));
  243. }
  244. };
  245. AndroidContentSharerFileObserver::JuceContentProviderFileObserver_Class AndroidContentSharerFileObserver::JuceContentProviderFileObserver;
  246. //==============================================================================
  247. class AndroidContentSharerPrepareFilesThread : private Thread
  248. {
  249. public:
  250. AndroidContentSharerPrepareFilesThread (AsyncUpdater& ownerToUse,
  251. const Array<URL>& fileUrlsToUse,
  252. const String& packageNameToUse,
  253. const String& uriBaseToUse)
  254. : Thread ("AndroidContentSharerPrepareFilesThread"),
  255. owner (ownerToUse),
  256. fileUrls (fileUrlsToUse),
  257. resultFileUris (GlobalRef (LocalRef<jobject> (getEnv()->NewObject (JavaArrayList,
  258. JavaArrayList.constructor,
  259. fileUrls.size())))),
  260. packageName (packageNameToUse),
  261. uriBase (uriBaseToUse)
  262. {
  263. startThread();
  264. }
  265. ~AndroidContentSharerPrepareFilesThread() override
  266. {
  267. signalThreadShouldExit();
  268. waitForThreadToExit (10000);
  269. for (auto& f : temporaryFilesFromAssetFiles)
  270. f.deleteFile();
  271. }
  272. jobject getResultFileUris() { return resultFileUris.get(); }
  273. const StringArray& getMimeTypes() const { return mimeTypes; }
  274. const StringArray& getFilePaths() const { return filePaths; }
  275. private:
  276. struct StreamCloser
  277. {
  278. StreamCloser (const LocalRef<jobject>& streamToUse)
  279. : stream (GlobalRef (streamToUse))
  280. {
  281. }
  282. ~StreamCloser()
  283. {
  284. if (stream.get() != nullptr)
  285. getEnv()->CallVoidMethod (stream, JavaCloseable.close);
  286. }
  287. GlobalRef stream;
  288. };
  289. void run() override
  290. {
  291. auto* env = getEnv();
  292. bool canSpecifyMimeTypes = true;
  293. for (auto f : fileUrls)
  294. {
  295. auto scheme = f.getScheme();
  296. // Only "file://" scheme or no scheme (for files in app bundle) are allowed!
  297. jassert (scheme.isEmpty() || scheme == "file");
  298. if (scheme.isEmpty())
  299. {
  300. // Raw resource names need to be all lower case
  301. jassert (f.toString (true).toLowerCase() == f.toString (true));
  302. // This will get us a file with file:// URI
  303. f = copyAssetFileToTemporaryFile (env, f.toString (true));
  304. if (f.isEmpty())
  305. continue;
  306. }
  307. if (threadShouldExit())
  308. return;
  309. auto filepath = URL::removeEscapeChars (f.toString (true).fromFirstOccurrenceOf ("file://", false, false));
  310. filePaths.add (filepath);
  311. auto filename = filepath.fromLastOccurrenceOf ("/", false, true);
  312. auto fileExtension = filename.fromLastOccurrenceOf (".", false, true);
  313. auto contentString = uriBase + String (filePaths.size() - 1) + "/" + filename;
  314. auto uri = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidUri, AndroidUri.parse,
  315. javaString (contentString).get()));
  316. if (canSpecifyMimeTypes)
  317. canSpecifyMimeTypes = fileExtension.isNotEmpty();
  318. if (canSpecifyMimeTypes)
  319. mimeTypes.addArray (getMimeTypesForFileExtension (fileExtension));
  320. else
  321. mimeTypes.clear();
  322. env->CallBooleanMethod (resultFileUris, JavaArrayList.add, uri.get());
  323. }
  324. owner.triggerAsyncUpdate();
  325. }
  326. URL copyAssetFileToTemporaryFile (JNIEnv* env, const String& filename)
  327. {
  328. auto resources = LocalRef<jobject> (env->CallObjectMethod (getAppContext().get(), AndroidContext.getResources));
  329. int fileId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (filename).get(),
  330. javaString ("raw").get(), javaString (packageName).get());
  331. // Raw resource not found. Please make sure that you include your file as a raw resource
  332. // and that you specify just the file name, without an extension.
  333. jassert (fileId != 0);
  334. if (fileId == 0)
  335. return {};
  336. auto assetFd = LocalRef<jobject> (env->CallObjectMethod (resources,
  337. AndroidResources.openRawResourceFd,
  338. fileId));
  339. auto inputStream = StreamCloser (LocalRef<jobject> (env->CallObjectMethod (assetFd,
  340. AssetFileDescriptor.createInputStream)));
  341. if (jniCheckHasExceptionOccurredAndClear())
  342. {
  343. // Failed to open file stream for resource
  344. jassertfalse;
  345. return {};
  346. }
  347. auto tempFile = File::createTempFile ({});
  348. tempFile.createDirectory();
  349. tempFile = tempFile.getChildFile (filename);
  350. auto outputStream = StreamCloser (LocalRef<jobject> (env->NewObject (JavaFileOutputStream,
  351. JavaFileOutputStream.constructor,
  352. javaString (tempFile.getFullPathName()).get())));
  353. if (jniCheckHasExceptionOccurredAndClear())
  354. {
  355. // Failed to open file stream for temporary file
  356. jassertfalse;
  357. return {};
  358. }
  359. auto buffer = LocalRef<jbyteArray> (env->NewByteArray (1024));
  360. int bytesRead = 0;
  361. for (;;)
  362. {
  363. if (threadShouldExit())
  364. return {};
  365. bytesRead = env->CallIntMethod (inputStream.stream, JavaFileInputStream.read, buffer.get());
  366. if (jniCheckHasExceptionOccurredAndClear())
  367. {
  368. // Failed to read from resource file.
  369. jassertfalse;
  370. return {};
  371. }
  372. if (bytesRead < 0)
  373. break;
  374. env->CallVoidMethod (outputStream.stream, JavaFileOutputStream.write, buffer.get(), 0, bytesRead);
  375. if (jniCheckHasExceptionOccurredAndClear())
  376. {
  377. // Failed to write to temporary file.
  378. jassertfalse;
  379. return {};
  380. }
  381. }
  382. temporaryFilesFromAssetFiles.add (tempFile);
  383. return URL (tempFile);
  384. }
  385. AsyncUpdater& owner;
  386. Array<URL> fileUrls;
  387. GlobalRef resultFileUris;
  388. String packageName;
  389. String uriBase;
  390. StringArray filePaths;
  391. Array<File> temporaryFilesFromAssetFiles;
  392. StringArray mimeTypes;
  393. };
  394. //==============================================================================
  395. class ContentSharer::ContentSharerNativeImpl : public ContentSharer::Pimpl,
  396. public AndroidContentSharerFileObserver::Owner,
  397. public AndroidContentSharerCursor::Owner,
  398. public AsyncUpdater,
  399. private Timer
  400. {
  401. public:
  402. ContentSharerNativeImpl (ContentSharer& cs)
  403. : owner (cs),
  404. packageName (juceString (LocalRef<jstring> ((jstring) getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageName)))),
  405. uriBase ("content://" + packageName + ".sharingcontentprovider/")
  406. {
  407. }
  408. ~ContentSharerNativeImpl() override
  409. {
  410. masterReference.clear();
  411. }
  412. void shareFiles (const Array<URL>& files) override
  413. {
  414. if (! isContentSharingEnabled())
  415. {
  416. // You need to enable "Content Sharing" in Projucer's Android exporter.
  417. jassertfalse;
  418. owner.sharingFinished (false, {});
  419. }
  420. prepareFilesThread.reset (new AndroidContentSharerPrepareFilesThread (*this, files, packageName, uriBase));
  421. }
  422. void shareText (const String& text) override
  423. {
  424. if (! isContentSharingEnabled())
  425. {
  426. // You need to enable "Content Sharing" in Projucer's Android exporter.
  427. jassertfalse;
  428. owner.sharingFinished (false, {});
  429. }
  430. auto* env = getEnv();
  431. auto intent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor));
  432. env->CallObjectMethod (intent, AndroidIntent.setAction,
  433. javaString ("android.intent.action.SEND").get());
  434. env->CallObjectMethod (intent, AndroidIntent.putExtra,
  435. javaString ("android.intent.extra.TEXT").get(),
  436. javaString (text).get());
  437. env->CallObjectMethod (intent, AndroidIntent.setType, javaString ("text/plain").get());
  438. auto chooserIntent = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidIntent, AndroidIntent.createChooser,
  439. intent.get(), javaString ("Choose share target").get()));
  440. WeakReference<ContentSharerNativeImpl> weakRef (this);
  441. startAndroidActivityForResult (chooserIntent, 1003,
  442. [weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
  443. {
  444. if (weakRef != nullptr)
  445. weakRef->sharingFinished (resultCode);
  446. });
  447. }
  448. //==============================================================================
  449. void cursorClosed (const AndroidContentSharerCursor& cursor) override
  450. {
  451. cursors.removeObject (&cursor);
  452. }
  453. void fileHandleClosed (const AndroidContentSharerFileObserver&) override
  454. {
  455. decrementPendingFileCountAndNotifyOwnerIfReady();
  456. }
  457. //==============================================================================
  458. jobject openFile (const LocalRef<jobject>& contentProvider,
  459. const LocalRef<jobject>& uri, const LocalRef<jstring>& mode)
  460. {
  461. ignoreUnused (mode);
  462. WeakReference<ContentSharerNativeImpl> weakRef (this);
  463. if (weakRef == nullptr)
  464. return nullptr;
  465. auto* env = getEnv();
  466. auto uriElements = getContentUriElements (env, uri);
  467. if (uriElements.filepath.isEmpty())
  468. return nullptr;
  469. return getAssetFileDescriptor (env, contentProvider, uriElements.filepath);
  470. }
  471. jobject query (const LocalRef<jobject>& contentProvider, const LocalRef<jobject>& uri,
  472. const LocalRef<jobjectArray>& projection, const LocalRef<jobject>& selection,
  473. const LocalRef<jobjectArray>& selectionArgs, const LocalRef<jobject>& sortOrder)
  474. {
  475. ignoreUnused (selection, selectionArgs, sortOrder);
  476. StringArray requestedColumns = javaStringArrayToJuce (projection);
  477. StringArray supportedColumns = getSupportedColumns();
  478. StringArray resultColumns;
  479. for (const auto& col : supportedColumns)
  480. {
  481. if (requestedColumns.contains (col))
  482. resultColumns.add (col);
  483. }
  484. // Unsupported columns were queried, file sharing may fail.
  485. if (resultColumns.isEmpty())
  486. return nullptr;
  487. auto resultJavaColumns = juceStringArrayToJava (resultColumns);
  488. auto* env = getEnv();
  489. auto cursor = cursors.add (new AndroidContentSharerCursor (*this, env, contentProvider,
  490. resultJavaColumns));
  491. auto uriElements = getContentUriElements (env, uri);
  492. if (uriElements.filepath.isEmpty())
  493. return cursor->getNativeCursor();
  494. auto values = LocalRef<jobjectArray> (env->NewObjectArray ((jsize) resultColumns.size(),
  495. JavaObject, nullptr));
  496. for (int i = 0; i < resultColumns.size(); ++i)
  497. {
  498. if (resultColumns.getReference (i) == "_display_name")
  499. {
  500. env->SetObjectArrayElement (values, i, javaString (uriElements.filename).get());
  501. }
  502. else if (resultColumns.getReference (i) == "_size")
  503. {
  504. auto javaFile = LocalRef<jobject> (env->NewObject (JavaFile, JavaFile.constructor,
  505. javaString (uriElements.filepath).get()));
  506. jlong fileLength = env->CallLongMethod (javaFile, JavaFile.length);
  507. env->SetObjectArrayElement (values, i, env->NewObject (JavaLong,
  508. JavaLong.constructor,
  509. fileLength));
  510. }
  511. }
  512. cursor->addRow (values);
  513. return cursor->getNativeCursor();
  514. }
  515. jobjectArray getStreamTypes (const LocalRef<jobject>& uri, const LocalRef<jstring>& mimeTypeFilter)
  516. {
  517. auto* env = getEnv();
  518. auto extension = getContentUriElements (env, uri).filename.fromLastOccurrenceOf (".", false, true);
  519. if (extension.isEmpty())
  520. return nullptr;
  521. return juceStringArrayToJava (filterMimeTypes (getMimeTypesForFileExtension (extension),
  522. juceString (mimeTypeFilter.get())));
  523. }
  524. void sharingFinished (int resultCode)
  525. {
  526. sharingActivityDidFinish = true;
  527. succeeded = resultCode == -1;
  528. // Give content sharer a chance to request file access.
  529. if (nonAssetFilesPendingShare.get() == 0)
  530. startTimer (2000);
  531. else
  532. notifyOwnerIfReady();
  533. }
  534. private:
  535. bool isContentSharingEnabled() const
  536. {
  537. auto* env = getEnv();
  538. LocalRef<jobject> packageManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageManager));
  539. constexpr int getProviders = 8;
  540. auto packageInfo = LocalRef<jobject> (env->CallObjectMethod (packageManager,
  541. AndroidPackageManager.getPackageInfo,
  542. javaString (packageName).get(),
  543. getProviders));
  544. auto providers = LocalRef<jobjectArray> ((jobjectArray) env->GetObjectField (packageInfo,
  545. AndroidPackageInfo.providers));
  546. if (providers == nullptr)
  547. return false;
  548. auto sharingContentProviderAuthority = packageName + ".sharingcontentprovider";
  549. const int numProviders = env->GetArrayLength (providers.get());
  550. for (int i = 0; i < numProviders; ++i)
  551. {
  552. auto providerInfo = LocalRef<jobject> (env->GetObjectArrayElement (providers, i));
  553. auto authority = LocalRef<jstring> ((jstring) env->GetObjectField (providerInfo,
  554. AndroidProviderInfo.authority));
  555. if (juceString (authority) == sharingContentProviderAuthority)
  556. return true;
  557. }
  558. return false;
  559. }
  560. void handleAsyncUpdate() override
  561. {
  562. jassert (prepareFilesThread != nullptr);
  563. if (prepareFilesThread == nullptr)
  564. return;
  565. filesPrepared (prepareFilesThread->getResultFileUris(), prepareFilesThread->getMimeTypes());
  566. }
  567. void filesPrepared (jobject fileUris, const StringArray& mimeTypes)
  568. {
  569. auto* env = getEnv();
  570. auto intent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor));
  571. env->CallObjectMethod (intent, AndroidIntent.setAction,
  572. javaString ("android.intent.action.SEND_MULTIPLE").get());
  573. env->CallObjectMethod (intent, AndroidIntent.setType,
  574. javaString (getCommonMimeType (mimeTypes)).get());
  575. constexpr int grantReadPermission = 1;
  576. env->CallObjectMethod (intent, AndroidIntent.setFlags, grantReadPermission);
  577. env->CallObjectMethod (intent, AndroidIntent.putParcelableArrayListExtra,
  578. javaString ("android.intent.extra.STREAM").get(),
  579. fileUris);
  580. auto chooserIntent = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidIntent,
  581. AndroidIntent.createChooser,
  582. intent.get(),
  583. javaString ("Choose share target").get()));
  584. WeakReference<ContentSharerNativeImpl> weakRef (this);
  585. startAndroidActivityForResult (chooserIntent, 1003,
  586. [weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
  587. {
  588. if (weakRef != nullptr)
  589. weakRef->sharingFinished (resultCode);
  590. });
  591. }
  592. void decrementPendingFileCountAndNotifyOwnerIfReady()
  593. {
  594. --nonAssetFilesPendingShare;
  595. notifyOwnerIfReady();
  596. }
  597. void notifyOwnerIfReady()
  598. {
  599. if (sharingActivityDidFinish && nonAssetFilesPendingShare.get() == 0)
  600. owner.sharingFinished (succeeded, {});
  601. }
  602. void timerCallback() override
  603. {
  604. stopTimer();
  605. notifyOwnerIfReady();
  606. }
  607. //==============================================================================
  608. struct ContentUriElements
  609. {
  610. String index;
  611. String filename;
  612. String filepath;
  613. };
  614. ContentUriElements getContentUriElements (JNIEnv* env, const LocalRef<jobject>& uri) const
  615. {
  616. jassert (prepareFilesThread != nullptr);
  617. if (prepareFilesThread == nullptr)
  618. return {};
  619. auto fullUri = juceString ((jstring) env->CallObjectMethod (uri.get(), AndroidUri.toString));
  620. auto index = fullUri.fromFirstOccurrenceOf (uriBase, false, false)
  621. .upToFirstOccurrenceOf ("/", false, true);
  622. auto filename = fullUri.fromLastOccurrenceOf ("/", false, true);
  623. return { index, filename, prepareFilesThread->getFilePaths()[index.getIntValue()] };
  624. }
  625. static StringArray getSupportedColumns()
  626. {
  627. return StringArray ("_display_name", "_size");
  628. }
  629. jobject getAssetFileDescriptor (JNIEnv* env, const LocalRef<jobject>& contentProvider,
  630. const String& filepath)
  631. {
  632. // This function can be called from multiple threads.
  633. {
  634. const ScopedLock sl (nonAssetFileOpenLock);
  635. if (! nonAssetFilePathsPendingShare.contains (filepath))
  636. {
  637. nonAssetFilePathsPendingShare.add (filepath);
  638. ++nonAssetFilesPendingShare;
  639. nonAssetFileObservers.add (new AndroidContentSharerFileObserver (*this, env,
  640. contentProvider,
  641. filepath));
  642. }
  643. }
  644. auto javaFile = LocalRef<jobject> (env->NewObject (JavaFile, JavaFile.constructor,
  645. javaString (filepath).get()));
  646. constexpr int modeReadOnly = 268435456;
  647. auto parcelFileDescriptor = LocalRef<jobject> (env->CallStaticObjectMethod (ParcelFileDescriptor,
  648. ParcelFileDescriptor.open,
  649. javaFile.get(), modeReadOnly));
  650. if (jniCheckHasExceptionOccurredAndClear())
  651. {
  652. // Failed to create file descriptor. Have you provided a valid file path/resource name?
  653. jassertfalse;
  654. return nullptr;
  655. }
  656. jlong startOffset = 0;
  657. jlong unknownLength = -1;
  658. assetFileDescriptors.add (GlobalRef (LocalRef<jobject> (env->NewObject (AssetFileDescriptor,
  659. AssetFileDescriptor.constructor,
  660. parcelFileDescriptor.get(),
  661. startOffset, unknownLength))));
  662. return assetFileDescriptors.getReference (assetFileDescriptors.size() - 1).get();
  663. }
  664. ContentSharer& owner;
  665. String packageName;
  666. String uriBase;
  667. std::unique_ptr<AndroidContentSharerPrepareFilesThread> prepareFilesThread;
  668. bool succeeded = false;
  669. String errorDescription;
  670. bool sharingActivityDidFinish = false;
  671. OwnedArray<AndroidContentSharerCursor> cursors;
  672. Array<GlobalRef> assetFileDescriptors;
  673. CriticalSection nonAssetFileOpenLock;
  674. StringArray nonAssetFilePathsPendingShare;
  675. Atomic<int> nonAssetFilesPendingShare { 0 };
  676. OwnedArray<AndroidContentSharerFileObserver> nonAssetFileObservers;
  677. WeakReference<ContentSharerNativeImpl>::Master masterReference;
  678. friend class WeakReference<ContentSharerNativeImpl>;
  679. //==============================================================================
  680. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  681. CALLBACK (contentSharerQuery, "contentSharerQuery", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;") \
  682. CALLBACK (contentSharerOpenFile, "contentSharerOpenFile", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;") \
  683. CALLBACK (contentSharerGetStreamTypes, "contentSharerGetStreamTypes", "(Landroid/net/Uri;Ljava/lang/String;)[Ljava/lang/String;") \
  684. DECLARE_JNI_CLASS_WITH_BYTECODE (JuceSharingContentProvider, "com/roli/juce/JuceSharingContentProvider", 16, javaJuceSharingContentProvider, sizeof (javaJuceSharingContentProvider))
  685. #undef JNI_CLASS_MEMBERS
  686. static jobject JNICALL contentSharerQuery (JNIEnv*, jobject contentProvider, jobject uri, jobjectArray projection,
  687. jobject selection, jobjectArray selectionArgs, jobject sortOrder)
  688. {
  689. if (auto *pimpl = (ContentSharer::ContentSharerNativeImpl *) ContentSharer::getInstance ()->pimpl.get ())
  690. return pimpl->query (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
  691. LocalRef<jobject> (static_cast<jobject> (uri)),
  692. LocalRef<jobjectArray> (
  693. static_cast<jobjectArray> (projection)),
  694. LocalRef<jobject> (static_cast<jobject> (selection)),
  695. LocalRef<jobjectArray> (
  696. static_cast<jobjectArray> (selectionArgs)),
  697. LocalRef<jobject> (static_cast<jobject> (sortOrder)));
  698. return nullptr;
  699. }
  700. static jobject JNICALL contentSharerOpenFile (JNIEnv*, jobject contentProvider, jobject uri, jstring mode)
  701. {
  702. if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
  703. return pimpl->openFile (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
  704. LocalRef<jobject> (static_cast<jobject> (uri)),
  705. LocalRef<jstring> (static_cast<jstring> (mode)));
  706. return nullptr;
  707. }
  708. static jobjectArray JNICALL contentSharerGetStreamTypes (JNIEnv*, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter)
  709. {
  710. if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
  711. return pimpl->getStreamTypes (LocalRef<jobject> (static_cast<jobject> (uri)),
  712. LocalRef<jstring> (static_cast<jstring> (mimeTypeFilter)));
  713. return nullptr;
  714. }
  715. };
  716. //==============================================================================
  717. ContentSharer::Pimpl* ContentSharer::createPimpl()
  718. {
  719. return new ContentSharerNativeImpl (*this);
  720. }
  721. ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider_Class ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider;
  722. } // namespace juce