Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc40dc7f authored by Nishant Dande's avatar Nishant Dande
Browse files

Implement network api using coroutine

parent 8463f689
Loading
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -147,6 +147,8 @@ allOpen {


dependencies {
dependencies {


    implementation project(path: ':modules')

    // TODO: Add splitinstall-lib to a repo https://gitlab.e.foundation/e/os/backlog/-/issues/628
    // TODO: Add splitinstall-lib to a repo https://gitlab.e.foundation/e/os/backlog/-/issues/628
    api files('libs/splitinstall-lib.jar')
    api files('libs/splitinstall-lib.jar')


+17 −3
Original line number Original line Diff line number Diff line
plugins {
plugins {
    id 'com.android.library'
    id 'com.android.library'
    id 'org.jetbrains.kotlin.android'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
    id("com.google.dagger.hilt.android")
}
}


ext {
ext {
@@ -8,9 +10,14 @@ ext {
    android_target_sdk_version = 33
    android_target_sdk_version = 33
    core_version = '1.10.1'
    core_version = '1.10.1'
    gson_version = '2.9.0'
    gson_version = '2.9.0'
    kotlin_reflection = '1.8.10'
    kotlin_reflection = '1.8.20'
    retrofit_version = '2.9.0'
    retrofit_version = '2.9.0'
    retrofit_interceptor_version = '5.0.0-alpha.2'
    retrofit_interceptor_version = '5.0.0-alpha.2'
    kotlin_coroutines_core = '1.7.2'
    google_play_api = '3.0.1'
    protobuf_java = '3.19.3'
    javax_version = '1'
    dagger_hilt_version = '2.46.1'
}
}


android {
android {
@@ -45,13 +52,20 @@ dependencies {
    implementation "androidx.core:core-ktx:$core_version"
    implementation "androidx.core:core-ktx:$core_version"
    implementation "com.google.code.gson:gson:$gson_version"
    implementation "com.google.code.gson:gson:$gson_version"
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_reflection"
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_reflection"
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_core")


    // region Retrofit
    implementation("com.squareup.retrofit2:retrofit:$retrofit_version")
    implementation("com.squareup.retrofit2:retrofit:$retrofit_version")
    implementation("com.squareup.retrofit2:converter-gson:$retrofit_version")
    implementation("com.squareup.retrofit2:converter-gson:$retrofit_version")
    implementation("com.squareup.retrofit2:converter-scalars:$retrofit_version")
    implementation("com.squareup.retrofit2:converter-scalars:$retrofit_version")
    implementation("com.squareup.okhttp3:logging-interceptor:$retrofit_interceptor_version")
    implementation("com.squareup.okhttp3:logging-interceptor:$retrofit_interceptor_version")
    // endregion

    implementation("foundation.e:gplayapi:$google_play_api")
    implementation("com.google.protobuf:protobuf-java:$protobuf_java")

    implementation("javax.inject:javax.inject:$javax_version")

    implementation("com.google.dagger:hilt-android:$dagger_hilt_version")
    kapt("com.google.dagger:hilt-android-compiler:$dagger_hilt_version")


    testImplementation 'junit:junit:4.13.2'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+149 −0
Original line number Original line Diff line number Diff line
package app.lounge

import app.lounge.model.AnonymousAuthDataRequestBody
import app.lounge.model.AnonymousAuthDataValidationRequestBody
import app.lounge.model.AuthDataResponse
import app.lounge.model.AuthDataValidationResponse
import app.lounge.networking.NetworkFetching
import app.lounge.networking.NetworkFetchingRetrofitAPI
import app.lounge.networking.NetworkFetchingRetrofitImpl
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient
import org.junit.Test
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.InterruptedIOException
import java.util.Properties
import java.util.concurrent.TimeUnit

class NetworkFetchingAPITest {

    private val networkFetchingToken: NetworkFetching = NetworkFetchingRetrofitImpl(
        Retrofit.Builder()
            .baseUrl(NetworkFetchingRetrofitAPI.tokenBaseURL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(
                OkHttpClient.Builder()
                    .callTimeout(10, TimeUnit.SECONDS)
                    .build()
            )
            .build()
    )

    private val networkFetchingGoogle: NetworkFetching = NetworkFetchingRetrofitImpl(
        Retrofit.Builder()
            .baseUrl(NetworkFetchingRetrofitAPI.googlePlayBaseURL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(
                OkHttpClient.Builder()
                    .callTimeout(10, TimeUnit.SECONDS)
                    .build()
            )
            .build()
    )

    private val networkFetchingTimeoutGoogle: NetworkFetching = NetworkFetchingRetrofitImpl(
        Retrofit.Builder()
            .baseUrl(NetworkFetchingRetrofitAPI.googlePlayBaseURL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(
                OkHttpClient.Builder()
                    .callTimeout(10, TimeUnit.MILLISECONDS)
                    .build()
            )
            .build()
    )

    private val requestBodyData = AnonymousAuthDataRequestBody(
        properties = testSystemProperties,
        userAgent = testUserAgent
    )

    companion object {
        var authData: AuthDataResponse? =  null
    }

    @Test
    fun test1OnSuccessReturnsAuthData() = runBlocking {
        authData = networkFetchingToken.requestAuthData(
            anonymousAuthDataRequestBody = requestBodyData,
        )
        assert(authData is AuthDataResponse) { "Assert!! Success must return data" }
    }

    @Test
    fun test2OnSuccessReturnsLoginData() = runBlocking {
        var result: AuthDataValidationResponse? = null
        authData?.let { authData ->
            authData.dfeCookie = "null"

            result = networkFetchingGoogle.requestAuthDataValidation(
                anonymousAuthDataValidationRequestBody = AnonymousAuthDataValidationRequestBody(
                    authDataResponse = authData
                )
            )
        }

        assert(authData is AuthDataResponse) { "Assert!! AuthData must be present" }
        assert(result is AuthDataValidationResponse) { "Assert!! `response` must have data" }
    }

    @Test
    fun test3OnTimeoutFailureReturnsError(): Unit = runBlocking {
        var failure: Exception = Exception("No Error")
        authData?.let { authData ->
            authData.dfeCookie = "null"

            try {
                networkFetchingTimeoutGoogle.requestAuthDataValidation(
                    anonymousAuthDataValidationRequestBody = AnonymousAuthDataValidationRequestBody(
                        authDataResponse = authData
                    )
                )
            } catch (e: InterruptedIOException) { failure = e }
        }
        assert(authData is AuthDataResponse) { "Assert!! AuthData must be present" }
        assert(failure is InterruptedIOException) { "Assert!! Timeout Failure callback must call" }
    }
}

private const val testUserAgent: String = "{\"package\":\"foundation.e.apps.debug\",\"version\":\"2.5.5.debug\",\"device\":\"coral\",\"api\":32,\"os_version\":\"1.11-s-20230511288805-dev-coral\",\"build_id\":\"319e25cd.20230630224839\"}"

private val testSystemProperties = Properties().apply {
    setProperty("UserReadableName", "coral-default")
    setProperty("Build.HARDWARE", "coral")
    setProperty("Build.RADIO", "g8150-00123-220402-B-8399852")
    setProperty("Build.FINGERPRINT","google/coral/coral:12/SQ3A.220705.003.A1/8672226:user/release-keys")
    setProperty("Build.BRAND", "google")
    setProperty("Build.DEVICE", "coral")
    setProperty("Build.VERSION.SDK_INT", "32")
    setProperty("Build.VERSION.RELEASE", "12")
    setProperty("Build.MODEL", "Pixel 4 XL")
    setProperty("Build.MANUFACTURER", "Google")
    setProperty("Build.PRODUCT", "coral")
    setProperty("Build.ID", "SQ3A.220705.004")
    setProperty("Build.BOOTLOADER", "c2f2-0.4-8351033")
    setProperty("TouchScreen", "3")
    setProperty("Keyboard", "1")
    setProperty("Navigation", "1")
    setProperty("ScreenLayout", "2")
    setProperty("HasHardKeyboard", "false")
    setProperty("HasFiveWayNavigation", "false")
    setProperty("Screen.Density", "560")
    setProperty("Screen.Width", "1440")
    setProperty("Screen.Height", "2984")
    setProperty("Platforms", "arm64-v8a,armeabi-v7a,armeabi")
    setProperty("Features", "android.hardware.sensor.proximity,com.verizon.hardware.telephony.lte,com.verizon.hardware.telephony.ehrpd,android.hardware.sensor.accelerometer,android.software.controls,android.hardware.faketouch,com.google.android.feature.D2D_CABLE_MIGRATION_FEATURE,android.hardware.telephony.euicc,android.hardware.reboot_escrow,android.hardware.usb.accessory,android.hardware.telephony.cdma,android.software.backup,android.hardware.touchscreen,android.hardware.touchscreen.multitouch,android.software.print,org.lineageos.weather,android.software.activities_on_secondary_displays,android.hardware.wifi.rtt,com.google.android.feature.PIXEL_2017_EXPERIENCE,android.software.voice_recognizers,android.software.picture_in_picture,android.hardware.sensor.gyroscope,android.hardware.audio.low_latency,android.software.vulkan.deqp.level,android.software.cant_save_state,com.google.android.feature.PIXEL_2018_EXPERIENCE,android.hardware.security.model.compatible,com.google.android.feature.PIXEL_2019_EXPERIENCE,android.hardware.opengles.aep,org.lineageos.livedisplay,org.lineageos.profiles,android.hardware.bluetooth,android.hardware.camera.autofocus,android.hardware.telephony.gsm,android.hardware.telephony.ims,android.software.incremental_delivery,android.software.sip.voip,android.hardware.se.omapi.ese,android.software.opengles.deqp.level,android.hardware.usb.host,android.hardware.audio.output,android.software.verified_boot,android.hardware.camera.flash,android.hardware.camera.front,android.hardware.sensor.hifi_sensors,com.google.android.apps.photos.PIXEL_2019_PRELOAD,android.hardware.se.omapi.uicc,android.hardware.strongbox_keystore,android.hardware.screen.portrait,android.hardware.nfc,com.google.android.feature.TURBO_PRELOAD,com.nxp.mifare,android.hardware.sensor.stepdetector,android.software.home_screen,android.hardware.context_hub,android.hardware.microphone,android.software.autofill,org.lineageos.hardware,org.lineageos.globalactions,android.software.securely_removes_users,com.google.android.feature.PIXEL_EXPERIENCE,android.hardware.bluetooth_le,android.hardware.sensor.compass,com.google.android.feature.GOOGLE_FI_BUNDLED,android.hardware.touchscreen.multitouch.jazzhand,android.hardware.sensor.barometer,android.software.app_widgets,android.hardware.telephony.carrierlock,android.software.input_methods,android.hardware.sensor.light,android.hardware.vulkan.version,android.software.companion_device_setup,android.software.device_admin,com.google.android.feature.WELLBEING,android.hardware.wifi.passpoint,android.hardware.camera,org.lineageos.trust,android.hardware.device_unique_attestation,android.hardware.screen.landscape,android.software.device_id_attestation,com.google.android.feature.AER_OPTIMIZED,android.hardware.ram.normal,org.lineageos.android,com.google.android.feature.PIXEL_2019_MIDYEAR_EXPERIENCE,android.software.managed_users,android.software.webview,android.hardware.sensor.stepcounter,android.hardware.camera.capability.manual_post_processing,android.hardware.camera.any,android.hardware.camera.capability.raw,android.hardware.vulkan.compute,android.software.connectionservice,android.hardware.touchscreen.multitouch.distinct,android.hardware.location.network,android.software.cts,android.software.sip,android.hardware.camera.capability.manual_sensor,android.software.app_enumeration,android.hardware.camera.level.full,android.hardware.identity_credential,android.hardware.wifi.direct,android.software.live_wallpaper,android.software.ipsec_tunnels,org.lineageos.settings,android.hardware.sensor.assist,android.hardware.audio.pro,android.hardware.nfc.hcef,android.hardware.nfc.uicc,android.hardware.location.gps,android.sofware.nfc.beam,android.software.midi,android.hardware.nfc.any,android.hardware.nfc.ese,android.hardware.nfc.hce,android.hardware.wifi,android.hardware.location,android.hardware.vulkan.level,android.hardware.wifi.aware,android.software.secure_lock_screen,android.hardware.biometrics.face,android.hardware.telephony,android.software.file_based_encryption")
    setProperty("Locales", "af,af_ZA,am,am_ET,ar,ar_EG,ar_XB,as,ast_ES,az,be,bg,bg_BG,bn,bs,ca,ca_ES,cs,cs_CZ,cy,da,da_DK,de,de_DE,el,el_GR,en,en_AU,en_CA,en_GB,en_IN,en_US,en_XA,en_XC,es,es_419,es_ES,es_US,et,eu,fa,fa_IR,fi,fi_FI,fil,fil_PH,fr,fr_CA,fr_FR,gd,gl,gu,hi,hi_IN,hr,hr_HR,hu,hu_HU,hy,in,in_ID,is,it,it_IT,iw,iw_IL,ja,ja_JP,ka,kk,km,kn,ko,ko_KR,ky,lo,lt,lt_LT,lv,lv_LV,mk,ml,mn,mr,ms,ms_MY,my,nb,nb_NO,ne,nl,nl_NL,or,pa,pl,pl_PL,pt,pt_BR,pt_PT,ro,ro_RO,ru,ru_RU,si,sk,sk_SK,sl,sl_SI,sq,sr,sr_Latn,sr_RS,sv,sv_SE,sw,sw_TZ,ta,te,th,th_TH,tr,tr_TR,uk,uk_UA,ur,uz,vi,vi_VN,zh_CN,zh_HK,zh_TW,zu,zu_ZA")
    setProperty("SharedLibraries", "android.test.base,android.test.mock,com.vzw.apnlib,android.hidl.manager-V1.0-java,qti-telephony-hidl-wrapper,libfastcvopt.so,google-ril,qti-telephony-utils,com.android.omadm.radioconfig,libcdsprpc.so,android.hidl.base-V1.0-java,com.qualcomm.qmapbridge,libairbrush-pixel.so,com.google.android.camera.experimental2019,libOpenCL-pixel.so,libadsprpc.so,com.android.location.provider,android.net.ipsec.ike,com.android.future.usb.accessory,libsdsprpc.so,android.ext.shared,javax.obex,izat.xt.srv,com.google.android.gms,lib_aion_buffer.so,com.qualcomm.uimremoteclientlibrary,libqdMetaData.so,com.qualcomm.uimremoteserverlibrary,com.qualcomm.qcrilhook,android.test.runner,org.apache.http.legacy,com.google.android.camera.extensions,com.google.android.hardwareinfo,com.android.cts.ctsshim.shared_library,com.android.nfc_extras,com.android.media.remotedisplay,com.android.mediadrm.signer,com.qualcomm.qti.imscmservice-V2.0-java,qti-telephony-hidl-wrapper-prd,com.qualcomm.qti.imscmservice-V2.1-java,com.qualcomm.qti.imscmservice-V2.2-java")
    setProperty("GL.Version", "196610")
    setProperty("GL.Extensions", ",GL_AMD_compressed_ATC_texture,GL_AMD_performance_monitor,GL_ANDROID_extension_pack_es31a,GL_APPLE_texture_2D_limited_npot,GL_ARB_vertex_buffer_object,GL_ARM_shader_framebuffer_fetch_depth_stencil,GL_EXT_EGL_image_array,GL_EXT_EGL_image_external_wrap_modes,GL_EXT_EGL_image_storage,GL_EXT_YUV_target,GL_EXT_blend_func_extended,GL_EXT_blit_framebuffer_params,GL_EXT_buffer_storage,GL_EXT_clip_control,GL_EXT_clip_cull_distance,GL_EXT_color_buffer_float,GL_EXT_color_buffer_half_float,GL_EXT_copy_image,GL_EXT_debug_label,GL_EXT_debug_marker,GL_EXT_discard_framebuffer,GL_EXT_disjoint_timer_query,GL_EXT_draw_buffers_indexed,GL_EXT_external_buffer,GL_EXT_fragment_invocation_density,GL_EXT_geometry_shader,GL_EXT_gpu_shader5,GL_EXT_memory_object,GL_EXT_memory_object_fd,GL_EXT_multisampled_render_to_texture,GL_EXT_multisampled_render_to_texture2,GL_EXT_primitive_bounding_box,GL_EXT_protected_textures,GL_EXT_read_format_bgra,GL_EXT_robustness,GL_EXT_sRGB,GL_EXT_sRGB_write_control,GL_EXT_shader_framebuffer_fetch,GL_EXT_shader_io_blocks,GL_EXT_shader_non_constant_global_initializers,GL_EXT_tessellation_shader,GL_EXT_texture_border_clamp,GL_EXT_texture_buffer,GL_EXT_texture_cube_map_array,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_format_BGRA8888,GL_EXT_texture_format_sRGB_override,GL_EXT_texture_norm16,GL_EXT_texture_sRGB_R8,GL_EXT_texture_sRGB_decode,GL_EXT_texture_type_2_10_10_10_REV,GL_KHR_blend_equation_advanced,GL_KHR_blend_equation_advanced_coherent,GL_KHR_debug,GL_KHR_no_error,GL_KHR_robust_buffer_access_behavior,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_NV_shader_noperspective_interpolation,GL_OES_EGL_image,GL_OES_EGL_image_external,GL_OES_EGL_image_external_essl3,GL_OES_EGL_sync,GL_OES_blend_equation_separate,GL_OES_blend_func_separate,GL_OES_blend_subtract,GL_OES_compressed_ETC1_RGB8_texture,GL_OES_compressed_paletted_texture,GL_OES_depth24,GL_OES_depth_texture,GL_OES_depth_texture_cube_map,GL_OES_draw_texture,GL_OES_element_index_uint,GL_OES_framebuffer_object,GL_OES_get_program_binary,GL_OES_matrix_palette,GL_OES_packed_depth_stencil,GL_OES_point_size_array,GL_OES_point_sprite,GL_OES_read_format,GL_OES_rgb8_rgba8,GL_OES_sample_shading,GL_OES_sample_variables,GL_OES_shader_image_atomic,GL_OES_shader_multisample_interpolation,GL_OES_standard_derivatives,GL_OES_stencil_wrap,GL_OES_surfaceless_context,GL_OES_texture_3D,GL_OES_texture_compression_astc,GL_OES_texture_cube_map,GL_OES_texture_env_crossbar,GL_OES_texture_float,GL_OES_texture_float_linear,GL_OES_texture_half_float,GL_OES_texture_half_float_linear,GL_OES_texture_mirrored_repeat,GL_OES_texture_npot,GL_OES_texture_stencil8,GL_OES_texture_storage_multisample_2d_array,GL_OES_texture_view,GL_OES_vertex_array_object,GL_OES_vertex_half_float,GL_OVR_multiview,GL_OVR_multiview2,GL_OVR_multiview_multisampled_render_to_texture,GL_QCOM_YUV_texture_gather,GL_QCOM_alpha_test,GL_QCOM_extended_get,GL_QCOM_motion_estimation,GL_QCOM_shader_framebuffer_fetch_noncoherent,GL_QCOM_shader_framebuffer_fetch_rate,GL_QCOM_texture_foveated,GL_QCOM_texture_foveated_subsampled_layout,GL_QCOM_tiled_rendering,GL_QCOM_validate_shader_binary")
    setProperty("Client", "android-google")
    setProperty("GSF.version", "223616055")
    setProperty("Vending.version", "82151710")
    setProperty("Vending.versionString", "21.5.17-21 [0] [PR] 326734551")
    setProperty("Roaming", "mobile-notroaming")
    setProperty("TimeZone", "UTC-10")
    setProperty("CellOperator", "310")
    setProperty("SimOperator", "38")
}
+59 −0
Original line number Original line Diff line number Diff line
package app.lounge.di

import app.lounge.networking.NetworkFetchingRetrofitAPI
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Named
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
internal object NetworkModule {

    private const val HTTP_TIMEOUT = 10L

    @Provides
    @Singleton
    internal fun providesRetrofit(
        okHttpClient: OkHttpClient,
        baseUrl: String = NetworkFetchingRetrofitAPI.tokenBaseURL
    ) : Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()
    }

    @Provides
    @Singleton
    @Named("privateOkHttpClient")
    internal fun providesOkHttpClient(
        httpLogger: HttpLoggingInterceptor
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .addNetworkInterceptor(httpLogger)
            .callTimeout(HTTP_TIMEOUT, TimeUnit.SECONDS)
            .build()
    }

    @Provides
    @Singleton
    internal fun providesHttpLogger() : HttpLoggingInterceptor {
        return run {
            val httpLoggingInterceptor = HttpLoggingInterceptor()
            httpLoggingInterceptor.apply {
                httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
            }
        }
    }

}
 No newline at end of file
+24 −0
Original line number Original line Diff line number Diff line
package app.lounge.model

import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.providers.HeaderProvider
import okhttp3.ResponseBody
import java.util.Properties


/** AnonymousAuthDataRequestBody */
data class AnonymousAuthDataRequestBody(
    val properties: Properties,
    val userAgent: String
)

/** AnonymousLoginRequestBody */
data class AnonymousAuthDataValidationRequestBody(
    val authDataResponse: AuthDataResponse,
) {
    val header = HeaderProvider.getDefaultHeaders(authDataResponse)
}

typealias AuthDataResponse = AuthData

typealias AuthDataValidationResponse = ResponseBody
 No newline at end of file
Loading