Prechádzať zdrojové kódy

* android: Use ICU to get timezone information if running on an Android version where libc does not implement timezone.

git-svn-id: trunk@34348 -
yury 9 rokov pred
rodič
commit
064375ea72

+ 3 - 3
rtl/android/Makefile

@@ -3572,7 +3572,7 @@ endif
 .NOTPARALLEL:
 include $(INC)/makefile.inc
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
-SYSINCDEPS:=$(SYSINCDEPS) sysandroid.inc
+SYSINCDEPS:=$(SYSINCDEPS) sysandroidh.inc sysandroid.inc
 include $(PROCINC)/makefile.cpu
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS)
@@ -3598,7 +3598,7 @@ strings$(PPUEXT) : $(INC)/strings.pp $(INC)/stringsi.inc\
 	$(COMPILER) $(INC)/strings.pp
 unix$(PPUEXT) : $(UNIXINC)/unix.pp strings$(PPUEXT) baseunix$(PPUEXT) $(INC)/textrec.inc $(INC)/filerec.inc \
 		 $(LINUXINC)/unxconst.inc $(UNIXINC)/timezone.inc $(SYSTEMUNIT)$(PPUEXT) \
-		 $(LINUXINC)/unxfunc.inc unixandroid.inc
+		 $(LINUXINC)/unxfunc.inc unixandroid.inc cwstring$(PPUEXT)
 	$(COMPILER) $(UNIXINC)/unix.pp
 syscall$(PPUEXT) : $(UNIXINC)/syscall.pp $(LINUXINC)/$(ARCH)/syscallh.inc $(LINUXINC)/$(ARCH)/sysnr.inc $(SYSTEMUNIT)$(PPUEXT)
 	$(COMPILER) $(UNIXINC)/syscall.pp
@@ -3612,7 +3612,7 @@ baseunix$(PPUEXT) : $(UNIXINC)/baseunix.pp $(LINUXINC)/errno.inc $(LINUXINC)/pty
   $(LINUXINC)/ostypes.inc $(LINUXINC)/osmacro.inc $(UNIXINC)/gensigset.inc \
   $(UNIXINC)/genfuncs.inc $(SYSTEMUNIT)$(PPUEXT)
 	$(COMPILER) $(UNIXINC)/baseunix.pp
-dl$(PPUEXT) : $(UNIXINC)/dl.pp $(SYSTEMUNIT)$(PPUEXT) dlandroid.inc
+dl$(PPUEXT) : $(UNIXINC)/dl.pp $(SYSTEMUNIT)$(PPUEXT) ctypes$(PPUEXT) dlandroid.inc
 	$(COMPILER) $(UNIXINC)/dl.pp
 dynlibs$(PPUEXT) : $(INC)/dynlibs.pas $(UNIXINC)/dynlibs.inc dl$(PPUEXT) objpas$(PPUEXT)
 	$(COMPILER) $(INC)/dynlibs.pas

+ 3 - 3
rtl/android/Makefile.fpc

@@ -83,7 +83,7 @@ OBJPASDIR=$(RTL)/objpas
 # SYSINCNAMES
 include $(INC)/makefile.inc
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
-SYSINCDEPS:=$(SYSINCDEPS) sysandroid.inc
+SYSINCDEPS:=$(SYSINCDEPS) sysandroidh.inc sysandroid.inc
 
 # Get the processor dependent include file names.
 # This will set the following variables :
@@ -139,7 +139,7 @@ strings$(PPUEXT) : $(INC)/strings.pp $(INC)/stringsi.inc\
 
 unix$(PPUEXT) : $(UNIXINC)/unix.pp strings$(PPUEXT) baseunix$(PPUEXT) $(INC)/textrec.inc $(INC)/filerec.inc \
                  $(LINUXINC)/unxconst.inc $(UNIXINC)/timezone.inc $(SYSTEMUNIT)$(PPUEXT) \
-                 $(LINUXINC)/unxfunc.inc unixandroid.inc
+                 $(LINUXINC)/unxfunc.inc unixandroid.inc cwstring$(PPUEXT)
         $(COMPILER) $(UNIXINC)/unix.pp
 
 syscall$(PPUEXT) : $(UNIXINC)/syscall.pp $(LINUXINC)/$(ARCH)/syscallh.inc $(LINUXINC)/$(ARCH)/sysnr.inc $(SYSTEMUNIT)$(PPUEXT)
@@ -158,7 +158,7 @@ baseunix$(PPUEXT) : $(UNIXINC)/baseunix.pp $(LINUXINC)/errno.inc $(LINUXINC)/pty
   $(UNIXINC)/genfuncs.inc $(SYSTEMUNIT)$(PPUEXT)
         $(COMPILER) $(UNIXINC)/baseunix.pp
 
-dl$(PPUEXT) : $(UNIXINC)/dl.pp $(SYSTEMUNIT)$(PPUEXT) dlandroid.inc
+dl$(PPUEXT) : $(UNIXINC)/dl.pp $(SYSTEMUNIT)$(PPUEXT) ctypes$(PPUEXT) dlandroid.inc
         $(COMPILER) $(UNIXINC)/dl.pp
 
 dynlibs$(PPUEXT) : $(INC)/dynlibs.pas $(UNIXINC)/dynlibs.inc dl$(PPUEXT) objpas$(PPUEXT)

+ 83 - 8
rtl/android/unixandroid.inc

@@ -13,6 +13,79 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  **********************************************************************}
 
+type
+  UErrorCode = SizeInt;
+  int32_t = longint;
+  uint32_t = longword;
+  UBool = LongBool;
+
+  UCalendar = pointer;
+  UCalendarType = longint;
+  UCalendarDisplayNameType = longint;
+  UCalendarDateFields = longint;
+
+const
+  UCAL_STANDARD = 0;
+  UCAL_SHORT_STANDARD = 1;
+  UCAL_DST = 2;
+  UCAL_SHORT_DST = 3;
+
+  UCAL_ZONE_OFFSET = 15;
+  UCAL_DST_OFFSET  = 16;
+
+var
+  ucal_open: function (zoneID: PUnicodeChar; len: int32_t; locale: PAnsiChar; ctype: UCalendarType; var status: UErrorCode): UCalendar; cdecl;
+  ucal_close: procedure (cal: UCalendar); cdecl;
+  ucal_getTimeZoneDisplayName: function (cal: UCalendar; dtype: UCalendarDisplayNameType; locale: PAnsiChar; result: PUnicodeChar; resultLength: int32_t;
+                                         var status: UErrorCode): int32_t; cdecl;
+  ucal_inDaylightTime: function (cal: UCalendar; var status: UErrorCode): UBool; cdecl;
+  ucal_get: function (cal: UCalendar; field: UCalendarDateFields; var status: UErrorCode): int32_t; cdecl;
+
+var
+  TZStandardName: utf8string;
+  TZDaylightName: utf8string;
+
+function GetIcuProc(const Name: AnsiString; var ProcPtr; libId: longint): boolean; external name 'CWSTRING_GET_ICU_PROC';
+
+procedure ReadTimeZoneFromICU;
+var
+  locale: utf8string;
+  tz: unicodestring;
+  res: unicodestring;
+  err: UErrorCode;
+  cal: UCalendar;
+begin
+  if not GetIcuProc('ucal_open', ucal_open, 1) then exit;
+  if not GetIcuProc('ucal_close', ucal_close, 1) then exit;
+  if not GetIcuProc('ucal_getTimeZoneDisplayName', ucal_getTimeZoneDisplayName, 1) then exit;
+  if not GetIcuProc('ucal_inDaylightTime', ucal_inDaylightTime, 1) then exit;
+  if not GetIcuProc('ucal_get', ucal_get, 1) then exit;
+
+  locale:='en_US';
+  tz:=unicodestring(GetSystemProperty('persist.sys.timezone'));
+  err:=0;
+  cal:=ucal_open(PUnicodeChar(tz), Length(tz), PAnsiChar(locale), 0, err);
+  if cal = nil then
+    exit;
+  tzdaylight:=ucal_inDaylightTime(cal, err);
+
+  SetLength(res, 200);
+  SetLength(res, ucal_getTimeZoneDisplayName(cal, UCAL_SHORT_STANDARD, PAnsiChar(locale), PUnicodeChar(res), Length(res), err));
+  TZStandardName:=utf8string(res);
+  tzname[False]:=PAnsiChar(TZStandardName);
+
+  SetLength(res, 200);
+  SetLength(res, ucal_getTimeZoneDisplayName(cal, UCAL_SHORT_DST, PAnsiChar(locale), PUnicodeChar(res), Length(res), err));
+  TZDaylightName:=utf8string(res);
+  tzname[True]:=PAnsiChar(TZDaylightName);
+
+  Tzseconds:=ucal_get(cal, UCAL_ZONE_OFFSET, err) div 1000;
+  if tzdaylight then
+    Tzseconds:=Tzseconds + ucal_get(cal, UCAL_DST_OFFSET, err) div 1000;
+
+  ucal_close(cal);
+end;
+
 type
    Ptm = ^tm;
    tm = record
@@ -34,10 +107,8 @@ function localtime(t: PLongInt): Ptm; cdecl; external 'c' name 'localtime';
 
 var
   c_tzname: array[0..1] of PAnsiChar; external 'c' name 'tzname';
-  c_timezone: longint; external 'c' name 'timezone';
-  c_daylignt: shortint; external 'c' name 'daylight';
 
-procedure InitLocalTime;
+procedure ReadTimeZoneFromLibC;
 var
   t: longint;
   tt: Ptm;
@@ -50,10 +121,14 @@ begin
     begin
       tzdaylight:=tt^.tm_isdst <> 0;
       tzseconds:=tt^.tm_gmtoff;
-    end
-  else
-    begin
-      tzdaylight:=c_daylignt <> 0;
-      tzseconds:=-c_timezone;
     end;
 end;
+
+procedure InitLocalTime;
+begin
+  ReadTimeZoneFromLibC;
+  // If cuurent Android version is too old and does not support timezone
+  // in libc, use ICU library.
+  if tzname[false] = nil then
+    ReadTimeZoneFromICU;
+end;

+ 5 - 1
rtl/unix/unix.pp

@@ -15,7 +15,11 @@
 Unit Unix;
 Interface
 
-Uses BaseUnix,UnixType;
+Uses
+{$ifdef android}
+  cwstring,
+{$endif android}
+  BaseUnix,UnixType;
 // If you deprecated new symbols, please annotate the version.
 // this makes it easier to decide if they can already be removed.