diff --git a/app/src/main/java/im/vector/riotredesign/Riot.kt b/app/src/main/java/im/vector/riotredesign/Riot.kt index 9332eec737..73b7e150cf 100644 --- a/app/src/main/java/im/vector/riotredesign/Riot.kt +++ b/app/src/main/java/im/vector/riotredesign/Riot.kt @@ -23,7 +23,7 @@ import com.facebook.stetho.Stetho import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.glide.GlideImageLoader import com.jakewharton.threetenabp.AndroidThreeTen -import im.vector.matrix.android.BuildConfig +import im.vector.matrix.android.api.Matrix import im.vector.riotredesign.core.di.AppModule import im.vector.riotredesign.features.home.HomeModule import org.koin.log.EmptyLogger @@ -44,6 +44,8 @@ class Riot : Application() { val appModule = AppModule(applicationContext).definition val homeModule = HomeModule().definition startKoin(listOf(appModule, homeModule), logger = EmptyLogger()) + + Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION) } override fun attachBaseContext(base: Context) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt index 84b37300e0..67f86d8242 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt @@ -26,6 +26,7 @@ import im.vector.matrix.android.internal.di.MatrixKoinComponent import im.vector.matrix.android.internal.di.MatrixKoinHolder import im.vector.matrix.android.internal.di.MatrixModule import im.vector.matrix.android.internal.di.NetworkModule +import im.vector.matrix.android.internal.network.UserAgentHolder import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import org.koin.standalone.inject import java.util.concurrent.atomic.AtomicBoolean @@ -38,6 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean class Matrix private constructor(context: Context) : MatrixKoinComponent { private val authenticator by inject() + private val userAgent by inject() private val backgroundDetectionObserver by inject() lateinit var currentSession: Session @@ -59,6 +61,13 @@ class Matrix private constructor(context: Context) : MatrixKoinComponent { return authenticator } + /** + * Set application flavor, to alter user agent. + */ + fun setApplicationFlavor(flavor: String) { + userAgent.setApplicationFlavor(flavor) + } + companion object { private lateinit var instance: Matrix private val isInit = AtomicBoolean(false) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt index e19c15daca..1aa733f7dc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt @@ -17,8 +17,8 @@ package im.vector.matrix.android.internal.di import com.facebook.stetho.okhttp3.StethoInterceptor -import im.vector.matrix.android.internal.network.AccessTokenInterceptor -import im.vector.matrix.android.internal.network.NetworkConnectivityChecker +import im.vector.matrix.android.BuildConfig +import im.vector.matrix.android.internal.network.* import im.vector.matrix.android.internal.network.UnitConverterFactory import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor @@ -33,6 +33,14 @@ class NetworkModule { val definition = module { + single { + UserAgentHolder(get()) + } + + single { + UserAgentInterceptor(get()) + } + single { AccessTokenInterceptor(get()) } @@ -58,6 +66,7 @@ class NetworkModule { .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .addNetworkInterceptor(get()) + .addInterceptor(get()) .addInterceptor(get()) .addInterceptor(get()) .addInterceptor(get()) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt index 864e8400d7..77d2ec926a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt @@ -28,7 +28,7 @@ internal class AccessTokenInterceptor(private val sessionParamsStore: SessionPar // Add the access token to all requests if it is set val sessionParams = sessionParamsStore.get() sessionParams?.let { - newRequestBuilder.addHeader("Authorization", "Bearer " + it.credentials.accessToken) + newRequestBuilder.addHeader(HttpHeaders.Authorization, "Bearer " + it.credentials.accessToken) } request = newRequestBuilder.build() return chain.proceed(request) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt new file mode 100644 index 0000000000..f4b93e8a31 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/HttpHeaders.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.network + +object HttpHeaders { + + const val Authorization = "Authorization" + const val UserAgent = "User-Agent" + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt new file mode 100644 index 0000000000..7917f960b6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentHolder.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.network + +import android.content.Context +import android.text.TextUtils +import im.vector.matrix.android.BuildConfig +import timber.log.Timber + +internal class UserAgentHolder(val context: Context) { + + var userAgent: String = "" + private set + + init { + setApplicationFlavor("NoFlavor") + } + + + /** + * Create an user agent with the application version. + * Ex: RiotX/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSDK_X 1.0) + * + * @param flavorDescription the flavor description + */ + fun setApplicationFlavor(flavorDescription: String) { + var appName = "" + var appVersion = "" + + try { + val appPackageName = context.applicationContext.packageName + val pm = context.packageManager + val appInfo = pm.getApplicationInfo(appPackageName, 0) + appName = pm.getApplicationLabel(appInfo).toString() + + val pkgInfo = pm.getPackageInfo(context.applicationContext.packageName, 0) + appVersion = pkgInfo.versionName + + // Use appPackageName instead of appName if appName contains any non-ASCII character + if (!appName.matches("\\A\\p{ASCII}*\\z".toRegex())) { + appName = appPackageName + } + } catch (e: Exception) { + Timber.e(e, "## initUserAgent() : failed " + e.message) + } + + var systemUserAgent = System.getProperty("http.agent") + + // cannot retrieve the application version + if (TextUtils.isEmpty(appName) || TextUtils.isEmpty(appVersion)) { + if (null == systemUserAgent) { + userAgent = "Java" + System.getProperty("java.version") + } + return + } + + // if there is no user agent or cannot parse it + if (null == systemUserAgent || systemUserAgent.lastIndexOf(")") == -1 || !systemUserAgent.contains("(")) { + userAgent = (appName + "/" + appVersion + " ( Flavour " + flavorDescription + + "; MatrixAndroidSDK_X " + BuildConfig.VERSION_NAME + ")") + } else { + // update + userAgent = appName + "/" + appVersion + " " + + systemUserAgent.substring(systemUserAgent.indexOf("("), systemUserAgent.lastIndexOf(")") - 1) + + "; Flavour " + flavorDescription + + "; MatrixAndroidSDK_X " + BuildConfig.VERSION_NAME + ")" + } + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt new file mode 100644 index 0000000000..151ba0c361 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/UserAgentInterceptor.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.network + +import okhttp3.Interceptor +import okhttp3.Response + +internal class UserAgentInterceptor(private val userAgentHolder: UserAgentHolder) : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val newRequestBuilder = request.newBuilder() + // Add the user agent to all requests if it is set + userAgentHolder.userAgent + .takeIf { it.isNotBlank() } + ?.let { + newRequestBuilder.addHeader(HttpHeaders.UserAgent, it) + } + request = newRequestBuilder.build() + return chain.proceed(request) + } + +} \ No newline at end of file