From 4076947705508da75a2609a4a7893c4348956adf Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Mon, 25 Sep 2017 21:10:49 +0200 Subject: reworked updater --- .../pixart/messenger/ui/ConversationActivity.java | 12 +- .../de/pixart/messenger/ui/UpdaterActivity.java | 381 ++++++++------------- .../java/de/pixart/messenger/ui/XmppActivity.java | 6 +- 3 files changed, 155 insertions(+), 244 deletions(-) (limited to 'src/main/java/de/pixart/messenger/ui') diff --git a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java index f4c66fbb8..a23daa6c0 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationActivity.java @@ -71,6 +71,7 @@ import de.pixart.messenger.entities.MucOptions; import de.pixart.messenger.entities.Presence; import de.pixart.messenger.entities.Transferable; import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.services.UpdateService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.services.XmppConnectionService.OnAccountUpdate; import de.pixart.messenger.services.XmppConnectionService.OnConversationUpdate; @@ -382,16 +383,19 @@ public class ConversationActivity extends XmppActivity String PREFS_NAME = "UpdateTimeStamp"; SharedPreferences UpdateTimeStamp = getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); long lastUpdateTime = UpdateTimeStamp.getLong("lastUpdateTime", 0); - Log.d(Config.LOGTAG, "AppUpdater - LastUpdateTime: " + lastUpdateTime); + Log.d(Config.LOGTAG, "AppUpdater: LastUpdateTime: " + lastUpdateTime); if ((lastUpdateTime + (Config.UPDATE_CHECK_TIMER * 1000)) < System.currentTimeMillis()) { lastUpdateTime = System.currentTimeMillis(); SharedPreferences.Editor editor = UpdateTimeStamp.edit(); editor.putLong("lastUpdateTime", lastUpdateTime); editor.commit(); // run AppUpdater - Log.d(Config.LOGTAG, "AppUpdater - CurrentTime: " + lastUpdateTime); - Intent AppUpdater = new Intent(this, UpdaterActivity.class); - startActivity(AppUpdater); + Log.d(Config.LOGTAG, "AppUpdater: CurrentTime: " + lastUpdateTime); + //Intent AppUpdater = new Intent(this, UpdaterActivity.class); + //startActivity(AppUpdater); + + UpdateService task = new UpdateService(this); + task.execute("false"); Log.d(Config.LOGTAG, "AppUpdater started"); } else { Log.d(Config.LOGTAG, "AppUpdater stopped"); diff --git a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java index d5a1a04f8..5ab90ca7f 100644 --- a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java +++ b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java @@ -3,71 +3,43 @@ package de.pixart.messenger.ui; import android.Manifest; import android.app.Activity; import android.app.AlertDialog; -import android.app.DownloadManager; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.support.v4.app.ActivityCompat; import android.util.Log; -import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; -import org.json.JSONException; -import org.json.JSONObject; +import org.apache.http.util.ByteArrayBuffer; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.persistance.FileBackend; -import de.pixart.messenger.services.UpdaterWebService; public class UpdaterActivity extends Activity { static final private String FileName = "update.apk"; String appURI = ""; - private UpdateReceiver receiver = null; - private int versionCode = 0; - private String localVersion = null; - private DownloadManager downloadManager; - private long downloadReference; - - BroadcastReceiver downloadReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - if (intent == null) { - Toast.makeText(getApplicationContext(), - getText(R.string.failed), - Toast.LENGTH_LONG).show(); - UpdaterActivity.this.finish(); - } - //check if the broadcast message is for our Enqueued download - long referenceId = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); - if (downloadReference == referenceId) { - File file = new File(FileBackend.getConversationsDirectory("Update", false), FileName); - //start the installation of the latest localVersion - Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); - installIntent.setDataAndType(FileBackend.getUriForFile(UpdaterActivity.this, file), "application/vnd.android.package-archive"); - installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); - installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); - installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - installIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(installIntent); - UpdaterActivity.this.finish(); - } - } - }; + String changelog = ""; + Integer filesize = 0; @Override protected void onCreate(Bundle savedInstanceState) { @@ -77,37 +49,80 @@ public class UpdaterActivity extends Activity { setContentView(R.layout.activity_updater); TextView textView = (TextView) findViewById(R.id.updater); textView.setText(R.string.update_info); + } - //Broadcast receiver for our Web Request - IntentFilter filter = new IntentFilter(UpdateReceiver.PROCESS_RESPONSE); - filter.addCategory(Intent.CATEGORY_DEFAULT); - receiver = new UpdateReceiver(); - registerReceiver(receiver, filter); - - //Broadcast receiver for the download manager (download complete) - registerReceiver(downloadReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); - - //check of internet is available before making a web service request - if (isNetworkAvailable(this)) { - Intent msgIntent = new Intent(this, UpdaterWebService.class); - msgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - msgIntent.putExtra(UpdaterWebService.REQUEST_STRING, Config.UPDATE_URL); + @Override + protected void onStart() { + super.onStart(); + if (getIntent() != null && getIntent().getStringExtra("update").equals("PixArtMessenger_UpdateService")) { + try { + appURI = getIntent().getStringExtra("url"); + } catch (Exception e) { + Toast.makeText(getApplicationContext(), getText(R.string.failed), Toast.LENGTH_LONG).show(); + UpdaterActivity.this.finish(); + } + try { + changelog = getIntent().getStringExtra("changelog"); + } catch (Exception e) { + Toast.makeText(getApplicationContext(), getText(R.string.failed), Toast.LENGTH_LONG).show(); + UpdaterActivity.this.finish(); + } + //delete old downloaded localVersion files + File dir = new File(FileBackend.getConversationsDirectory("Update", false)); + if (dir.isDirectory()) { + String[] children = dir.list(); + for (String aChildren : children) { + Log.d(Config.LOGTAG, "AppUpdater: delete old update files " + aChildren + " in " + dir); + new File(dir, aChildren).delete(); + } + } - Toast.makeText(getApplicationContext(), - getText(R.string.checking_for_updates), - Toast.LENGTH_SHORT).show(); - startService(msgIntent); + //oh yeah we do need an upgrade, let the user know send an alert message + AlertDialog.Builder builder = new AlertDialog.Builder(UpdaterActivity.this); + builder.setCancelable(false); + builder.setMessage(getString(R.string.install_update)) + .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { + //if the user agrees to upgrade + public void onClick(DialogInterface dialog, int id) { + Log.d(Config.LOGTAG, "AppUpdater: downloading " + FileName + " from " + appURI); + //ask for permissions on devices >= SDK 23 + if (isStoragePermissionGranted() && isNetworkAvailable(getApplicationContext())) { + //start downloading the file using the download manager + DownloadFromUrl(appURI, FileName); + Toast.makeText(getApplicationContext(), getText(R.string.download_started), Toast.LENGTH_LONG).show(); + } else { + Log.d(Config.LOGTAG, "AppUpdater: failed - has storage permissions " + isStoragePermissionGranted() + " and internet " + isNetworkAvailable(getApplicationContext())); + } + } + }) + .setNeutralButton(R.string.changelog, new DialogInterface.OnClickListener() { + //open link to changelog + public void onClick(DialogInterface dialog, int id) { + Uri uri = Uri.parse("https://github.com/kriztan/Conversations/blob/master/CHANGELOG.md"); // missing 'http://' will cause crashed + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + //restart updater to show dialog again after coming back after opening changelog + recreate(); + } + }) + .setNegativeButton(R.string.remind_later, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + UpdaterActivity.this.finish(); + } + }); + //show the alert message + builder.create().show(); + } else { + Toast.makeText(getApplicationContext(), getText(R.string.failed), Toast.LENGTH_LONG).show(); + UpdaterActivity.this.finish(); } } @Override public void onDestroy() { - //unregister your receivers - this.unregisterReceiver(receiver); - this.unregisterReceiver(downloadReceiver); super.onDestroy(); - //enable touch events - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); } @Override @@ -120,6 +135,70 @@ public class UpdaterActivity extends Activity { super.onRestoreInstanceState(savedInstanceState); } + public void DownloadFromUrl(final String DownloadUrl, final String FileName) { + final Thread thread = new Thread(new Runnable() { + + @Override + public void run() { + try { + File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + FileBackend.getDirectoryName("Update", false)); + + URL url = new URL(DownloadUrl); + File file = new File(dir, FileName); + Log.d(Config.LOGTAG, "AppUpdater: save file to " + file.toString()); + + long startTime = System.currentTimeMillis(); + Log.d(Config.LOGTAG, "AppUpdater: download update from url: " + url + " to file name: " + file.toString()); + + // Open a connection to that URL. + URLConnection connection = url.openConnection(); + + //Define InputStreams to read from the URLConnection. + InputStream is = connection.getInputStream(); + BufferedInputStream bis = new BufferedInputStream(is); + + //Read file size + List values = connection.getHeaderFields().get("content-Length"); + if (values != null && !values.isEmpty()) { + String sLength = (String) values.get(0); + if (sLength != null) { + filesize = Integer.parseInt(sLength); + } + } + //Read bytes to the Buffer until there is nothing more to read(-1). + ByteArrayBuffer baf = new ByteArrayBuffer(5000); + int current = 0; + while ((current = bis.read()) != -1) { + baf.append((byte) current); + } + + // Convert the Bytes read to a String. + FileOutputStream fos = new FileOutputStream(file); + fos.write(baf.toByteArray()); + fos.flush(); + fos.close(); + Log.d(Config.LOGTAG, "AppUpdater: download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec"); + + //start the installation of the latest localVersion + Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); + installIntent.setDataAndType(FileBackend.getUriForFile(UpdaterActivity.this, file), "application/vnd.android.package-archive"); + installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); + installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); + installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + installIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + startActivity(installIntent); + UpdaterActivity.this.finish(); + + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + Log.d(Config.LOGTAG, "AppUpdater: Error: " + e); + } + } + }); + thread.start(); + } + //check for internet connection private boolean isNetworkAvailable(Context context) { ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); @@ -170,180 +249,4 @@ public class UpdaterActivity extends Activity { AlertDialog alert = builder.create(); alert.show(); } - - /** - * Use this instead of String.compareTo() for a non-lexicographical - * comparison that works for version strings. e.g. "1.10".compareTo("1.6"). - * - * @param str1 a string of ordinal numbers separated by decimal points. - * @param str2 a string of ordinal numbers separated by decimal points. - * @return The result is a negative integer if str1 is _numerically_ less than str2. - * The result is a positive integer if str1 is _numerically_ greater than str2. - * The result is zero if the strings are _numerically_ equal. - * @note It does not work if "1.10" is supposed to be equal to "1.10.0". - */ - private int checkVersion(String remoteVersion, String installedVersion) { - String[] remote = null; - String[] installed = null; - String[] remoteV = null; - String[] installedV = null; - try { - installedV = installedVersion.split(" "); - Log.d(Config.LOGTAG, "Updater Version installed: " + installedV[0]); - installed = installedV[0].split("\\."); - } catch (Exception e) { - e.printStackTrace(); - } - try { - remoteV = remoteVersion.split(" "); - if (installedV != null && installedV.length > 1) { - if (installedV[1] != null) { - remoteV[0] = remoteV[0] + ".1"; - } - } - Log.d(Config.LOGTAG, "Updater Version on server: " + remoteV[0]); - remote = remoteV[0].split("\\."); - } catch (Exception e) { - e.printStackTrace(); - } - int i = 0; - // set index to first non-equal ordinal or length of shortest localVersion string - if (remote != null && installed != null) { - while (i < remote.length && i < installed.length && remote[i].equals(installed[i])) { - i++; - } - // compare first non-equal ordinal number - if (i < remote.length && i < installed.length) { - int diff = Integer.valueOf(remote[i]).compareTo(Integer.valueOf(installed[i])); - return Integer.signum(diff); - } - // the strings are equal or one string is a substring of the other - // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" - return Integer.signum(remote.length - installed.length); - } - return 0; - } - - //broadcast receiver to get notification when the web request finishes - public class UpdateReceiver extends BroadcastReceiver { - - public static final String PROCESS_RESPONSE = "de.pixart.messenger.intent.action.PROCESS_RESPONSE"; - - @Override - public void onReceive(Context context, Intent intent) { - - //disable touch events - getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - - String responseMessage = intent.getStringExtra(UpdaterWebService.RESPONSE_MESSAGE); - - if (responseMessage == "" || responseMessage.isEmpty() || responseMessage == null) { - Toast.makeText(getApplicationContext(), - getText(R.string.failed), - Toast.LENGTH_LONG).show(); - UpdaterActivity.this.finish(); - } else { - //parse the JSON reponse - JSONObject reponseObj; - - try { - //if the response was successful check further - reponseObj = new JSONObject(responseMessage); - boolean success = reponseObj.getBoolean("success"); - if (success) { - //Overall information about the contents of a package - //This corresponds to all of the information collected from AndroidManifest.xml. - PackageInfo pInfo = null; - try { - pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - //get the app localVersion Name for display - String localVersion = pInfo.versionName; - //get the latest localVersion from the JSON string - int latestVersionCode = reponseObj.getInt("latestVersionCode"); - String remoteVersion = reponseObj.getString("latestVersion"); - String filesize = reponseObj.getString("filesize"); - String changelog = reponseObj.getString("changelog"); - //get the lastest application URI from the JSON string - appURI = reponseObj.getString("appURI"); - //check if we need to upgrade? - if (checkVersion(remoteVersion, localVersion) >= 1) { - //delete old downloaded localVersion files - File dir = new File(FileBackend.getConversationsDirectory("Update", false)); - if (dir.isDirectory()) { - String[] children = dir.list(); - for (String aChildren : children) { - Log.d(Config.LOGTAG, "Updater delete old update files " + aChildren + " in " + dir); - new File(dir, aChildren).delete(); - } - } - //enable touch events - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - - //oh yeah we do need an upgrade, let the user know send an alert message - AlertDialog.Builder builder = new AlertDialog.Builder(UpdaterActivity.this); - builder.setCancelable(false); - String UpdateMessageInfo = getResources().getString(R.string.update_available); - builder.setMessage(String.format(UpdateMessageInfo, remoteVersion, filesize, localVersion, changelog)) - .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { - //if the user agrees to upgrade - public void onClick(DialogInterface dialog, int id) { - //disable touch events - getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - //ask for permissions on devices >= SDK 23 - if (isStoragePermissionGranted()) { - //start downloading the file using the download manager - downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); - Uri Download_Uri = Uri.parse(appURI); - DownloadManager.Request request = new DownloadManager.Request(Download_Uri); - request.setTitle("Pix-Art Messenger Update"); - request.setDestinationInExternalPublicDir(FileBackend.getDirectoryName("Update", false), FileName); - downloadReference = downloadManager.enqueue(request); - Toast.makeText(getApplicationContext(), - getText(R.string.download_started), - Toast.LENGTH_LONG).show(); - } - } - }) - .setNeutralButton(R.string.changelog, new DialogInterface.OnClickListener() { - //open link to changelog - public void onClick(DialogInterface dialog, int id) { - Uri uri = Uri.parse("https://github.com/kriztan/Conversations/blob/master/CHANGELOG.md"); // missing 'http://' will cause crashed - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - //restart updater to show dialog again after coming back after opening changelog - recreate(); - } - }) - .setNegativeButton(R.string.remind_later, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User cancelled the dialog - UpdaterActivity.this.finish(); - } - }); - //show the alert message - builder.create().show(); - } else { - Toast.makeText(getApplicationContext(), - getText(R.string.no_update_available), - Toast.LENGTH_SHORT).show(); - UpdaterActivity.this.finish(); - } - } else { - Toast.makeText(getApplicationContext(), - getText(R.string.failed), - Toast.LENGTH_LONG).show(); - UpdaterActivity.this.finish(); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - } } diff --git a/src/main/java/de/pixart/messenger/ui/XmppActivity.java b/src/main/java/de/pixart/messenger/ui/XmppActivity.java index e5b894322..0fe6e7600 100644 --- a/src/main/java/de/pixart/messenger/ui/XmppActivity.java +++ b/src/main/java/de/pixart/messenger/ui/XmppActivity.java @@ -79,6 +79,7 @@ import de.pixart.messenger.entities.Presences; import de.pixart.messenger.http.HttpConnectionManager; import de.pixart.messenger.services.AvatarService; import de.pixart.messenger.services.BarcodeProvider; +import de.pixart.messenger.services.UpdateService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.services.XmppConnectionService.XmppConnectionBinder; import de.pixart.messenger.utils.CryptoHelper; @@ -376,7 +377,10 @@ public abstract class XmppActivity extends Activity { break; case R.id.action_check_updates: if (xmppConnectionService.hasInternetConnection()) { - startActivity(new Intent(this, UpdaterActivity.class)); + //startActivity(new Intent(this, UpdaterActivity.class)); + + UpdateService task = new UpdateService(this); + task.execute("true"); } else { Toast.makeText(this, R.string.account_status_no_internet, Toast.LENGTH_LONG).show(); } -- cgit v1.2.3