Unverified Commit 66cff88d authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #680 from RocketChat/notifications

[NEW] Integrated GCM and added notifications support
parents 226e069b 502a39c6
......@@ -140,4 +140,4 @@ Network Trash Folder
Temporary Items
.apdisk
# End of https://www.gitignore.io/api/osx
# End of https://www.gitignore.io/api/osx
\ No newline at end of file
......@@ -79,6 +79,8 @@ dependencies {
implementation libraries.androidSvg
implementation libraries.playServicesGcm
implementation libraries.aVLoadingIndicatorView
implementation libraries.textDrawable
......@@ -105,3 +107,5 @@ task compileSdk(type:Exec) {
commandLine './build-sdk.sh'
}
preBuild.dependsOn compileSdk
apply plugin: 'com.google.gms.google-services'
{
"project_info": {
"project_number": "1020987621558",
"firebase_url": "https://rocketchatnative.firebaseio.com",
"project_id": "rocketchatnative",
"storage_bucket": "rocketchatnative.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1020987621558:android:16da2e50aff9f0c9",
"android_client_info": {
"package_name": "chat.rocket.android"
}
},
"oauth_client": [
{
"client_id": "1020987621558-trk61fjrahho0ujtjap095p1jmi48pfq.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDc7VYUdU6kRkoRTToiCn1rh-W0wJvhLWk"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:1020987621558:android:1551054db195f705",
"android_client_info": {
"package_name": "chat.rocket.android.dev"
}
},
"oauth_client": [
{
"client_id": "1020987621558-trk61fjrahho0ujtjap095p1jmi48pfq.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDc7VYUdU6kRkoRTToiCn1rh-W0wJvhLWk"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
......@@ -5,6 +5,13 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<application
android:name=".app.RocketChatApplication"
......@@ -35,7 +42,35 @@
<activity
android:name=".app.ChatRoomActivity"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme"></activity>
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<service
android:name=".push.FirebaseTokenService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".push.GcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<activity
android:name=".webview.WebViewActivity"
......
......@@ -2,24 +2,29 @@ package chat.rocket.android.app
import android.app.Activity
import android.app.Application
import android.app.Service
import chat.rocket.android.BuildConfig
import chat.rocket.android.app.utils.CustomImageFormatConfigurator
import com.facebook.drawee.backends.pipeline.DraweeConfig
import chat.rocket.android.dagger.DaggerAppComponent
import com.facebook.drawee.backends.pipeline.DraweeConfig
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig
import com.jakewharton.threetenabp.AndroidThreeTen
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector
import dagger.android.HasServiceInjector
import timber.log.Timber
import javax.inject.Inject
class RocketChatApplication : Application(), HasActivityInjector {
class RocketChatApplication : Application(), HasActivityInjector, HasServiceInjector {
@Inject
lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
@Inject
lateinit var serviceDispatchingAndroidInjector: DispatchingAndroidInjector<Service>
override fun onCreate() {
super.onCreate()
......@@ -52,4 +57,8 @@ class RocketChatApplication : Application(), HasActivityInjector {
override fun activityInjector(): AndroidInjector<Activity> {
return activityDispatchingAndroidInjector
}
override fun serviceInjector(): AndroidInjector<Service> {
return serviceDispatchingAndroidInjector
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package chat.rocket.android.authentication.login.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI
......@@ -11,11 +12,14 @@ import chat.rocket.common.RocketChatTwoFactorException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.registerPushToken
import javax.inject.Inject
class LoginPresenter @Inject constructor(private val view: LoginView,
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val localRepository: LocalRepository,
private val settingsInteractor: GetSettingsInteractor,
private val serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory) {
......@@ -89,6 +93,7 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
try {
client.login(usernameOrEmail, password) // TODO This function returns a user token so should we save it?
registerPushToken()
navigator.toChatList()
} catch (exception: RocketChatException) {
when (exception) {
......@@ -117,4 +122,11 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
fun signup() {
navigator.toSignUp()
}
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it)
}
// TODO: Schedule push token registering when it comes up null
}
}
\ No newline at end of file
......@@ -3,20 +3,26 @@ package chat.rocket.android.authentication.signup.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.registerPushToken
import chat.rocket.core.internal.rest.signup
import javax.inject.Inject
class SignupPresenter @Inject constructor(private val view: SignupView,
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val localRepository: LocalRepository,
private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory) {
private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
fun signup(name: String, username: String, password: String, email: String) {
val server = serverInteractor.get()
when {
......@@ -44,6 +50,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
try {
client.signup(email, name, username, password) // TODO This function returns a user so should we save it?
client.login(username, password) // TODO This function returns a user token so should we save it?
registerPushToken()
navigator.toChatList()
} catch (exception: RocketChatException) {
val errorMessage = exception.message
......@@ -74,4 +81,11 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
navigator.toWebPage("/privacy-policy")
}
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it)
}
// TODO: Schedule push token registering when it comes up null
}
}
\ No newline at end of file
......@@ -2,21 +2,27 @@ package chat.rocket.android.authentication.twofactor.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatAuthException
import chat.rocket.common.RocketChatException
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.registerPushToken
import javax.inject.Inject
class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val localRepository: LocalRepository,
private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory) {
private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
// TODO: If the usernameOrEmail and password was informed by the user on the previous screen, then we should pass only the pin, like this: fun authenticate(pin: EditText)
fun authenticate(usernameOrEmail: String, password: String, twoFactorAuthenticationCode: String) {
val server = serverInteractor.get()
......@@ -34,6 +40,7 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
try {
// The token is saved via the client TokenProvider
client.login(usernameOrEmail, password, twoFactorAuthenticationCode)
registerPushToken()
navigator.toChatList()
} catch (exception: RocketChatException) {
if (exception is RocketChatAuthException) {
......@@ -58,4 +65,11 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
fun signup() {
navigator.toSignUp()
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it)
}
// TODO: Schedule push token registering when it comes up null
}
}
\ No newline at end of file
......@@ -4,13 +4,15 @@ import android.app.Application
import chat.rocket.android.app.RocketChatApplication
import chat.rocket.android.dagger.module.ActivityBuilder
import chat.rocket.android.dagger.module.AppModule
import chat.rocket.android.dagger.module.ServiceBuilder
import chat.rocket.android.push.FirebaseTokenService
import dagger.BindsInstance
import dagger.Component
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, ActivityBuilder::class])
@Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, ActivityBuilder::class, ServiceBuilder::class])
interface AppComponent {
@Component.Builder
......@@ -23,6 +25,8 @@ interface AppComponent {
fun inject(app: RocketChatApplication)
fun inject(service: FirebaseTokenService)
/*@Component.Builder
abstract class Builder : AndroidInjector.Builder<RocketChatApplication>()*/
}
......@@ -7,6 +7,8 @@ import android.content.SharedPreferences
import chat.rocket.android.BuildConfig
import chat.rocket.android.app.RocketChatDatabase
import chat.rocket.android.authentication.infraestructure.AuthTokenRepository
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.SharedPrefsLocalRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.infraestructure.MemorySettingsRepository
......@@ -93,6 +95,12 @@ class AppModule {
return context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE)
}
@Provides
@Singleton
fun provideSharedPreferencesRepository(prefs: SharedPreferences): LocalRepository {
return SharedPrefsLocalRepository(prefs)
}
@Provides
@Singleton
fun provideCurrentServerRepository(prefs: SharedPreferences): CurrentServerRepository {
......
package chat.rocket.android.dagger.module
import chat.rocket.android.push.FirebaseTokenService
import chat.rocket.android.push.di.FirebaseTokenServiceProvider
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module abstract class ServiceBuilder {
@ContributesAndroidInjector(modules = [FirebaseTokenServiceProvider::class])
abstract fun bindFirebaseTokenService(): FirebaseTokenService
}
\ No newline at end of file
package chat.rocket.android.infrastructure
interface LocalRepository {
companion object {
val KEY_PUSH_TOKEN = "KEY_PUSH_TOKEN"
}
fun save(key: String, value: String?)
fun get(key: String): String?
}
\ No newline at end of file
package chat.rocket.android.infrastructure
import android.content.SharedPreferences
class SharedPrefsLocalRepository(private val preferences: SharedPreferences) : LocalRepository {
override fun save(key: String, value: String?) {
preferences.edit().putString(key, value).apply()
}
override fun get(key: String): String? {
return preferences.getString(key, null)
}
}
\ No newline at end of file
package chat.rocket.android.push
import chat.rocket.android.R
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.common.RocketChatException
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.registerPushToken
import com.google.android.gms.gcm.GoogleCloudMessaging
import com.google.android.gms.iid.InstanceID
import com.google.firebase.iid.FirebaseInstanceIdService
import dagger.android.AndroidInjection
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
class FirebaseTokenService : FirebaseInstanceIdService() {
@Inject
lateinit var client: RocketChatClient
@Inject
lateinit var localRepository: LocalRepository
override fun onCreate() {
super.onCreate()
AndroidInjection.inject(this);
}
override fun onTokenRefresh() {
//TODO: We need to use the Cordova Project gcm_sender_id since it's the one configured on RC
// default push gateway. We should register this project's own project sender id into it.
val gcmToken = InstanceID.getInstance(this)
.getToken(getString(R.string.gcm_sender_id), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null)
gcmToken?.let {
localRepository.save(LocalRepository.KEY_PUSH_TOKEN, gcmToken)
launch {
try {
client.registerPushToken(gcmToken)
} catch (ex: RocketChatException) {
Timber.e(ex)
}
}
}
}
}
\ No newline at end of file
package chat.rocket.android.push
import android.os.Bundle
import com.google.android.gms.gcm.GcmListenerService
class GcmListenerService : GcmListenerService() {
override fun onMessageReceived(from: String?, data: Bundle?) {
data?.let {
PushManager.handle(this, data)
}
}
}
\ No newline at end of file
This diff is collapsed.
package chat.rocket.android.push.di
import chat.rocket.android.dagger.module.AppModule
import chat.rocket.android.push.FirebaseTokenService
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module abstract class FirebaseTokenServiceProvider {
@ContributesAndroidInjector(modules = [AppModule::class])
abstract fun provideFirebaseTokenService(): FirebaseTokenService
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="48.0"
android:viewportWidth="48.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M44.99,23.47C44.99,21.42 44.38,19.45 43.16,17.62C42.07,15.97 40.54,14.52 38.62,13.29C34.91,10.92 30.03,9.62 24.88,9.62C23.16,9.62 21.47,9.77 19.82,10.05C18.8,9.1 17.61,8.24 16.35,7.57C9.6,4.3 4,7.49 4,7.49C4,7.49 9.21,11.76 8.36,15.49C6.03,17.8 4.77,20.58 4.77,23.47C4.77,23.48 4.77,23.49 4.77,23.5C4.77,23.51 4.77,23.51 4.77,23.52C4.77,26.42 6.03,29.2 8.36,31.5C9.21,35.24 4,39.5 4,39.5C4,39.5 9.6,42.69 16.35,39.43C17.61,38.75 18.8,37.89 19.82,36.94C21.47,37.23 23.16,37.37 24.88,37.37C30.03,37.37 34.91,36.07 38.62,33.7C40.54,32.48 42.07,31.02 43.16,29.38C44.38,27.55 44.99,25.58 44.99,23.53C44.99,23.52 44.99,23.51 44.99,23.5L44.99,23.47ZM24.88,12.53C34.41,12.53 42.14,17.45 42.14,23.52C42.14,29.6 34.41,34.52 24.88,34.52C22.76,34.52 20.73,34.28 18.85,33.83C16.94,36.12 12.74,39.31 8.67,38.28C9.99,36.86 11.96,34.45 11.54,30.5C9.09,28.6 7.63,26.17 7.63,23.52C7.63,17.45 15.35,12.53 24.88,12.53Z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M24.88,26.17C26.15,26.17 27.17,25.14 27.17,23.88C27.17,22.61 26.15,21.59 24.88,21.59C23.62,21.59 22.59,22.61 22.59,23.88C22.59,25.14 23.62,26.17 24.88,26.17ZM32.85,26.17C34.12,26.17 35.14,25.14 35.14,23.88C35.14,22.61 34.12,21.59 32.85,21.59C31.59,21.59 30.56,22.61 30.56,23.88C30.56,25.14 31.59,26.17 32.85,26.17ZM16.91,26.17C18.18,26.17 19.2,25.14 19.2,23.88C19.2,22.62 18.18,21.59 16.91,21.59C15.65,21.59 14.62,22.62 14.62,23.88C14.62,25.14 15.65,26.17 16.91,26.17L16.91,26.17Z" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- This is the Cordova GCM sender id-->
<string name="gcm_sender_id" translatable="false">673693445664</string>
</resources>
\ No newline at end of file
......@@ -11,6 +11,7 @@ buildscript {
classpath "com.android.tools.build:gradle:3.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:3.1.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
......
......@@ -9,7 +9,7 @@ ext {
kotlin : '1.2.10',
coroutine : '0.21',
dokka : '0.9.15',
kotshi : '0.3.0-beta2',
kotshi : '0.3.0',
// Main dependencies
support : '27.0.2',
......@@ -29,6 +29,7 @@ ext {
androidSvg : '1.2.1',
aVLoadingIndicatorView : '2.1.3',
textDrawable : '1.0.2',
playServices : '11.8.0',
// For testing
junit : '4.12',
......@@ -85,6 +86,8 @@ ext {
textDrawable : "com.github.rocketchat:textdrawable:${versions.textDrawable}",
playServicesGcm : "com.google.android.gms:play-services-gcm:${versions.playServices}",
// For testing
toolsJar : files(Jvm.current().getToolsJar()),
junit : "junit:junit:$versions.junit",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment