diff --git a/README.md b/README.md
index dbe5827fe..76a8d6e63 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# Wulkanowy
-[](https://www.codacy.com/app/wulkanowy/wulkanowy)
[](https://codecov.io/gh/wulkanowy/wulkanowy)
[](https://www.versioneye.com/user/projects/5969ff0b0fb24f004f8c711b)
[](https://circleci.com/gh/wulkanowy/wulkanowy)
@@ -8,6 +7,6 @@
[](https://bettercodehub.com/)
[](https://bintray.com/wulkanowy/wulkanowy/api)
-[Pobierz wersję rozwojową](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/app-debug.apk)
+[Pobierz wersję rozwojową](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/app-release-bitrise-signed.apk)
Wulkanowy to projekt aplikacji na androida ułatwiającej używanie dziennika VULCANa.
diff --git a/app/build.gradle b/app/build.gradle
index 72f6ab7c0..96076b3a8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,7 +5,7 @@ apply from: '../android-sonarqube.gradle'
android {
compileSdkVersion 27
- buildToolsVersion "27.0.2"
+ buildToolsVersion "27.0.3"
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
@@ -15,7 +15,10 @@ android {
versionName "0.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
+ buildConfigField "String", "UPDATE_URL", "\"https://bitrise-redirector.herokuapp.com" +
+ "/v0.1/apps/daeff1893f3c8128/builds/" + "${getCurrentGitBranch()}" + "/artifacts/app-release-bitrise-signed.apk/info\""
}
+
buildTypes {
release {
minifyEnabled false
@@ -59,6 +62,7 @@ dependencies {
implementation 'org.greenrobot:greendao:3.2.2'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'joda-time:joda-time:2.9.9'
+ implementation 'com.github.javiersantos:AppUpdater:2.6.4'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
@@ -71,3 +75,20 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'org.mockito:mockito-android:2.11.0'
}
+
+static def getCurrentGitBranch() {
+ if (gitBranch() == "HEAD") {
+ return System.getenv("BITRISE_GIT_BRANCH")
+ }
+
+ return gitBranch()
+}
+
+static def gitBranch() {
+ def branch = "null"
+ def proc = "git rev-parse --abbrev-ref HEAD".execute()
+ proc.in.eachLine { line -> branch = line }
+ proc.err.eachLine { line -> println line }
+ proc.waitFor()
+ branch
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 89cd9b7fd..b9ecb1f06 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,6 +49,16 @@
+
+
+
+
diff --git a/app/src/main/java/io/github/wulkanowy/services/Updater.java b/app/src/main/java/io/github/wulkanowy/services/Updater.java
new file mode 100644
index 000000000..5e4b90ac6
--- /dev/null
+++ b/app/src/main/java/io/github/wulkanowy/services/Updater.java
@@ -0,0 +1,189 @@
+package io.github.wulkanowy.services;
+
+import android.Manifest;
+import android.app.Activity;
+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.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.FileProvider;
+import android.support.v7.app.AlertDialog;
+import android.util.Log;
+
+import com.github.javiersantos.appupdater.AppUpdaterUtils;
+import com.github.javiersantos.appupdater.enums.AppUpdaterError;
+import com.github.javiersantos.appupdater.enums.UpdateFrom;
+import com.github.javiersantos.appupdater.objects.Update;
+
+import java.io.File;
+
+import io.github.wulkanowy.BuildConfig;
+import io.github.wulkanowy.R;
+
+public class Updater {
+
+ private static final String DEBUG_TAG = "WulkanowyUpdater";
+
+ private static final int PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 0;
+
+ private Activity activity;
+
+ private Update update;
+
+ private DownloadManager downloadManager;
+
+ private BroadcastReceiver onComplete = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ DownloadManager.Query query = new DownloadManager.Query();
+ Cursor c = downloadManager.query(query);
+ if (c.moveToFirst()) {
+ String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
+
+ if (uriString.substring(0, 7).matches("file://")) {
+ uriString = uriString.substring(7);
+ }
+
+ File file = new File(uriString);
+
+ Intent install;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
+ install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ install.setData(FileProvider.getUriForFile(context,
+ BuildConfig.APPLICATION_ID + ".fileprovider", file));
+ } else {
+ install = new Intent(Intent.ACTION_VIEW);
+ install.setDataAndType(Uri.parse("file://" + file.getAbsolutePath()),
+ "application/vnd.android.package-archive");
+ }
+
+ context.startActivity(install);
+ }
+ }
+ };
+
+ public Updater(Activity activity) {
+ this.activity = activity;
+
+ downloadManager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
+ activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+ }
+
+ private void downloadUpdate() {
+ if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ == PackageManager.PERMISSION_GRANTED) {
+ startDownload();
+ } else {
+ requestWriteStoragePermission();
+ }
+ }
+
+ private void requestWriteStoragePermission() {
+ ActivityCompat.requestPermissions(activity,
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
+ }
+
+ private void startDownload() {
+ Snackbar.make(activity.findViewById(R.id.fragment_container), "Downloading started.", Snackbar.LENGTH_SHORT).show();
+
+ String path = Environment.getExternalStorageDirectory().toString() + File.separator +
+ Environment.DIRECTORY_DOWNLOADS + File.separator + "wulkanowy";
+
+ File dir = new File(path);
+ if(!dir.mkdirs()) {
+ for (String aChildren : dir.list()) {
+ new File(dir, aChildren).delete();
+ }
+ }
+
+ DownloadManager.Request request = new DownloadManager.Request(Uri.parse(update.getUrlToDownload().toString()))
+ .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
+ .setAllowedOverRoaming(false)
+ .setTitle("Wulkanowy v" + update.getLatestVersionCode())
+ .setDescription(update.getLatestVersion())
+ .setVisibleInDownloadsUi(true)
+ .setMimeType("application/vnd.android.package-archive")
+ .setDestinationUri(Uri.fromFile(new File(path + File.separator + update.getLatestVersion() + ".apk")));
+
+ downloadManager.enqueue(request);
+ }
+
+ public void onRequestPermissionsResult(int requestCode, @NonNull int[] grantResults) {
+ if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) {
+ if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ downloadUpdate();
+ } else {
+ Snackbar.make(activity.findViewById(R.id.fragment_container),
+ "Write storage permission request was denied.",
+ Snackbar.LENGTH_LONG)
+ .show();
+ }
+ }
+ }
+
+ public Updater checkForUpdates() {
+ AppUpdaterUtils appUpdaterUtils = new AppUpdaterUtils(activity)
+ .setUpdateFrom(UpdateFrom.JSON)
+ .setUpdateJSON(BuildConfig.UPDATE_URL)
+ .withListener(new AppUpdaterUtils.UpdateListener() {
+
+ @Override
+ public void onSuccess(final Update currentUpdate, Boolean isUpdateAvailable) {
+ Log.d(DEBUG_TAG, "Latest Version: " + currentUpdate.getLatestVersion());
+ Log.d(DEBUG_TAG, "Latest Version Code: " + currentUpdate.getLatestVersionCode().toString());
+ Log.d(DEBUG_TAG, "URL: " + currentUpdate.getUrlToDownload().toString());
+ Log.d(DEBUG_TAG, "Is update available?: " + Boolean.toString(isUpdateAvailable));
+
+ update = currentUpdate;
+ showDialog(isUpdateAvailable);
+ }
+
+ @Override
+ public void onFailed(AppUpdaterError error) {
+ Log.e(DEBUG_TAG, "Something went wrong");
+ Log.e(DEBUG_TAG, error.toString());
+ }
+ });
+ appUpdaterUtils.start();
+
+ return this;
+ }
+
+ private void showDialog(boolean isUpdateAvailable) {
+ if (isUpdateAvailable) {
+ new AlertDialog.Builder(activity)
+ .setTitle("Update is available")
+ .setMessage("Update to version " + update.getLatestVersionCode().toString() +
+ " is available. Your version is " + BuildConfig.VERSION_CODE + ". Update?")
+ .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ downloadUpdate();
+ }
+ })
+ .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ })
+ .show();
+ }
+ }
+
+ public void onDestroy(Activity activity) {
+ activity.unregisterReceiver(onComplete);
+ }
+}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java
index c6b941dc0..322e75c22 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java
+++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.customtabs.CustomTabsIntent;
import android.text.TextUtils;
import android.view.KeyEvent;
@@ -21,6 +22,7 @@ import android.widget.TextView;
import java.util.LinkedHashMap;
import io.github.wulkanowy.R;
+import io.github.wulkanowy.services.Updater;
/**
* A login screen that offers login via email/password.
@@ -35,11 +37,15 @@ public class LoginActivity extends Activity {
private AutoCompleteTextView symbolView;
+ private Updater updater;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
+ updater = new Updater(this).checkForUpdates();
+
// Set up the login form.
emailView = findViewById(R.id.email);
passwordView = findViewById(R.id.password);
@@ -67,6 +73,12 @@ public class LoginActivity extends Activity {
));
}
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ updater.onRequestPermissionsResult(requestCode, grantResults);
+ }
+
private TextView.OnEditorActionListener getTextViewSignInListener() {
return new TextView.OnEditorActionListener() {
@Override
@@ -215,4 +227,10 @@ public class LoginActivity extends Activity {
}
return super.dispatchTouchEvent(ev);
}
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ updater.onDestroy(this);
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java
index 7066d2528..37b141220 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java
+++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java
@@ -158,7 +158,7 @@ public class LoginTask extends AsyncTask {
break;
default:
- Snackbar.make(activity.get().findViewById(R.id.coordinatorLayout),
+ Snackbar.make(activity.get().findViewById(R.id.fragment_container),
messageID, Snackbar.LENGTH_LONG).show();
break;
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/DashboardActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/DashboardActivity.java
index 66015bbe2..6015de007 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/main/DashboardActivity.java
+++ b/app/src/main/java/io/github/wulkanowy/ui/main/DashboardActivity.java
@@ -9,6 +9,7 @@ import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import io.github.wulkanowy.R;
+import io.github.wulkanowy.services.Updater;
import io.github.wulkanowy.ui.main.attendance.AttendanceFragment;
import io.github.wulkanowy.ui.main.board.BoardFragment;
import io.github.wulkanowy.ui.main.grades.GradesFragment;
@@ -26,6 +27,10 @@ public class DashboardActivity extends AppCompatActivity {
private TimetableFragment timetableFragment = new TimetableFragment();
+ private Updater updater;
+
+ private boolean showed;
+
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@@ -87,6 +92,21 @@ public class DashboardActivity extends AppCompatActivity {
.replace(R.id.fragment_container, currentFragment).commit();
}
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (!showed) {
+ updater = new Updater(this).checkForUpdates();
+ showed = true;
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ updater.onRequestPermissionsResult(requestCode, grantResults);
+ }
+
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -104,4 +124,10 @@ public class DashboardActivity extends AppCompatActivity {
moveTaskToBack(true);
}
}
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ updater.onDestroy(this);
+ }
}
diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java
index af8cd2f46..a4d39e06e 100644
--- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java
+++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java
@@ -32,14 +32,16 @@ public class SplashActivity extends AppCompatActivity {
}
private void executeOnRunApp() {
+ Intent intent;
+
if (getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0) == 0) {
- Intent intent = new Intent(this, LoginActivity.class);
- startActivity(intent);
+ intent = new Intent(this, LoginActivity.class);
} else {
new FullSyncJob().scheduledJob(getApplicationContext());
- Intent intent = new Intent(this, DashboardActivity.class);
- startActivity(intent);
+ intent = new Intent(this, DashboardActivity.class);
}
+
+ startActivity(intent);
}
}
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 6f61acab4..86e67f94c 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -6,7 +6,7 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
- android:id="@+id/coordinatorLayout"
+ android:id="@+id/fragment_container"
tools:context="io.github.wulkanowy.ui.login.LoginActivity"
>
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 000000000..3dd0ebffc
--- /dev/null
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index 6fd4d5c7d..e4bc7beca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -37,6 +37,7 @@ allprojects {
jcenter()
mavenCentral()
maven { url 'https://maven.google.com' }
+ maven { url "https://jitpack.io" }
}
}