Commit c650a340 authored by Ilias Rinis's avatar Ilias Rinis
Browse files

Remove deprecated GCM client service and update FCM APIs

parent f8b5341a
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
compileSdkVersion 27
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "com.futurae.futuraedemo"
minSdkVersion 16
targetSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0.0"
resConfigs "en", "el"
......@@ -27,22 +27,22 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.0.2'
implementation 'com.google.android.gms:play-services-vision:11.8.0'
implementation 'com.google.android.gms:play-services-gcm:11.8.0'
compile 'com.jakewharton:butterknife:8.8.1'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.android.gms:play-services-vision:17.0.2'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
compile 'com.google.firebase:firebase-core:11.8.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.firebase:firebase-core:16.0.7'
implementation 'com.google.firebase:firebase-messaging:17.4.0'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-moshi:2.3.0'
compile 'com.squareup.moshi:moshi-adapters:1.4.0'
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
compile(name:'futuraekit', ext:'aar')
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
implementation 'com.squareup.moshi:moshi-adapters:1.6.0'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation(name:'futuraekit', ext:'aar')
}
apply plugin: 'com.google.gms.google-services'
......@@ -9,12 +9,6 @@
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<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:allowBackup="true"
......@@ -29,39 +23,12 @@
android:name="com.google.android.gms.vision.DEPENDENCIES"
android:value="barcode"/>
<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.REGISTRATION"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="${applicationId}"/>
</intent-filter>
</receiver>
<service
android:name="com.futurae.sdk.gcm.FTRGcmListenerService"
android:exported="false">
<service android:name="com.futurae.sdk.messaging.FTRFcmMessagingService">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name="com.futurae.sdk.gcm.FTRInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
<service
android:name="com.futurae.sdk.gcm.FTRRegistrationIntentService"
android:exported="false"
/>
<activity android:name=".ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......
......@@ -11,6 +11,6 @@ public class AppMain extends Application {
super.onCreate();
FuturaeClient.launch(this);
FuturaeClient.launch(this, null);
}
}
......@@ -17,24 +17,21 @@ import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.futurae.futuraedemo.R;
import com.futurae.sdk.FuturaeCallback;
import com.futurae.sdk.FuturaeClient;
import com.futurae.sdk.Shared;
import com.futurae.sdk.approve.ApproveSession;
import com.futurae.sdk.gcm.FTRApproveNotification;
import com.futurae.sdk.gcm.FTRNotification;
import com.futurae.sdk.gcm.FTRRegistrationIntentService;
import com.futurae.sdk.gcm.FTRUnenrollNotification;
import com.futurae.sdk.model.Account;
import com.futurae.sdk.model.CurrentTotp;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.futurae.sdk.utils.NotificationUtils;
import com.google.android.gms.vision.barcode.Barcode;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
......@@ -42,6 +39,8 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private AlertDialog approveDialog;
// overrides
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
......@@ -63,9 +62,8 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
managePermissions();
checkAndAskForPermission(Manifest.permission.CAMERA, getString(R.string.camera_perm_explain), 2);
initRegistrationService();
initLocalBroadcastReceiver();
// TODO: Handle URI call
......@@ -95,12 +93,6 @@ public class MainActivity extends AppCompatActivity {
}
}
@Override
protected void onResume() {
super.onResume();
initRegistrationService();
}
// handlers
@OnClick(R.id.main_btn_enroll)
protected void onEnroll() {
......@@ -205,7 +197,7 @@ public class MainActivity extends AppCompatActivity {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Approve");
builder.setMessage("Would you like to approve the request?");
builder.setNeutralButton("Approve", new DialogInterface.OnClickListener() {
builder.setPositiveButton("Approve", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
FuturaeClient.sharedClient().approveAuth(session.getUserId(),
session.getSessionId(), new FuturaeCallback() {
......@@ -238,14 +230,12 @@ public class MainActivity extends AppCompatActivity {
}
});
AlertDialog dialog = builder.create();
dialog.show();
approveDialog = builder.create();
approveDialog.show();
}
// private
private void managePermissions() {
final String permission = Manifest.permission.CAMERA;
final int requestID = 1;
private void checkAndAskForPermission(final String permission, final String message, final int requestID) {
final Activity activity = this;
if (ContextCompat.checkSelfPermission(this, permission)
......@@ -259,7 +249,7 @@ public class MainActivity extends AppCompatActivity {
// sees the explanation, try again to request the permission.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.camera_perm_explain))
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
......@@ -282,15 +272,16 @@ public class MainActivity extends AppCompatActivity {
private void initLocalBroadcastReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE);
intentFilter.addAction(Shared.INTENT_APPROVE_AUTH_MESSAGE);
intentFilter.addAction(Shared.INTENT_GENERIC_NOTIFICATION_ERROR);
intentFilter.addAction(NotificationUtils.INTENT_ACCOUNT_UNENROLL_MESSAGE);
intentFilter.addAction(NotificationUtils.INTENT_APPROVE_AUTH_MESSAGE);
intentFilter.addAction(NotificationUtils.INTENT_GENERIC_NOTIFICATION_ERROR);
intentFilter.addAction(NotificationUtils.INTENT_APPROVE_CANCEL_MESSAGE);
LocalBroadcastManager.getInstance(this).registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String error = intent.getStringExtra(FTRNotification.PARAM_ERROR);
String error = intent.getStringExtra(NotificationUtils.PARAM_ERROR);
if (!TextUtils.isEmpty(error)) {
Log.e(TAG, "Received Intent '" + intent.getAction() + "' with error: " + error);
return;
......@@ -299,19 +290,18 @@ public class MainActivity extends AppCompatActivity {
switch(intent.getAction()) {
// TODO: Handle unenroll notification (e.g. refresh lists)
case Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE:
Log.d(TAG, Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE);
case NotificationUtils.INTENT_ACCOUNT_UNENROLL_MESSAGE:
Log.d(TAG, NotificationUtils.INTENT_ACCOUNT_UNENROLL_MESSAGE);
String userId = intent.getStringExtra(FTRUnenrollNotification.PARAM_USER_ID);
String userId = intent.getStringExtra(NotificationUtils.PARAM_USER_ID);
Log.i(TAG, "Received logout and deleted account: " + userId);
break;
// TODO: Handle approve notification (e.g. show approve view)
case Shared.INTENT_APPROVE_AUTH_MESSAGE:
Log.d(TAG, Shared.INTENT_APPROVE_AUTH_MESSAGE);
case NotificationUtils.INTENT_APPROVE_AUTH_MESSAGE:
Log.d(TAG, NotificationUtils.INTENT_APPROVE_AUTH_MESSAGE);
final ApproveSession session = intent.getParcelableExtra(
FTRApproveNotification.PARAM_APPROVE_SESSION);
NotificationUtils.PARAM_APPROVE_SESSION);
runOnUiThread(new Runnable() {
@Override
......@@ -321,42 +311,20 @@ public class MainActivity extends AppCompatActivity {
});
break;
case Shared.INTENT_GENERIC_NOTIFICATION_ERROR:
Log.d(TAG, Shared.INTENT_GENERIC_NOTIFICATION_ERROR);
case NotificationUtils.INTENT_APPROVE_CANCEL_MESSAGE:
if (approveDialog != null && approveDialog.isShowing()) {
approveDialog.dismiss();
}
break;
case NotificationUtils.INTENT_GENERIC_NOTIFICATION_ERROR:
Log.d(TAG, NotificationUtils.INTENT_GENERIC_NOTIFICATION_ERROR);
break;
}
}
}, intentFilter);
}
private void initRegistrationService() {
if (!checkPlayServices()) {
Log.i(TAG, "No valid Google Play Services APK found.");
return;
}
startService(new Intent(this, FTRRegistrationIntentService.class));
}
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS) {
return true;
}
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
finish();
}
return false;
}
private void showAlert(String title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title);
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ftr_api_key">{FuturaeApiKey}</string>
<string name="ftr_push_gcm_sender_id">{GcmSenderId}</string>
<string name="ftr_sdk_id">{FuturaeSdkId}</string>
<string name="ftr_sdk_key">{FuturaeSdkKey}</string>
<string name="ftr_base_url">https://api.futurae.com:443</string>
</resources>
\ No newline at end of file
......@@ -5,8 +5,8 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.google.gms:google-services:3.2.0'
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.google.gms:google-services:4.2.0'
}
}
......
#Fri Feb 02 10:10:30 EET 2018
#Fri Mar 15 11:07:02 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
......@@ -14,8 +14,8 @@ This is the Android SDK of Futurae. You can read more about Futurae™ at [futur
* [Callbacks](#callbacks)
* [URI Schemes](#uri-schemes)
* [Push Notifications](#push-notifications)
* [GCM Token Registration](#gcm-token-registration)
* [GCM Listener Service](#gcm-listener-service)
* [FCM Token Registration](#fcm-token-registration)
* [FCM Listener Service](#fcm-listener-service)
* [Local Intents](#local-intents)
* [Enroll User](#enroll-user)
* [Logout User](#logout-user)
......@@ -111,17 +111,14 @@ Secondly, in your `res/values` folder make sure to create a file `futurae.xml` w
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ftr_api_key">{FuturaeApiKey}</string>
<string name="ftr_push_gcm_sender_id">{GcmSenderId}</string>
<string name="ftr_sdk_id">{FuturaeSdkId}</string>
<string name="ftr_sdk_key">{FuturaeSdkKey}</string>
<string name="ftr_base_url">https://api.futurae.com:443</string>
</resources>
```
![][config-xml]
**Note**: Initializing the FuturaeKit SDK like this is `very important`. Replace `{FuturaeApiKey}` with your SDK API key (in case you do not have one yet, use the following placeholder key: `0000000000000000000000000000000000000000`),
and `{GoogleApiProjectNumber}` with the project number of the Google API you have set up for the GCM (see the [GCM Token Registration](#gcm-token-registration) section for more information).
**Note**: Initializing the FuturaeKit SDK like this is `very important`. Replace `{FuturaeSdkId}` and `{FuturaeSdkKey}` with your SDK ID and key.
### <a id="build-your-app" />Build your app
......@@ -156,63 +153,38 @@ FuturaeClient.sharedClient().handleUri(uriString, new FuturaeCallback() {
```
### <a id="push-notifications" />Push Notifications
Your app must be set up to receive GCM push notifications from our server. You can choose to receive and handle these notifications yourself, or alternatively you can use the existing infrastructure provided in the SDK. You can find more information on how to setup GCM push notifications for your app in the [Google Cloud Messaging Developer Guide](https://developers.google.com/cloud-messaging/android/client).
In order to be able to receive GCM notifications, you need to specify the following components inside the application section of your Manifest:
Your app must be set up to receive Firebase Cloud Messaging (FCM) push notifications from our server. You can choose to receive and handle these notifications yourself, or alternatively you can use the existing infrastructure provided in the SDK. You can find more information on how to setup FCM push notifications for your app in the [Firebase Cloud Messaging Developer Guide](https://firebase.google.com/docs/cloud-messaging/).
The GCM Receiver:
In order to be able to receive FCM notifications, you need to specify the Firebase Messaging service inside the application section of your Manifest:
```xml
<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.REGISTRATION"/>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="${applicationId}"/>
</intent-filter>
</receiver>
<service android:name="com.futurae.sdk.messaging.FTRFcmMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
```
The Instance ID listener service and Registration intent service (the ones provided in the SDK, or your own):
```xml
<service
android:name="com.futurae.sdk.gcm.FTRInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
For this purpose, you can either use the one included in the SDK (`com.futurae.sdk.messaging.FTRFcmMessagingService`), or write your own. This service overrides two important methods:
```java
@Override
public void onNewToken(String token);
<service
android:name="com.futurae.sdk.gcm.FTRRegistrationIntentService"
android:exported="false"
/>
@Override
public void onMessageReceived(RemoteMessage message);
```
The GCM Listener service (the one provided in the SDK, or your own):
```xml
<service
android:name="com.futurae.sdk.gcm.FTRGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
</intent-filter>
</service>
```
The first one is invoked whenever a new FCM push token has been generated for the app; it is important to register this token with the Futurae backend in order to continue receiving push notifications. The `FTRFcmMessagingService` implements this functionality.
#### <a id="gcm-token" />GCM Token Registration
The `FTRRegistrationIntentService` is responsible for registering the app's GCM token to the Futurae server. This is important for the server to be able to issue GCM notifications for your app. The provided service handles this, however if you need to, you can write your own or extend the existing one. In any case, the `FTRRegistrationIntentService` needs to be started in your app in order to handle changes in the GCM token. To start the service, you need to call the `Context.startService()` method; for example, inside your main activity, use the following code:
```java
startService(new Intent(packageContext, FTRRegistrationIntentService.class));
```
The second one is invoked whenever a new push notification (or cloud message) is received by the app. The `FTRFcmMessagingService` then processes this message and invokes the SDK accordingly.
#### <a id="fcm-token-registration" />FCM Token Registration
The `FTRFcmMessagingService` is responsible for registering the app's FCM token to the Futurae server. This is important for the server to be able to issue FCM notifications for your app. The provided service handles this, however if you need to, you can write your own or extend the existing one.
If you are implementing your own GCM notification handling, you should register the GCM token to the Futurae server every time it changes. The call that registers the GCM token to the Futurae server is `registerPushToken()`, and it is necessary every time the GCM token is generated or is changed by GCM.
If you are implementing **your own FCM notification handling**, you should register the FCM token to the Futurae server every time it changes. The call that registers the FCM token to the Futurae server is `registerPushToken()`, and it is necessary every time the FCM token is generated or is changed by FCM.
For example, once the app receives a new GCM token (e.g. via an `InstanceIdListenerService`), the token needs to be obtained and registered to the Futurae server using the following code:
For example, once the app receives a new FCM token (e.g. via an `onNewToken()` callback in your own `FirebaseMessagingService` subclass), the token needs to be obtained and registered to the Futurae server using the following code:
```java
FuturaeClient.sharedClient().registerPushToken(gcmToken, new FuturaeCallback() {
FuturaeClient.sharedClient().registerPushToken(fcmToken, new FuturaeCallback() {
@Override
public void success() {
......@@ -225,23 +197,23 @@ FuturaeClient.sharedClient().registerPushToken(gcmToken, new FuturaeCallback() {
});
```
#### <a id="gcm-listener" />GCM Listener Service
The `FTRGcmListenerService` receives GCM push notifications and handles them, according to the actions dictated by the Futurae server. You can use or extend the service provided by the SDK, or write your own. There are two distinct push notification types issued by the Futurae server: **Aprove** or **Unenroll**.
#### <a id="fcm-listener-service" />FCM Listener Service
The `FTRFcmMessagingService` receives FCM push notifications and handles them, according to the actions dictated by the Futurae server. You can use or extend the service provided by the SDK, or write your own. There are two distinct push notification types issued by the Futurae server: **Aprove** or **Unenroll**.
In case you want to process and handle the GCM notifications without using `FTRGcmListenerService`, you must use the following code in order to process and handle the notifications sent by the Futurae server, inside the implementation of your `GcmListenerService`:
In case you want to process and handle the FCM notifications without using `FTRFcmMessagingService`, you must use the following code in order to process and handle the notifications sent by the Futurae server, inside the implementation of your own `FirebaseMessagingService` subclass:
```java
@Override
public void onMessageReceived(String from, Bundle data) {
public void onMessageReceived(RemoteMessage message) {
// Create and handle a Futurae notification
FTRNotification notification = notificationFactory.createNotification(data);
// Create and handle a Futurae notification, containing a Bundle with any data from message.getData()
FTRNotification notification = notificationFactory.createNotification(service, data);
notification.handle();
}
```
#### <a id="local-intents" />Local Intents
Once a Futurae GCM notification has been handled, the SDK will notify the host app using **local broadcasts**. The app should register a broadcast receiver for these intents and react accordingly. There are three distinct Intents that the notification handlers might send in a local broadcast:
* `INTENT_GENERIC_NOTIFICATION_ERROR`: Indicates that an error was encountered during the processing or handling of a GCM notification.
Once a Futurae FCM notification has been handled, the SDK will notify the host app using **local broadcasts**. The app should register a broadcast receiver for these intents and react accordingly. There are three distinct Intents that the notification handlers might send in a local broadcast:
* `INTENT_GENERIC_NOTIFICATION_ERROR`: Indicates that an error was encountered during the processing or handling of a FCM notification.
* `INTENT_APPROVE_AUTH_MESSAGE`: Indicates that a Push Notification Authentication has been initiated.
* `INTENT_ACCOUNT_UNENROLL_MESSAGE`: Indicates that a user account has been logged out remotely.
......@@ -267,7 +239,7 @@ LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastRe
break;
case Shared.INTENT_GENERIC_NOTIFICATION_ERROR:
// Handle GCM notification error
// Handle FCM notification error
break;
}
}
......@@ -323,7 +295,7 @@ FuturaeClient.sharedClient().logout(userId, new FuturaeCallback() {
});
```
Typically this should happen either when the user removes the account manually from the app, or when a user has been logged out remotely by the server. In the former case, calling the `logout()` method is enough, as it notifies the server of the logout and deletes the account from the SDK too. In the latter case, the server will send a GCM notification to the app, and the default handler of the notification will delete the account from the SDK as well. In this case, the notification handler will also send a local broadcast to the app (see `INTENT_ACCOUNT_UNENROLL_MESSAGE` [above](#local-intents), so that the app can also perform any further action required (e.g. refresh the list of active accounts in an account view).
Typically this should happen either when the user removes the account manually from the app, or when a user has been logged out remotely by the server. In the former case, calling the `logout()` method is enough, as it notifies the server of the logout and deletes the account from the SDK too. In the latter case, the server will send a FCM notification to the app, and the default handler of the notification will delete the account from the SDK as well. In this case, the notification handler will also send a local broadcast to the app (see `INTENT_ACCOUNT_UNENROLL_MESSAGE` [above](#local-intents), so that the app can also perform any further action required (e.g. refresh the list of active accounts in an account view).
The intent contains the User ID as an extra:
```java
......
No preview for this file type
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