2

I started doing an app for android in Delphi XE5, and encountered some troubles.

I really don't understand about getting paths. After I set the permissions to Write and Read External storage, I tried to get paths so I can see where I'm saving files I create, and this is what I get:

for System.IOUtils.TPath. ->

GetDocumentsPath;       -  /data/data/com.myapp.app1/files
GetDownloadsPath;       -  /storage/emulated/0/Android/data/com.myapp.app1/files/Download
GetHomePath;            -  /data/data/com.myapp.app1/files
GetSharedDocumentsPath; -  /storage/emulated/0/Android/data/com.myapp.app1/files
GetLibraryPath;         -  /data/data/com.myapp.app1/files
GetPublicPath;          -  /storage/emulated/0/Android/data/com.myapp.app1/files
GetPicturesPath;        -  /storage/emulated/0/Android/data/com.myapp.app1/files/Pictures

As far as I understood from other topics, the GetDocumentsPath should be default sdcard path, Downloads should be sdcard/Downloads, but instead it's using /Android/data/application's folder/files/ here creats folders which already exists on the sdcard itself.

/emulated/0/ is actually the same as /sdcard/ on my phone, if that's confusing for anyone (just in case....).

It has several shortcuts, as far as I understand, storage/emulated/0/, storage/sdcard0/, also from root's folder is directly access to sdcard/ (but I guess the apps without root access has only default access to storage/ folder, hence the storage/sdcard0 and emulated/0 folders exists; don't know why are duplicated shortcuts to the same folder, though....)

[[ There's also storage/emulated/legacy/, which also seems to point to the same folder, but I never touch it, since I used to have some troubles with file duplicates and strange Music library behaviour, right before I rooted and formatted it. Never figured what really happened, but don't even care. Fact is, that the emulated folder seems to be evil and unexplained ;) ]]

Also, are these path troubles related to the fact, that the phone has no mount option, but only MTP, or that it's android 4.3, or....?

Thanks.

// Update: Splitted questions about this and screen resolutions as Sir Rufo suggested.

UPDATE: Looks like hardcoding '/sdcard/filename.extension' as path string does the job, however I'm not sure how wise it is to hardcore the location in the app... ://

That Marc
  • 1,134
  • 3
  • 19
  • 42
  • 2
    you should split this into two questions - one question per SO question :o) – Sir Rufo Jan 13 '14 at 19:56
  • 1
    Does [Standard RTL Path Functions Across the Supported Target Platforms](http://docwiki.embarcadero.com/RADStudio/XE5/en/Standard_RTL_Path_Functions_across_the_Supported_Target_Platforms) help? – Ken White Jan 13 '14 at 23:37
  • Well, as for this documentation, it's all as I already figured. So shared does send me to external memory into the correct directory, such as Pictures, Download, Music, etc. But the problem persists, if I want to make my own apps folder within sd card. It's ridiculous for me to send a user search through Android/data/com.something.appname/files to find the file he exported, but rather create folder within SD card. Also, I hate it when apps make folders within my Downloads.. If pictures, it's ok to have subfolder in /Pictures, Music as well, but I'm exporting messages, so this doesn't – That Marc Jan 14 '14 at 00:18
  • belong to any of existing subfolders on SD card, which would be system. I just find it ridiculous, if, as this documentation seems to suggest, there is no way to get direct path to sdcard root folder, without hard coding it. As for my phone, if not rooted or no root access of app, it cannot store anything in it's internal memory, as the "sdcard" is actually the internal memory itself, but acts as external. So, I can't use any path to internal, but don't have an option to get external root path, or do I? :/ Thanks, though. It does help, if nothing else, to verify my results of paths.... – That Marc Jan 14 '14 at 00:21
  • I don't understand your problem. This is how Android works. If this is a problem, for what problem do you want a solution? You mention path troubles, which one? – Arnold Jan 17 '14 at 19:14
  • Well, basically the main problem I mentioned and asked about was, how to get to the root of sd card folder? I updated that question with a different one: is there any ither way of doing this, instead of hard coding the "/sdcard/" path into my app, as Im not sure if hardcoding is a good choice.... – That Marc Jan 18 '14 at 02:30

2 Answers2

3

Try not to hard code the path. The paths to external storage may vary for different Android platforms and you'll miss the advantage of cross-platform programming. When I started programming for Android I wrote a small App 'Where' targeted at listing all 'special' directories for all platforms. That was very useful as I didn't know these directories for even Windows, let alone Android. In your example you miss the SharedDirectories. This will return the path to /storage/emulated/0/Music/ for GetSharedMusicPath for example, and so on for Movies, Download, etc. I thought it was different for my Galaxy Tab but I'm not sure. Just remove the last name and you have the path to external storage.

Take care that you have READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE set if you want to read and write to your external storage (somewhere in Project | Options | Android). I don't know whether Android allows you to write in the external storage root, you must try that yourself.

uses System.IOUtils;

procedure THeaderFooterForm.Loaded;
begin
   inherited Loaded;

   TPath.SetApplicationPath ('WhereAppTest');

   add_path (TPath.GetTempPath, 'GetTempPath');
   add_path (TPath.GetHomePath, 'GetHomePath');
   add_path (TPath.GetDocumentsPath, 'GetDocumentsPath');
   add_path (TPath.GetApplicationPath ('WhereAppTest'), 'GetApplicationPath');
   add_path (TPath.GetSharedDocumentsPath, 'GetSharedDocumentsPath');
   add_path (TPath.GetLibraryPath, 'GetLibraryPath');
   add_path (TPath.GetCachePath, 'GetCachePath');
   add_path (TPath.GetPublicPath, 'GetPublicPath');
   add_path (TPath.GetPicturesPath, 'GetPicturesPath');
   add_path (TPath.GetSharedPicturesPath, 'GetSharedPicturesPath');
   add_path (TPath.GetCameraPath, 'GetCameraPath');
   add_path (TPath.GetSharedCameraPath, 'GetSharedCameraPath');
   add_path (TPath.GetMusicPath, 'GetMusicPath');
   add_path (TPath.GetSharedMusicPath, 'GetSharedMusicPath');
   add_path (TPath.GetMoviesPath, 'GetMoviesPath');
   add_path (TPath.GetSharedMoviesPath, 'GetSharedMoviesPath');
   add_path (TPath.GetAlarmsPath, 'GetAlarmsPath');
   add_path (TPath.GetSharedAlarmsPath, 'GetSharedAlarmsPath');
   add_path (TPath.GetDownloadsPath, 'GetDownloadsPath');
   add_path (TPath.GetSharedDownloadsPath, 'GetSharedDownloadsPath');
   add_path (TPath.GetRingtonesPath.Empty, 'GetRingtonesPath');
   add_path (TPath.GetSharedRingtonesPath, 'GetSharedRingtonesPath');
   FMediaPlayer := TMediaPlayer.Create(Self);
end; // Loaded //

procedure THeaderFooterForm.add_path (path, header: string);
var
   item: TListViewItem;
   bitmap: TBitmap;
begin
   item := List_Paths.Items.Add;
   item.ButtonText := 'button';
   item.Detail := path;
   item.Text := header;
end; // add_path //
Arnold
  • 4,578
  • 6
  • 52
  • 91
  • It does allow to write to root of external (in my case it's virtually external, though ;)) storage, many programs do that. It's not root access, so the app with permissions set (which you mentioned, I already set that, thanks) can write wherever it wants inside of the storage path. I did notice the SharedDirectories, thought about removing the last part as well, instead of hard coding, but as told, it's just very strange to me that there isn't GetSharedPath function, that would get the root of sd, instead of making all this remove-last-part stuff. It's hilarious. – That Marc Jan 18 '14 at 21:03
  • Oh, and thanks for the code. If I'd have this a week ago, it'd save me a few hours of work on checking paths manually. :D I thought that hard coding isn't good, yes. But I'm not sure if using GetSharedMusicPath and removing the last part is useful, since I can't be sure that all platforms uses sdcard/Music as default Music path. Or is there 100% sure info about that? I thought about a possibility that some uses sdcard/media/music, or something similar, which would lead to wrong path then... What's your opinion on this one? Thanks! – That Marc Jan 18 '14 at 21:05
  • Well, I checked on my Galaxy Tab 7, and it has /storage/sdcard/Music. If you strip Music you're left with /storage/sdcard which is the external root for the galaxy. As is /storage/emulated/0 for the Nexus 7. Even when it is /sdcard/media/Music, the sdcard/media well do pretty well. Best is to find the source of the GetSharedSomething path and see how it is defined. You will find the other GetShared... path definititions as well. Oh, and if you are satisfied with the answer, please flag it as correct. In this forum everybody needs votes ;-) – Arnold Jan 18 '14 at 21:42
  • Then I'll assume everyone has that path, so I'll just go with Music path and remove the last part. :) I'm not even sure why I'm complicating that much, since I'm doing the app for myself in the first place, and haven't really planned to put it on market anyway, but still, it's good to know and do things the right way, I believe. :) – That Marc Jan 18 '14 at 22:33
  • Sure! Will accept it, but I suggest you add the actual code/function to get one of shared paths and remove the last part (function to get string would be a good choice, I think), just so that your answer has an actual answer to my question, for other users when reviewing this post. :) And believe me, I know that votes are needed here :) Thanks. – That Marc Jan 18 '14 at 22:36
  • I had to write my own version of Arnold's path capture utility too because I'd not found this useful SO answer. This path capture code should be in the EMB mobile examples because this is so fundamental to starting to work with Android. – Brian Frost Sep 20 '14 at 09:39
1

Here's the function that will get you the default SDCard path from GetShared paths; The first is simple and will get you just the SDCard path from fixed path of the SharedMusic;

function GetSDCardPath: string;
var MusicPathLength: integer;
    MusicPath, SDCardPath: string;
begin
  MusicPath:=System.IOUtils.TPath.GetSharedMusicPath;
  MusicPathLength:=Length(MusicPath);
  SDCardPath:=Copy(MusicPath, 0, MusicPathLength-5);
  Result:=SDCardPath;
end;

I could add the function to extract sdcard path from any of provided paths results, but I think the example above is the most simple you could use, and works flawlessly for me. Thanks to @Arnold for help too. :)

Community
  • 1
  • 1
That Marc
  • 1,134
  • 3
  • 19
  • 42