mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-13 00:04:19 +00:00
909 lines
43 KiB
C++
909 lines
43 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library.
|
|
Copyright (c) 2017 - ROLI Ltd.
|
|
|
|
JUCE is an open source library subject to commercial or open-source
|
|
licensing.
|
|
|
|
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
|
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
|
27th April 2017).
|
|
|
|
End User License Agreement: www.juce.com/juce-5-licence
|
|
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
|
|
|
Or: You may also use this code under the terms of the GPL v3 (see
|
|
www.gnu.org/licenses).
|
|
|
|
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
|
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
|
DISCLAIMED.
|
|
|
|
==============================================================================
|
|
*/
|
|
namespace juce
|
|
{
|
|
|
|
//==============================================================================
|
|
// This byte-code is generated from native/javacore/app/com/roli/juce/JuceSharingContentProvider.java with min sdk version 16
|
|
// See juce_core/native/java/README.txt on how to generate this byte-code.
|
|
static const uint8 javaJuceSharingContentProvider[] =
|
|
{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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
12,0,0,0,16,0,0,1,0,0,0,160,12,0,0,0,0};
|
|
|
|
//==============================================================================
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
FIELD (authority, "authority", "Ljava/lang/String;")
|
|
|
|
DECLARE_JNI_CLASS (AndroidProviderInfo, "android/content/pm/ProviderInfo")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
METHOD (constructor, "<init>", "(Landroid/os/ParcelFileDescriptor;JJ)V") \
|
|
METHOD (createInputStream, "createInputStream", "()Ljava/io/FileInputStream;") \
|
|
METHOD (getLength, "getLength", "()J")
|
|
|
|
DECLARE_JNI_CLASS (AssetFileDescriptor, "android/content/res/AssetFileDescriptor")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
METHOD (close, "close", "()V")
|
|
|
|
DECLARE_JNI_CLASS (JavaCloseable, "java/io/Closeable")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
STATICMETHOD (open, "open", "(Ljava/io/File;I)Landroid/os/ParcelFileDescriptor;")
|
|
|
|
DECLARE_JNI_CLASS (ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
//==============================================================================
|
|
class AndroidContentSharerCursor
|
|
{
|
|
public:
|
|
class Owner
|
|
{
|
|
public:
|
|
virtual ~Owner() {}
|
|
|
|
virtual void cursorClosed (const AndroidContentSharerCursor&) = 0;
|
|
};
|
|
|
|
AndroidContentSharerCursor (Owner& ownerToUse, JNIEnv* env,
|
|
const LocalRef<jobject>& contentProvider,
|
|
const LocalRef<jobjectArray>& resultColumns)
|
|
: owner (ownerToUse),
|
|
cursor (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderCursor,
|
|
JuceContentProviderCursor.constructor,
|
|
contentProvider.get(),
|
|
reinterpret_cast<jlong> (this),
|
|
resultColumns.get()))))
|
|
{
|
|
// the content provider must be created first
|
|
jassert (contentProvider.get() != nullptr);
|
|
}
|
|
|
|
jobject getNativeCursor() { return cursor.get(); }
|
|
|
|
void cursorClosed()
|
|
{
|
|
MessageManager::callAsync ([this] { owner.cursorClosed (*this); });
|
|
}
|
|
|
|
void addRow (LocalRef<jobjectArray>& values)
|
|
{
|
|
auto* env = getEnv();
|
|
|
|
env->CallVoidMethod (cursor.get(), JuceContentProviderCursor.addRow, values.get());
|
|
}
|
|
|
|
private:
|
|
Owner& owner;
|
|
GlobalRef cursor;
|
|
|
|
//==============================================================================
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
METHOD (addRow, "addRow", "([Ljava/lang/Object;)V") \
|
|
METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;J[Ljava/lang/String;)V") \
|
|
CALLBACK (contentSharerCursorClosed, "contentSharerCursorClosed", "(J)V") \
|
|
|
|
DECLARE_JNI_CLASS (JuceContentProviderCursor, "com/roli/juce/JuceSharingContentProvider$ProviderCursor")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
static void JNICALL contentSharerCursorClosed(JNIEnv*, jobject, jlong host)
|
|
{
|
|
if (auto* myself = reinterpret_cast<AndroidContentSharerCursor*> (host))
|
|
myself->cursorClosed();
|
|
}
|
|
};
|
|
|
|
AndroidContentSharerCursor::JuceContentProviderCursor_Class AndroidContentSharerCursor::JuceContentProviderCursor;
|
|
|
|
//==============================================================================
|
|
class AndroidContentSharerFileObserver
|
|
{
|
|
public:
|
|
class Owner
|
|
{
|
|
public:
|
|
virtual ~Owner() {}
|
|
|
|
virtual void fileHandleClosed (const AndroidContentSharerFileObserver&) = 0;
|
|
};
|
|
|
|
AndroidContentSharerFileObserver (Owner& ownerToUse, JNIEnv* env,
|
|
const LocalRef<jobject>& contentProvider,
|
|
const String& filepathToUse)
|
|
: owner (ownerToUse),
|
|
filepath (filepathToUse),
|
|
fileObserver (GlobalRef (LocalRef<jobject> (env->NewObject (JuceContentProviderFileObserver,
|
|
JuceContentProviderFileObserver.constructor,
|
|
contentProvider.get(),
|
|
reinterpret_cast<jlong> (this),
|
|
javaString (filepath).get(),
|
|
open | access | closeWrite | closeNoWrite))))
|
|
{
|
|
// the content provider must be created first
|
|
jassert (contentProvider.get() != nullptr);
|
|
|
|
env->CallVoidMethod (fileObserver, JuceContentProviderFileObserver.startWatching);
|
|
}
|
|
|
|
void onFileEvent (int event, const LocalRef<jstring>& path)
|
|
{
|
|
ignoreUnused (path);
|
|
|
|
if (event == open)
|
|
{
|
|
++numOpenedHandles;
|
|
}
|
|
else if (event == access)
|
|
{
|
|
fileWasRead = true;
|
|
}
|
|
else if (event == closeNoWrite || event == closeWrite)
|
|
{
|
|
--numOpenedHandles;
|
|
|
|
// numOpenedHandles may get negative if we don't receive open handle event.
|
|
if (fileWasRead && numOpenedHandles <= 0)
|
|
{
|
|
MessageManager::callAsync ([this]
|
|
{
|
|
getEnv()->CallVoidMethod (fileObserver, JuceContentProviderFileObserver.stopWatching);
|
|
owner.fileHandleClosed (*this);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
static constexpr int open = 32;
|
|
static constexpr int access = 1;
|
|
static constexpr int closeWrite = 8;
|
|
static constexpr int closeNoWrite = 16;
|
|
|
|
bool fileWasRead = false;
|
|
int numOpenedHandles = 0;
|
|
|
|
Owner& owner;
|
|
String filepath;
|
|
GlobalRef fileObserver;
|
|
|
|
//==============================================================================
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
METHOD (constructor, "<init>", "(Lcom/roli/juce/JuceSharingContentProvider;JLjava/lang/String;I)V") \
|
|
METHOD (startWatching, "startWatching", "()V") \
|
|
METHOD (stopWatching, "stopWatching", "()V") \
|
|
CALLBACK (contentSharerFileObserverEvent, "contentSharerFileObserverEvent", "(JILjava/lang/String;)V") \
|
|
|
|
DECLARE_JNI_CLASS (JuceContentProviderFileObserver, "com/roli/juce/JuceSharingContentProvider$ProviderFileObserver")
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
static void JNICALL contentSharerFileObserverEvent (JNIEnv*, jobject /*fileObserver*/, jlong host, int event, jstring path)
|
|
{
|
|
if (auto* myself = reinterpret_cast<AndroidContentSharerFileObserver*> (host))
|
|
myself->onFileEvent (event, LocalRef<jstring> (path));
|
|
}
|
|
};
|
|
|
|
AndroidContentSharerFileObserver::JuceContentProviderFileObserver_Class AndroidContentSharerFileObserver::JuceContentProviderFileObserver;
|
|
|
|
//==============================================================================
|
|
class AndroidContentSharerPrepareFilesThread : private Thread
|
|
{
|
|
public:
|
|
AndroidContentSharerPrepareFilesThread (AsyncUpdater& ownerToUse,
|
|
const Array<URL>& fileUrlsToUse,
|
|
const String& packageNameToUse,
|
|
const String& uriBaseToUse)
|
|
: Thread ("AndroidContentSharerPrepareFilesThread"),
|
|
owner (ownerToUse),
|
|
fileUrls (fileUrlsToUse),
|
|
resultFileUris (GlobalRef (LocalRef<jobject> (getEnv()->NewObject (JavaArrayList,
|
|
JavaArrayList.constructor,
|
|
fileUrls.size())))),
|
|
packageName (packageNameToUse),
|
|
uriBase (uriBaseToUse)
|
|
{
|
|
startThread();
|
|
}
|
|
|
|
~AndroidContentSharerPrepareFilesThread() override
|
|
{
|
|
signalThreadShouldExit();
|
|
waitForThreadToExit (10000);
|
|
|
|
for (auto& f : temporaryFilesFromAssetFiles)
|
|
f.deleteFile();
|
|
}
|
|
|
|
jobject getResultFileUris() { return resultFileUris.get(); }
|
|
const StringArray& getMimeTypes() const { return mimeTypes; }
|
|
const StringArray& getFilePaths() const { return filePaths; }
|
|
|
|
private:
|
|
struct StreamCloser
|
|
{
|
|
StreamCloser (const LocalRef<jobject>& streamToUse)
|
|
: stream (GlobalRef (streamToUse))
|
|
{
|
|
}
|
|
|
|
~StreamCloser()
|
|
{
|
|
if (stream.get() != nullptr)
|
|
getEnv()->CallVoidMethod (stream, JavaCloseable.close);
|
|
}
|
|
|
|
GlobalRef stream;
|
|
};
|
|
|
|
void run() override
|
|
{
|
|
auto* env = getEnv();
|
|
|
|
bool canSpecifyMimeTypes = true;
|
|
|
|
for (auto f : fileUrls)
|
|
{
|
|
auto scheme = f.getScheme();
|
|
|
|
// Only "file://" scheme or no scheme (for files in app bundle) are allowed!
|
|
jassert (scheme.isEmpty() || scheme == "file");
|
|
|
|
if (scheme.isEmpty())
|
|
{
|
|
// Raw resource names need to be all lower case
|
|
jassert (f.toString (true).toLowerCase() == f.toString (true));
|
|
|
|
// This will get us a file with file:// URI
|
|
f = copyAssetFileToTemporaryFile (env, f.toString (true));
|
|
|
|
if (f.isEmpty())
|
|
continue;
|
|
}
|
|
|
|
if (threadShouldExit())
|
|
return;
|
|
|
|
auto filepath = URL::removeEscapeChars (f.toString (true).fromFirstOccurrenceOf ("file://", false, false));
|
|
|
|
filePaths.add (filepath);
|
|
|
|
auto filename = filepath.fromLastOccurrenceOf ("/", false, true);
|
|
auto fileExtension = filename.fromLastOccurrenceOf (".", false, true);
|
|
auto contentString = uriBase + String (filePaths.size() - 1) + "/" + filename;
|
|
|
|
auto uri = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidUri, AndroidUri.parse,
|
|
javaString (contentString).get()));
|
|
|
|
if (canSpecifyMimeTypes)
|
|
canSpecifyMimeTypes = fileExtension.isNotEmpty();
|
|
|
|
if (canSpecifyMimeTypes)
|
|
mimeTypes.addArray (getMimeTypesForFileExtension (fileExtension));
|
|
else
|
|
mimeTypes.clear();
|
|
|
|
env->CallBooleanMethod (resultFileUris, JavaArrayList.add, uri.get());
|
|
}
|
|
|
|
owner.triggerAsyncUpdate();
|
|
}
|
|
|
|
URL copyAssetFileToTemporaryFile (JNIEnv* env, const String& filename)
|
|
{
|
|
auto resources = LocalRef<jobject> (env->CallObjectMethod (getAppContext().get(), AndroidContext.getResources));
|
|
int fileId = env->CallIntMethod (resources, AndroidResources.getIdentifier, javaString (filename).get(),
|
|
javaString ("raw").get(), javaString (packageName).get());
|
|
|
|
// Raw resource not found. Please make sure that you include your file as a raw resource
|
|
// and that you specify just the file name, without an extension.
|
|
jassert (fileId != 0);
|
|
|
|
if (fileId == 0)
|
|
return {};
|
|
|
|
auto assetFd = LocalRef<jobject> (env->CallObjectMethod (resources,
|
|
AndroidResources.openRawResourceFd,
|
|
fileId));
|
|
|
|
auto inputStream = StreamCloser (LocalRef<jobject> (env->CallObjectMethod (assetFd,
|
|
AssetFileDescriptor.createInputStream)));
|
|
|
|
if (jniCheckHasExceptionOccurredAndClear())
|
|
{
|
|
// Failed to open file stream for resource
|
|
jassertfalse;
|
|
return {};
|
|
}
|
|
|
|
auto tempFile = File::createTempFile ({});
|
|
tempFile.createDirectory();
|
|
tempFile = tempFile.getChildFile (filename);
|
|
|
|
auto outputStream = StreamCloser (LocalRef<jobject> (env->NewObject (JavaFileOutputStream,
|
|
JavaFileOutputStream.constructor,
|
|
javaString (tempFile.getFullPathName()).get())));
|
|
|
|
if (jniCheckHasExceptionOccurredAndClear())
|
|
{
|
|
// Failed to open file stream for temporary file
|
|
jassertfalse;
|
|
return {};
|
|
}
|
|
|
|
auto buffer = LocalRef<jbyteArray> (env->NewByteArray (1024));
|
|
int bytesRead = 0;
|
|
|
|
for (;;)
|
|
{
|
|
if (threadShouldExit())
|
|
return {};
|
|
|
|
bytesRead = env->CallIntMethod (inputStream.stream, JavaFileInputStream.read, buffer.get());
|
|
|
|
if (jniCheckHasExceptionOccurredAndClear())
|
|
{
|
|
// Failed to read from resource file.
|
|
jassertfalse;
|
|
return {};
|
|
}
|
|
|
|
if (bytesRead < 0)
|
|
break;
|
|
|
|
env->CallVoidMethod (outputStream.stream, JavaFileOutputStream.write, buffer.get(), 0, bytesRead);
|
|
|
|
if (jniCheckHasExceptionOccurredAndClear())
|
|
{
|
|
// Failed to write to temporary file.
|
|
jassertfalse;
|
|
return {};
|
|
}
|
|
}
|
|
|
|
temporaryFilesFromAssetFiles.add (tempFile);
|
|
|
|
return URL (tempFile);
|
|
}
|
|
|
|
AsyncUpdater& owner;
|
|
Array<URL> fileUrls;
|
|
|
|
GlobalRef resultFileUris;
|
|
String packageName;
|
|
String uriBase;
|
|
|
|
StringArray filePaths;
|
|
Array<File> temporaryFilesFromAssetFiles;
|
|
StringArray mimeTypes;
|
|
};
|
|
|
|
//==============================================================================
|
|
class ContentSharer::ContentSharerNativeImpl : public ContentSharer::Pimpl,
|
|
public AndroidContentSharerFileObserver::Owner,
|
|
public AndroidContentSharerCursor::Owner,
|
|
public AsyncUpdater,
|
|
private Timer
|
|
{
|
|
public:
|
|
ContentSharerNativeImpl (ContentSharer& cs)
|
|
: owner (cs),
|
|
packageName (juceString (LocalRef<jstring> ((jstring) getEnv()->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageName)))),
|
|
uriBase ("content://" + packageName + ".sharingcontentprovider/")
|
|
{
|
|
}
|
|
|
|
~ContentSharerNativeImpl() override
|
|
{
|
|
masterReference.clear();
|
|
}
|
|
|
|
void shareFiles (const Array<URL>& files) override
|
|
{
|
|
if (! isContentSharingEnabled())
|
|
{
|
|
// You need to enable "Content Sharing" in Projucer's Android exporter.
|
|
jassertfalse;
|
|
owner.sharingFinished (false, {});
|
|
}
|
|
|
|
prepareFilesThread.reset (new AndroidContentSharerPrepareFilesThread (*this, files, packageName, uriBase));
|
|
}
|
|
|
|
void shareText (const String& text) override
|
|
{
|
|
if (! isContentSharingEnabled())
|
|
{
|
|
// You need to enable "Content Sharing" in Projucer's Android exporter.
|
|
jassertfalse;
|
|
owner.sharingFinished (false, {});
|
|
}
|
|
|
|
auto* env = getEnv();
|
|
|
|
auto intent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor));
|
|
env->CallObjectMethod (intent, AndroidIntent.setAction,
|
|
javaString ("android.intent.action.SEND").get());
|
|
env->CallObjectMethod (intent, AndroidIntent.putExtra,
|
|
javaString ("android.intent.extra.TEXT").get(),
|
|
javaString (text).get());
|
|
env->CallObjectMethod (intent, AndroidIntent.setType, javaString ("text/plain").get());
|
|
|
|
auto chooserIntent = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidIntent, AndroidIntent.createChooser,
|
|
intent.get(), javaString ("Choose share target").get()));
|
|
|
|
WeakReference<ContentSharerNativeImpl> weakRef (this);
|
|
|
|
startAndroidActivityForResult (chooserIntent, 1003,
|
|
[weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
|
|
{
|
|
if (weakRef != nullptr)
|
|
weakRef->sharingFinished (resultCode);
|
|
});
|
|
}
|
|
|
|
//==============================================================================
|
|
void cursorClosed (const AndroidContentSharerCursor& cursor) override
|
|
{
|
|
cursors.removeObject (&cursor);
|
|
}
|
|
|
|
void fileHandleClosed (const AndroidContentSharerFileObserver&) override
|
|
{
|
|
decrementPendingFileCountAndNotifyOwnerIfReady();
|
|
}
|
|
|
|
//==============================================================================
|
|
jobject openFile (const LocalRef<jobject>& contentProvider,
|
|
const LocalRef<jobject>& uri, const LocalRef<jstring>& mode)
|
|
{
|
|
ignoreUnused (mode);
|
|
|
|
WeakReference<ContentSharerNativeImpl> weakRef (this);
|
|
|
|
if (weakRef == nullptr)
|
|
return nullptr;
|
|
|
|
auto* env = getEnv();
|
|
|
|
auto uriElements = getContentUriElements (env, uri);
|
|
|
|
if (uriElements.filepath.isEmpty())
|
|
return nullptr;
|
|
|
|
return getAssetFileDescriptor (env, contentProvider, uriElements.filepath);
|
|
}
|
|
|
|
jobject query (const LocalRef<jobject>& contentProvider, const LocalRef<jobject>& uri,
|
|
const LocalRef<jobjectArray>& projection, const LocalRef<jobject>& selection,
|
|
const LocalRef<jobjectArray>& selectionArgs, const LocalRef<jobject>& sortOrder)
|
|
{
|
|
ignoreUnused (selection, selectionArgs, sortOrder);
|
|
|
|
StringArray requestedColumns = javaStringArrayToJuce (projection);
|
|
StringArray supportedColumns = getSupportedColumns();
|
|
|
|
StringArray resultColumns;
|
|
|
|
for (const auto& col : supportedColumns)
|
|
{
|
|
if (requestedColumns.contains (col))
|
|
resultColumns.add (col);
|
|
}
|
|
|
|
// Unsupported columns were queried, file sharing may fail.
|
|
if (resultColumns.isEmpty())
|
|
return nullptr;
|
|
|
|
auto resultJavaColumns = juceStringArrayToJava (resultColumns);
|
|
|
|
auto* env = getEnv();
|
|
|
|
auto cursor = cursors.add (new AndroidContentSharerCursor (*this, env, contentProvider,
|
|
resultJavaColumns));
|
|
|
|
auto uriElements = getContentUriElements (env, uri);
|
|
|
|
if (uriElements.filepath.isEmpty())
|
|
return cursor->getNativeCursor();
|
|
|
|
auto values = LocalRef<jobjectArray> (env->NewObjectArray ((jsize) resultColumns.size(),
|
|
JavaObject, nullptr));
|
|
|
|
for (int i = 0; i < resultColumns.size(); ++i)
|
|
{
|
|
if (resultColumns.getReference (i) == "_display_name")
|
|
{
|
|
env->SetObjectArrayElement (values, i, javaString (uriElements.filename).get());
|
|
}
|
|
else if (resultColumns.getReference (i) == "_size")
|
|
{
|
|
auto javaFile = LocalRef<jobject> (env->NewObject (JavaFile, JavaFile.constructor,
|
|
javaString (uriElements.filepath).get()));
|
|
|
|
jlong fileLength = env->CallLongMethod (javaFile, JavaFile.length);
|
|
|
|
env->SetObjectArrayElement (values, i, env->NewObject (JavaLong,
|
|
JavaLong.constructor,
|
|
fileLength));
|
|
}
|
|
}
|
|
|
|
cursor->addRow (values);
|
|
return cursor->getNativeCursor();
|
|
}
|
|
|
|
jobjectArray getStreamTypes (const LocalRef<jobject>& uri, const LocalRef<jstring>& mimeTypeFilter)
|
|
{
|
|
auto* env = getEnv();
|
|
|
|
auto extension = getContentUriElements (env, uri).filename.fromLastOccurrenceOf (".", false, true);
|
|
|
|
if (extension.isEmpty())
|
|
return nullptr;
|
|
|
|
return juceStringArrayToJava (filterMimeTypes (getMimeTypesForFileExtension (extension),
|
|
juceString (mimeTypeFilter.get())));
|
|
}
|
|
|
|
void sharingFinished (int resultCode)
|
|
{
|
|
sharingActivityDidFinish = true;
|
|
|
|
succeeded = resultCode == -1;
|
|
|
|
// Give content sharer a chance to request file access.
|
|
if (nonAssetFilesPendingShare.get() == 0)
|
|
startTimer (2000);
|
|
else
|
|
notifyOwnerIfReady();
|
|
}
|
|
|
|
private:
|
|
bool isContentSharingEnabled() const
|
|
{
|
|
auto* env = getEnv();
|
|
|
|
LocalRef<jobject> packageManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getPackageManager));
|
|
|
|
constexpr int getProviders = 8;
|
|
auto packageInfo = LocalRef<jobject> (env->CallObjectMethod (packageManager,
|
|
AndroidPackageManager.getPackageInfo,
|
|
javaString (packageName).get(),
|
|
getProviders));
|
|
auto providers = LocalRef<jobjectArray> ((jobjectArray) env->GetObjectField (packageInfo,
|
|
AndroidPackageInfo.providers));
|
|
|
|
if (providers == nullptr)
|
|
return false;
|
|
|
|
auto sharingContentProviderAuthority = packageName + ".sharingcontentprovider";
|
|
const int numProviders = env->GetArrayLength (providers.get());
|
|
|
|
for (int i = 0; i < numProviders; ++i)
|
|
{
|
|
auto providerInfo = LocalRef<jobject> (env->GetObjectArrayElement (providers, i));
|
|
auto authority = LocalRef<jstring> ((jstring) env->GetObjectField (providerInfo,
|
|
AndroidProviderInfo.authority));
|
|
|
|
if (juceString (authority) == sharingContentProviderAuthority)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void handleAsyncUpdate() override
|
|
{
|
|
jassert (prepareFilesThread != nullptr);
|
|
|
|
if (prepareFilesThread == nullptr)
|
|
return;
|
|
|
|
filesPrepared (prepareFilesThread->getResultFileUris(), prepareFilesThread->getMimeTypes());
|
|
}
|
|
|
|
void filesPrepared (jobject fileUris, const StringArray& mimeTypes)
|
|
{
|
|
auto* env = getEnv();
|
|
|
|
auto intent = LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor));
|
|
env->CallObjectMethod (intent, AndroidIntent.setAction,
|
|
javaString ("android.intent.action.SEND_MULTIPLE").get());
|
|
|
|
env->CallObjectMethod (intent, AndroidIntent.setType,
|
|
javaString (getCommonMimeType (mimeTypes)).get());
|
|
|
|
constexpr int grantReadPermission = 1;
|
|
env->CallObjectMethod (intent, AndroidIntent.setFlags, grantReadPermission);
|
|
|
|
env->CallObjectMethod (intent, AndroidIntent.putParcelableArrayListExtra,
|
|
javaString ("android.intent.extra.STREAM").get(),
|
|
fileUris);
|
|
|
|
auto chooserIntent = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidIntent,
|
|
AndroidIntent.createChooser,
|
|
intent.get(),
|
|
javaString ("Choose share target").get()));
|
|
WeakReference<ContentSharerNativeImpl> weakRef (this);
|
|
|
|
startAndroidActivityForResult (chooserIntent, 1003,
|
|
[weakRef] (int /*requestCode*/, int resultCode, LocalRef<jobject> /*intentData*/) mutable
|
|
{
|
|
if (weakRef != nullptr)
|
|
weakRef->sharingFinished (resultCode);
|
|
});
|
|
}
|
|
|
|
void decrementPendingFileCountAndNotifyOwnerIfReady()
|
|
{
|
|
--nonAssetFilesPendingShare;
|
|
|
|
notifyOwnerIfReady();
|
|
}
|
|
|
|
void notifyOwnerIfReady()
|
|
{
|
|
if (sharingActivityDidFinish && nonAssetFilesPendingShare.get() == 0)
|
|
owner.sharingFinished (succeeded, {});
|
|
}
|
|
|
|
void timerCallback() override
|
|
{
|
|
stopTimer();
|
|
|
|
notifyOwnerIfReady();
|
|
}
|
|
|
|
//==============================================================================
|
|
struct ContentUriElements
|
|
{
|
|
String index;
|
|
String filename;
|
|
String filepath;
|
|
};
|
|
|
|
ContentUriElements getContentUriElements (JNIEnv* env, const LocalRef<jobject>& uri) const
|
|
{
|
|
jassert (prepareFilesThread != nullptr);
|
|
|
|
if (prepareFilesThread == nullptr)
|
|
return {};
|
|
|
|
auto fullUri = juceString ((jstring) env->CallObjectMethod (uri.get(), AndroidUri.toString));
|
|
|
|
auto index = fullUri.fromFirstOccurrenceOf (uriBase, false, false)
|
|
.upToFirstOccurrenceOf ("/", false, true);
|
|
|
|
auto filename = fullUri.fromLastOccurrenceOf ("/", false, true);
|
|
|
|
return { index, filename, prepareFilesThread->getFilePaths()[index.getIntValue()] };
|
|
}
|
|
|
|
static StringArray getSupportedColumns()
|
|
{
|
|
return StringArray ("_display_name", "_size");
|
|
}
|
|
|
|
jobject getAssetFileDescriptor (JNIEnv* env, const LocalRef<jobject>& contentProvider,
|
|
const String& filepath)
|
|
{
|
|
// This function can be called from multiple threads.
|
|
{
|
|
const ScopedLock sl (nonAssetFileOpenLock);
|
|
|
|
if (! nonAssetFilePathsPendingShare.contains (filepath))
|
|
{
|
|
nonAssetFilePathsPendingShare.add (filepath);
|
|
++nonAssetFilesPendingShare;
|
|
|
|
nonAssetFileObservers.add (new AndroidContentSharerFileObserver (*this, env,
|
|
contentProvider,
|
|
filepath));
|
|
}
|
|
}
|
|
|
|
auto javaFile = LocalRef<jobject> (env->NewObject (JavaFile, JavaFile.constructor,
|
|
javaString (filepath).get()));
|
|
|
|
constexpr int modeReadOnly = 268435456;
|
|
auto parcelFileDescriptor = LocalRef<jobject> (env->CallStaticObjectMethod (ParcelFileDescriptor,
|
|
ParcelFileDescriptor.open,
|
|
javaFile.get(), modeReadOnly));
|
|
|
|
if (jniCheckHasExceptionOccurredAndClear())
|
|
{
|
|
// Failed to create file descriptor. Have you provided a valid file path/resource name?
|
|
jassertfalse;
|
|
return nullptr;
|
|
}
|
|
|
|
jlong startOffset = 0;
|
|
jlong unknownLength = -1;
|
|
|
|
assetFileDescriptors.add (GlobalRef (LocalRef<jobject> (env->NewObject (AssetFileDescriptor,
|
|
AssetFileDescriptor.constructor,
|
|
parcelFileDescriptor.get(),
|
|
startOffset, unknownLength))));
|
|
|
|
return assetFileDescriptors.getReference (assetFileDescriptors.size() - 1).get();
|
|
}
|
|
|
|
ContentSharer& owner;
|
|
String packageName;
|
|
String uriBase;
|
|
|
|
std::unique_ptr<AndroidContentSharerPrepareFilesThread> prepareFilesThread;
|
|
|
|
bool succeeded = false;
|
|
String errorDescription;
|
|
|
|
bool sharingActivityDidFinish = false;
|
|
|
|
OwnedArray<AndroidContentSharerCursor> cursors;
|
|
|
|
Array<GlobalRef> assetFileDescriptors;
|
|
|
|
CriticalSection nonAssetFileOpenLock;
|
|
StringArray nonAssetFilePathsPendingShare;
|
|
Atomic<int> nonAssetFilesPendingShare { 0 };
|
|
OwnedArray<AndroidContentSharerFileObserver> nonAssetFileObservers;
|
|
|
|
WeakReference<ContentSharerNativeImpl>::Master masterReference;
|
|
friend class WeakReference<ContentSharerNativeImpl>;
|
|
|
|
//==============================================================================
|
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
|
CALLBACK (contentSharerQuery, "contentSharerQuery", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;") \
|
|
CALLBACK (contentSharerOpenFile, "contentSharerOpenFile", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;") \
|
|
CALLBACK (contentSharerGetStreamTypes, "contentSharerGetStreamTypes", "(Landroid/net/Uri;Ljava/lang/String;)[Ljava/lang/String;") \
|
|
|
|
|
|
DECLARE_JNI_CLASS_WITH_BYTECODE (JuceSharingContentProvider, "com/roli/juce/JuceSharingContentProvider", 16, javaJuceSharingContentProvider, sizeof (javaJuceSharingContentProvider))
|
|
#undef JNI_CLASS_MEMBERS
|
|
|
|
static jobject JNICALL contentSharerQuery (JNIEnv*, jobject contentProvider, jobject uri, jobjectArray projection,
|
|
jobject selection, jobjectArray selectionArgs, jobject sortOrder)
|
|
{
|
|
if (auto *pimpl = (ContentSharer::ContentSharerNativeImpl *) ContentSharer::getInstance ()->pimpl.get ())
|
|
return pimpl->query (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
|
|
LocalRef<jobject> (static_cast<jobject> (uri)),
|
|
LocalRef<jobjectArray> (
|
|
static_cast<jobjectArray> (projection)),
|
|
LocalRef<jobject> (static_cast<jobject> (selection)),
|
|
LocalRef<jobjectArray> (
|
|
static_cast<jobjectArray> (selectionArgs)),
|
|
LocalRef<jobject> (static_cast<jobject> (sortOrder)));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static jobject JNICALL contentSharerOpenFile (JNIEnv*, jobject contentProvider, jobject uri, jstring mode)
|
|
{
|
|
if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
|
|
return pimpl->openFile (LocalRef<jobject> (static_cast<jobject> (contentProvider)),
|
|
LocalRef<jobject> (static_cast<jobject> (uri)),
|
|
LocalRef<jstring> (static_cast<jstring> (mode)));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static jobjectArray JNICALL contentSharerGetStreamTypes (JNIEnv*, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter)
|
|
{
|
|
if (auto* pimpl = (ContentSharer::ContentSharerNativeImpl*) ContentSharer::getInstance()->pimpl.get())
|
|
return pimpl->getStreamTypes (LocalRef<jobject> (static_cast<jobject> (uri)),
|
|
LocalRef<jstring> (static_cast<jstring> (mimeTypeFilter)));
|
|
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
//==============================================================================
|
|
ContentSharer::Pimpl* ContentSharer::createPimpl()
|
|
{
|
|
return new ContentSharerNativeImpl (*this);
|
|
}
|
|
|
|
ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider_Class ContentSharer::ContentSharerNativeImpl::JuceSharingContentProvider;
|
|
|
|
} // namespace juce
|