Skip to content

Commit 486c27e

Browse files
committed
Replace download manager with custom async task to fix TLSv1.2 problem
1 parent eda8e7c commit 486c27e

File tree

3 files changed

+145
-229
lines changed

3 files changed

+145
-229
lines changed

AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2424
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2525
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
26+
<uses-permission android:name="android.permission.WAKE_LOCK" />
2627

2728
<application
2829
android:allowBackup="true"

src/se/bitcraze/crazyfliecontrol/bootloader/BootloaderActivity.java

Lines changed: 142 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@
2828
package se.bitcraze.crazyfliecontrol.bootloader;
2929

3030
import java.io.File;
31+
import java.io.FileOutputStream;
3132
import java.io.IOException;
33+
import java.io.InputStream;
34+
import java.io.OutputStream;
35+
import java.net.URL;
36+
import java.security.KeyManagementException;
37+
import java.security.NoSuchAlgorithmException;
3238
import java.util.ArrayList;
3339
import java.util.Collections;
3440
import java.util.List;
@@ -38,24 +44,21 @@
3844
import se.bitcraze.crazyflie.lib.bootloader.Bootloader.BootloaderListener;
3945
import se.bitcraze.crazyflie.lib.bootloader.FirmwareRelease;
4046
import se.bitcraze.crazyflie.lib.crazyradio.RadioDriver;
41-
import se.bitcraze.crazyfliecontrol.bootloader.FirmwareDownloader.FirmwareDownloadListener;
4247
import se.bitcraze.crazyfliecontrol2.MainActivity;
4348
import se.bitcraze.crazyfliecontrol2.R;
4449
import se.bitcraze.crazyfliecontrol2.UsbLinkAndroid;
4550
import android.app.Activity;
4651
import android.app.AlertDialog;
47-
import android.app.DownloadManager;
4852
import android.app.ProgressDialog;
4953
import android.content.Context;
5054
import android.content.DialogInterface;
51-
import android.content.IntentFilter;
5255
import android.content.pm.ActivityInfo;
5356
import android.graphics.Color;
5457
import android.os.AsyncTask;
5558
import android.os.AsyncTask.Status;
56-
import android.os.Build;
5759
import android.os.Bundle;
5860
import android.os.Handler;
61+
import android.os.PowerManager;
5962
import android.text.Spannable;
6063
import android.text.style.ForegroundColorSpan;
6164
import android.util.Log;
@@ -71,6 +74,8 @@
7174
import android.widget.TextView;
7275
import android.widget.Toast;
7376

77+
import javax.net.ssl.HttpsURLConnection;
78+
7479
public class BootloaderActivity extends Activity {
7580

7681
private static final String LOG_TAG = "BootloaderActivity";
@@ -106,15 +111,11 @@ protected void onCreate(Bundle savedInstanceState) {
106111
initializeFirmwareSpinner();
107112

108113
mFirmwareDownloader = new FirmwareDownloader(this);
109-
110-
this.registerReceiver(mFirmwareDownloader.onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
111114
}
112115

113-
114116
@Override
115117
protected void onDestroy() {
116118
super.onDestroy();
117-
this.unregisterReceiver(mFirmwareDownloader.onComplete);
118119
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
119120
}
120121

@@ -235,20 +236,6 @@ public void run() {
235236
});
236237
}
237238

238-
private FirmwareDownloadListener mDownloadListener = new FirmwareDownloadListener () {
239-
public void downloadFinished() {
240-
//flash firmware once firmware is downloaded
241-
appendConsole("Firmware downloaded.");
242-
startBootloader();
243-
}
244-
245-
public void downloadProblem(String msg) {
246-
//flash firmware once firmware is downloaded
247-
appendConsole("Firmware download failed: " + msg);
248-
stopFlashProcess(false);
249-
}
250-
};
251-
252239
public void startFlashProcess(final View view) {
253240
// disable button and spinner
254241
mFlashFirmwareButton.setEnabled(false);
@@ -261,8 +248,139 @@ public void startFlashProcess(final View view) {
261248
// download firmware file
262249
appendConsole("Downloading firmware...");
263250

264-
mFirmwareDownloader.addDownloadListener(mDownloadListener);
265-
mFirmwareDownloader.downloadFirmware(this.mSelectedFirmwareRelease);
251+
DownloadTask mDownloadTask = new DownloadTask();
252+
mDownloadTask.execute(this.mSelectedFirmwareRelease);
253+
}
254+
255+
private class DownloadTask extends AsyncTask<FirmwareRelease, Integer, String> {
256+
257+
private PowerManager.WakeLock mWakeLock;
258+
private boolean mAlreadyDownloaded = false;
259+
260+
private String downloadFile (String urlString, String fileName, String tagName) {
261+
InputStream input = null;
262+
OutputStream output = null;
263+
HttpsURLConnection connection = null;
264+
265+
// Retrofitting support for TLSv1.2, because GitHub only supports TLSv1.2
266+
try {
267+
HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory());
268+
} catch (KeyManagementException | NoSuchAlgorithmException e) {
269+
e.printStackTrace();
270+
}
271+
272+
try {
273+
URL url = new URL(urlString);
274+
connection = (HttpsURLConnection) url.openConnection();
275+
connection.connect();
276+
277+
// expect HTTP 200 OK, so we don't mistakenly save error report instead of the file
278+
if (connection.getResponseCode() != HttpsURLConnection.HTTP_OK) {
279+
return "Server returned HTTP " + connection.getResponseCode() + " " + connection.getResponseMessage();
280+
}
281+
282+
// this will be useful to display download percentage. it might be -1: server did not report the length
283+
int fileLength = connection.getContentLength();
284+
285+
// download the file
286+
File outputFile = new File(BootloaderActivity.this.getExternalFilesDir(null) + "/" + BootloaderActivity.BOOTLOADER_DIR + "/" + tagName + "/", fileName);
287+
outputFile.getParentFile().mkdirs();
288+
input = connection.getInputStream();
289+
output = new FileOutputStream(outputFile);
290+
291+
byte data[] = new byte[4096];
292+
long total = 0;
293+
int count;
294+
while ((count = input.read(data)) != -1) {
295+
// allow canceling
296+
if (isCancelled()) {
297+
input.close();
298+
return null;
299+
}
300+
total += count;
301+
// publishing the progress....
302+
if (fileLength > 0) { // only if total length is known
303+
publishProgress((int) (total * 100 / fileLength));
304+
}
305+
output.write(data, 0, count);
306+
}
307+
} catch (Exception e) {
308+
return e.toString();
309+
} finally {
310+
try {
311+
if (output != null) {
312+
output.close();
313+
}
314+
if (input != null) {
315+
input.close();
316+
}
317+
} catch (IOException ignored) {
318+
319+
}
320+
if (connection != null) {
321+
connection.disconnect();
322+
}
323+
}
324+
return null;
325+
}
326+
327+
@Override
328+
protected String doInBackground(FirmwareRelease... sFirmwareRelease) {
329+
mSelectedFirmwareRelease = sFirmwareRelease[0];
330+
331+
if (mSelectedFirmwareRelease != null) {
332+
if (mFirmwareDownloader.isFileAlreadyDownloaded(mSelectedFirmwareRelease.getTagName() + "/" + mSelectedFirmwareRelease.getAssetName())) {
333+
mAlreadyDownloaded = true;
334+
return null;
335+
}
336+
String browserDownloadUrl = mSelectedFirmwareRelease.getBrowserDownloadUrl();
337+
if (mFirmwareDownloader.isNetworkAvailable()) {
338+
return downloadFile(browserDownloadUrl, mSelectedFirmwareRelease.getAssetName(), mSelectedFirmwareRelease.getTagName());
339+
} else {
340+
Log.d(LOG_TAG, "Network connection not available.");
341+
return "No network connection available.\nPlease check your connectivity.";
342+
}
343+
} else {
344+
return "Selected firmware does not have assets.";
345+
}
346+
}
347+
348+
@Override
349+
protected void onPreExecute() {
350+
super.onPreExecute();
351+
// take CPU lock to prevent CPU from going off if the user presses the power button during download
352+
PowerManager pm = (PowerManager) BootloaderActivity.this.getSystemService(Context.POWER_SERVICE);
353+
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
354+
mWakeLock.acquire();
355+
mProgressBar.setProgress(0);
356+
}
357+
358+
@Override
359+
protected void onProgressUpdate(Integer... progress) {
360+
super.onProgressUpdate(progress);
361+
// if we get here, length is known, now set indeterminate to false
362+
mProgressBar.setIndeterminate(false);
363+
mProgressBar.setMax(100);
364+
mProgressBar.setProgress(progress[0]);
365+
}
366+
367+
@Override
368+
protected void onPostExecute(String result) {
369+
mWakeLock.release();
370+
if (result != null) {
371+
//flash firmware once firmware is downloaded
372+
appendConsole("Firmware download failed: " + result);
373+
stopFlashProcess(false);
374+
} else {
375+
//flash firmware once firmware is downloaded
376+
if (mAlreadyDownloaded) {
377+
appendConsole("Firmware file already downloaded.");
378+
} else {
379+
appendConsole("Firmware downloaded.");
380+
}
381+
startBootloader();
382+
}
383+
}
266384
}
267385

268386
private void startBootloader() {
@@ -436,7 +554,6 @@ private void stopFlashProcess(boolean reset) {
436554
if (mBootloader != null) {
437555
mBootloader.close();
438556
}
439-
mFirmwareDownloader.removeDownloadListener(mDownloadListener);
440557
//re-enable widgets
441558
mFlashFirmwareButton.setEnabled(true);
442559
mReleaseNotesButton.setEnabled(true);
@@ -446,11 +563,4 @@ private void stopFlashProcess(boolean reset) {
446563
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
447564
}
448565

449-
/**
450-
* @param context used to check the device version and DownloadManager information
451-
* @return true if the download manager is available
452-
*/
453-
public static boolean isDownloadManagerAvailable(Context context) {
454-
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
455-
}
456566
}

0 commit comments

Comments
 (0)