~singpolyma/cheogram-android

52ecd9347c9f9cbc3aa082b20bca60cfdadd5c3c — Daniel Gultsch 5 years ago 584cf43
added dialogs for rate limiting and out of date version
M build.gradle => build.gradle +1 -1
@@ 104,7 104,7 @@ android {
        quick {
            dimension "mode"
            applicationId = "im.conversations.quick"
            resValue "string", "app_name", "Quick Conversations"
            resValue "string", "app_name", "Quicksy"
            resValue "string", "applicationId", applicationId
        }


M src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java => src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +5 -1
@@ 69,7 69,11 @@ public abstract class AbstractGenerator {
	}

	public String getIdentityName() {
		return mXmppConnectionService.getString(R.string.app_name) + " " + getIdentityVersion();
		return mXmppConnectionService.getString(R.string.app_name) + ' ' + getIdentityVersion();
	}

	public String getUserAgent() {
		return mXmppConnectionService.getString(R.string.app_name) + '/' + getIdentityVersion();
	}

	String getIdentityType() {

M src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java => src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +2 -2
@@ 288,7 288,7 @@ public class HttpDownloadConnection implements Transferable {
				}
				connection.setUseCaches(false);
				Log.d(Config.LOGTAG, "url: " + connection.getURL().toString());
				connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName());
				connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getUserAgent());
				if (connection instanceof HttpsURLConnection) {
					mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
				}


@@ 367,7 367,7 @@ public class HttpDownloadConnection implements Transferable {
					mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
				}
				connection.setUseCaches(false);
				connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName());
				connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getUserAgent());
				final boolean tryResume = file.exists() && file.getKey() == null && file.getSize() > 0;
				long resumeSize = 0;
				long expected = file.getExpectedSize();

M src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java => src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +1 -1
@@ 166,7 166,7 @@ public class HttpUploadConnection implements Transferable {
			connection.setUseCaches(false);
			connection.setRequestMethod("PUT");
			connection.setFixedLengthStreamingMode(expectedFileSize);
			connection.setRequestProperty("User-Agent",mXmppConnectionService.getIqGenerator().getIdentityName());
			connection.setRequestProperty("User-Agent",mXmppConnectionService.getIqGenerator().getUserAgent());
			if(slot.getHeaders() != null) {
				for(HashMap.Entry<String,String> entry : slot.getHeaders().entrySet()) {
					connection.setRequestProperty(entry.getKey(),entry.getValue());

M src/main/res/values/strings.xml => src/main/res/values/strings.xml +6 -1
@@ 754,7 754,7 @@
    <string name="choose_a_country">Choose a country</string>
    <string name="phone_number">phone number</string>
    <string name="verify_your_phone_number">Verify your phone number</string>
    <string name="enter_country_code_and_phone_number">Quick Conversations will send an SMS message (carrier charges may apply) to verify your phone number. Enter your country code and phone number:</string>
    <string name="enter_country_code_and_phone_number">Quicksy will send an SMS message (carrier charges may apply) to verify your phone number. Enter your country code and phone number:</string>
    <string name="we_will_be_verifying"><![CDATA[We will be verifying the phone number<br/><br/><b>%s</b><br/><br/>Is this OK, or would you like to edit the number?]]></string>
    <string name="not_a_valid_phone_number">%s is not a valid phone number.</string>
    <string name="please_enter_your_phone_number">Please enter your phone number.</string>


@@ 783,4 783,9 @@
    <string name="invalid_user_input">Invalid user input</string>
    <string name="temporarily_unavailable">Temporarily unavailable. Try again later.</string>
    <string name="no_network_connection">No network connection.</string>
    <string name="try_again_in_x">Please try again in %s</string>
    <string name="rate_limited">You are rate limited</string>
    <string name="too_many_attempts">Too many attempts</string>
    <string name="the_app_is_out_of_date">You are using an out of date version of this app.</string>
    <string name="update">Update</string>
</resources>

M src/quick/java/eu/siacs/conversations/services/QuickConversationsService.java => src/quick/java/eu/siacs/conversations/services/QuickConversationsService.java +28 -20
@@ 1,7 1,9 @@
package eu.siacs.conversations.services;


import android.content.SharedPreferences;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;

import java.io.BufferedWriter;


@@ 10,11 12,12 @@ import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;



@@ 40,6 43,8 @@ public class QuickConversationsService {

    private static final String BASE_URL = "http://venus.fritz.box:4567";

    private static final String INSTALLATION_ID = "eu.siacs.conversations.installation-id";

    private final XmppConnectionService service;

    private final Set<OnVerificationRequested> mOnVerificationRequested = Collections.newSetFromMap(new WeakHashMap<>());


@@ 78,14 83,6 @@ public class QuickConversationsService {

    public void requestVerification(Phonenumber.PhoneNumber phoneNumber) {
        final String e164 = PhoneNumberUtilWrapper.normalize(service, phoneNumber);

        /**
         * GET /authentication/+phoneNumber
         *
         * - returns too many requests, (sms ist unterwegs), retry after seconden -- auf jeden fall in nächste activity (verify activity) weiter leiten weil es sein kann das sms noch ankommt
         * - returns OK; success (auch in activity weiter lassen. aber ohne error paramater; dh send again button is activ; und vielleicht kurzer toast bzw snackbar
         * - returns invalid request user error wenn die phone number falsch ist
         */
        if (mVerificationRequestInProgress.compareAndSet(false, true)) {
            new Thread(() -> {
                try {


@@ 96,6 93,7 @@ public class QuickConversationsService {
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
                    setHeader(connection);
                    final int code = connection.getResponseCode();
                    if (code == 200) {
                        createAccountAndWait(phoneNumber, 0L);


@@ 150,16 148,6 @@ public class QuickConversationsService {
    }

    public void verify(final Account account, String pin) {
        /**
         * POST /password
         * authentication gesetzt mit telephone nummber und verification code
         * body = password
         *
         * retry after, too many requests
         * code wrong
         * OK (weiterleiten auf publish avatar activity
         *
         */
        if (mVerificationInProgress.compareAndSet(false, true)) {
            new Thread(() -> {
                try {


@@ 172,6 160,7 @@ public class QuickConversationsService {
                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Authorization", Plain.getMessage(account.getUsername(), pin));
                    setHeader(connection);
                    final OutputStream os = connection.getOutputStream();
                    final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
                    writer.write(account.getPassword());


@@ 217,6 206,25 @@ public class QuickConversationsService {
        }
    }

    private void setHeader(HttpURLConnection connection) {
        connection.setRequestProperty("User-Agent", service.getIqGenerator().getUserAgent());
        connection.setRequestProperty("Installation-Id", getInstallationId());
        connection.setRequestProperty("Accept-Language", Locale.getDefault().getLanguage());
    }

    private String getInstallationId() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(service);
        String id = preferences.getString(INSTALLATION_ID, null);
        if (id != null) {
            return id;
        } else {
            id = UUID.randomUUID().toString();
            preferences.edit().putString(INSTALLATION_ID, id).apply();
            return id;
        }

    }

    private int getApiErrorCode(Exception e) {
        if (!service.hasInternetConnection()) {
            return API_ERROR_AIRPLANE_MODE;


@@ 227,7 235,7 @@ public class QuickConversationsService {
        } else if (e instanceof SSLHandshakeException) {
            return API_ERROR_SSL_HANDSHAKE;
        } else {
            Log.d(Config.LOGTAG,e.getClass().getName());
            Log.d(Config.LOGTAG, e.getClass().getName());
            return API_ERROR_OTHER;
        }
    }

M src/quick/java/eu/siacs/conversations/ui/EnterPhoneNumberActivity.java => src/quick/java/eu/siacs/conversations/ui/EnterPhoneNumberActivity.java +2 -5
@@ 4,23 4,20 @@ import android.app.AlertDialog;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.Html;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;

import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityEnterNumberBinding;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.ui.drawable.TextDrawable;
import eu.siacs.conversations.ui.util.ApiErrorDialogHelper;
import eu.siacs.conversations.ui.util.ApiDialogHelper;
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
import io.michaelrocks.libphonenumber.android.NumberParseException;
import io.michaelrocks.libphonenumber.android.PhoneNumberUtil;


@@ 180,7 177,7 @@ public class EnterPhoneNumberActivity extends XmppActivity implements QuickConve
    public void onVerificationRequestFailed(int code) {
        runOnUiThread(() -> {
            setRequestingVerificationState(false);
            ApiErrorDialogHelper.create(this, code).show();
            ApiDialogHelper.createError(this, code).show();
        });
    }


M src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java => src/quick/java/eu/siacs/conversations/ui/VerifyActivity.java +11 -5
@@ 19,7 19,7 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityVerifyBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.ui.util.ApiErrorDialogHelper;
import eu.siacs.conversations.ui.util.ApiDialogHelper;
import eu.siacs.conversations.ui.util.PinEntryWrapper;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;


@@ 286,7 286,7 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
                builder.setPositiveButton(R.string.ok, null);
                builder.create().show();
            } else {
                ApiErrorDialogHelper.create(this, code).show();
                ApiDialogHelper.createError(this, code).show();
            }
        });
    }


@@ 299,7 299,10 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
    @Override
    public void onVerificationRetryAt(long timestamp) {
        this.retryVerificationAfter = timestamp;
        runOnUiThread(() -> setVerifyingState(false));
        runOnUiThread(() -> {
            ApiDialogHelper.createTooManyAttempts(this).show();
            setVerifyingState(false);
        });
        mHandler.removeCallbacks(VERIFICATION_TIMEOUT_UPDATER);
        runOnUiThread(VERIFICATION_TIMEOUT_UPDATER);
    }


@@ 309,7 312,7 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
    public void onVerificationRequestFailed(int code) {
        runOnUiThread(() -> {
            setRequestingVerificationState(false);
            ApiErrorDialogHelper.create(this, code).show();
            ApiDialogHelper.createError(this, code).show();
        });
    }



@@ 328,7 331,10 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
    @Override
    public void onVerificationRequestedRetryAt(long timestamp) {
        this.retrySmsAfter = timestamp;
        runOnUiThread(() -> setRequestingVerificationState(false));
        runOnUiThread(() -> {
            ApiDialogHelper.createRateLimited(this, timestamp).show();
            setRequestingVerificationState(false);
        });
        mHandler.removeCallbacks(SMS_TIMEOUT_UPDATER);
        runOnUiThread(SMS_TIMEOUT_UPDATER);
    }

R src/quick/java/eu/siacs/conversations/ui/util/ApiErrorDialogHelper.java => src/quick/java/eu/siacs/conversations/ui/util/ApiDialogHelper.java +39 -3
@@ 3,14 3,19 @@ package eu.siacs.conversations.ui.util;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.SystemClock;
import android.support.annotation.StringRes;

import eu.siacs.conversations.R;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.utils.TimeframeUtils;

public class ApiErrorDialogHelper {
public class ApiDialogHelper {

    public static Dialog create(Context context, int code) {
    public static Dialog createError(final Context context, final int code) {
        @StringRes final int res;
        switch (code) {
            case QuickConversationsService.API_ERROR_AIRPLANE_MODE:


@@ 31,6 36,9 @@ public class ApiErrorDialogHelper {
            case 400:
                res = R.string.invalid_user_input;
                break;
            case 403:
                res = R.string.the_app_is_out_of_date;
                break;
            case 502:
            case 503:
            case 504:


@@ 39,9 47,37 @@ public class ApiErrorDialogHelper {
            default:
                res = R.string.unknown_api_error_response;
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage(res);
        if (code == 403 && resolvable(context, getMarketViewIntent(context))) {
            builder.setNegativeButton(R.string.cancel, null);
            builder.setPositiveButton(R.string.update, (dialog, which) -> context.startActivity(getMarketViewIntent(context)));
        } else {
            builder.setPositiveButton(R.string.ok, null);
        }
        return builder.create();
    }

    public static Dialog createRateLimited(final Context context, final long timestamp) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(R.string.rate_limited);
        builder.setMessage(context.getString(R.string.try_again_in_x, TimeframeUtils.resolve(context, timestamp - SystemClock.elapsedRealtime())));
        builder.setPositiveButton(R.string.ok, null);
        return builder.create();
    }

    public static Dialog createTooManyAttempts(final Context context) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage(R.string.too_many_attempts);
        builder.setPositiveButton(R.string.ok, null);
        return builder.create();
    }

    private static Intent getMarketViewIntent(Context context) {
        return new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + context.getPackageName()));
    }

    private static boolean resolvable(Context context, Intent intent) {
        return context.getPackageManager().queryIntentActivities(intent, 0).size() > 0;
    }
}