Saludos, compañeros.
En esta entrada, quiero compartirles una pequeña práctica que realicé en Delphi XE7, en la cual obtengo información sobre los dispositivos de almacenamiento en un dispositivo Android.
Estuve buscando por algún tiempo en la red y no encontraba como realizar esta tarea, logré hacer la práctica en Android Studio, pero ahora la requería es Delphi. Desconozco si hay alguna forma más práctica y menos rebuscada de obtener estos datos, pero igual subo mi ejemplo, esperando que sea de utilidad para alguien.
Primero que nada, me encontré una utilería bastante interesante llamada Java2Pas, misma que me facilitó el trabajo al generar la interfaz para Firemonkey, las dos interfaces que necesité son android.os.Environment.pas 6,53KB 7 descargas y android.os.StatFs.pas 2,88KB 6 descargas (Estos que adjunto, son los archivos originales).
Por mi cuenta, modifiqué los PAS de las interfaces añadiendo las funciones que me permiten obtener:
- Espacio usado de almacenamiento interno.
- Espacio libre de almacenamiento interno.
- Tamaño del disco almacenamiento interno*.
- Espacio usado del dispositivo de almacenamiento predeterminado (Debería ser la SDCard, pero depende de la configuración del dispositivo).
- Espacio libre del dispositivo de almacenamiento predeterminado (Debería ser la SDCard, pero depende de la configuración del dispositivo).
- Tamaño del dispositivo de almacenamiento predeterminado (Debería ser la SDCard, pero depende de la configuración del dispositivo)*.
*Cabe mencionar que los tamaños de dispositivo los obtiene después del espacio que reserva Android para el sistema, así pues, un dispositivo de 16 GB podría mostrar un tamaño de 10 GB ya que el sistema utiliza 6 aproximadamente.
Quedaron así:
android.os.StatFs.pas
unit android.os.StatFs; interface uses SysUtils, android.os.Environment, AndroidAPI.Helpers, AndroidAPI.JNIBridge, Androidapi.JNI.JavaTypes; type TByteStringFormat = (bsfDefault, bsfBytes, bsfKB, bsfMB, bsfGB, bsfTB); JStatFs = interface; JStatFsClass = interface(JObjectClass) ['{DE76BDF6-C6A3-44F2-B699-2798F2BA4E88}'] function getAvailableBlocks: Integer; deprecated; cdecl; // ()I A: $1 function getAvailableBlocksLong: Int64; cdecl; // ()J A: $1 function getAvailableBytes: Int64; cdecl; // ()J A: $1 function getBlockCount: Integer; deprecated; cdecl; // ()I A: $1 function getBlockCountLong: Int64; cdecl; // ()J A: $1 function getBlockSize: Integer; deprecated; cdecl; // ()I A: $1 function getBlockSizeLong: Int64; cdecl; // ()J A: $1 function getFreeBlocks: Integer; deprecated; cdecl; // ()I A: $1 function getFreeBlocksLong: Int64; cdecl; // ()J A: $1 function getFreeBytes: Int64; cdecl; // ()J A: $1 function getTotalBytes: Int64; cdecl; // ()J A: $1 function init(path: JString): JStatFs; cdecl; // (Ljava/lang/String;)V A: $1 procedure restat(path: JString); cdecl; // (Ljava/lang/String;)V A: $1 end; [JavaSignature('android/os/StatFs')] JStatFs = interface(JObject) ['{9CF05AFA-FD0A-4AE1-BF6A-86D06CD77216}'] function getAvailableBlocks: Integer; deprecated; cdecl; // ()I A: $1 function getAvailableBlocksLong: Int64; cdecl; // ()J A: $1 function getAvailableBytes: Int64; cdecl; // ()J A: $1 function getBlockCount: Integer; deprecated; cdecl; // ()I A: $1 function getBlockCountLong: Int64; cdecl; // ()J A: $1 function getBlockSize: Integer; deprecated; cdecl; // ()I A: $1 function getBlockSizeLong: Int64; cdecl; // ()J A: $1 function getFreeBlocks: Integer; deprecated; cdecl; // ()I A: $1 function getFreeBlocksLong: Int64; cdecl; // ()J A: $1 function getFreeBytes: Int64; cdecl; // ()J A: $1 function getTotalBytes: Int64; cdecl; // ()J A: $1 procedure restat(path: JString); cdecl; // (Ljava/lang/String;)V A: $1 end; TJStatFs = class(TJavaGenericImport<JStatFsClass, JStatFs>) end; function GetBytesDPredeFree: Int64; function GetDPredeFree(Format: TByteStringFormat = bsfDefault): string; function GetBytesDPredeUsed: Int64; function GetDPredeUsed(Format: TByteStringFormat = bsfDefault): string; function GetBytesDPredeTotal: Int64; function GetDPredeTotal(Format: TByteStringFormat = bsfDefault): string; function GetBytesInStoraFree: Int64; function GetInStoraFree(Format: TByteStringFormat = bsfDefault): string; function GetBytesInStoraUsed: Int64; function GetInStoraUsed(Format: TByteStringFormat = bsfDefault): string; function GetBytesInStoraTotal: Int64; function GetInStoraTotal(Format: TByteStringFormat = bsfDefault): string; const KB = 1024; MB = KB * KB; GB = KB * MB; TB = Int64(KB) * GB; implementation function FormatByteString(Bytes: UInt64; Format: TByteStringFormat): string; begin if Format = bsfDefault then begin if Bytes < KB then begin Format := bsfBytes; end else if Bytes < MB then begin Format := bsfKB; end else if Bytes < GB then begin Format := bsfMB; end else if Bytes < TB then begin Format := bsfGB; end else begin Format := bsfTB; end; end; case Format of bsfBytes: Result := SysUtils.Format('%d bytes', [Bytes]); bsfKB: Result := SysUtils.Format('%.2n KB', [Bytes / KB]); bsfMB: Result := SysUtils.Format('%.2n MB', [Bytes / MB]); bsfGB: Result := SysUtils.Format('%.2n GB', [Bytes / GB]); bsfTB: Result := SysUtils.Format('%.2n TB', [Bytes / TB]); end; end; {Disco predeterminado / SD Card} function GetBytesDPredeFree: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := Stat.getAvailableBlocksLong * Stat.getBlockSizeLong; end; function GetDPredeFree(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := FormatByteString(Stat.getAvailableBlocksLong * Stat.getBlockSizeLong, Format); end; function GetBytesDPredeUsed: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := (stat.getBlockCountLong - stat.getAvailableBlocksLong) * stat.getBlockSizeLong; end; function GetDPredeUsed(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := FormatByteString((stat.getBlockCountLong - stat.getAvailableBlocksLong) * stat.getBlockSizeLong, Format); end; function GetBytesDPredeTotal: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := stat.getBlockCountLong * stat.getBlockSizeLong; end; function GetDPredeTotal(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetSDCardPath)); Result := FormatByteString(stat.getBlockCountLong * stat.getBlockSizeLong, Format); end; { Almacenamiento interno } function GetBytesInStoraFree: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := Stat.getAvailableBlocksLong * Stat.getBlockSizeLong; end; function GetInStoraFree(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := FormatByteString(Stat.getAvailableBlocksLong * Stat.getBlockSizeLong, Format); end; function GetBytesInStoraUsed: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := (stat.getBlockCountLong - stat.getAvailableBlocksLong) * stat.getBlockSizeLong; end; function GetInStoraUsed(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := FormatByteString((stat.getBlockCountLong - stat.getAvailableBlocksLong) * stat.getBlockSizeLong, Format); end; function GetBytesInStoraTotal: Int64; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := stat.getBlockCountLong * stat.getBlockSizeLong; end; function GetInStoraTotal(Format: TByteStringFormat = bsfDefault): string; var Stat: JStatFs; begin Stat := TJStatFs.JavaClass.init(StringToJString(GetPhoneStoragePath)); Result := FormatByteString(stat.getBlockCountLong * stat.getBlockSizeLong, Format); end; end.
android.os.Environment.pas
// // Generated by JavaToPas v1.5 20150831 - 132355 //////////////////////////////////////////////////////////////////////////////// unit android.os.Environment; interface uses Androidapi.Helpers, AndroidAPI.JNIBridge, Androidapi.JNI.JavaTypes; type sdCardState = (sdCardWritable, sdCardReadOnly, sdCardNotAvailable); JEnvironment = interface; JEnvironmentClass = interface(JObjectClass) ['{2185A416-0AE4-4FD9-AF1F-29622A58D6AD}'] function _GetDIRECTORY_ALARMS: JString; cdecl; // A: $9 function _GetDIRECTORY_DCIM: JString; cdecl; // A: $9 function _GetDIRECTORY_DOCUMENTS: JString; cdecl; // A: $9 function _GetDIRECTORY_DOWNLOADS: JString; cdecl; // A: $9 function _GetDIRECTORY_MOVIES: JString; cdecl; // A: $9 function _GetDIRECTORY_MUSIC: JString; cdecl; // A: $9 function _GetDIRECTORY_NOTIFICATIONS: JString; cdecl; // A: $9 function _GetDIRECTORY_PICTURES: JString; cdecl; // A: $9 function _GetDIRECTORY_PODCASTS: JString; cdecl; // A: $9 function _GetDIRECTORY_RINGTONES: JString; cdecl; // A: $9 function _GetMEDIA_BAD_REMOVAL: JString; cdecl; // A: $19 function _GetMEDIA_CHECKING: JString; cdecl; // A: $19 function _GetMEDIA_EJECTING: JString; cdecl; // A: $19 function _GetMEDIA_MOUNTED: JString; cdecl; // A: $19 function _GetMEDIA_MOUNTED_READ_ONLY: JString; cdecl; // A: $19 function _GetMEDIA_NOFS: JString; cdecl; // A: $19 function _GetMEDIA_REMOVED: JString; cdecl; // A: $19 function _GetMEDIA_SHARED: JString; cdecl; // A: $19 function _GetMEDIA_UNKNOWN: JString; cdecl; // A: $19 function _GetMEDIA_UNMOUNTABLE: JString; cdecl; // A: $19 function _GetMEDIA_UNMOUNTED: JString; cdecl; // A: $19 function getDataDirectory: JFile; cdecl; // ()Ljava/io/File; A: $9 function getDownloadCacheDirectory: JFile; cdecl; // ()Ljava/io/File; A: $9 function getExternalStorageDirectory: JFile; cdecl; // ()Ljava/io/File; A: $9 function getExternalStoragePublicDirectory(&type: JString): JFile; cdecl; // (Ljava/lang/String;)Ljava/io/File; A: $9 function getExternalStorageState: JString; cdecl; overload; // ()Ljava/lang/String; A: $9 function getExternalStorageState(path: JFile): JString; cdecl; overload; // (Ljava/io/File;)Ljava/lang/String; A: $9 function getRootDirectory: JFile; cdecl; // ()Ljava/io/File; A: $9 function getStorageState(path: JFile): JString; deprecated; cdecl; // (Ljava/io/File;)Ljava/lang/String; A: $9 function init: JEnvironment; cdecl; // ()V A: $1 function isExternalStorageEmulated: boolean; cdecl; overload; // ()Z A: $9 function isExternalStorageEmulated(path: JFile): boolean; cdecl; overload;// (Ljava/io/File;)Z A: $9 function isExternalStorageRemovable: boolean; cdecl; overload; // ()Z A: $9 function isExternalStorageRemovable(path: JFile): boolean; cdecl; overload;// (Ljava/io/File;)Z A: $9 property DIRECTORY_ALARMS: JString read _GetDIRECTORY_ALARMS; // Ljava/lang/String; A: $9 property DIRECTORY_DCIM: JString read _GetDIRECTORY_DCIM; // Ljava/lang/String; A: $9 property DIRECTORY_DOCUMENTS: JString read _GetDIRECTORY_DOCUMENTS; // Ljava/lang/String; A: $9 property DIRECTORY_DOWNLOADS: JString read _GetDIRECTORY_DOWNLOADS; // Ljava/lang/String; A: $9 property DIRECTORY_MOVIES: JString read _GetDIRECTORY_MOVIES; // Ljava/lang/String; A: $9 property DIRECTORY_MUSIC: JString read _GetDIRECTORY_MUSIC; // Ljava/lang/String; A: $9 property DIRECTORY_NOTIFICATIONS: JString read _GetDIRECTORY_NOTIFICATIONS; // Ljava/lang/String; A: $9 property DIRECTORY_PICTURES: JString read _GetDIRECTORY_PICTURES; // Ljava/lang/String; A: $9 property DIRECTORY_PODCASTS: JString read _GetDIRECTORY_PODCASTS; // Ljava/lang/String; A: $9 property DIRECTORY_RINGTONES: JString read _GetDIRECTORY_RINGTONES; // Ljava/lang/String; A: $9 property MEDIA_BAD_REMOVAL: JString read _GetMEDIA_BAD_REMOVAL; // Ljava/lang/String; A: $19 property MEDIA_CHECKING: JString read _GetMEDIA_CHECKING; // Ljava/lang/String; A: $19 property MEDIA_EJECTING: JString read _GetMEDIA_EJECTING; // Ljava/lang/String; A: $19 property MEDIA_MOUNTED: JString read _GetMEDIA_MOUNTED; // Ljava/lang/String; A: $19 property MEDIA_MOUNTED_READ_ONLY: JString read _GetMEDIA_MOUNTED_READ_ONLY; // Ljava/lang/String; A: $19 property MEDIA_NOFS: JString read _GetMEDIA_NOFS; // Ljava/lang/String; A: $19 property MEDIA_REMOVED: JString read _GetMEDIA_REMOVED; // Ljava/lang/String; A: $19 property MEDIA_SHARED: JString read _GetMEDIA_SHARED; // Ljava/lang/String; A: $19 property MEDIA_UNKNOWN: JString read _GetMEDIA_UNKNOWN; // Ljava/lang/String; A: $19 property MEDIA_UNMOUNTABLE: JString read _GetMEDIA_UNMOUNTABLE; // Ljava/lang/String; A: $19 property MEDIA_UNMOUNTED: JString read _GetMEDIA_UNMOUNTED; // Ljava/lang/String; A: $19 end; [JavaSignature('android/os/Environment')] JEnvironment = interface(JObject) ['{8C3C74C2-670C-4DC6-AE2B-1CFCF52E8359}'] end; TJEnvironment = class(TJavaGenericImport<JEnvironmentClass, JEnvironment>) end; function GetSDcardState: sdCardState; function GetSDCardPath: string; function GetPhoneStoragePath: string; const TJEnvironmentMEDIA_BAD_REMOVAL = 'bad_removal'; TJEnvironmentMEDIA_CHECKING = 'checking'; TJEnvironmentMEDIA_EJECTING = 'ejecting'; TJEnvironmentMEDIA_MOUNTED = 'mounted'; TJEnvironmentMEDIA_MOUNTED_READ_ONLY = 'mounted_ro'; TJEnvironmentMEDIA_NOFS = 'nofs'; TJEnvironmentMEDIA_REMOVED = 'removed'; TJEnvironmentMEDIA_SHARED = 'shared'; TJEnvironmentMEDIA_UNKNOWN = 'unknown'; TJEnvironmentMEDIA_UNMOUNTABLE = 'unmountable'; TJEnvironmentMEDIA_UNMOUNTED = 'unmounted'; implementation function GetSDcardState: sdCardState; var state: JString; begin state := TJEnvironment.JavaClass.getExternalStorageState; if state.equals(TJEnvironment.JavaClass.MEDIA_MOUNTED) then Result := sdCardWritable else if state.equals(TJEnvironment.JavaClass.MEDIA_MOUNTED_READ_ONLY) then Result := sdCardReadOnly else Result := sdCardNotAvailable; end; function GetSDCardPath: string; var vFile: JFile; begin vFile := TJEnvironment.JavaClass.getExternalStorageDirectory; Result := JStringToString(vFile.getPath); end; function GetPhoneStoragePath: string; var vFile: JFile; begin vFile := TJEnvironment.JavaClass.getDataDirectory; Result := JStringToString(vFile.getPath); end; end.
Con estas dos unidades, serán capaces de obtener lo necesario para graficar el espacio en disco de su dispositivo Android u obtener el espacio disponible antes de descargar o almacenar un archivo que podría ser relativamente grande, entre otros usos que se les ocurran.
Andaba inspirado, así que en mi proyecto añadí un par de monerías a mi proyecto y quedó de esta manera:
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMXTee.Series, FMXTee.Engine, FMXTee.Procs, FMXTee.Chart, FMX.Objects, FMX.Layouts, AndroidAPI.JNI.GraphicsContentViewText, AndroidAPI.JNI.JavaTypes, AndroidAPI.JNI.OS, FMX.platform.Android, Androidapi.JNIBridge, Androidapi.Jni, androidapi.JNI.Net, FMX.Helpers.Android, Androidapi.Helpers; type TForm1 = class(TForm) btn1: TButton; lblBatt: TLabel; loBatt: TLayout; loPred: TLayout; lblPred: TLabel; loInt: TLayout; lblInt: TLabel; imgDiscoInt: TImage; rctnglIntOcupa: TRectangle; lblTitPred: TLabel; lblTitInt: TLabel; lblTitBatt: TLabel; loDiscInt: TLayout; loDiscPred: TLayout; rctnglPredOcupa: TRectangle; imgDiscoPred: TImage; vrtscrlbx1: TVertScrollBox; loimgBatt: TLayout; rctnglBatt: TRectangle; imgBatt: TImage; procedure btn1Click(Sender: TObject); private public end; const BateryHealthStr: array[1..7] of string = ('unknown', 'Good', 'Overhead', 'Dead', 'Over voltage', 'unspecified failure', 'Cold'); BateryPluggedStr: array[1..4] of string = ('AC plugged', 'USB plugged', 'unknown', 'Wireless plugged'); BateryStatusStr: array[1..5] of string = ('Unknown', 'Charging', 'Discharging', 'Not charging', 'Full'); var Form1: TForm1; implementation uses android.os.Environment, android.os.StatFs; {$R *.fmx} procedure TForm1.btn1Click(Sender: TObject); var aColor: TAlphaColorRec; PercUso, PercLib: Double; rightMa: Integer; filter: JIntentFilter; intentBatt: JIntent; iLevel, iScale: Integer; i: Integer; Str: JString; b: boolean; myContext: JContext; begin { BATERÍA } myContext := SharedActivityContext; filter := TJIntentFilter.Create; filter.addAction(TJIntent.JavaClass.ACTION_BATTERY_CHANGED); intentBatt := myContext.registerReceiver(nil, filter); i := intentBatt.getIntExtra(StringToJString('health'), -1); lblBatt.Text := 'Salut: ' + BateryHealthStr[i] + #13 + #10; iLevel := intentBatt.getIntExtra(StringToJString('level'), -1); lblBatt.Text := lblBatt.Text + 'Level: ' + IntToStr(iLevel) + #13 + #10; i := intentBatt.getIntExtra(StringToJString('plugged'), -1); lblBatt.Text := lblBatt.Text + 'Enchufado: ' + BateryPluggedStr[i] + #13 + #10; b := intentBatt.getBooleanExtra(StringToJString('present'), False); lblBatt.Text := lblBatt.Text + 'Presente: ' + BoolToStr(b, True) + #13 + #10; iScale := intentBatt.getIntExtra(StringToJString('scale'), -1); lblBatt.Text := lblBatt.Text + 'Escala: ' + IntToStr(iScale) + #13 + #10; i := intentBatt.getIntExtra(StringToJString('status'), -1); lblBatt.Text := lblBatt.Text + 'Estado: ' + BateryStatusStr[i] + #13 + #10; Str := intentBatt.getStringExtra(StringToJString('technology')); lblBatt.Text := lblBatt.Text + 'Tecnología: ' + JStringToString(Str) + #13 + #10; i := intentBatt.getIntExtra(StringToJString('temperature'), -1); lblBatt.Text := lblBatt.Text + 'Temperatura: ' + FloatToStr(i / 10) + '°' + #13 + #10; i := intentBatt.getIntExtra(StringToJString('voltage'), -1); lblBatt.Text := lblBatt.Text + 'Voltaje: ' + FloatToStr(i / 1000) + ' v.' + #13 + #10; i := (100 * iLevel) div iScale; lblBatt.Text := lblBatt.Text + IntToStr(i) + '%'; aColor.R := Round(255 * (1 - (i / 100))); aColor.G := Round(255 * (i / 100)); aColor.B := 0; aColor.A := 150; rctnglBatt.Fill.Color := TAlphaColor(aColor); rctnglBatt.Scale.X := (i / 100); { ALMACENAMIENTO INTERNO } PercUso := GetBytesInStoraUsed / GetBytesInStoraTotal; PercLib := GetBytesInStoraFree / GetBytesInStoraTotal; aColor.R := Round(255 * PercUso); aColor.G := Round(255 * PercLib); aColor.B := 0; aColor.A := 150; rctnglIntOcupa.Fill.Color := TAlphaColor(aColor); rctnglIntOcupa.Scale.X := PercUso; lblInt.Text := GetPhoneStoragePath + #13 + #10 + GetInStoraFree + ' Libres' + #13 + #10 + GetInStoraUsed + ' Utilizados' + #13 + #10 + GetInStoraTotal + ' en disco' + #13 + #10 + IntToStr(Round(PercLib * 100)) + ' % libre'; { SD / DISP. ALMACENAMIENTO PREDETERMINADO } PercUso := GetBytesDPredeUsed / GetBytesDPredeTotal; PercLib := GetBytesDPredeFree / GetBytesDPredeTotal; aColor.R := Round(255 * PercUso); aColor.G := Round(255 * PercLib); aColor.B := 0; aColor.A := 150; rctnglPredOcupa.Fill.Color := TAlphaColor(aColor); rctnglPredOcupa.Scale.X := PercUso; lblPred.Text := GetSDCardPath + #13 + #10 + GetDPredeFree + ' Libres' + #13 + #10 + GetDPredeUsed + ' Utilizados' + #13 + #10 + GetDPredeTotal + ' en disco' + #13 + #10 + IntToStr(Round(PercLib * 100)) + ' % libre'; end; end.
Screenshot_2016-12-06-16-28-41.png 76,4KB 2 descargas
Aqui, testAlmacenamiento2.rar 139,55KB 18 descargas les dejo el proyecto completo.
Espero que sea de ayuda. Saludos.