automatically receive Quicksy SMS. fixes #3962
requires new version of QuicksyServer
This commit is contained in:
parent
624bb565a8
commit
26a4598f3c
|
@ -13,8 +13,7 @@ before_script:
|
||||||
- mkdir libs
|
- mkdir libs
|
||||||
- wget -O libs/libwebrtc-m87.aar https://gultsch.de/files/libwebrtc-m87.aar
|
- wget -O libs/libwebrtc-m87.aar https://gultsch.de/files/libwebrtc-m87.aar
|
||||||
script:
|
script:
|
||||||
- ./gradlew assembleConversationsFreeSystemRelease
|
- ./gradlew assembleDebug
|
||||||
- ./gradlew assembleQuicksyFreeCompatRelease
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- yes | sdkmanager "platforms;android-28"
|
- yes | sdkmanager "platforms;android-28"
|
||||||
|
|
14
build.gradle
14
build.gradle
|
@ -26,6 +26,8 @@ configurations {
|
||||||
conversationsFreeCompatImplementation
|
conversationsFreeCompatImplementation
|
||||||
conversationsPlaystoreCompatImplementation
|
conversationsPlaystoreCompatImplementation
|
||||||
conversationsPlaystoreSystemImplementation
|
conversationsPlaystoreSystemImplementation
|
||||||
|
quicksyPlaystoreCompatImplementation
|
||||||
|
quicksyPlaystoreSystemImplementation
|
||||||
quicksyFreeCompatImplementation
|
quicksyFreeCompatImplementation
|
||||||
quicksyImplementation
|
quicksyImplementation
|
||||||
}
|
}
|
||||||
|
@ -41,6 +43,8 @@ dependencies {
|
||||||
}
|
}
|
||||||
conversationsPlaystoreCompatImplementation("com.android.installreferrer:installreferrer:2.2")
|
conversationsPlaystoreCompatImplementation("com.android.installreferrer:installreferrer:2.2")
|
||||||
conversationsPlaystoreSystemImplementation("com.android.installreferrer:installreferrer:2.2")
|
conversationsPlaystoreSystemImplementation("com.android.installreferrer:installreferrer:2.2")
|
||||||
|
quicksyPlaystoreCompatImplementation 'com.google.android.gms:play-services-auth-api-phone:17.0.0'
|
||||||
|
quicksyPlaystoreSystemImplementation 'com.google.android.gms:play-services-auth-api-phone:17.0.0'
|
||||||
implementation 'org.sufficientlysecure:openpgp-api:10.0'
|
implementation 'org.sufficientlysecure:openpgp-api:10.0'
|
||||||
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
|
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
|
@ -156,14 +160,21 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
quicksyFreeSystem {
|
||||||
|
java {
|
||||||
|
srcDir 'src/quicksyFree/java'
|
||||||
|
}
|
||||||
|
}
|
||||||
quicksyFreeCompat {
|
quicksyFreeCompat {
|
||||||
java {
|
java {
|
||||||
srcDir 'src/freeCompat/java'
|
srcDir 'src/freeCompat/java'
|
||||||
|
srcDir 'src/quicksyFree/java'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quicksyPlaystoreCompat {
|
quicksyPlaystoreCompat {
|
||||||
java {
|
java {
|
||||||
srcDir 'src/playstoreCompat/java'
|
srcDir 'src/playstoreCompat/java'
|
||||||
|
srcDir 'src/quicksyPlaystore/java'
|
||||||
}
|
}
|
||||||
res {
|
res {
|
||||||
srcDir 'src/playstoreCompat/res'
|
srcDir 'src/playstoreCompat/res'
|
||||||
|
@ -171,6 +182,9 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quicksyPlaystoreSystem {
|
quicksyPlaystoreSystem {
|
||||||
|
java {
|
||||||
|
srcDir 'src/quicksyPlaystore/java'
|
||||||
|
}
|
||||||
res {
|
res {
|
||||||
srcDir 'src/quicksyPlaystore/res'
|
srcDir 'src/quicksyPlaystore/res'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package eu.siacs.conversations.services;
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
public class QuickConversationsService extends AbstractQuickConversationsService {
|
public class QuickConversationsService extends AbstractQuickConversationsService {
|
||||||
|
|
||||||
QuickConversationsService(XmppConnectionService xmppConnectionService) {
|
QuickConversationsService(XmppConnectionService xmppConnectionService) {
|
||||||
|
@ -25,4 +30,9 @@ public class QuickConversationsService extends AbstractQuickConversationsService
|
||||||
public void considerSyncBackground(boolean force) {
|
public void considerSyncBackground(boolean force) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleSmsReceived(Intent intent) {
|
||||||
|
Log.d(Config.LOGTAG,"ignoring received SMS");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -72,12 +72,14 @@
|
||||||
|
|
||||||
<service android:name=".services.XmppConnectionService" />
|
<service android:name=".services.XmppConnectionService" />
|
||||||
|
|
||||||
<receiver android:name=".services.EventReceiver">
|
<receiver android:name=".services.EventReceiver"
|
||||||
|
android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||||
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
|
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
|
||||||
<action android:name="android.media.RINGER_MODE_CHANGED" />
|
<action android:name="android.media.RINGER_MODE_CHANGED" />
|
||||||
|
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package eu.siacs.conversations.services;
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
import eu.siacs.conversations.BuildConfig;
|
import eu.siacs.conversations.BuildConfig;
|
||||||
|
|
||||||
public abstract class AbstractQuickConversationsService {
|
public abstract class AbstractQuickConversationsService {
|
||||||
|
|
||||||
|
|
||||||
|
public static final String SMS_RETRIEVED_ACTION = "com.google.android.gms.auth.api.phone.SMS_RETRIEVED";
|
||||||
|
|
||||||
protected final XmppConnectionService service;
|
protected final XmppConnectionService service;
|
||||||
|
|
||||||
public AbstractQuickConversationsService(XmppConnectionService service) {
|
public AbstractQuickConversationsService(XmppConnectionService service) {
|
||||||
|
@ -25,4 +30,6 @@ public abstract class AbstractQuickConversationsService {
|
||||||
public abstract boolean isSynchronizing();
|
public abstract boolean isSynchronizing();
|
||||||
|
|
||||||
public abstract void considerSyncBackground(boolean force);
|
public abstract void considerSyncBackground(boolean force);
|
||||||
|
|
||||||
|
public abstract void handleSmsReceived(Intent intent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class EventReceiver extends BroadcastReceiver {
|
||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
intentForService.putExtras(extras);
|
intentForService.putExtras(extras);
|
||||||
}
|
}
|
||||||
if ("ui".equals(action) || hasEnabledAccounts(context)) {
|
if ("ui".equals(action) || QuickConversationsService.SMS_RETRIEVED_ACTION.equals(action) || hasEnabledAccounts(context)) {
|
||||||
Compatibility.startService(context, intentForService);
|
Compatibility.startService(context, intentForService);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, "EventReceiver ignored action " + intentForService.getAction());
|
Log.d(Config.LOGTAG, "EventReceiver ignored action " + intentForService.getAction());
|
||||||
|
|
|
@ -32,10 +32,6 @@ import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.security.KeyChain;
|
import android.security.KeyChain;
|
||||||
import androidx.annotation.BoolRes;
|
|
||||||
import androidx.annotation.IntegerRes;
|
|
||||||
import androidx.core.app.RemoteInput;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import android.telephony.PhoneStateListener;
|
import android.telephony.PhoneStateListener;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
@ -44,6 +40,11 @@ import android.util.Log;
|
||||||
import android.util.LruCache;
|
import android.util.LruCache;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.BoolRes;
|
||||||
|
import androidx.annotation.IntegerRes;
|
||||||
|
import androidx.core.app.RemoteInput;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
|
@ -135,6 +136,7 @@ import eu.siacs.conversations.utils.WakeLockHelper;
|
||||||
import eu.siacs.conversations.utils.XmppUri;
|
import eu.siacs.conversations.utils.XmppUri;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.OnBindListener;
|
import eu.siacs.conversations.xmpp.OnBindListener;
|
||||||
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
|
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
|
||||||
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||||
|
@ -159,7 +161,6 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
||||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
|
||||||
|
|
||||||
public class XmppConnectionService extends Service {
|
public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
|
@ -633,6 +634,9 @@ public class XmppConnectionService extends Service {
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
final String uuid = intent.getStringExtra("uuid");
|
final String uuid = intent.getStringExtra("uuid");
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
case QuickConversationsService.SMS_RETRIEVED_ACTION:
|
||||||
|
mQuickConversationsService.handleSmsReceived(intent);
|
||||||
|
break;
|
||||||
case ConnectivityManager.CONNECTIVITY_ACTION:
|
case ConnectivityManager.CONNECTIVITY_ACTION:
|
||||||
if (hasInternetConnection()) {
|
if (hasInternetConnection()) {
|
||||||
if (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0) {
|
if (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0) {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package eu.siacs.conversations.services;
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -47,6 +49,7 @@ import eu.siacs.conversations.utils.AccountUtils;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
|
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
|
||||||
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
|
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
|
||||||
|
import eu.siacs.conversations.utils.SmsRetrieverWrapper;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
@ -122,6 +125,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
|
||||||
public void requestVerification(Phonenumber.PhoneNumber phoneNumber) {
|
public void requestVerification(Phonenumber.PhoneNumber phoneNumber) {
|
||||||
final String e164 = PhoneNumberUtilWrapper.normalize(service, phoneNumber);
|
final String e164 = PhoneNumberUtilWrapper.normalize(service, phoneNumber);
|
||||||
if (mVerificationRequestInProgress.compareAndSet(false, true)) {
|
if (mVerificationRequestInProgress.compareAndSet(false, true)) {
|
||||||
|
SmsRetrieverWrapper.start(service);
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
final URL url = new URL(BASE_URL + "/authentication/" + e164);
|
final URL url = new URL(BASE_URL + "/authentication/" + e164);
|
||||||
|
@ -322,6 +326,28 @@ public class QuickConversationsService extends AbstractQuickConversationsService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleSmsReceived(final Intent intent) {
|
||||||
|
final Bundle extras = intent.getExtras();
|
||||||
|
final String pin = SmsRetrieverWrapper.extractPin(extras);
|
||||||
|
if (pin == null) {
|
||||||
|
Log.d(Config.LOGTAG, "unable to extract Pin from received SMS");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Account account = AccountUtils.getFirst(service);
|
||||||
|
if (account == null) {
|
||||||
|
Log.d(Config.LOGTAG, "no account configured to process PIN received by SMS");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verify(account, pin);
|
||||||
|
synchronized (mOnVerification) {
|
||||||
|
for (OnVerification onVerification : mOnVerification) {
|
||||||
|
onVerification.startBackgroundVerification(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void considerSync(boolean forced) {
|
private void considerSync(boolean forced) {
|
||||||
Map<String, PhoneNumberContact> contacts = PhoneNumberContact.load(service);
|
Map<String, PhoneNumberContact> contacts = PhoneNumberContact.load(service);
|
||||||
|
@ -429,11 +455,13 @@ public class QuickConversationsService extends AbstractQuickConversationsService
|
||||||
void onVerificationSucceeded();
|
void onVerificationSucceeded();
|
||||||
|
|
||||||
void onVerificationRetryAt(long timestamp);
|
void onVerificationRetryAt(long timestamp);
|
||||||
|
|
||||||
|
void startBackgroundVerification(String pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Attempt {
|
private static class Attempt {
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private int hash;
|
private final int hash;
|
||||||
|
|
||||||
private static final Attempt NULL = new Attempt(0, 0);
|
private static final Attempt NULL = new Attempt(0, 0);
|
||||||
|
|
||||||
|
|
|
@ -316,6 +316,12 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
|
||||||
runOnUiThread(VERIFICATION_TIMEOUT_UPDATER);
|
runOnUiThread(VERIFICATION_TIMEOUT_UPDATER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startBackgroundVerification(String pin) {
|
||||||
|
pinEntryWrapper.setPin(pin);
|
||||||
|
setVerifyingState(true);
|
||||||
|
}
|
||||||
|
|
||||||
//send sms again button callback
|
//send sms again button callback
|
||||||
@Override
|
@Override
|
||||||
public void onVerificationRequestFailed(int code) {
|
public void onVerificationRequestFailed(int code) {
|
||||||
|
@ -329,6 +335,7 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
|
||||||
@Override
|
@Override
|
||||||
public void onVerificationRequested() {
|
public void onVerificationRequested() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
|
pinEntryWrapper.clear();
|
||||||
setRequestingVerificationState(false);
|
setRequestingVerificationState(false);
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(R.string.we_have_sent_you_another_sms);
|
builder.setMessage(R.string.we_have_sent_you_another_sms);
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
|
|
||||||
|
public class SmsRetrieverWrapper {
|
||||||
|
|
||||||
|
public static void start(XmppConnectionService service) {
|
||||||
|
//nop
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String extractPin(Bundle extras) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
||||||
|
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
|
||||||
|
import com.google.android.gms.common.api.CommonStatusCodes;
|
||||||
|
import com.google.android.gms.common.api.Status;
|
||||||
|
import com.google.android.gms.tasks.Task;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
|
||||||
|
public class SmsRetrieverWrapper {
|
||||||
|
|
||||||
|
public static void start(final Context context) {
|
||||||
|
final SmsRetrieverClient client = SmsRetriever.getClient(context);
|
||||||
|
final Task<Void> task = client.startSmsRetriever();
|
||||||
|
task.addOnSuccessListener(aVoid -> Log.d(Config.LOGTAG, "successfully started SMS retriever"));
|
||||||
|
task.addOnFailureListener(e -> Log.d(Config.LOGTAG, "unable to start SMS retriever", e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String extractPin(Bundle extras) {
|
||||||
|
final Status status = extras == null ? null : (Status) extras.get(SmsRetriever.EXTRA_STATUS);
|
||||||
|
if (status != null && status.getStatusCode() == CommonStatusCodes.SUCCESS) {
|
||||||
|
Log.d(Config.LOGTAG, "Verification SMS received with status success");
|
||||||
|
final String message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE);
|
||||||
|
final Matcher m = Pattern.compile("(?<!\\d)\\d{6}(?!\\d)").matcher(Strings.nullToEmpty(message));
|
||||||
|
if (m.find()) {
|
||||||
|
return m.group();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue