diff --git a/app/build.gradle b/app/build.gradle index 7ca6452..5b6921d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,5 +45,8 @@ dependencies { implementation libs.preference implementation 'com.github.MikeOrtiz:TouchImageView:3.6' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.0.1' + implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' } \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/LoginActivity.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/LoginActivity.java index 4312735..b7683ff 100644 --- a/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/LoginActivity.java +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/LoginActivity.java @@ -1,9 +1,16 @@ package com.utopiaindustries.hseobservationsapp.activities; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Bundle; +import android.util.Log; +import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; import androidx.activity.EdgeToEdge; @@ -16,17 +23,30 @@ import androidx.lifecycle.ViewModelProvider; import com.utopiaindustries.hseobservationsapp.R; import com.utopiaindustries.hseobservationsapp.apiservice.ApiService; import com.utopiaindustries.hseobservationsapp.apiservice.ApiServiceFactory; +import com.utopiaindustries.hseobservationsapp.apiservice.GiteaClient; +import com.utopiaindustries.hseobservationsapp.apiservice.GiteaRestService; import com.utopiaindustries.hseobservationsapp.helper.Helper; import com.utopiaindustries.hseobservationsapp.helper.Preference; +import com.utopiaindustries.hseobservationsapp.helper.PropertyReader; +import com.utopiaindustries.hseobservationsapp.helper.Release; import com.utopiaindustries.hseobservationsapp.utils.ProgressDialogFragment; import com.utopiaindustries.hseobservationsapp.viewmodels.LoginViewModel; +import java.util.Properties; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + public class LoginActivity extends AppCompatActivity { EditText tfEmail, tfPassword; Button btnLogin; LoginViewModel loginViewModel; ApiService apiService; + TextView txtVersion; + ImageView imgCheckUpdate; + private String currentVersionName; @Override protected void onCreate(Bundle savedInstanceState) { @@ -60,12 +80,34 @@ public class LoginActivity extends AppCompatActivity { finish();*/ } }); + + imgCheckUpdate.setOnClickListener(v -> { + if (!Helper.isNetworkConnected(this)) { + Toast.makeText(this, "No Internet Connection", Toast.LENGTH_LONG).show(); + } + else { + checkForUpdates(); + } + }); + } + + public void setAppVersion() { + PackageManager packageManager = getPackageManager(); + try { + PackageInfo info = packageManager.getPackageInfo( getPackageName(), 0 ); + txtVersion.setText(String.format("Version: %s", info.versionName)); + + } catch ( Exception e ) { + e.printStackTrace(); + } } public void initializeLayout() { tfEmail = findViewById(R.id.tf_email); tfPassword = findViewById(R.id.tf_password); btnLogin = findViewById(R.id.btn_login); + txtVersion = findViewById(R.id.txt_version); + imgCheckUpdate = findViewById(R.id.img_check_update); apiService = ApiServiceFactory.getApiService(); loginViewModel = new ViewModelProvider(this).get(LoginViewModel.class); @@ -102,6 +144,8 @@ public class LoginActivity extends AppCompatActivity { } }); + setAppVersion(); + /*loginViewModel.getUserLiveData().observe(this, user -> { if (user != null) { Preference.setMyBooleanPref(Helper.project_file, "isLoggedIn", getApplicationContext(), true); @@ -156,4 +200,63 @@ public class LoginActivity extends AppCompatActivity { progressDialog.dismiss(); } } + + /** + * check for updates + */ + private void checkForUpdates() { + Log.e("checkForUpdates: ","*****"); + PackageManager packageManager = getPackageManager(); + try { + PackageInfo info = packageManager.getPackageInfo( getPackageName(), 0 ); + currentVersionName = info.versionName; + Log.e("currentVersionName: ",""+currentVersionName); + + } catch ( Exception e ) { + Log.e("Version-Exception: ",""+e.getMessage()); + e.printStackTrace(); + } + // adjust views + showProgressDialog(); + // get properties + Properties properties = PropertyReader.getProperties( LoginActivity.this ); + String token = properties.getProperty( "gitea_access_token" ); + // send request + GiteaRestService restService = GiteaClient.getInstance().create( GiteaRestService.class ); + Call call = restService.getLatestRelease( token ); + call.enqueue( new Callback() { + @Override + public void onResponse( Call call, Response response ) { + Log.e("Response: ",""+response.body()); + if ( response.body() != null ) { + Release release = response.body(); + try { + float releaseVersion = Float.parseFloat( release.getName().replace( "v", "" ) ); + float currentVersion = Float.parseFloat( currentVersionName.replace( "v", "" ) ); + if ( releaseVersion > currentVersion && !Helper.isNullOrEmpty( release.getDownloadUrl() ) ) { + String msg = String.format( "Updating to version %s", release.getName() ); + Toast.makeText( LoginActivity.this, msg, Toast.LENGTH_LONG ).show(); + Intent intent = new Intent( Intent.ACTION_VIEW, Uri.parse( release.getDownloadUrl() ) ); + startActivity( intent ); + //startApkDownloadAndPerformUpdate( release.getDownloadUrl(), release.getName() ); + } else { + Toast.makeText( LoginActivity.this, "Latest version is already installed", Toast.LENGTH_LONG ).show(); + } + } catch ( Exception e ) { + Log.e("Response-Exception: ",""+e.getMessage()); + Toast.makeText( LoginActivity.this, e.getMessage(), Toast.LENGTH_LONG ).show(); + e.printStackTrace(); + } + } + dismissProgressDialog(); + } + + @Override + public void onFailure( Call call, Throwable t ) { + dismissProgressDialog(); + Log.e("Failure: ",""+t.getMessage()); + t.printStackTrace(); + } + } ); + } } \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/SplashActivity.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/SplashActivity.java index e8b0287..0737f86 100644 --- a/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/SplashActivity.java +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/activities/SplashActivity.java @@ -1,6 +1,8 @@ package com.utopiaindustries.hseobservationsapp.activities; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.widget.TextView; @@ -33,7 +35,7 @@ public class SplashActivity extends AppCompatActivity { }); txtVersion = findViewById(R.id.txt_version); - txtVersion.setText(getResources().getString(R.string.app_version)); + setAppVersion(); isLoggedIn = Preference.getMyBooleanPref(Helper.project_file, "isLoggedIn", getApplicationContext()); @@ -54,4 +56,15 @@ public class SplashActivity extends AppCompatActivity { } }, TIMER); } + + public void setAppVersion() { + PackageManager packageManager = getPackageManager(); + try { + PackageInfo info = packageManager.getPackageInfo( getPackageName(), 0 ); + txtVersion.setText(String.format("Version: %s", info.versionName)); + + } catch ( Exception e ) { + e.printStackTrace(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaClient.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaClient.java new file mode 100644 index 0000000..8142b2f --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaClient.java @@ -0,0 +1,27 @@ +package com.utopiaindustries.hseobservationsapp.apiservice; + +import retrofit2.Retrofit; +import retrofit2.converter.jackson.JacksonConverterFactory; + +public class GiteaClient { + private static Retrofit retrofit; + private static final String BASE_URL = "https://git.utopiadeals.com/api/v1/repos/UIND/Quality-Checker-Android-Releases/"; + + /** + * get retrofit instance + */ + public static Retrofit getInstance() { + if ( retrofit == null ) { + try { + retrofit = new Retrofit.Builder() + .baseUrl( BASE_URL ) + .addConverterFactory( JacksonConverterFactory.create() ) + .client( SSLCheckHttpClient.getOkHttpClient() ) + .build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return retrofit; + } +} diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaRestService.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaRestService.java new file mode 100644 index 0000000..455f456 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/GiteaRestService.java @@ -0,0 +1,16 @@ +package com.utopiaindustries.hseobservationsapp.apiservice; + +import com.utopiaindustries.hseobservationsapp.helper.Release; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface GiteaRestService { + + /** + * get latest release + */ + @GET( "releases/latest" ) + Call getLatestRelease(@Query( "access_token" ) String accessToken ); +} diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/SSLCheckHttpClient.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/SSLCheckHttpClient.java new file mode 100644 index 0000000..3ee6e02 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/apiservice/SSLCheckHttpClient.java @@ -0,0 +1,52 @@ +package com.utopiaindustries.hseobservationsapp.apiservice; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import okhttp3.OkHttpClient; + +public class SSLCheckHttpClient { + public static OkHttpClient getOkHttpClient() throws NoSuchAlgorithmException, KeyManagementException { + // Create a trust manager that does not validate certificate chains + final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + }; + + // Install the all-trusting trust manager + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + // Create an ssl socket factory with our all-trusting manager + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + + return new OkHttpClient.Builder() + .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier((hostname, session) -> true) + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .build(); + } +} diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Helper.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Helper.java index 3d6e82b..792c260 100644 --- a/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Helper.java +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Helper.java @@ -187,4 +187,8 @@ public class Helper { } } + public static boolean isNullOrEmpty( String str ) { + return str == null || str.isEmpty(); + } + } diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/PropertyReader.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/PropertyReader.java new file mode 100644 index 0000000..5d2c7c7 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/PropertyReader.java @@ -0,0 +1,24 @@ +package com.utopiaindustries.hseobservationsapp.helper; + +import android.content.Context; +import android.content.res.Resources; + +import com.utopiaindustries.hseobservationsapp.R; + +import java.io.InputStream; +import java.util.Properties; + +public class PropertyReader { + + public static Properties getProperties( Context context ) { + Properties properties = new Properties(); + try { + Resources resources = context.getResources(); + InputStream inputStream = resources.openRawResource( R.raw.application ); + properties.load( inputStream ); + } catch ( Exception e ) { + e.printStackTrace(); + } + return properties; + } +} diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Release.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Release.java new file mode 100644 index 0000000..dde9702 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/Release.java @@ -0,0 +1,69 @@ +package com.utopiaindustries.hseobservationsapp.helper; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import java.util.List; + +@JsonIgnoreProperties( ignoreUnknown = true ) +@JsonNaming( PropertyNamingStrategy.SnakeCaseStrategy.class ) +public class Release { + private String id; + private String tagName; + private String name; + private List assets; + + public Release() { + } + + public String getId() { + return id; + } + + public void setId( String id ) { + this.id = id; + } + + public String getTagName() { + return tagName; + } + + public void setTagName( String tagName ) { + this.tagName = tagName; + } + + public String getName() { + return name; + } + + public void setName( String name ) { + this.name = name; + } + + public List getAssets() { + return assets; + } + + public void setAssets( List assets ) { + this.assets = assets; + } + + public String getDownloadUrl() { + if ( this.assets == null || this.assets.isEmpty() ) { + return null; + } + return this.assets.get( 0 ).getBrowserDownloadUrl(); + } + + @Override + public String toString() { + return "Release{" + + "id='" + id + '\'' + + ", tagName='" + tagName + '\'' + + ", name='" + name + '\'' + + ", assets=" + assets + + '}'; + } +} diff --git a/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/ReleaseAsset.java b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/ReleaseAsset.java new file mode 100644 index 0000000..e13ae13 --- /dev/null +++ b/app/src/main/java/com/utopiaindustries/hseobservationsapp/helper/ReleaseAsset.java @@ -0,0 +1,89 @@ +package com.utopiaindustries.hseobservationsapp.helper; + +import java.time.ZonedDateTime; + + +@JsonIgnoreProperties( ignoreUnknown = true ) +@JsonNaming( PropertyNamingStrategy.SnakeCaseStrategy.class ) +public class ReleaseAsset { + private String id; + private String name; + private long size; + private long downloadCount; + @JsonDeserialize( using = ZonedDateTimeDeserializer.class ) + private ZonedDateTime createdAt; + private String uuid; + private String browserDownloadUrl; + + public ReleaseAsset() { + } + + public String getId() { + return id; + } + + public void setId( String id ) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName( String name ) { + this.name = name; + } + + public long getSize() { + return size; + } + + public void setSize( long size ) { + this.size = size; + } + + public long getDownloadCount() { + return downloadCount; + } + + public void setDownloadCount( long downloadCount ) { + this.downloadCount = downloadCount; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt( ZonedDateTime createdAt ) { + this.createdAt = createdAt; + } + + public String getUuid() { + return uuid; + } + + public void setUuid( String uuid ) { + this.uuid = uuid; + } + + public String getBrowserDownloadUrl() { + return browserDownloadUrl; + } + + public void setBrowserDownloadUrl( String browserDownloadUrl ) { + this.browserDownloadUrl = browserDownloadUrl; + } + + @Override + public String toString() { + return "ReleaseAsset{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", size=" + size + + ", downloadCount=" + downloadCount + + ", createdAt=" + createdAt + + ", uuid='" + uuid + '\'' + + ", browserDownloadUrl='" + browserDownloadUrl + '\'' + + '}'; + } +} diff --git a/app/src/main/res/drawable/icon_gear_fill.xml b/app/src/main/res/drawable/icon_gear_fill.xml new file mode 100644 index 0000000..ebb000d --- /dev/null +++ b/app/src/main/res/drawable/icon_gear_fill.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/icon_update.xml b/app/src/main/res/drawable/icon_update.xml new file mode 100644 index 0000000..6be0972 --- /dev/null +++ b/app/src/main/res/drawable/icon_update.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index cbd2bc0..cc2a7e1 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -88,4 +88,26 @@ android:textSize="@dimen/_15sdp" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/application.properties b/app/src/main/res/raw/application.properties new file mode 100644 index 0000000..b2a3222 --- /dev/null +++ b/app/src/main/res/raw/application.properties @@ -0,0 +1 @@ +gitea_access_token=3efaddad018362af36b515c091d66da34b97abe2 \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 6f4fe8d..396ea9d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -20,6 +20,8 @@ #C5EAF8 #E2F4FB + #334155 + #9933CC #A041D0 #A750D3