Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Release v1.1.0 with OkHttp library for downloading files from network
  • Loading branch information
Javinator9889 committed Apr 21, 2020
1 parent a4f7710 commit 08d166c
Show file tree
Hide file tree
Showing 23 changed files with 381 additions and 64 deletions.
17 changes: 8 additions & 9 deletions app/build.gradle
Expand Up @@ -43,9 +43,10 @@ android {
applicationId "com.javinator9889.handwashingreminder"
minSdkVersion 17
targetSdkVersion 29
versionCode 94
versionName "1.0.1-${gitCommitHash}"
versionCode 100
versionName "1.1.0-${gitCommitHash}"
multiDexEnabled true
resConfigs "en", "es"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -89,7 +90,7 @@ android {
preDexLibraries true
javaMaxHeapSize "1G"
}
dynamicFeatures = [":appintro", ":ads", ":bundledemoji"]
dynamicFeatures = [":appintro", ":ads", ":bundledemoji", ":okhttp", ":okhttplegacy"]

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand All @@ -100,7 +101,6 @@ android {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}


}

dependencies {
Expand All @@ -127,11 +127,6 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
// https://developer.android.com/studio/build/multidex
implementation 'androidx.multidex:multidex:2.0.1'
// https://github.com/afollestad/material-dialogs
implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:datetime:3.3.0'
implementation 'com.afollestad.material-dialogs:lifecycle:3.3.0'
implementation 'com.afollestad.material-dialogs:bottomsheets:3.3.0'
// https://github.com/mikepenz/Android-Iconics
implementation 'com.mikepenz:iconics-core:5.0.2'
implementation 'com.mikepenz:iconics-views:5.0.2'
Expand Down Expand Up @@ -190,4 +185,8 @@ dependencies {
implementation 'com.beust:klaxon:5.2'
// https://github.com/SufficientlySecure/html-textview
implementation 'org.sufficientlysecure:html-textview:3.9'
// https://square.github.io/okio/#releases
implementation 'com.squareup.okio:okio:2.5.0'
// https://github.com/google/conscrypt/
implementation 'org.conscrypt:conscrypt-android:2.4.0'
}
16 changes: 16 additions & 0 deletions app/proguard-rules.pro
Expand Up @@ -36,6 +36,22 @@
*;
}

-keep class com.javinator9889.handwashingreminder.okhttp.OkHttpDownloader {
com.javinator9889.handwashingreminder.okhttp.OkHttpDownloader$Provider Provider;
}

-keep com.javinator9889.handwashingreminder.okhttp.OkHttpDownloader$Provider {
*;
}

-keep class com.javinator9889.handwashingreminder.okhttplegacy.OkHttpDownloader {
com.javinator9889.handwashingreminder.okhttplegacy.OkHttpDownloader$Provider Provider;
}

-keep com.javinator9889.handwashingreminder.okhttplegacy.OkHttpDownloader$Provider {
*;
}

-keep class com.javinator9889.handwashingreminder.bundledemoji.BundledEmojiConfig {
*;
}
Expand Down
Expand Up @@ -49,7 +49,9 @@ import com.mikepenz.iconics.Iconics
import javinator9889.localemanager.utils.languagesupport.LanguagesSupport
import kotlinx.android.synthetic.main.splash_screen.*
import kotlinx.coroutines.*
import org.conscrypt.Conscrypt
import timber.log.Timber
import java.security.Security
import java.util.*
import kotlin.collections.ArrayList

Expand Down Expand Up @@ -138,13 +140,7 @@ class LauncherActivity : AppCompatActivity() {
if (app.sharedPreferences.getBoolean(ADS_ENABLED, true)) {
when (resultCode) {
Activity.RESULT_OK -> {
val className = "${Ads.PACKAGE_NAME}.${Ads
.CLASS_NAME}\$${Ads.PROVIDER_NAME}"
val adProvider = Class.forName(className).kotlin
.objectInstance as AdLoader.Provider
app.adLoader = adProvider.instance(app)
val adsEnabler = AdsEnabler(app)
adsEnabler.enableAds()
initAds()
data.notNull {
createPackageContext(packageName, 0).also {
SplitCompat.install(it)
Expand Down Expand Up @@ -189,6 +185,10 @@ class LauncherActivity : AppCompatActivity() {
modules += AppIntro.MODULE_NAME
launchOnInstall = true
}
modules += if (isAtLeast(AndroidVersion.LOLLIPOP) && false)
OkHttp.MODULE_NAME
else
OkHttpLegacy.MODULE_NAME
if (googleApi.isGooglePlayServicesAvailable(
this,
GOOGLE_PLAY_SERVICES_MIN_VERSION
Expand All @@ -213,6 +213,16 @@ class LauncherActivity : AppCompatActivity() {
startActivityForResult(intent, DYNAMIC_FEATURE_INSTALL_RESULT_CODE)
}

private fun initAds() {
val className = "${Ads.PACKAGE_NAME}.${Ads
.CLASS_NAME}\$${Ads.PROVIDER_NAME}"
val adProvider = Class.forName(className).kotlin
.objectInstance as AdLoader.Provider
app.adLoader = adProvider.instance(app)
val adsEnabler = AdsEnabler(app)
adsEnabler.enableAds()
}

private fun createDynamicFeatureActivityIntent(
modules: Array<String>,
launchOnInstall: Boolean = false,
Expand All @@ -228,6 +238,9 @@ class LauncherActivity : AppCompatActivity() {
private fun initVariables() {
Timber.d("Initializing Iconics")
Iconics.init(this)
Timber.d("Setting-up security providers")
Security.insertProviderAt(Conscrypt.newProvider(), 1)
Timber.d("Setting-up activity recognition")
if (app.sharedPreferences.getBoolean(
Preferences.ACTIVITY_TRACKING_ENABLED, false
) && with(GoogleApiAvailability.getInstance()) {
Expand All @@ -239,13 +252,15 @@ class LauncherActivity : AppCompatActivity() {
} else {
app.activityHandler.disableActivityTracker()
}
Timber.d("Initializing Billing Service")
app.billingService = BillingService(this)
try {
app.workHandler.enqueuePeriodicNotificationsWorker()
Timber.d("Adding periodic notifications if not enqueued yet")
} catch (_: UninitializedPropertyAccessException) {
Timber.i("Scheduler times have not been initialized")
}
Timber.d("Setting-up Firebase custom properties")
setupFirebaseProperties()
}

Expand All @@ -261,22 +276,24 @@ class LauncherActivity : AppCompatActivity() {
with(firebaseRemoteConfig) {
Timber.d("Initializing Firebase Remote Config")
setConfigSettingsAsync(config)
setDefaultsAsync(when (Locale.getDefault().language) {
Locale(LanguagesSupport.Language.SPANISH).language -> {
firebaseAnalytics.setUserProperty(
Firebase.Properties.LANGUAGE,
LanguagesSupport.Language.SPANISH
)
R.xml.remote_config_defaults_es
}
else -> {
firebaseAnalytics.setUserProperty(
Firebase.Properties.LANGUAGE,
LanguagesSupport.Language.ENGLISH
)
R.xml.remote_config_defaults
setDefaultsAsync(
when (Locale.getDefault().language) {
Locale(LanguagesSupport.Language.SPANISH).language -> {
firebaseAnalytics.setUserProperty(
Firebase.Properties.LANGUAGE,
LanguagesSupport.Language.SPANISH
)
R.xml.remote_config_defaults_es
}
else -> {
firebaseAnalytics.setUserProperty(
Firebase.Properties.LANGUAGE,
LanguagesSupport.Language.ENGLISH
)
R.xml.remote_config_defaults
}
}
})
)
fetchAndActivate().addOnSuccessListener {
if (canFinishActivity)
finish()
Expand Down
Expand Up @@ -127,7 +127,6 @@ class SliderView : BaseFragmentView() {
GlideApp.with(this)
.load(drawableId)
.centerInside()
.centerCrop()
.into(image)
} catch (e: Exception) {
Timber.e(e, "Error while loading Glide view")
Expand Down
Expand Up @@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import com.google.firebase.perf.metrics.AddTrace
import com.javinator9889.handwashingreminder.application.HandwashingApplication
import com.javinator9889.handwashingreminder.network.HttpDownloader
import com.javinator9889.handwashingreminder.utils.Videos.URI.FILENAME
import com.javinator9889.handwashingreminder.utils.Videos.URI.HASH
import com.javinator9889.handwashingreminder.utils.Videos.URI.URL
Expand All @@ -32,10 +33,14 @@ import com.javinator9889.handwashingreminder.utils.isConnected
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.withContext
import okio.HashingSink
import okio.buffer
import okio.sink
import timber.log.Timber
import java.io.*
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.math.BigInteger
import java.net.URL
import java.security.MessageDigest
import javax.inject.Inject

Expand Down Expand Up @@ -78,32 +83,20 @@ class VideoModel(
): File {
val file = File(cachePath, name)
withContext(Dispatchers.IO) {
val digest = MessageDigest.getInstance("SHA-256")
if (!isConnected() || !needsToDownloadFile(file, hash))
return@withContext
else
file.createNewFile()
val hashingSink = HashingSink.sha256(file.sink())
do {
if (!isConnected() || !needsToDownloadFile(file, hash))
return@withContext
else
file.createNewFile()
val stream = with(URL(url)) {
openStream()
}.let { BufferedInputStream(it, 8192) }
val data = ByteArray(8192)
val output = FileOutputStream(file)
try {
var count = stream.read(data)
while (count > 0) {
output.write(data, 0, count)
digest.update(data, 0, count)
count = stream.read(data)
val okHttpDownloader = HttpDownloader.newInstance()
with(okHttpDownloader.downloadFile(url)) {
hashingSink.buffer().use {
it.writeAll(this)
}
output.flush()
} catch (e: IOException) {
Timber.e(e, "Unable to download video $name")
} finally {
output.close()
stream.close()
close()
}
} while (!sameSHA2Hash(hash, digest))
} while (!hashingSink.hash.hex().equals(hash, true))
}
return file
}
Expand Down
Expand Up @@ -22,7 +22,9 @@

import androidx.annotation.NonNull;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.module.AppGlideModule;
Expand All @@ -37,4 +39,10 @@ public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder
.format(DecodeFormat.PREFER_ARGB_8888)
);
}

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
// super.registerComponents(context, glide, registry);
// glide.getRegistry().
}
}
@@ -0,0 +1,37 @@
/*
* Copyright © 2020 - present | Handwashing reminder by Javinator9889
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*
* Created by Javinator9889 on 21/04/20 - Handwashing reminder.
*/
package com.javinator9889.handwashingreminder.network

import com.javinator9889.handwashingreminder.utils.AndroidVersion
import com.javinator9889.handwashingreminder.utils.OkHttp
import com.javinator9889.handwashingreminder.utils.OkHttpLegacy
import com.javinator9889.handwashingreminder.utils.isAtLeast

object HttpDownloader {
fun newInstance(): OkHttpDownloader {
val className = if (isAtLeast(AndroidVersion.LOLLIPOP) && false)
"${OkHttp.PACKAGE_NAME}.${OkHttp.CLASS_NAME}\$${OkHttp.PROVIDER_NAME}"
else
"${OkHttpLegacy.PACKAGE_NAME}.${OkHttpLegacy
.CLASS_NAME}\$${OkHttpLegacy.PROVIDER_NAME}"
val okHttpProvider = Class.forName(className).kotlin.objectInstance
as OkHttpDownloader.Provider
return okHttpProvider.newInstance()
}
}
@@ -0,0 +1,29 @@
/*
* Copyright © 2020 - present | Handwashing reminder by Javinator9889
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*
* Created by Javinator9889 on 21/04/20 - Handwashing reminder.
*/
package com.javinator9889.handwashingreminder.network

import okio.BufferedSource

interface OkHttpDownloader {
interface Provider {
fun newInstance(): OkHttpDownloader
}

fun downloadFile(url: String): BufferedSource
}
Expand Up @@ -79,6 +79,24 @@ class BundledEmoji {
}
}

class OkHttp {
companion object Modules {
const val MODULE_NAME = "okhttp"
const val PACKAGE_NAME = "com.javinator9889.handwashingreminder.okhttp"
const val CLASS_NAME = "OkHttpDownloader"
const val PROVIDER_NAME = "Provider"
}
}

class OkHttpLegacy {
companion object Modules {
const val MODULE_NAME = "okhttplegacy"
const val PACKAGE_NAME = "com.javinator9889.handwashingreminder.okhttplegacy"
const val CLASS_NAME = "OkHttpDownloader"
const val PROVIDER_NAME = "Provider"
}
}

class RemoteConfig {
companion object Keys {
const val SPECIAL_EVENT = "special_event"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Expand Up @@ -275,4 +275,6 @@
<string name="prevention">Prevention</string>
<string name="written_by">Written by %s</string>
<string name="available_at">Available at: %s</string>
<string name="title_okhttp" translatable="false">OkHttp</string>
<string name="title_okhttplegacy" translatable="false">Ok HTTP Legacy</string>
</resources>

0 comments on commit 08d166c

Please sign in to comment.