03b34f705d38feeb3a9a2f76dd9f4a6b5d536feb
[oweals/minetest.git] / build / android / src / main / java / net.minetest.minetest / MinetestAssetCopy.java
1 package net.minetest.minetest;
2
3 import android.app.Activity;
4 import android.content.res.AssetFileDescriptor;
5 import android.os.AsyncTask;
6 import android.os.Build;
7 import android.os.Bundle;
8 import android.os.Environment;
9 import android.util.Log;
10 import android.view.Display;
11 import android.view.View;
12 import android.widget.ProgressBar;
13 import android.widget.TextView;
14
15 import java.io.BufferedReader;
16 import java.io.File;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.InputStreamReader;
21 import java.io.OutputStream;
22 import java.util.Iterator;
23 import java.util.Vector;
24
25 public class MinetestAssetCopy extends Activity {
26         ProgressBar m_ProgressBar;
27         TextView m_Filename;
28         copyAssetTask m_AssetCopy;
29
30         @Override
31         public void onCreate(Bundle savedInstanceState) {
32                 super.onCreate(savedInstanceState);
33                 setContentView(R.layout.assetcopy);
34                 m_ProgressBar = findViewById(R.id.progressBar1);
35                 m_Filename = findViewById(R.id.textView1);
36                 Display display = getWindowManager().getDefaultDisplay();
37                 m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
38                 m_ProgressBar.invalidate();
39
40                 /* check if there's already a copy in progress and reuse in case it is*/
41                 MinetestAssetCopy prevActivity =
42                                 (MinetestAssetCopy) getLastNonConfigurationInstance();
43                 if (prevActivity != null) {
44                         m_AssetCopy = prevActivity.m_AssetCopy;
45                 } else {
46                         m_AssetCopy = new copyAssetTask();
47                         m_AssetCopy.execute();
48                 }
49         }
50
51         @Override
52         protected void onResume() {
53                 super.onResume();
54                 makeFullScreen();
55         }
56         
57         @Override
58         protected void onDestroy() {
59                 super.onDestroy();
60                 if (m_AssetCopy != null) {
61                         m_AssetCopy.cancel(true);
62                 }
63         }
64
65         public void makeFullScreen() {
66                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
67                         this.getWindow().getDecorView().setSystemUiVisibility(
68                                         View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
69                         );
70                 }
71         }
72
73         @Override
74         public void onWindowFocusChanged(boolean hasFocus) {
75                 super.onWindowFocusChanged(hasFocus);
76                 if (hasFocus) {
77                         makeFullScreen();
78                 }
79         }
80
81         /* preserve asset copy background task to prevent restart of copying */
82         /* this way of doing it is not recommended for latest android version */
83         /* but the recommended way isn't available on android 2.x */
84         public Object onRetainNonConfigurationInstance() {
85                 return this;
86         }
87
88         private static class copyAssetTask extends AsyncTask<String, Integer, String> {
89                 boolean m_copy_started = false;
90                 String m_Foldername = "media";
91                 Vector<String> m_foldernames;
92                 Vector<String> m_filenames;
93                 Vector<String> m_tocopy;
94                 Vector<String> m_asset_size_unknown;
95
96                 private long getFullSize(String filename) {
97                         long size = 0;
98                         try {
99                                 InputStream src = getAssets().open(filename);
100                                 byte[] buf = new byte[4096];
101
102                                 int len = 0;
103                                 while ((len = src.read(buf)) > 0) {
104                                         size += len;
105                                 }
106                         } catch (IOException e) {
107                                 e.printStackTrace();
108                         }
109                         return size;
110                 }
111
112                 @Override
113                 protected String doInBackground(String... files) {
114                         m_foldernames = new Vector<String>();
115                         m_filenames = new Vector<String>();
116                         m_tocopy = new Vector<String>();
117                         m_asset_size_unknown = new Vector<String>();
118                         String baseDir =
119                                         Environment.getExternalStorageDirectory().getAbsolutePath()
120                                                         + "/";
121
122
123                         // prepare temp folder
124                         File TempFolder = new File(baseDir + "Minetest/tmp/");
125
126                         if (!TempFolder.exists()) {
127                                 TempFolder.mkdir();
128                         } else {
129                                 File[] todel = TempFolder.listFiles();
130
131                                 for (int i = 0; i < todel.length; i++) {
132                                         Log.v("MinetestAssetCopy", "deleting: " + todel[i].getAbsolutePath());
133                                         todel[i].delete();
134                                 }
135                         }
136
137                         // add a .nomedia file
138                         try {
139                                 OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
140                                 dst.close();
141                         } catch (IOException e) {
142                                 Log.e("MinetestAssetCopy", "Failed to create .nomedia file");
143                                 e.printStackTrace();
144                         }
145
146
147                         // build lists from prepared data
148                         BuildFolderList();
149                         BuildFileList();
150
151                         // scan filelist
152                         ProcessFileList();
153
154                         // doing work
155                         m_copy_started = true;
156                         m_ProgressBar.setMax(m_tocopy.size());
157
158                         for (int i = 0; i < m_tocopy.size(); i++) {
159                                 try {
160                                         String filename = m_tocopy.get(i);
161                                         publishProgress(i);
162
163                                         boolean asset_size_unknown = false;
164                                         long filesize = -1;
165
166                                         if (m_asset_size_unknown.contains(filename)) {
167                                                 File testme = new File(baseDir + "/" + filename);
168
169                                                 if (testme.exists()) {
170                                                         filesize = testme.length();
171                                                 }
172                                                 asset_size_unknown = true;
173                                         }
174
175                                         InputStream src;
176                                         try {
177                                                 src = getAssets().open(filename);
178                                         } catch (IOException e) {
179                                                 Log.e("MinetestAssetCopy", "Copying file: " + filename + " FAILED (not in assets)");
180                                                 e.printStackTrace();
181                                                 continue;
182                                         }
183
184                                         // Transfer bytes from in to out
185                                         byte[] buf = new byte[1024];
186                                         int len = src.read(buf, 0, 1024);
187
188                                         /* following handling is crazy but we need to deal with    */
189                                         /* compressed assets.Flash chips limited livetime due to   */
190                                         /* write operations, we can't allow large files to destroy */
191                                         /* users flash.                                            */
192                                         if (asset_size_unknown) {
193                                                 if ((len > 0) && (len < buf.length) && (len == filesize)) {
194                                                         src.close();
195                                                         continue;
196                                                 }
197
198                                                 if (len == buf.length) {
199                                                         src.close();
200                                                         long size = getFullSize(filename);
201                                                         if (size == filesize) {
202                                                                 continue;
203                                                         }
204                                                         src = getAssets().open(filename);
205                                                         len = src.read(buf, 0, 1024);
206                                                 }
207                                         }
208                                         if (len > 0) {
209                                                 int total_filesize = 0;
210                                                 OutputStream dst;
211                                                 try {
212                                                         dst = new FileOutputStream(baseDir + "/" + filename);
213                                                 } catch (IOException e) {
214                                                         Log.e("MinetestAssetCopy", "Copying file: " + baseDir +
215                                                                         "/" + filename + " FAILED (couldn't open output file)");
216                                                         e.printStackTrace();
217                                                         src.close();
218                                                         continue;
219                                                 }
220                                                 dst.write(buf, 0, len);
221                                                 total_filesize += len;
222
223                                                 while ((len = src.read(buf)) > 0) {
224                                                         dst.write(buf, 0, len);
225                                                         total_filesize += len;
226                                                 }
227
228                                                 dst.close();
229                                                 Log.v("MinetestAssetCopy", "Copied file: " +
230                                                                 m_tocopy.get(i) + " (" + total_filesize +
231                                                                 " bytes)");
232                                         } else if (len < 0) {
233                                                 Log.e("MinetestAssetCopy", "Copying file: " +
234                                                                 m_tocopy.get(i) + " failed, size < 0");
235                                         }
236                                         src.close();
237                                 } catch (IOException e) {
238                                         Log.e("MinetestAssetCopy", "Copying file: " +
239                                                         m_tocopy.get(i) + " failed");
240                                         e.printStackTrace();
241                                 }
242                         }
243                         return "";
244                 }
245
246                 /**
247                  * update progress bar
248                  */
249                 protected void onProgressUpdate(Integer... progress) {
250
251                         if (m_copy_started) {
252                                 boolean shortened = false;
253                                 String todisplay = m_tocopy.get(progress[0]);
254                                 m_ProgressBar.setProgress(progress[0]);
255                                 m_Filename.setText(todisplay);
256                         } else {
257                                 boolean shortened = false;
258                                 String todisplay = m_Foldername;
259                                 String full_text = "scanning " + todisplay + " ...";
260                                 m_Filename.setText(full_text);
261                         }
262                 }
263
264                 /**
265                  * check all files and folders in filelist
266                  */
267                 protected void ProcessFileList() {
268                         String FlashBaseDir =
269                                         Environment.getExternalStorageDirectory().getAbsolutePath();
270
271                         Iterator itr = m_filenames.iterator();
272
273                         while (itr.hasNext()) {
274                                 String current_path = (String) itr.next();
275                                 String FlashPath = FlashBaseDir + "/" + current_path;
276
277                                 if (isAssetFolder(current_path)) {
278                                         /* store information and update gui */
279                                         m_Foldername = current_path;
280                                         publishProgress(0);
281
282                                         /* open file in order to check if it's a folder */
283                                         File current_folder = new File(FlashPath);
284                                         if (!current_folder.exists()) {
285                                                 if (!current_folder.mkdirs()) {
286                                                         Log.e("MinetestAssetCopy", "\t failed create folder: " +
287                                                                         FlashPath);
288                                                 } else {
289                                                         Log.v("MinetestAssetCopy", "\t created folder: " +
290                                                                         FlashPath);
291                                                 }
292                                         }
293
294                                         continue;
295                                 }
296
297                                 /* if it's not a folder it's most likely a file */
298                                 boolean refresh = true;
299
300                                 File testme = new File(FlashPath);
301
302                                 long asset_filesize = -1;
303                                 long stored_filesize = -1;
304
305                                 if (testme.exists()) {
306                                         try {
307                                                 AssetFileDescriptor fd = getAssets().openFd(current_path);
308                                                 asset_filesize = fd.getLength();
309                                                 fd.close();
310                                         } catch (IOException e) {
311                                                 refresh = true;
312                                                 m_asset_size_unknown.add(current_path);
313                                                 Log.e("MinetestAssetCopy", "Failed to open asset file \"" +
314                                                                 FlashPath + "\" for size check");
315                                         }
316
317                                         stored_filesize = testme.length();
318
319                                         if (asset_filesize == stored_filesize) {
320                                                 refresh = false;
321                                         }
322
323                                 }
324
325                                 if (refresh) {
326                                         m_tocopy.add(current_path);
327                                 }
328                         }
329                 }
330
331                 /**
332                  * read list of folders prepared on package build
333                  */
334                 protected void BuildFolderList() {
335                         try {
336                                 InputStream is = getAssets().open("index.txt");
337                                 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
338
339                                 String line = reader.readLine();
340                                 while (line != null) {
341                                         m_foldernames.add(line);
342                                         line = reader.readLine();
343                                 }
344                                 is.close();
345                         } catch (IOException e1) {
346                                 Log.e("MinetestAssetCopy", "Error on processing index.txt");
347                                 e1.printStackTrace();
348                         }
349                 }
350
351                 /**
352                  * read list of asset files prepared on package build
353                  */
354                 protected void BuildFileList() {
355                         long entrycount = 0;
356                         try {
357                                 InputStream is = getAssets().open("filelist.txt");
358                                 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
359
360                                 String line = reader.readLine();
361                                 while (line != null) {
362                                         m_filenames.add(line);
363                                         line = reader.readLine();
364                                         entrycount++;
365                                 }
366                                 is.close();
367                         } catch (IOException e1) {
368                                 Log.e("MinetestAssetCopy", "Error on processing filelist.txt");
369                                 e1.printStackTrace();
370                         }
371                 }
372
373                 protected void onPostExecute(String result) {
374                         finish();
375                 }
376
377                 protected boolean isAssetFolder(String path) {
378                         return m_foldernames.contains(path);
379                 }
380         }
381 }