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