android.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. """Android."""
  2. from __future__ import annotations
  3. import os
  4. import re
  5. import sys
  6. from functools import lru_cache
  7. from typing import cast
  8. from .api import PlatformDirsABC
  9. class Android(PlatformDirsABC):
  10. """
  11. Follows the guidance `from here <https://android.stackexchange.com/a/216132>`_. Makes use of the
  12. `appname <platformdirs.api.PlatformDirsABC.appname>`,
  13. `version <platformdirs.api.PlatformDirsABC.version>`,
  14. `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
  15. """
  16. @property
  17. def user_data_dir(self) -> str:
  18. """:return: data directory tied to the user, e.g. ``/data/user/<userid>/<packagename>/files/<AppName>``"""
  19. return self._append_app_name_and_version(cast(str, _android_folder()), "files")
  20. @property
  21. def site_data_dir(self) -> str:
  22. """:return: data directory shared by users, same as `user_data_dir`"""
  23. return self.user_data_dir
  24. @property
  25. def user_config_dir(self) -> str:
  26. """
  27. :return: config directory tied to the user, e.g. \
  28. ``/data/user/<userid>/<packagename>/shared_prefs/<AppName>``
  29. """
  30. return self._append_app_name_and_version(cast(str, _android_folder()), "shared_prefs")
  31. @property
  32. def site_config_dir(self) -> str:
  33. """:return: config directory shared by the users, same as `user_config_dir`"""
  34. return self.user_config_dir
  35. @property
  36. def user_cache_dir(self) -> str:
  37. """:return: cache directory tied to the user, e.g. e.g. ``/data/user/<userid>/<packagename>/cache/<AppName>``"""
  38. return self._append_app_name_and_version(cast(str, _android_folder()), "cache")
  39. @property
  40. def site_cache_dir(self) -> str:
  41. """:return: cache directory shared by users, same as `user_cache_dir`"""
  42. return self.user_cache_dir
  43. @property
  44. def user_state_dir(self) -> str:
  45. """:return: state directory tied to the user, same as `user_data_dir`"""
  46. return self.user_data_dir
  47. @property
  48. def user_log_dir(self) -> str:
  49. """
  50. :return: log directory tied to the user, same as `user_cache_dir` if not opinionated else ``log`` in it,
  51. e.g. ``/data/user/<userid>/<packagename>/cache/<AppName>/log``
  52. """
  53. path = self.user_cache_dir
  54. if self.opinion:
  55. path = os.path.join(path, "log") # noqa: PTH118
  56. return path
  57. @property
  58. def user_documents_dir(self) -> str:
  59. """:return: documents directory tied to the user e.g. ``/storage/emulated/0/Documents``"""
  60. return _android_documents_folder()
  61. @property
  62. def user_downloads_dir(self) -> str:
  63. """:return: downloads directory tied to the user e.g. ``/storage/emulated/0/Downloads``"""
  64. return _android_downloads_folder()
  65. @property
  66. def user_pictures_dir(self) -> str:
  67. """:return: pictures directory tied to the user e.g. ``/storage/emulated/0/Pictures``"""
  68. return _android_pictures_folder()
  69. @property
  70. def user_videos_dir(self) -> str:
  71. """:return: videos directory tied to the user e.g. ``/storage/emulated/0/DCIM/Camera``"""
  72. return _android_videos_folder()
  73. @property
  74. def user_music_dir(self) -> str:
  75. """:return: music directory tied to the user e.g. ``/storage/emulated/0/Music``"""
  76. return _android_music_folder()
  77. @property
  78. def user_desktop_dir(self) -> str:
  79. """:return: desktop directory tied to the user e.g. ``/storage/emulated/0/Desktop``"""
  80. return "/storage/emulated/0/Desktop"
  81. @property
  82. def user_runtime_dir(self) -> str:
  83. """
  84. :return: runtime directory tied to the user, same as `user_cache_dir` if not opinionated else ``tmp`` in it,
  85. e.g. ``/data/user/<userid>/<packagename>/cache/<AppName>/tmp``
  86. """
  87. path = self.user_cache_dir
  88. if self.opinion:
  89. path = os.path.join(path, "tmp") # noqa: PTH118
  90. return path
  91. @property
  92. def site_runtime_dir(self) -> str:
  93. """:return: runtime directory shared by users, same as `user_runtime_dir`"""
  94. return self.user_runtime_dir
  95. @lru_cache(maxsize=1)
  96. def _android_folder() -> str | None:
  97. """:return: base folder for the Android OS or None if it cannot be found"""
  98. try:
  99. # First try to get path to android app via pyjnius
  100. from jnius import autoclass
  101. context = autoclass("android.content.Context")
  102. result: str | None = context.getFilesDir().getParentFile().getAbsolutePath()
  103. except Exception: # noqa: BLE001
  104. # if fails find an android folder looking path on the sys.path
  105. pattern = re.compile(r"/data/(data|user/\d+)/(.+)/files")
  106. for path in sys.path:
  107. if pattern.match(path):
  108. result = path.split("/files")[0]
  109. break
  110. else:
  111. result = None
  112. return result
  113. @lru_cache(maxsize=1)
  114. def _android_documents_folder() -> str:
  115. """:return: documents folder for the Android OS"""
  116. # Get directories with pyjnius
  117. try:
  118. from jnius import autoclass
  119. context = autoclass("android.content.Context")
  120. environment = autoclass("android.os.Environment")
  121. documents_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOCUMENTS).getAbsolutePath()
  122. except Exception: # noqa: BLE001
  123. documents_dir = "/storage/emulated/0/Documents"
  124. return documents_dir
  125. @lru_cache(maxsize=1)
  126. def _android_downloads_folder() -> str:
  127. """:return: downloads folder for the Android OS"""
  128. # Get directories with pyjnius
  129. try:
  130. from jnius import autoclass
  131. context = autoclass("android.content.Context")
  132. environment = autoclass("android.os.Environment")
  133. downloads_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
  134. except Exception: # noqa: BLE001
  135. downloads_dir = "/storage/emulated/0/Downloads"
  136. return downloads_dir
  137. @lru_cache(maxsize=1)
  138. def _android_pictures_folder() -> str:
  139. """:return: pictures folder for the Android OS"""
  140. # Get directories with pyjnius
  141. try:
  142. from jnius import autoclass
  143. context = autoclass("android.content.Context")
  144. environment = autoclass("android.os.Environment")
  145. pictures_dir: str = context.getExternalFilesDir(environment.DIRECTORY_PICTURES).getAbsolutePath()
  146. except Exception: # noqa: BLE001
  147. pictures_dir = "/storage/emulated/0/Pictures"
  148. return pictures_dir
  149. @lru_cache(maxsize=1)
  150. def _android_videos_folder() -> str:
  151. """:return: videos folder for the Android OS"""
  152. # Get directories with pyjnius
  153. try:
  154. from jnius import autoclass
  155. context = autoclass("android.content.Context")
  156. environment = autoclass("android.os.Environment")
  157. videos_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DCIM).getAbsolutePath()
  158. except Exception: # noqa: BLE001
  159. videos_dir = "/storage/emulated/0/DCIM/Camera"
  160. return videos_dir
  161. @lru_cache(maxsize=1)
  162. def _android_music_folder() -> str:
  163. """:return: music folder for the Android OS"""
  164. # Get directories with pyjnius
  165. try:
  166. from jnius import autoclass
  167. context = autoclass("android.content.Context")
  168. environment = autoclass("android.os.Environment")
  169. music_dir: str = context.getExternalFilesDir(environment.DIRECTORY_MUSIC).getAbsolutePath()
  170. except Exception: # noqa: BLE001
  171. music_dir = "/storage/emulated/0/Music"
  172. return music_dir
  173. __all__ = [
  174. "Android",
  175. ]