Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 9 - Last Post: Oct 26, 2015 2:00 AM Last Post By: GAI CHEW KAI
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 21, 2015 12:52 AM
Embarcadero® C++Builder XE8 Version 22.0.19027.8951 and Indy 10.
Window 10 Pro x64, Version 10.0.10240
Android 4.1.2

QUESTIONS

1. How to attach a file to an application eg. Dropbox, GMail... etc ?

I have the following code but just cannot attach a file which is stored in ./sdcard/documents/

_di_JIntent oIntent;
_di_Jnet_Uri uri;

UnicodeString us;

//
// I have tried the following path but no file is attaching to the selected application.
//

us = L"file:///sdcard/Documents/UNICODE 测试_.txt";
//us = L"file://./sdcard/Documents/UNICODE 测试_.txt";
//us = L"./sdcard/Documents/UNICODE 测试_.txt";
//us = L"/sdcard/Documents/UNICODE 测试_.txt";

String s;

s = us;

uri = StrToJURI( s );

try
{
oIntent = TJIntent::JavaClass->init();
if( oIntent )
{
oIntent->setAction( TJIntent::JavaClass->ACTION_SEND );

oIntent->setData( uri );

oIntent->setType( StringToJString( "application/*" ) );

oIntent->putExtra( TJIntent::JavaClass->EXTRA_STREAM, StringToJString( JURIToStr( uri ) ) );

::SharedActivityContext()->startActivity( oIntent );
}
}
catch( Exception& e )
{
ShowMessage( e.Message );
}

Please advise.
Remy Lebeau (Te...


Posts: 8,950
Registered: 12/23/01
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 21, 2015 10:07 AM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

us = L"file:///sdcard/Documents/UNICODE 测试_.txt";
//us = L"file://./sdcard/Documents/UNICODE 测试_.txt";
//us = L"./sdcard/Documents/UNICODE 测试_.txt";
//us = L"/sdcard/Documents/UNICODE 测试_.txt";


Don't hard-code paths, especially to the SDCard path. It can differ from
one device to another. Either use Delphi's TPath class instead:

Standard RTL Path Functions across the Supported Target Platforms
http://docwiki.embarcadero.com/RADStudio/en/Standard_RTL_Path_Functions_across_the_Supported_Target_Platforms

Or, you may have to use Android's Environment class directly, for paths that
TPath does not natively support, eg:

uri := TJnet_Uri::JavaClass->parse( TJEnvironment::JavaClass->getExternalStoragePublicDirectory( 
TJEnvironment::JavaClass->DIRECTORY_DOCUMENTS ), StringToJString( L"UNICODE 
测试_.txt" ) ) );


oIntent->setData( uri );

You don't need to use setData() in this situation.

oIntent->setType( StringToJString( "application/*" ) );

If you don't know the exact MIME type of the attachment, use "/" instead.
But since you are attaching a .txt file, use "text/plain".

oIntent->putExtra( TJIntent::JavaClass->EXTRA_STREAM, StringToJString(
JURIToStr( uri ) ) );

EXTRA_STREAM expects the actual URI object, not a String representation of
the URI:

oIntent->putExtra( TJIntent::JavaClass->EXTRA_STREAM, uri );


--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 21, 2015 11:02 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
> TJEnvironment::JavaClass->DIRECTORY_DOCUMENTS ), StringToJString( L"UNICODE
- There is error with TJEnvironment in CBXE8:
[bccaarm Error] oMain.cpp(1594): use of undeclared identifier 'TJEnvironment'

> EXTRA_STREAM expects the actual URI object, not a String representation of the URI:
> oIntent->putExtra( TJIntent::JavaClass->EXTRA_STREAM, uri );
- There is error with uri as second parameter such as:
[bccaarm Error] oMain.cpp(1637): call to member function 'putExtra' is ambiguous

- I noticed _di_JFile cannot hold "file://" although UnicodeString variable "us" below reported as "file:///storage/...".

#define _u( x ) UTF8String( (x).w_str() ).c_str()
#define _us( x ) UnicodeString( (x) )

UnicodeString us;
_di_JFile oFile;
_di_JFile oPath;

// us...reported as "file://..."
us = _us( L"file://" ) + m_usPathPublic;

*// oPath...is "file:/storage/sdcard0/Android/data/com.embarcadero.MBXC/files" where only "file:/" is found.*
// via __dw( L"xdebug...oPath=[%s]", _u( _us( JStringToString( oPath->toString() ) ) ) );
oPath = TJFile::JavaClass->init( StringToJString( us ) );

// oFile....is "file:/storage/sdcard0/Android/data/com.embarcadero.MBXC/files/UNICODE.txt"
oFile = TJFile::JavaClass->init( oPath, StringToJString( UnicodeString( L"TEST.TXT" ) ) );

However, the file UNICODE.TXT failed to be inserted into GMail or Dropbox...

Please advise.

Remy Lebeau (Te...


Posts: 8,950
Registered: 12/23/01
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?[Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 22, 2015 12:29 AM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

- There is error with TJEnvironment in CBXE8:
*[bccaarm Error] oMain.cpp(1594): use of undeclared identifier
'TJEnvironment'*

Apparently Embarcadero does not provide a declaration for Android's Environment
class. You will have to declare it manually in your own code. Sorry. And
because of the syntax and RTTI involved, it would be easier to do that in
Delphi than in C++. However, you can add a Delphi .pas file to a C++Builder
project, and the IDE will compile the .pas file into a .hpp file that you
can then #include in your C++ source as needed.

+> EXTRA_STREAM expects the actual URI object, not a String representation
of the URI:+
> oIntent->putExtra( TJIntent::JavaClass->EXTRA_STREAM, uri );

- There is error with uri as second parameter such as:
*[bccaarm Error] oMain.cpp(1637): call to member function 'putExtra' is
ambiguous*

There are many overloads of the JIntent::putExtra() method, but none of them
take a JURI as input. In Android, the URI class implements the Parcelable
interface, and there is an overload of putExtra() that takes a Parcelable
as input. So in Java, it is possible to pass a URI directly to putExtra().
But alas, in Delphi and C++Builder, the JUri interface does not derive from
the JParcelable interface, so you can't pass a JURI directly to putExtra().
Try using the putParcelableArrayListExtra() method instead (which you will
have to do anyway if you want to add multiple attachments):

_di_JArrayList arr = TJArrayList::JavaClass->init();
arr->add(uri);
oIntent->putParcelableArrayListExtra(TJIntent::JavaClass->EXTRA_STREAM, arr);


--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?[Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 23, 2015 8:17 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
> Apparently Embarcadero does not provide a declaration for Android's Environment
> class. You will have to declare it manually in your own code. Sorry. And
> because of the syntax and RTTI involved, it would be easier to do that in
+> Delphi than in C++. However, you can add a Delphi .pas file to a C++Builder+
> project, and the IDE will compile the .pas file into a .hpp file that you
+> can then #include in your C++ source as needed.+

- I am using C++Builder XE Pro version 8, how to add the .pas file ?
- Secondly is CBXE 10 with Android's Environment class declared ?

> Try using the putParcelableArrayListExtra() method instead (which you will
> have to do anyway if you want to add multiple attachments):

- Is there any other configuration like the .manifest file permissions or FileProvider/ContentProvider necessary to make ORI visible to the receiver application ?

I am running out of ideas of how to finalize the file attach to GMAIL via Android using CBXE8,

I have posted this article to Embarcadero Forum Community, is there any way to assist me to resolve this issues in C++Builder XE ? ( eg. CBXE 10 more complete API wrapping ? )

Please advise.

Remy Lebeau (Te...


Posts: 8,950
Registered: 12/23/01
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android?[Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 24, 2015 3:54 PM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

I am using C++Builder XE Pro version 8, how to add the .pas file ?

Just add it to the project like any other file. For example (untested):

Androidapi.JNI.Environment.pas:

unit Androidapi.JNI.Environment;
 
interface
 
uses
  Androidapi.JNI.JavaTypes,
  Androidapi.JNIBridge;
 
type
  JEnvironmentClass = interface(JObjectClass)
    ['{A279F602-8427-424D-B11D-68828D9DF67C}']
    function _GetMEDIA_BAD_REMOVAL: JString; cdecl;
    function _GetMEDIA_CHECKING: JString; cdecl;
    function _GetMEDIA_EJECTING: JString; cdecl;
    function _GetMEDIA_MOUNTED: JString; cdecl;
    function _GetMEDIA_MOUNTED_READ_ONLY: JString; cdecl;
    function _GetMEDIA_NOFS: JString; cdecl;
    function _GetMEDIA_REMOVED: JString; cdecl;
    function _GetMEDIA_SHARED: JString; cdecl;
    function _GetMEDIA_UNKNOWN: JString; cdecl;
    function _GetMEDIA_UNMOUNTABLE: JString; cdecl;
    function _GetMEDIA_UNMOUNTED: JString; cdecl;
    function _GetDIRECTORY_ALARMS: JString; cdecl;
    function _GetDIRECTORY_DCIM: JString; cdecl;
    function _GetDIRECTORY_DOCUMENTS: JString; cdecl;
    function _GetDIRECTORY_DOWNLOADS: JString; cdecl;
    function _GetDIRECTORY_MOVIES: JString; cdecl;
    function _GetDIRECTORY_MUSIC: JString; cdecl;
    function _GetDIRECTORY_NOTIFICATIONS: JString; cdecl;
    function _GetDIRECTORY_PICTURES: JString read; cdecl;
    function _GetDIRECTORY_PODCASTS: JString; cdecl;
    function _GetDIRECTORY_RINGTONES: JString; cdecl;
    function getDataDirectory: JFile; cdecl;
    function getDownloadCacheDirectory: JFile; cdecl;
    function getExternalStorageDirectory: JFile; cdecl;
    function getExternalStoragePublicDirectory(type: JString): JFile; cdecl;
    function getExternalStorageState(path: JFile): JString; cdecl;
    function getExternalStorageState: JString; cdecl;
    function getRootDirectory: JFile; cdecl;
    function getStorageState(path: JFile): JString; cdecl;
    function isExternalStorageEmulated: Boolean; cdecl;
    function isExternalStorageEmulated(path: JFile): Boolean; cdecl;
    function isExternalStorageRemovable(path: JFile): Boolean; cdecl;
    function isExternalStorageRemovable: Boolean; cdecl;
    property MEDIA_BAD_REMOVAL: JString read _GetMEDIA_BAD_REMOVAL;
    property MEDIA_CHECKING: JString read _GetMEDIA_CHECKING;
    property MEDIA_EJECTING: JString read _GetMEDIA_EJECTING;
    property MEDIA_MOUNTED: JString read _GetMEDIA_MOUNTED;
    property MEDIA_MOUNTED_READ_ONLY: JString read _GetMEDIA_MOUNTED_READ_ONLY;
    property MEDIA_NOFS: JString read _GetMEDIA_NOFS;
    property MEDIA_REMOVED: JString read _GetMEDIA_REMOVED;
    property MEDIA_SHARED: JString read _GetMEDIA_SHARED;
    property MEDIA_UNKNOWN: JString read _GetMEDIA_UNKNOWN;
    property MEDIA_UNMOUNTABLE: JString read _GetMEDIA_UNMOUNTABLE;
    property MEDIA_UNMOUNTED: JString read _GetMEDIA_UNMOUNTED;
    property DIRECTORY_ALARMS: JString read _GetDIRECTORY_ALARMS;
    property DIRECTORY_DCIM: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_DOCUMENTS: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_DOWNLOADS: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_MOVIES: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_MUSIC: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_NOTIFICATIONS: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_PICTURES: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_PODCASTS: JString read _GetDIRECTORY_DCIM;
    property DIRECTORY_RINGTONES: JString read _GetDIRECTORY_DCIM;
  end;
 
  [JavaSignature('android/os/Environment')]
  JEnvironment = interface(JObject)
    ['{25098D43-E206-4813-B88A-49C58E76D987}']
  end;
  TJEnvironment = class(TJavaGenericImport<JEnvironmentClass, JEnvironment>) 
end;
 
implementation
 
initialization
  TRegTypes.RegisterType('Androidapi.JNI.Environment.JEnvironment', TypeInfo(Androidapi.JNI.Environment.JEnvironment));
 
end.


Secondly is CBXE 10 with Android's Environment class declared ?

No, it is not. I have already files a QualityPortal ticket about it.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 8,950
Registered: 12/23/01
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?[Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 22, 2015 12:35 AM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

- I noticed _di_JFile cannot hold "file://" although UnicodeString
variable "us" below reported as "file:///storage/...".

Yes, it can. And the code you showed proves that.

#define _u( x ) UTF8String( (x).w_str() ).c_str()
#define _us( x ) UnicodeString( (x) )

Why are you using those macros? It makes your code harder to read, and forces
redundant assignments.

*// oPath...is "file:/storage/sdcard0/Android/data/com.embarcadero.MBXC/files"
where only "file:/" is found.*
*// via __dw( L"xdebug...oPath=[%s]", _u( _us( JStringToString( oPath->toString()
) ) ) );*

What is __dw() exactly? The fact that it takes a wchar_t* as the formatting
string suggests that its %s specifier likely expects a wchar_t*, but you
are passing it a UTF-8 encoded char* instead. Are you sure that is right?

// oFile....is "file:/storage/sdcard0/Android/data/com.embarcadero.MBXC/files/UNICODE.txt"

Then clearly oPath is being created correctly, which means JFile is handling
your path strings correctly. So the problem has to be in your __dw() function
instead.

--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android ?[Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 22, 2015 1:05 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy, here is the current modified source but still unable to attach a file to GMail, Dropbox...etc

_di_JIntent oIntent;
_di_Jnet_Uri oURI;
_di_JFile oPath;
_di_JFile oFile;

UnicodeString us;
UnicodeStirng usFName;
UnicodeString usPathPublic;

// UNICODE.TXT is a file that copied into usPath dynamically, it is confirmed there.
usFName = L"UNICODE.TXT";

// usPath....is gained via System::Ioutils::TPath::GetPublicPath() as "/storage/sdcard0/Android/data/com.embarcadero.MBXC/files"
usPath = System::Ioutils::TPath::GetPublicPath();

// NOTE: Both methods below also failed to attach a file into GMail or Dropbox...etc

#if 0 // Method 1

oPath = TJFile::JavaClass->init( StringToJString( usPath ) );
oFile = TJFile::JavaClass->init( oPath, StringToJString( usFName ) );
oURI = TJnet_Uri::JavaClass->fromFile( oFile );

#else // Method 2

us = usPath + L"/" + usFName;
oURI = TJnet_Uri::JavaClass->parse( StringToJString( L"file://" + us ) );

#endif

// NOTE: oURI.toString() is "file:///storage/sdcard0/Android/data/com.embarcadero.MBXC/files/UNICODE.TXT"
oURI = TJnet_Uri::JavaClass->parse( StringToJString( us ) );

try
{
oIntent = TJIntent::JavaClass->init();

if( oIntent )
{
oIntent->setAction( TJIntent::JavaClass->ACTION_SEND );

oIntent->setType( StringToJString( "message/rfc822" ) );

_di_JArrayList arr = TJArrayList::JavaClass->init();
arr->add( oURI );
oIntent->putParcelableArrayListExtra( TJIntent::JavaClass->EXTRA_STREAM, arr );

oIntent->setFlags( TJIntent::JavaClass->FLAG_ACTIVITY_NEW_TASK );

::SharedActivityContext()->startActivity( oIntent );
}
}
catch( Exception& e )
{
ShowMessage( e.Message );
}

Please advise.

Remy Lebeau (Te...


Posts: 8,950
Registered: 12/23/01
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android?[Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 22, 2015 10:30 AM   in response to: GAI CHEW KAI in response to: GAI CHEW KAI
GAI wrote:

Remy, here is the current modified source but still unable to attach
a file to GMail, Dropbox...etc

I cannot comment on Gmail, but Dropbox is not email, so try using "file/*"
instead of "message/rfc822" when calling oIntent->setType().

Other than that, I see no other problems in the code. You clearly have a
valid URI, so it is a matter of how the receiving application decides to
process that URI.

--
Remy Lebeau (TeamB)
GAI CHEW KAI

Posts: 117
Registered: 7/25/14
Re: CBXE8 - How to attach a file to GMAIL/Dropbox...etc in Android?[Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 26, 2015 1:55 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
...just found the answer, and is by changing

oIntent->setAction( TJIntent::JavaClass->ACTION_SEND );

to

oIntent->setAction( TJIntent::JavaClass->ACTION_SEND_MULTIPLE );

Here is the complete fully working version which able to attach a file to GMail, Dropbox...etc

_di_JIntent oIntent;
_di_Jnet_Uri oURI;
_di_JFile oPath;
_di_JFile oFile;

UnicodeString us;
UnicodeStirng usFName;
UnicodeString usPathPublic;

// UNICODE.TXT is a file that copied into usPath dynamically, it is confirmed there.
usFName = L"UNICODE.TXT";

// usPath....is gained via System::Ioutils::TPath::GetPublicPath() as "/storage/sdcard0/Android/data/com.embarcadero.MBXC/files"
usPath = System::Ioutils::TPath::GetPublicPath();

#if 0 // Method 1

oPath = TJFile::JavaClass->init( StringToJString( usPath ) );
oFile = TJFile::JavaClass->init( oPath, StringToJString( usFName ) );
oURI = TJnet_Uri::JavaClass->fromFile( oFile );

#else // Method 2

us = usPath + L"/" + usFName;

// NOTE: oURI.toString() is "file:///storage/sdcard0/Android/data/com.embarcadero.MBXC/files/UNICODE.TXT"
oURI = TJnet_Uri::JavaClass->parse( StringToJString( L"file://" + us ) );

// Alternative to TJnet_Uri::JavaClass->parse(), will work the same.
// oURI = StrToJURI( us );

#endif

try
{
oIntent = TJIntent::JavaClass->init();

if( oIntent )
{
// NOTE: You have to use ACTION_SEND_MULTIPLE to attach a file successfully.
oIntent->setAction( TJIntent::JavaClass->ACTION_SEND_MULTIPLE );

oIntent->setType( StringToJString( "/" ) );

_di_JArrayList arr = TJArrayList::JavaClass->init();
arr->add( oURI );
oIntent->putParcelableArrayListExtra( TJIntent::JavaClass->EXTRA_STREAM, arr );

oIntent->setFlags( TJIntent::JavaClass->FLAG_ACTIVITY_NEW_TASK );

::SharedActivityContext()->startActivity( oIntent );
}
}
catch( Exception& e )
{
ShowMessage( e.Message );
}

Hopes, this gives a Crystal Clear answer.

Remy, thanks again for great hints.

Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02