blob: 7be632cd27eb4bf4a10b4322e54a51feea7eb117 [file] [log] [blame]
Jose Pascoalb690af12014-10-06 18:29:26 +01001package com.fairphone.updater.fragments;
2
Jose Pascoal54b3ae62014-10-07 20:29:58 +01003import java.io.File;
4import java.io.IOException;
5import java.util.concurrent.TimeoutException;
6
Jose Pascoalb690af12014-10-06 18:29:26 +01007import android.app.DownloadManager;
Jose Pascoal54b3ae62014-10-07 20:29:58 +01008import android.app.ProgressDialog;
9import android.content.BroadcastReceiver;
10import android.content.Context;
11import android.content.Intent;
12import android.content.IntentFilter;
13import android.content.res.Resources;
14import android.content.res.Resources.NotFoundException;
Jose Pascoalb690af12014-10-06 18:29:26 +010015import android.database.Cursor;
Jose Pascoal54b3ae62014-10-07 20:29:58 +010016import android.os.AsyncTask;
Jose Pascoalb690af12014-10-06 18:29:26 +010017import android.os.Bundle;
18import android.os.Environment;
19import android.util.Log;
20import android.view.LayoutInflater;
21import android.view.View;
Jose Pascoal54b3ae62014-10-07 20:29:58 +010022import android.view.View.OnClickListener;
Jose Pascoalb690af12014-10-06 18:29:26 +010023import android.view.ViewGroup;
24import android.widget.Button;
25import android.widget.LinearLayout;
26import android.widget.ProgressBar;
27import android.widget.TextView;
28import android.widget.Toast;
29
30import com.fairphone.updater.FairphoneUpdater2Activity.HeaderType;
31import com.fairphone.updater.FairphoneUpdater2Activity.UpdaterState;
32import com.fairphone.updater.R;
33import com.fairphone.updater.Version;
Jose Pascoal54b3ae62014-10-07 20:29:58 +010034import com.fairphone.updater.VersionParserHelper;
35import com.fairphone.updater.gappsinstaller.GappsInstallerHelper;
Jose Pascoalb690af12014-10-06 18:29:26 +010036import com.fairphone.updater.tools.Utils;
Jose Pascoal54b3ae62014-10-07 20:29:58 +010037import com.stericson.RootTools.RootTools;
38import com.stericson.RootTools.exceptions.RootDeniedException;
39import com.stericson.RootTools.execution.CommandCapture;
40import com.stericson.RootTools.execution.Shell;
Jose Pascoalb690af12014-10-06 18:29:26 +010041
42public class DownloadAndRestartFragment extends BaseFragment {
43
44 protected static final String TAG = DownloadAndRestartFragment.class
45 .getSimpleName();
46
47 private TextView mDownloadVersionName;
48 private LinearLayout mVersionDownloadingGroup;
49 private ProgressBar mVersionDownloadProgressBar;
50 private LinearLayout mVersionInstallGroup;
51 private Button mRestartButton;
52 private Button mCancelButton;
53 private Version mSelectedVersion;
54
Jose Pascoal54b3ae62014-10-07 20:29:58 +010055 private DownloadManager mDownloadManager;
56
57 private DownloadBroadCastReceiver mDownloadBroadCastReceiver;
58
59 private long mLatestUpdateDownloadId;
60
Jose Pascoalb690af12014-10-06 18:29:26 +010061 @Override
62 public View onCreateView(LayoutInflater inflater, ViewGroup container,
63 Bundle savedInstanceState) {
64 // Inflate the layout for this fragment
65 mSelectedVersion = mainActivity.getSelectedVersion();
66 View view = inflateViewByImageType(inflater, container);
67
68 setupLayout(view);
Jose Pascoal54b3ae62014-10-07 20:29:58 +010069
Jose Pascoalb690af12014-10-06 18:29:26 +010070 updateHeader();
71 mDownloadVersionName.setText(mainActivity
72 .getVersionName(mSelectedVersion));
73
74 toggleDownloadProgressAndRestart();
75
76 return view;
77 }
78
79 private void toggleDownloadProgressAndRestart() {
80 switch (mainActivity.getCurrentUpdaterState()) {
81 case DOWNLOAD:
Jose Pascoal54b3ae62014-10-07 20:29:58 +010082 setupDownloadState();
Jose Pascoalb690af12014-10-06 18:29:26 +010083
84 mVersionInstallGroup.setVisibility(View.GONE);
85 mVersionDownloadingGroup.setVisibility(View.VISIBLE);
86 break;
87
88 case PREINSTALL:
Jose Pascoal54b3ae62014-10-07 20:29:58 +010089 setupPreInstallState();
90
Jose Pascoalb690af12014-10-06 18:29:26 +010091 mVersionDownloadingGroup.setVisibility(View.GONE);
92 mVersionInstallGroup.setVisibility(View.VISIBLE);
93 break;
94
95 default:
96 break;
97 }
Jose Pascoal54b3ae62014-10-07 20:29:58 +010098
99 mCancelButton.setOnClickListener(new OnClickListener() {
100
101 @Override
102 public void onClick(View v) {
103 removeLastUpdateDownload();
104 mainActivity.updateStatePreference(UpdaterState.NORMAL);
105 mainActivity.removeLastFragment();
106 }
107 });
Jose Pascoalb690af12014-10-06 18:29:26 +0100108 }
109
110 private void updateHeader() {
111 if (mSelectedVersion != null) {
112 if (Version.IMAGE_TYPE_FAIRPHONE.equalsIgnoreCase(mSelectedVersion
113 .getImageType())) {
114 mainActivity.updateHeader(HeaderType.MAIN_FAIRPHONE, "");
115 } else if (Version.IMAGE_TYPE_AOSP
116 .equalsIgnoreCase(mSelectedVersion.getImageType())) {
117 mainActivity.updateHeader(HeaderType.MAIN_ANDROID, "");
118 }
119 } else {
120 mainActivity.updateHeader(HeaderType.MAIN_FAIRPHONE, "");
121 }
122 }
123
124 private void startDownloadProgressUpdateThread() {
125 new Thread(new Runnable() {
126
127 @Override
128 public void run() {
129
130 boolean downloading = true;
131
Jose Pascoal54b3ae62014-10-07 20:29:58 +0100132 long latestUpdateDownloadId = mainActivity
133 .getLatestDownloadId();
134 while (latestUpdateDownloadId != 0 && downloading) {
Jose Pascoalb690af12014-10-06 18:29:26 +0100135
136 DownloadManager.Query q = new DownloadManager.Query();
137 q.setFilterById(latestUpdateDownloadId);
138
Jose Pascoal54b3ae62014-10-07 20:29:58 +0100139 Cursor cursor = mDownloadManager.query(q);
Jose Pascoalb690af12014-10-06 18:29:26 +0100140 if (cursor != null) {
141 cursor.moveToFirst();
142 try {
143 int bytes_downloaded = cursor.getInt(cursor
144 .getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
145 int bytes_total = cursor.getInt(cursor
146 .getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
147
148 if ((bytes_total + 10000) > Utils
149 .getAvailablePartitionSizeInBytes(Environment
150 .getExternalStorageDirectory())) {
151 downloading = false;
152 Toast.makeText(
153 mainActivity,
154 getResources()
155 .getString(
156 R.string.noSpaceAvailableSdcard),
157 Toast.LENGTH_LONG).show();
158 mainActivity.changeState(UpdaterState.NORMAL);
159 }
160
161 if (cursor.getInt(cursor
162 .getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
163 downloading = false;
164
165 bytes_downloaded = 0;
166 bytes_total = 0;
167 }
168
169 mVersionDownloadProgressBar
170 .setProgress(bytes_downloaded);
Jose Pascoal54b3ae62014-10-07 20:29:58 +0100171 mVersionDownloadProgressBar.setMax(bytes_total);
Jose Pascoalb690af12014-10-06 18:29:26 +0100172 } catch (Exception e) {
173 downloading = false;
174 Log.e(TAG,
175 "Error updating download progress: "
176 + e.getMessage());
177 }
178
179 cursor.close();
180 try {
Jose Pascoal54b3ae62014-10-07 20:29:58 +0100181 // TODO WHYYYYYY???????
Jose Pascoalb690af12014-10-06 18:29:26 +0100182 Thread.sleep(3000);
183 } catch (InterruptedException e) {
184 e.printStackTrace();
185 }
186 }
187 }
188 }
189 }).start();
190 }
191
192 private View inflateViewByImageType(LayoutInflater inflater,
193 ViewGroup container) {
194 View view = inflater.inflate(R.layout.fragment_download_fairphone,
195 container, false);
196 if (mSelectedVersion != null) {
197 if (Version.IMAGE_TYPE_AOSP.equalsIgnoreCase(mSelectedVersion
198 .getImageType())) {
199 view = inflater.inflate(R.layout.fragment_download_android,
200 container, false);
201 } else if (Version.IMAGE_TYPE_FAIRPHONE
202 .equalsIgnoreCase(mSelectedVersion.getImageType())) {
203 view = inflater.inflate(R.layout.fragment_download_fairphone,
204 container, false);
205 }
206 }
207 return view;
208 }
209
210 private void setupLayout(View view) {
211 mDownloadVersionName = (TextView) view
212 .findViewById(R.id.download_version_name_text);
213
214 // download in progress group
215 mVersionDownloadingGroup = (LinearLayout) view
216 .findViewById(R.id.version_downloading_group);
217 mVersionDownloadProgressBar = (ProgressBar) view
218 .findViewById(R.id.version_download_progress_bar);
219
220 // restart group
221 mVersionInstallGroup = (LinearLayout) view
222 .findViewById(R.id.version_install_group);
223 mRestartButton = (Button) view.findViewById(R.id.restart_button);
224
225 mCancelButton = (Button) view.findViewById(R.id.cancel_button);
226 }
227
Jose Pascoal54b3ae62014-10-07 20:29:58 +0100228 @Override
229 public void onResume() {
230 super.onResume();
231
232 setupInstallationReceivers();
233 registerDownloadBroadCastReceiver();
234 }
235
236 @Override
237 public void onPause() {
238 super.onPause();
239
240 unregisterBroadCastReceiver();
241 }
242
243 private void setupInstallationReceivers() {
244 mDownloadManager = (DownloadManager) mainActivity
245 .getSystemService(Context.DOWNLOAD_SERVICE);
246
247 mDownloadBroadCastReceiver = new DownloadBroadCastReceiver();
248 }
249
250 private void registerDownloadBroadCastReceiver() {
251 mainActivity.registerReceiver(mDownloadBroadCastReceiver,
252 new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
253 }
254
255 private void unregisterBroadCastReceiver() {
256 mainActivity.unregisterReceiver(mDownloadBroadCastReceiver);
257 }
258
259 private class DownloadBroadCastReceiver extends BroadcastReceiver {
260
261 @Override
262 public void onReceive(Context context, Intent intent) {
263
264 mainActivity.getLatestUpdateDownloadIdFromSharedPreference();
265
266 updateDownloadFile();
267 }
268 }
269
270 private void updateDownloadFile() {
271
272 long downloadId = mainActivity.getLatestDownloadId();
273
274 if (downloadId != 0) {
275 DownloadManager.Query query = new DownloadManager.Query();
276
277 query.setFilterById();
278
279 Cursor cursor = mDownloadManager.query(query);
280
281 if (cursor.moveToFirst()) {
282 int columnIndex = cursor
283 .getColumnIndex(DownloadManager.COLUMN_STATUS);
284 int status = cursor.getInt(columnIndex);
285
286 switch (status) {
287 case DownloadManager.STATUS_SUCCESSFUL:
288 mainActivity.updateStatePreference(UpdaterState.PREINSTALL);
289 toggleDownloadProgressAndRestart();
290 break;
291 case DownloadManager.STATUS_RUNNING:
292 startDownloadProgressUpdateThread();
293 break;
294 case DownloadManager.STATUS_FAILED:
295 Resources resources = getResources();
296 if (mSelectedVersion != null) {
297 String downloadTitle = mSelectedVersion.getName()
298 + " "
299 + mSelectedVersion
300 .getImageTypeDescription(resources);
301 Toast.makeText(
302 mainActivity,
303 resources
304 .getString(R.string.updateDownloadError)
305 + " " + downloadTitle,
306 Toast.LENGTH_LONG).show();
307 } else {
308 Toast.makeText(
309 mainActivity,
310 resources
311 .getString(R.string.updateDownloadError),
312 Toast.LENGTH_LONG).show();
313 }
314 mainActivity.changeState(UpdaterState.NORMAL);
315 break;
316 }
317 }
318
319 cursor.close();
320 }
321 }
322
323 // ************************************************************************************
324 // PRE INSTALL
325 // ************************************************************************************
326
327 private void setupPreInstallState() {
328
329 Resources resources = mainActivity.getResources();
330 // the latest version data must exist
331 if (mSelectedVersion != null) {
332
333 // check the md5 of the file
334 File file = new File(getVersionDownloadPath(mSelectedVersion));
335
336 if (file.exists()) {
337 if (Utils.checkMD5(mSelectedVersion.getMd5Sum(), file)) {
338 copyUpdateToCache(file);
339 return;
340 } else {
341 Toast.makeText(
342 mainActivity,
343 resources
344 .getString(R.string.invalidMD5DownloadMessage),
345 Toast.LENGTH_LONG).show();
346 removeLastUpdateDownload();
347 }
348 }
349 }
350
351 // remove the updater directory
352 File fileDir = new File(Environment.getExternalStorageDirectory()
353 + resources.getString(R.string.updaterFolder));
354 fileDir.delete();
355
356 // else if the perfect case does not happen, reset the download
357 mainActivity.changeState(UpdaterState.NORMAL);
358 }
359
360 // ************************************************************************************
361 // DOWNLOAD UPDATE
362 // ************************************************************************************
363
364 public void setupDownloadState() {
365 // setup the download state views
366 if (mSelectedVersion == null) {
367 Resources resources = getResources();
368
369 // we don't have the lastest.xml so get back to initial state
370 File updateDir = new File(Environment.getExternalStorageDirectory()
371 + resources.getString(R.string.updaterFolder));
372
373 updateDir.delete();
374
375 mainActivity.changeState(UpdaterState.NORMAL);
376
377 return;
378 }
379
380 // if there is a download ID on the shared preferences
381 if (mLatestUpdateDownloadId == 0) {
382 mLatestUpdateDownloadId = mainActivity.getLatestUpdateDownloadIdFromSharedPreference();
383
384 // invalid download Id
385 if (mLatestUpdateDownloadId == 0) {
386 mainActivity.changeState(UpdaterState.NORMAL);
387 return;
388 }
389 }
390
391 updateDownloadFile();
392 }
393
394 private void startPreInstall() {
395
396 if (RootTools.isAccessGiven()) {
397 // set the command for the recovery
398 Resources resources = getResources();
399 // Process p;
400 try {
401
402 Shell.runRootCommand(new CommandCapture(0,
403 "rm -f /cache/recovery/command"));
404
405 Shell.runRootCommand(new CommandCapture(0,
406 "rm -f /cache/recovery/extendedcommand"));
407
408 Shell.runRootCommand(new CommandCapture(0,
409 "echo '--wipe_cache' >> /cache/recovery/command"));
410
411 if (canCopyToCache()) {
412 Shell.runRootCommand(new CommandCapture(
413 0,
414 "echo '--update_package=/"
415 + resources
416 .getString(R.string.recoveryCachePath)
417 + "/"
418 + VersionParserHelper
419 .getNameFromVersion(mSelectedVersion)
420 + "' >> /cache/recovery/command"));
421 } else {
422 Shell.runRootCommand(new CommandCapture(
423 0,
424 "echo '--update_package=/"
425 + resources
426 .getString(R.string.recoverySdCardPath)
427 + resources
428 .getString(R.string.updaterFolder)
429 + VersionParserHelper
430 .getNameFromVersion(mSelectedVersion)
431 + "' >> /cache/recovery/command"));
432 }
433 } catch (IOException e) {
434 // TODO Auto-generated catch block
435 e.printStackTrace();
436 } catch (NotFoundException e) {
437 // TODO Auto-generated catch block
438 e.printStackTrace();
439 } catch (TimeoutException e) {
440 // TODO Auto-generated catch block
441 e.printStackTrace();
442 } catch (RootDeniedException e) {
443 // TODO Auto-generated catch block
444 e.printStackTrace();
445 }
446
447 // send broadcast intent
448 Intent broadcastIntent = new Intent();
449 broadcastIntent.setAction(GappsInstallerHelper.GAPPS_REINSTALATION);
450 mainActivity.sendBroadcast(broadcastIntent);
451
452 if (canCopyToCache()) {
453 removeLastUpdateDownload();
454 }
455
456 // remove the update files from data
457 removeUpdateFilesFromData();
458 // reboot the device into recovery
459 // ((PowerManager)
460 // getSystemService(POWER_SERVICE)).reboot("recovery");
461 try {
462 mainActivity.updateStatePreference(UpdaterState.NORMAL);
463 Shell.runRootCommand(new CommandCapture(0, "reboot recovery"));
464 } catch (IOException e) {
465 // TODO Auto-generated catch block
466 e.printStackTrace();
467 } catch (TimeoutException e) {
468 // TODO Auto-generated catch block
469 e.printStackTrace();
470 } catch (RootDeniedException e) {
471 // TODO Auto-generated catch block
472 e.printStackTrace();
473 }
474 } else {
475 // TODO: show warning
476 }
477 }
478
479 private void copyUpdateToCache(File file) {
480 if (canCopyToCache()) {
481 CopyFileToCacheTask copyTask = new CopyFileToCacheTask();
482 copyTask.execute(
483 file.getPath(),
484 Environment.getDownloadCacheDirectory()
485 + "/"
486 + VersionParserHelper
487 .getNameFromVersion(mSelectedVersion));
488 } else {
489 Log.d(TAG, "No space on cache. Defaulting to Sdcard");
490 Toast.makeText(mainActivity,
491 getResources().getString(R.string.noSpaceAvailableCache),
492 Toast.LENGTH_LONG).show();
493 }
494 }
495
496 public boolean canCopyToCache() {
497 Resources resources = getResources();
498 double cacheSize = Utils.getPartitionSizeInMBytes(Environment
499 .getDownloadCacheDirectory());
500 return cacheSize > resources
501 .getInteger(R.integer.FP1CachePartitionSizeMb)
502 && cacheSize > resources
503 .getInteger(R.integer.minimalCachePartitionSizeMb);
504 }
505
506 private void clearCache() {
507 File f = Environment.getDownloadCacheDirectory();
508 File files[] = f.listFiles();
509 if (files != null) {
510 Log.d(TAG, "Size: " + files.length);
511 for (int i = 0; i < files.length; i++) {
512 String filename = files[i].getName();
513
514 if (filename.endsWith(".zip")) {
515 files[i].delete();
516 Log.d(TAG, "Deleted file " + filename);
517 }
518 }
519 }
520 }
521
522 // ************************************************************************************
523 // Update Removal
524 // ************************************************************************************
525 private void removeUpdateFilesFromData() {
526 try {
527 Shell.runRootCommand(new CommandCapture(
528 0,
529 getResources().getString(R.string.removePlayStoreCommand),
530 getResources().getString(R.string.removeGooglePlusCommand),
531 getResources().getString(R.string.removeSoundSearchCommand),
532 getResources().getString(R.string.removeGmailCommand),
533 getResources()
534 .getString(R.string.removePlayServicesCommand),
535 getResources().getString(R.string.removeQuicksearchCommand),
536 getResources().getString(R.string.removeTalkbackCommand),
537 getResources().getString(R.string.removeText2SpeechCommand)));
538 } catch (IOException e) {
539 e.printStackTrace();
540 } catch (TimeoutException e) {
541 e.printStackTrace();
542 } catch (RootDeniedException e) {
543 e.printStackTrace();
544 }
545 }
546
547 public void removeLastUpdateDownload() {
548 long latestUpdateDownloadId = mainActivity
549 .getLatestUpdateDownloadIdFromSharedPreference();
550 if (latestUpdateDownloadId != 0) {
551 // residue download ID
552 mDownloadManager.remove(latestUpdateDownloadId);
553
554 mainActivity.resetLastUpdateDownloadId();
555 }
556 }
557
558 private class CopyFileToCacheTask extends
559 AsyncTask<String, Integer, Integer> {
560
561 ProgressDialog mProgress;
562
563 @Override
564 protected Integer doInBackground(String... params) {
565 // check the correct number of
566 if (params.length != 2) {
567 return -1;
568 }
569
570 String originalFilePath = params[0];
571 String destinyFilePath = params[1];
572
573 if (RootTools.isAccessGiven()) {
574 clearCache();
575
576 File otaFilePath = new File(originalFilePath);
577 File otaFileCache = new File(destinyFilePath);
578
579 if (!otaFileCache.exists()) {
580 RootTools.copyFile(otaFilePath.getPath(),
581 otaFileCache.getPath(), false, false);
582 }
583 }
584
585 return 1;
586 }
587
588 protected void onProgressUpdate(Integer... progress) {
589
590 }
591
592 protected void onPreExecute() {
593
594 if (mProgress == null) {
595 String title = "";
596 String message = mainActivity.getResources()
597 .getString(R.string.pleaseWait);
598 mProgress = ProgressDialog.show(mainActivity,
599 title, message, true, false);
600 }
601 }
602
603 protected void onPostExecute(Integer result) {
604 // disable the spinner
605 if (mProgress != null) {
606 mProgress.dismiss();
607 mProgress = null;
608 }
609 }
610 }
611
612 private String getVersionDownloadPath(Version version) {
613 Resources resources = mainActivity.getResources();
614 return Environment.getExternalStorageDirectory()
615 + resources.getString(R.string.updaterFolder)
616 + VersionParserHelper.getNameFromVersion(version);
617 }
Jose Pascoalb690af12014-10-06 18:29:26 +0100618}