client side support for XEP-0357: Push Notifications
This commit is contained in:
parent
93dad9b737
commit
32da65f910
37
build.gradle
37
build.gradle
|
@ -7,6 +7,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:1.3.1'
|
classpath 'com.android.tools.build:gradle:1.3.1'
|
||||||
|
classpath 'com.google.gms:google-services:1.5.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +22,17 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
playstoreCompile
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':libs:MemorizingTrustManager')
|
compile project(':libs:MemorizingTrustManager')
|
||||||
compile 'org.sufficientlysecure:openpgp-api:10.0'
|
compile 'org.sufficientlysecure:openpgp-api:10.0'
|
||||||
|
@ -44,6 +50,7 @@ dependencies {
|
||||||
compile 'com.kyleduo.switchbutton:library:1.2.8'
|
compile 'com.kyleduo.switchbutton:library:1.2.8'
|
||||||
compile 'org.whispersystems:axolotl-android:1.3.4'
|
compile 'org.whispersystems:axolotl-android:1.3.4'
|
||||||
compile 'com.makeramen:roundedimageview:2.2.0'
|
compile 'com.makeramen:roundedimageview:2.2.0'
|
||||||
|
playstoreCompile 'com.google.android.gms:play-services-gcm:8.3.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -55,7 +62,7 @@ android {
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 123
|
versionCode 123
|
||||||
versionName "1.9.4"
|
versionName "1.9.4"
|
||||||
project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName);
|
archivesBaseName += "-$versionName"
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -63,15 +70,10 @@ android {
|
||||||
targetCompatibility JavaVersion.VERSION_1_7
|
targetCompatibility JavaVersion.VERSION_1_7
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
productFlavors {
|
||||||
// To sign release builds, create the file `gradle.properties` in
|
playstore
|
||||||
// $HOME/.gradle or in your project directory with this content:
|
free
|
||||||
//
|
}
|
||||||
// mStoreFile=/path/to/key.store
|
|
||||||
// mStorePassword=xxx
|
|
||||||
// mKeyAlias=alias
|
|
||||||
// mKeyPassword=xxx
|
|
||||||
//
|
|
||||||
if (project.hasProperty('mStoreFile') &&
|
if (project.hasProperty('mStoreFile') &&
|
||||||
project.hasProperty('mStorePassword') &&
|
project.hasProperty('mStorePassword') &&
|
||||||
project.hasProperty('mKeyAlias') &&
|
project.hasProperty('mKeyAlias') &&
|
||||||
|
@ -89,16 +91,6 @@ android {
|
||||||
buildTypes.release.signingConfig = null
|
buildTypes.release.signingConfig = null
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationVariants.all { variant ->
|
|
||||||
if (variant.name.equals('release')) {
|
|
||||||
variant.outputs.each { output ->
|
|
||||||
if (output.zipAlign != null) {
|
|
||||||
output.zipAlign.outputFile = new File(output.outputFile.parent, rootProject.name + "-${variant.versionName}.apk")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
disable 'ExtraTranslation', 'MissingTranslation', 'InvalidPackage', 'MissingQuantity', 'AppCompatResource'
|
disable 'ExtraTranslation', 'MissingTranslation', 'InvalidPackage', 'MissingQuantity', 'AppCompatResource'
|
||||||
}
|
}
|
||||||
|
@ -116,4 +108,9 @@ android {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
exclude 'META-INF/BCKEY.DSA'
|
||||||
|
exclude 'META-INF/BCKEY.SF'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
|
||||||
|
public class PushManagementService {
|
||||||
|
|
||||||
|
protected final XmppConnectionService mXmppConnectionService;
|
||||||
|
|
||||||
|
public PushManagementService(XmppConnectionService service) {
|
||||||
|
this.mXmppConnectionService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerPushTokenOnServer(Account account) {
|
||||||
|
//stub implementation. only affects playstore flavor
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean available() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,6 +109,5 @@ public final class Config {
|
||||||
};
|
};
|
||||||
|
|
||||||
private Config() {
|
private Config() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,7 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
public IqPacket requestHttpUploadSlot(Jid host, DownloadableFile file, String mime) {
|
public IqPacket requestHttpUploadSlot(Jid host, DownloadableFile file, String mime) {
|
||||||
IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
|
IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
|
||||||
packet.setTo(host);
|
packet.setTo(host);
|
||||||
Element request = packet.addChild("request",Xmlns.HTTP_UPLOAD);
|
Element request = packet.addChild("request", Xmlns.HTTP_UPLOAD);
|
||||||
request.addChild("filename").setContent(file.getName());
|
request.addChild("filename").setContent(file.getName());
|
||||||
request.addChild("size").setContent(String.valueOf(file.getExpectedSize()));
|
request.addChild("size").setContent(String.valueOf(file.getExpectedSize()));
|
||||||
if (mime != null) {
|
if (mime != null) {
|
||||||
|
@ -307,4 +307,18 @@ public class IqGenerator extends AbstractGenerator {
|
||||||
|
|
||||||
return register;
|
return register;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IqPacket pushTokenToAppServer(Jid appServer, String token, String deviceId) {
|
||||||
|
IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
|
||||||
|
packet.setTo(appServer);
|
||||||
|
Element command = packet.addChild("command", "http://jabber.org/protocol/commands");
|
||||||
|
command.setAttribute("node","register-push-gcm");
|
||||||
|
command.setAttribute("action","execute");
|
||||||
|
Data data = new Data();
|
||||||
|
data.put("token", token);
|
||||||
|
data.put("device-id", deviceId);
|
||||||
|
data.submit();
|
||||||
|
command.addChild(data);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,6 @@ import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.MucOptions;
|
import eu.siacs.conversations.entities.MucOptions;
|
||||||
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
|
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
|
||||||
import eu.siacs.conversations.entities.Presence;
|
import eu.siacs.conversations.entities.Presence;
|
||||||
import eu.siacs.conversations.entities.Presences;
|
|
||||||
import eu.siacs.conversations.entities.Roster;
|
import eu.siacs.conversations.entities.Roster;
|
||||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||||
import eu.siacs.conversations.entities.Transferable;
|
import eu.siacs.conversations.entities.Transferable;
|
||||||
|
@ -127,6 +126,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
public static final String ACTION_TRY_AGAIN = "try_again";
|
public static final String ACTION_TRY_AGAIN = "try_again";
|
||||||
public static final String ACTION_DISABLE_ACCOUNT = "disable_account";
|
public static final String ACTION_DISABLE_ACCOUNT = "disable_account";
|
||||||
private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
|
private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
|
||||||
|
public static final String ACTION_GCM_TOKEN_REFRESH = "gcm_token_refresh";
|
||||||
|
public static final String ACTION_GCM_MESSAGE_RECEIVED = "gcm_message_received";
|
||||||
private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor();
|
private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor();
|
||||||
private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor();
|
private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor();
|
||||||
private final IBinder mBinder = new XmppConnectionBinder();
|
private final IBinder mBinder = new XmppConnectionBinder();
|
||||||
|
@ -198,6 +199,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
this);
|
this);
|
||||||
private AvatarService mAvatarService = new AvatarService(this);
|
private AvatarService mAvatarService = new AvatarService(this);
|
||||||
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
|
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
|
||||||
|
private PushManagementService mPushManagementService = new PushManagementService(this);
|
||||||
private OnConversationUpdate mOnConversationUpdate = null;
|
private OnConversationUpdate mOnConversationUpdate = null;
|
||||||
private final FileObserver fileObserver = new FileObserver(
|
private final FileObserver fileObserver = new FileObserver(
|
||||||
FileBackend.getConversationsImageDirectory()) {
|
FileBackend.getConversationsImageDirectory()) {
|
||||||
|
@ -265,7 +267,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
private OnStatusChanged statusListener = new OnStatusChanged() {
|
private OnStatusChanged statusListener = new OnStatusChanged() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStatusChanged(Account account) {
|
public void onStatusChanged(final Account account) {
|
||||||
XmppConnection connection = account.getXmppConnection();
|
XmppConnection connection = account.getXmppConnection();
|
||||||
if (mOnAccountUpdate != null) {
|
if (mOnAccountUpdate != null) {
|
||||||
mOnAccountUpdate.onAccountUpdate();
|
mOnAccountUpdate.onAccountUpdate();
|
||||||
|
@ -296,6 +298,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
account.pendingConferenceJoins.clear();
|
account.pendingConferenceJoins.clear();
|
||||||
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
|
scheduleWakeUpCall(Config.PING_MAX_INTERVAL, account.getUuid().hashCode());
|
||||||
|
|
||||||
|
if (mPushManagementService.pushAvailable(account)) {
|
||||||
|
mPushManagementService.registerPushTokenOnServer(account);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (account.getStatus() == Account.State.OFFLINE) {
|
} else if (account.getStatus() == Account.State.OFFLINE) {
|
||||||
resetSendingToWaiting(account);
|
resetSendingToWaiting(account);
|
||||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||||
|
@ -512,6 +519,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
refreshAllPresences();
|
refreshAllPresences();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACTION_GCM_TOKEN_REFRESH:
|
||||||
|
refreshAllGcmTokens();
|
||||||
|
break;
|
||||||
|
case ACTION_GCM_MESSAGE_RECEIVED:
|
||||||
|
Log.d(Config.LOGTAG,"gcm push message arrived in service. extras="+intent.getExtras());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.wakeLock.acquire();
|
this.wakeLock.acquire();
|
||||||
|
@ -572,7 +584,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
reconnectAccount(account, true, interactive);
|
reconnectAccount(account, true, interactive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (mOnAccountUpdate != null) {
|
if (mOnAccountUpdate != null) {
|
||||||
mOnAccountUpdate.onAccountUpdate();
|
mOnAccountUpdate.onAccountUpdate();
|
||||||
|
@ -2845,6 +2856,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void refreshAllGcmTokens() {
|
||||||
|
for(Account account : getAccounts()) {
|
||||||
|
if (account.isOnlineAndConnected() && mPushManagementService.pushAvailable(account)) {
|
||||||
|
mPushManagementService.registerPushTokenOnServer(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void sendOfflinePresence(final Account account) {
|
public void sendOfflinePresence(final Account account) {
|
||||||
sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account));
|
sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account));
|
||||||
}
|
}
|
||||||
|
@ -3005,7 +3024,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
databaseBackend.insertDiscoveryResult(disco);
|
databaseBackend.insertDiscoveryResult(disco);
|
||||||
injectServiceDiscorveryResult(account.getRoster(), presence.getHash(), presence.getVer(), disco);
|
injectServiceDiscorveryResult(account.getRoster(), presence.getHash(), presence.getVer(), disco);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": mismatch in caps for contact " + jid+" "+presence.getVer()+" vs "+disco.getVer());
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": mismatch in caps for contact " + jid + " " + presence.getVer() + " vs " + disco.getVer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account.inProgressDiscoFetches.remove(key);
|
account.inProgressDiscoFetches.remove(key);
|
||||||
|
@ -3041,6 +3060,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PushManagementService getPushManagementService() {
|
||||||
|
return mPushManagementService;
|
||||||
|
}
|
||||||
|
|
||||||
public interface OnMamPreferencesFetched {
|
public interface OnMamPreferencesFetched {
|
||||||
void onPreferencesFetched(Element prefs);
|
void onPreferencesFetched(Element prefs);
|
||||||
void onPreferencesFetchFailed();
|
void onPreferencesFetchFailed();
|
||||||
|
|
|
@ -29,6 +29,7 @@ import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TableLayout;
|
import android.widget.TableLayout;
|
||||||
|
import android.widget.TableRow;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
private TextView mServerInfoBlocking;
|
private TextView mServerInfoBlocking;
|
||||||
private TextView mServerInfoPep;
|
private TextView mServerInfoPep;
|
||||||
private TextView mServerInfoHttpUpload;
|
private TextView mServerInfoHttpUpload;
|
||||||
|
private TextView mServerInfoPush;
|
||||||
private TextView mSessionEst;
|
private TextView mSessionEst;
|
||||||
private TextView mOtrFingerprint;
|
private TextView mOtrFingerprint;
|
||||||
private TextView mAxolotlFingerprint;
|
private TextView mAxolotlFingerprint;
|
||||||
|
@ -223,6 +225,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private Toast mFetchingMamPrefsToast;
|
private Toast mFetchingMamPrefsToast;
|
||||||
|
private TableRow mPushRow;
|
||||||
|
|
||||||
public void refreshUiReal() {
|
public void refreshUiReal() {
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
|
@ -422,6 +425,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm);
|
this.mServerInfoSm = (TextView) findViewById(R.id.server_info_sm);
|
||||||
this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep);
|
this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep);
|
||||||
this.mServerInfoHttpUpload = (TextView) findViewById(R.id.server_info_http_upload);
|
this.mServerInfoHttpUpload = (TextView) findViewById(R.id.server_info_http_upload);
|
||||||
|
this.mPushRow = (TableRow) findViewById(R.id.push_row);
|
||||||
|
this.mServerInfoPush = (TextView) findViewById(R.id.server_info_push);
|
||||||
this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
|
this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
|
||||||
this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box);
|
this.mOtrFingerprintBox = (RelativeLayout) findViewById(R.id.otr_fingerprint_box);
|
||||||
this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
|
this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
|
||||||
|
@ -680,6 +685,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
||||||
} else {
|
} else {
|
||||||
this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
|
this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().available() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
if (features.push()) {
|
||||||
|
this.mServerInfoPush.setText(R.string.server_info_available);
|
||||||
|
} else {
|
||||||
|
this.mServerInfoPush.setText(R.string.server_info_unavailable);
|
||||||
|
}
|
||||||
final String otrFingerprint = this.mAccount.getOtrFingerprint();
|
final String otrFingerprint = this.mAccount.getOtrFingerprint();
|
||||||
if (otrFingerprint != null) {
|
if (otrFingerprint != null) {
|
||||||
this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
|
this.mOtrFingerprintBox.setVisibility(View.VISIBLE);
|
||||||
|
|
|
@ -1495,17 +1495,13 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mam() {
|
public boolean mam() {
|
||||||
if (hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")) {
|
return hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")
|
||||||
return true;
|
|| hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
|
||||||
} else {
|
|
||||||
return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean advancedStreamFeaturesLoaded() {
|
public boolean push() {
|
||||||
synchronized (XmppConnection.this.disco) {
|
return hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:push:0")
|
||||||
return disco.containsKey(account.getServer());
|
|| hasDiscoFeature(account.getServer(), "urn:xmpp:push:0");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean rosterVersioning() {
|
public boolean rosterVersioning() {
|
||||||
|
|
|
@ -399,6 +399,26 @@
|
||||||
android:textSize="?attr/TextSizeBody"
|
android:textSize="?attr/TextSizeBody"
|
||||||
tools:ignore="RtlHardcoded"/>
|
tools:ignore="RtlHardcoded"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
<TableRow
|
||||||
|
android:id="@+id/push_row"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_info_push"
|
||||||
|
android:textColor="@color/black87"
|
||||||
|
android:textSize="?attr/TextSizeBody"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/server_info_push"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="right"
|
||||||
|
android:textColor="@color/black87"
|
||||||
|
android:textSize="?attr/TextSizeBody"/>
|
||||||
|
</TableRow>
|
||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
@ -416,8 +436,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="right"
|
android:layout_gravity="right"
|
||||||
android:textColor="@color/black87"
|
android:textColor="@color/black87"
|
||||||
android:textSize="?attr/TextSizeBody"
|
android:textSize="?attr/TextSizeBody"/>
|
||||||
tools:ignore="RtlHardcoded"/>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@
|
||||||
<string name="server_info_stream_management">XEP-0198: Stream Management</string>
|
<string name="server_info_stream_management">XEP-0198: Stream Management</string>
|
||||||
<string name="server_info_pep">XEP-0163: PEP (Avatars / OMEMO)</string>
|
<string name="server_info_pep">XEP-0163: PEP (Avatars / OMEMO)</string>
|
||||||
<string name="server_info_http_upload">XEP-0363: HTTP File Upload</string>
|
<string name="server_info_http_upload">XEP-0363: HTTP File Upload</string>
|
||||||
|
<string name="server_info_push">XEP-0357: Push</string>
|
||||||
<string name="server_info_available">available</string>
|
<string name="server_info_available">available</string>
|
||||||
<string name="server_info_unavailable">unavailable</string>
|
<string name="server_info_unavailable">unavailable</string>
|
||||||
<string name="missing_public_keys">Missing public key announcements</string>
|
<string name="missing_public_keys">Missing public key announcements</string>
|
||||||
|
|
35
src/playstore/AndroidManifest.xml
Normal file
35
src/playstore/AndroidManifest.xml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest
|
||||||
|
package="eu.siacs.conversations"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<permission android:name="eu.siacs.conversations.permission.C2D_MESSAGE"
|
||||||
|
android:protectionLevel="signature"/>
|
||||||
|
<uses-permission android:name="eu.siacs.conversations.permission.C2D_MESSAGE"/>
|
||||||
|
|
||||||
|
<application>
|
||||||
|
|
||||||
|
<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" />
|
||||||
|
<category android:name="com.example.gcm" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<service
|
||||||
|
android:name=".services.PushMessageReceiver"
|
||||||
|
android:exported="false" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service android:name=".services.InstanceIdService" android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.gms.iid.InstanceID"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
|
@ -0,0 +1,15 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.google.android.gms.iid.InstanceIDListenerService;
|
||||||
|
|
||||||
|
public class InstanceIdService extends InstanceIDListenerService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTokenRefresh() {
|
||||||
|
Intent intent = new Intent(this, XmppConnectionService.class);
|
||||||
|
intent.setAction(XmppConnectionService.ACTION_GCM_TOKEN_REFRESH);
|
||||||
|
startService(intent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
|
import com.google.android.gms.common.GoogleApiAvailability;
|
||||||
|
import com.google.android.gms.gcm.GoogleCloudMessaging;
|
||||||
|
import com.google.android.gms.iid.InstanceID;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||||
|
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||||
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
|
|
||||||
|
public class PushManagementService {
|
||||||
|
|
||||||
|
private static final String APP_SERVER = "push.conversations.im";
|
||||||
|
|
||||||
|
protected final XmppConnectionService mXmppConnectionService;
|
||||||
|
|
||||||
|
public PushManagementService(XmppConnectionService service) {
|
||||||
|
this.mXmppConnectionService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerPushTokenOnServer(final Account account) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": has push support");
|
||||||
|
retrieveGcmInstanceToken(new OnGcmInstanceTokenRetrieved() {
|
||||||
|
@Override
|
||||||
|
public void onGcmInstanceTokenRetrieved(String token) {
|
||||||
|
try {
|
||||||
|
final String deviceId = Settings.Secure.getString(mXmppConnectionService.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||||
|
IqPacket packet = mXmppConnectionService.getIqGenerator().pushTokenToAppServer(Jid.fromString(APP_SERVER), token, deviceId);
|
||||||
|
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
@Override
|
||||||
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
|
Log.d(Config.LOGTAG, "push to app server result: " + packet.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InvalidJidException ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retrieveGcmInstanceToken(final OnGcmInstanceTokenRetrieved instanceTokenRetrieved) {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
InstanceID instanceID = InstanceID.getInstance(mXmppConnectionService);
|
||||||
|
try {
|
||||||
|
String token = instanceID.getToken(mXmppConnectionService.getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
|
||||||
|
instanceTokenRetrieved.onGcmInstanceTokenRetrieved(token);
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean available() {
|
||||||
|
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(mXmppConnectionService) == ConnectionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean pushAvailable(Account account) {
|
||||||
|
return account.getXmppConnection().getFeatures().push() && available();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnGcmInstanceTokenRetrieved {
|
||||||
|
void onGcmInstanceTokenRetrieved(String token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.gcm.GcmListenerService;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
|
public class PushMessageReceiver extends GcmListenerService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageReceived(String from, Bundle data) {
|
||||||
|
Intent intent = new Intent(this, XmppConnectionService.class);
|
||||||
|
intent.setAction(XmppConnectionService.ACTION_GCM_MESSAGE_RECEIVED);
|
||||||
|
intent.replaceExtras(data);
|
||||||
|
startService(intent);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue