Unverified Commit d4f4c5b4 authored by Leonardo Aramaki's avatar Leonardo Aramaki Committed by GitHub

Merge pull request #541 from RocketChat/fix/notifications

[WIP] New rewritten push notification handler
parents 9613b461 0846097e
......@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<permission
android:name="chat.rocket.android.permission.C2D_MESSAGE"
......@@ -56,10 +57,32 @@
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="com.example.gcm"/>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="chat.rocket.android"/>
</intent-filter>
</receiver>
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="chat.rocket.android"/>
</intent-filter>
</receiver>
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<service android:name="com.google.firebase.iid.FirebaseInstanceIdService"
android:exported="true">
<intent-filter android:priority="-500">
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".push.gcm.GCMIntentService"
android:exported="false">
......@@ -76,6 +99,12 @@
</intent-filter>
</service>
<receiver android:name=".push.PushManager$DeleteReceiver"
android:exported="false" />
<receiver android:name=".push.PushManager$ReplyReceiver"
android:exported="false" />
<meta-data
android:name="io.fabric.ApiKey"
android:value="12ac6e94f850aaffcdff52001af77ca415d06a43" />
......
......@@ -22,12 +22,15 @@ import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.annotations.NonNull;
import io.reactivex.annotations.Nullable;
import okhttp3.HttpUrl;
/**
* sharedpreference-based cache.
*/
public class RocketChatCache {
private static final String KEY_SELECTED_SERVER_HOSTNAME = "KEY_SELECTED_SERVER_HOSTNAME";
private static final String KEY_SELECTED_SITE_URL = "KEY_SELECTED_SITE_URL";
private static final String KEY_SELECTED_SITE_NAME = "KEY_SELECTED_SITE_NAME";
private static final String KEY_SELECTED_ROOM_ID = "KEY_SELECTED_ROOM_ID";
private static final String KEY_PUSH_ID = "KEY_PUSH_ID";
private static final String KEY_HOSTNAME_LIST = "KEY_HOSTNAME_LIST";
......@@ -50,6 +53,72 @@ public class RocketChatCache {
setString(KEY_SELECTED_SERVER_HOSTNAME, newHostname);
}
public void addHostSiteName(@NonNull String currentHostname, @NonNull String siteName) {
try {
String hostSiteNamesJson = getHostSiteNamesJson();
JSONObject jsonObject = (hostSiteNamesJson == null) ?
new JSONObject() : new JSONObject(hostSiteNamesJson);
jsonObject.put(currentHostname, siteName);
setString(KEY_SELECTED_SITE_NAME, jsonObject.toString());
} catch (JSONException e) {
RCLog.e(e);
}
}
public @NonNull String getHostSiteName(@NonNull String host) {
if (host.startsWith("http")) {
HttpUrl url = HttpUrl.parse(host);
if (url != null) {
host = url.host();
}
}
try {
String hostSiteNamesJson = getHostSiteNamesJson();
JSONObject jsonObject = (hostSiteNamesJson == null) ?
new JSONObject() : new JSONObject(hostSiteNamesJson);
host = getSiteUrlFor(host);
return jsonObject.optString(host);
} catch (JSONException e) {
RCLog.e(e);
}
return "";
}
private @Nullable String getHostSiteNamesJson() {
return getString(KEY_SELECTED_SITE_NAME, null);
}
public void addHostnameSiteUrl(@Nullable String hostnameAlias, @NonNull String currentHostname) {
String alias = null;
if (hostnameAlias != null) {
alias = hostnameAlias.toLowerCase();
}
try {
String selectedHostnameAliasJson = getLoginHostnamesJson();
JSONObject jsonObject = selectedHostnameAliasJson == null ?
new JSONObject() : new JSONObject(selectedHostnameAliasJson);
jsonObject.put(alias, currentHostname);
setString(KEY_SELECTED_SITE_URL, jsonObject.toString());
} catch (JSONException e) {
RCLog.e(e);
}
}
public @NonNull String getSiteUrlFor(String hostname) {
try {
String selectedServerHostname = getSelectedServerHostname();
return new JSONObject(getLoginHostnamesJson())
.optString(hostname, selectedServerHostname);
} catch (JSONException e) {
RCLog.e(e);
}
return null;
}
private @Nullable String getLoginHostnamesJson() {
return getString(KEY_SELECTED_SITE_URL, null);
}
public void addHostname(@NonNull String hostname, @Nullable String hostnameAvatarUri, String siteName) {
String hostnameList = getString(KEY_HOSTNAME_LIST, null);
try {
......
......@@ -3,21 +3,24 @@ package chat.rocket.android.activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.hadisatrio.optional.Optional;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.List;
import chat.rocket.android.LaunchUtil;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.Logger;
import chat.rocket.android.push.PushConstants;
import chat.rocket.android.push.PushNotificationHandler;
import chat.rocket.android.push.PushManager;
import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.core.models.ServerInfo;
import chat.rocket.persistence.realm.RealmStore;
import chat.rocket.persistence.realm.models.ddp.RealmRoom;
import icepick.State;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.HttpUrl;
abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
@State protected String hostname;
......@@ -53,20 +56,36 @@ abstract class AbstractAuthedActivity extends AbstractFragmentActivity {
return;
}
if (intent.hasExtra(PushConstants.HOSTNAME)) {
rocketChatCache.setSelectedServerHostname(intent.getStringExtra(PushConstants.HOSTNAME));
if (intent.hasExtra(PushConstants.ROOM_ID)) {
rocketChatCache.setSelectedRoomId(intent.getStringExtra(PushConstants.ROOM_ID));
if (intent.hasExtra(PushManager.EXTRA_HOSTNAME)) {
String hostname = intent.getStringExtra(PushManager.EXTRA_HOSTNAME);
HttpUrl url = HttpUrl.parse(hostname);
if (url != null) {
String hostnameFromPush = url.host();
String loginHostname = rocketChatCache.getSiteUrlFor(hostnameFromPush);
rocketChatCache.setSelectedServerHostname(loginHostname);
if (intent.hasExtra(PushManager.EXTRA_ROOM_ID)) {
rocketChatCache.setSelectedRoomId(intent.getStringExtra(PushManager.EXTRA_ROOM_ID));
}
}
PushManager.INSTANCE.clearNotificationsByHost(hostname);
} else {
updateHostnameIfNeeded(rocketChatCache.getSelectedServerHostname());
}
if (intent.hasExtra(PushConstants.NOT_ID)) {
if (intent.hasExtra(PushManager.EXTRA_NOT_ID) && intent.hasExtra(PushManager.EXTRA_HOSTNAME)) {
isNotification = true;
PushNotificationHandler
.cleanUpNotificationStack(intent.getIntExtra(PushConstants.NOT_ID, 0));
int notificationId = intent.getIntExtra(PushManager.EXTRA_NOT_ID, 0);
String hostname = intent.getStringExtra(PushManager.EXTRA_HOSTNAME);
HttpUrl url = HttpUrl.parse(hostname);
if (url != null) {
String hostnameFromPush = url.host();
String loginHostname = rocketChatCache.getSiteUrlFor(hostnameFromPush);
PushManager.INSTANCE.clearNotificationsByHostAndNotificationId(loginHostname, notificationId);
} else {
PushManager.INSTANCE.clearNotificationsByNotificationId(notificationId);
}
}
}
......
......@@ -74,8 +74,10 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
onHostnameUpdated();
}
} else {
presenter.bindViewOnly(this);
ConnectivityManager.getInstance(getApplicationContext()).keepAliveServer();
presenter.bindView(this);
presenter.loadSignedInServers(hostname);
roomId = new RocketChatCache(getApplicationContext()).getSelectedRoomId();
}
}
......@@ -172,7 +174,7 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
sessionInteractor,
new MethodCallHelper(this, hostname),
ConnectivityManager.getInstance(getApplicationContext()),
rocketChatCache,
rocketChatCache,
publicSettingRepository
);
......@@ -302,6 +304,15 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
}
}
@Override
public void refreshRoom() {
Fragment fragment = getSupportFragmentManager().findFragmentById(getLayoutContainerForFragment());
if (fragment != null && fragment instanceof RoomFragment) {
RoomFragment roomFragment = (RoomFragment) fragment;
roomFragment.loadMessages();
}
}
private void changeServerIfNeeded(String serverHostname) {
if (!hostname.equalsIgnoreCase(serverHostname)) {
RocketChatCache rocketChatCache = new RocketChatCache(getApplicationContext());
......@@ -328,7 +339,6 @@ public class MainActivity extends AbstractAuthedActivity implements MainContract
public static final int STATUS_DISMISS = 0;
public static final int STATUS_CONNECTION_ERROR = 1;
public static final int STATUS_TOKEN_LOGIN = 2;
public static final int STATUS_LOGGING_OUT = 3;
private int status;
private Snackbar snackbar;
......
......@@ -26,6 +26,8 @@ public interface MainContract {
void showConnectionOk();
void showSignedInServers(List<Pair<String, Pair<String, String>>> serverList);
void refreshRoom();
}
interface Presenter extends BaseContract.Presenter<View> {
......
......@@ -225,6 +225,7 @@ public class MainPresenter extends BasePresenter<MainContract.View>
connectivity -> {
if (connectivity.state == ServerConnectivity.STATE_CONNECTED) {
view.showConnectionOk();
view.refreshRoom();
return;
}
view.showConnecting();
......
......@@ -11,11 +11,13 @@ import java.util.UUID;
import bolts.Continuation;
import bolts.Task;
import chat.rocket.android.RocketChatCache;
import chat.rocket.android.helper.CheckSum;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.service.DDPClientRef;
import chat.rocket.android_ddp.DDPClientCallback;
import chat.rocket.core.PublicSettingsConstants;
import chat.rocket.core.SyncState;
import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.persistence.realm.RealmStore;
......@@ -30,6 +32,7 @@ import chat.rocket.persistence.realm.models.ddp.RealmSpotlightUser;
import chat.rocket.persistence.realm.models.internal.MethodCall;
import chat.rocket.persistence.realm.models.internal.RealmSession;
import hugo.weaving.DebugLog;
import okhttp3.HttpUrl;
/**
* Utility class for creating/handling MethodCall or RPC.
......@@ -65,6 +68,12 @@ public class MethodCallHelper {
this.ddpClientRef = ddpClientRef;
}
public MethodCallHelper(Context context, RealmHelper realmHelper, DDPClientRef ddpClientRef) {
this.context = context.getApplicationContext();
this.realmHelper = realmHelper;
this.ddpClientRef = ddpClientRef;
}
@DebugLog
private Task<String> executeMethodCall(String methodName, String param, long timeout) {
if (ddpClientRef != null) {
......@@ -422,13 +431,31 @@ public class MethodCallHelper {
.onSuccessTask(task -> Task.forResult(null));
}
public Task<Void> getPublicSettings() {
public Task<Void> getPublicSettings(String currentHostname) {
return call("public-settings/get", TIMEOUT_MS)
.onSuccessTask(CONVERT_TO_JSON_ARRAY)
.onSuccessTask(task -> {
final JSONArray settings = task.getResult();
String siteUrl = null;
String siteName = null;
for (int i = 0; i < settings.length(); i++) {
RealmPublicSetting.customizeJson(settings.getJSONObject(i));
JSONObject jsonObject = settings.getJSONObject(i);
RealmPublicSetting.customizeJson(jsonObject);
if (isPublicSetting(jsonObject, PublicSettingsConstants.General.SITE_URL)) {
siteUrl = jsonObject.getString(RealmPublicSetting.VALUE);
} else if (isPublicSetting(jsonObject, PublicSettingsConstants.General.SITE_NAME)) {
siteName = jsonObject.getString(RealmPublicSetting.VALUE);
}
}
if (siteName != null && siteUrl != null) {
HttpUrl httpSiteUrl = HttpUrl.parse(siteUrl);
if (httpSiteUrl != null) {
String host = httpSiteUrl.host();
RocketChatCache rocketChatCache = new RocketChatCache(context);
rocketChatCache.addHostnameSiteUrl(host, currentHostname);
rocketChatCache.addHostSiteName(currentHostname, siteName);
}
}
return realmHelper.executeTransaction(realm -> {
......@@ -439,6 +466,10 @@ public class MethodCallHelper {
});
}
private boolean isPublicSetting(JSONObject jsonObject, String id) {
return jsonObject.optString(RealmPublicSetting.ID).equalsIgnoreCase(id);
}
public Task<Void> getPermissions() {
return call("permissions/get", TIMEOUT_MS)
.onSuccessTask(CONVERT_TO_JSON_ARRAY)
......
......@@ -715,4 +715,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements
startActivity(intent);
}
}
public void loadMessages() {
presenter.loadMessages();
}
}
\ No newline at end of file
This diff is collapsed.
package chat.rocket.android.push.gcm;
import com.google.android.gms.gcm.GcmListenerService;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.gcm.GcmListenerService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import chat.rocket.android.push.PushConstants;
import chat.rocket.android.push.PushNotificationHandler;
import chat.rocket.android.push.PushManager;
@SuppressLint("NewApi")
public class GCMIntentService extends GcmListenerService implements PushConstants {
......@@ -33,9 +35,7 @@ public class GCMIntentService extends GcmListenerService implements PushConstant
extras = normalizeExtras(applicationContext, extras);
PushNotificationHandler pushNotificationHandler = new PushNotificationHandler();
pushNotificationHandler.showNotificationIfPossible(applicationContext, extras);
PushManager.INSTANCE.handle(applicationContext, extras);
}
/*
......
package chat.rocket.android.service;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.List;
......@@ -22,4 +23,6 @@ public interface ConnectivityManagerApi {
List<ServerInfo> getServerList();
Observable<ServerConnectivity> getServerConnectivityAsObservable();
int getConnectivityState(@NonNull String hostname);
}
......@@ -4,6 +4,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.ArrayList;
......@@ -148,6 +149,11 @@ import rx.subjects.PublishSubject;
return Observable.concat(Observable.from(getCurrentConnectivityList()), connectivitySubject);
}
@Override
public int getConnectivityState(@NonNull String hostname) {
return serverConnectivityList.get(hostname);
}
@DebugLog
private Single<Boolean> connectToServerIfNeeded(String hostname, boolean forceConnect) {
return Single.defer(() -> {
......
......@@ -105,11 +105,14 @@ public class RocketChatService extends Service implements ConnectivityServiceInt
private Single<RocketChatWebSocketThread> getOrCreateWebSocketThread(String hostname) {
return Single.defer(() -> {
webSocketThreadLock.acquire();
if (webSocketThreads.containsKey(hostname)) {
int connectivityState = ConnectivityManager.getInstance(getApplicationContext()).getConnectivityState(hostname);
boolean isConnected = connectivityState == ServerConnectivity.STATE_CONNECTED;
if (webSocketThreads.containsKey(hostname) && isConnected) {
RocketChatWebSocketThread thread = webSocketThreads.get(hostname);
webSocketThreadLock.release();
return Single.just(thread);
}
connectivityManager.notifyConnecting(hostname);
return RocketChatWebSocketThread.getStarted(getApplicationContext(), hostname)
.doOnSuccess(thread -> {
webSocketThreads.put(hostname, thread);
......
......@@ -211,6 +211,8 @@ public class RocketChatWebSocketThread extends HandlerThread {
if (task.isFaulted()) {
Exception error = task.getError();
RCLog.e(error);
connectivityManager.notifyConnectionLost(
hostname, ConnectivityManagerInternal.REASON_NETWORK_ERROR);
emitter.onError(error);
} else {
keepAliveTimer.update();
......@@ -345,7 +347,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
}
private Task<Void> fetchPublicSettings() {
return new MethodCallHelper(realmHelper, ddpClientRef).getPublicSettings();
return new MethodCallHelper(appContext, realmHelper, ddpClientRef).getPublicSettings(hostname);
}
private Task<Void> fetchPermissions() {
......
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