~singpolyma/cheogram-android

26a4598f3c4a76baef69ae509dd2e77b8d5c25b7 — Daniel Gultsch 2 years ago 624bb56
automatically receive Quicksy SMS. fixes #3962

requires new version of QuicksyServer
M .travis.yml => .travis.yml +1 -2
@@ 13,8 13,7 @@ before_script:
    - mkdir libs
    - wget -O libs/libwebrtc-m87.aar https://gultsch.de/files/libwebrtc-m87.aar
script:
    - ./gradlew assembleConversationsFreeSystemRelease
    - ./gradlew assembleQuicksyFreeCompatRelease
    - ./gradlew assembleDebug

before_install:
    - yes | sdkmanager "platforms;android-28"

M build.gradle => build.gradle +14 -0
@@ 26,6 26,8 @@ configurations {
    conversationsFreeCompatImplementation
    conversationsPlaystoreCompatImplementation
    conversationsPlaystoreSystemImplementation
    quicksyPlaystoreCompatImplementation
    quicksyPlaystoreSystemImplementation
    quicksyFreeCompatImplementation
    quicksyImplementation
}


@@ 41,6 43,8 @@ dependencies {
    }
    conversationsPlaystoreCompatImplementation("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 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
    implementation 'androidx.appcompat:appcompat:1.2.0'


@@ 156,14 160,21 @@ android {
    }

    sourceSets {
        quicksyFreeSystem {
            java {
                srcDir 'src/quicksyFree/java'
            }
        }
        quicksyFreeCompat {
            java {
                srcDir 'src/freeCompat/java'
                srcDir 'src/quicksyFree/java'
            }
        }
        quicksyPlaystoreCompat {
            java {
                srcDir 'src/playstoreCompat/java'
                srcDir 'src/quicksyPlaystore/java'
            }
            res {
                srcDir 'src/playstoreCompat/res'


@@ 171,6 182,9 @@ android {
            }
        }
        quicksyPlaystoreSystem {
            java {
                srcDir 'src/quicksyPlaystore/java'
            }
            res {
                srcDir 'src/quicksyPlaystore/res'
            }

M src/conversations/java/eu/siacs/conversations/services/QuickConversationsService.java => src/conversations/java/eu/siacs/conversations/services/QuickConversationsService.java +10 -0
@@ 1,5 1,10 @@
package eu.siacs.conversations.services;

import android.content.Intent;
import android.util.Log;

import eu.siacs.conversations.Config;

public class QuickConversationsService extends AbstractQuickConversationsService {

    QuickConversationsService(XmppConnectionService xmppConnectionService) {


@@ 25,4 30,9 @@ public class QuickConversationsService extends AbstractQuickConversationsService
    public void considerSyncBackground(boolean force) {

    }

    @Override
    public void handleSmsReceived(Intent intent) {
        Log.d(Config.LOGTAG,"ignoring received SMS");
    }
}
\ No newline at end of file

M src/main/AndroidManifest.xml => src/main/AndroidManifest.xml +3 -1
@@ 72,12 72,14 @@

        <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>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.intent.action.ACTION_SHUTDOWN" />
                <action android:name="android.media.RINGER_MODE_CHANGED" />
                <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
            </intent-filter>
        </receiver>


M src/main/java/eu/siacs/conversations/services/AbstractQuickConversationsService.java => src/main/java/eu/siacs/conversations/services/AbstractQuickConversationsService.java +7 -0
@@ 1,9 1,14 @@
package eu.siacs.conversations.services;

import android.content.Intent;

import eu.siacs.conversations.BuildConfig;

public abstract class AbstractQuickConversationsService {


    public static final String SMS_RETRIEVED_ACTION = "com.google.android.gms.auth.api.phone.SMS_RETRIEVED";

    protected final XmppConnectionService service;

    public AbstractQuickConversationsService(XmppConnectionService service) {


@@ 25,4 30,6 @@ public abstract class AbstractQuickConversationsService {
    public abstract boolean isSynchronizing();

    public abstract void considerSyncBackground(boolean force);

    public abstract void handleSmsReceived(Intent intent);
}

M src/main/java/eu/siacs/conversations/services/EventReceiver.java => src/main/java/eu/siacs/conversations/services/EventReceiver.java +1 -1
@@ 27,7 27,7 @@ public class EventReceiver extends BroadcastReceiver {
        if (extras != null) {
            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);
        } else {
            Log.d(Config.LOGTAG, "EventReceiver ignored action " + intentForService.getAction());

M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +9 -5
@@ 32,10 32,6 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
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.TelephonyManager;
import android.text.TextUtils;


@@ 44,6 40,11 @@ import android.util.Log;
import android.util.LruCache;
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.Strings;



@@ 135,6 136,7 @@ import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
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.PresencePacket;
import me.leolin.shortcutbadger.ShortcutBadger;
import eu.siacs.conversations.xmpp.Jid;

public class XmppConnectionService extends Service {



@@ 633,6 634,9 @@ public class XmppConnectionService extends Service {
        if (action != null) {
            final String uuid = intent.getStringExtra("uuid");
            switch (action) {
                case QuickConversationsService.SMS_RETRIEVED_ACTION:
                    mQuickConversationsService.handleSmsReceived(intent);
                break;
                case ConnectivityManager.CONNECTIVITY_ACTION:
                    if (hasInternetConnection()) {
                        if (Config.POST_CONNECTIVITY_CHANGE_PING_INTERVAL > 0) {

M src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java => src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java +29 -1
@@ 1,8 1,10 @@
package eu.siacs.conversations.services;


import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
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.PhoneNumberUtilWrapper;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.utils.SmsRetrieverWrapper;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;


@@ 122,6 125,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
    public void requestVerification(Phonenumber.PhoneNumber phoneNumber) {
        final String e164 = PhoneNumberUtilWrapper.normalize(service, phoneNumber);
        if (mVerificationRequestInProgress.compareAndSet(false, true)) {
            SmsRetrieverWrapper.start(service);
            new Thread(() -> {
                try {
                    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) {
        Map<String, PhoneNumberContact> contacts = PhoneNumberContact.load(service);


@@ 429,11 455,13 @@ public class QuickConversationsService extends AbstractQuickConversationsService
        void onVerificationSucceeded();

        void onVerificationRetryAt(long timestamp);

        void startBackgroundVerification(String pin);
    }

    private static class Attempt {
        private final long timestamp;
        private int hash;
        private final int hash;

        private static final Attempt NULL = new Attempt(0, 0);


M src/quicksy/java/eu/siacs/conversations/ui/VerifyActivity.java => src/quicksy/java/eu/siacs/conversations/ui/VerifyActivity.java +7 -0
@@ 316,6 316,12 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
        runOnUiThread(VERIFICATION_TIMEOUT_UPDATER);
    }

    @Override
    public void startBackgroundVerification(String pin) {
        pinEntryWrapper.setPin(pin);
        setVerifyingState(true);
    }

    //send sms again button callback
    @Override
    public void onVerificationRequestFailed(int code) {


@@ 329,6 335,7 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
    @Override
    public void onVerificationRequested() {
        runOnUiThread(() -> {
            pinEntryWrapper.clear();
            setRequestingVerificationState(false);
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage(R.string.we_have_sent_you_another_sms);

A src/quicksyFree/java/eu/siacs/conversations/utils/SmsRetrieverWrapper.java => src/quicksyFree/java/eu/siacs/conversations/utils/SmsRetrieverWrapper.java +16 -0
@@ 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;
    }
}
\ No newline at end of file

A src/quicksyPlaystore/java/eu/siacs/conversations/utils/SmsRetrieverWrapper.java => src/quicksyPlaystore/java/eu/siacs/conversations/utils/SmsRetrieverWrapper.java +40 -0
@@ 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;
    }
}
\ No newline at end of file