com.mobicage.rogerthat.plugins.scan.ProcessScanActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.mobicage.rogerthat.plugins.scan.ProcessScanActivity.java

Source

/*
 * Copyright 2016 Mobicage NV
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @@license_version:1.1@@
 */

package com.mobicage.rogerthat.plugins.scan;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import java.util.regex.Matcher;

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;

import com.mobicage.rogerth.at.R;
import com.mobicage.rogerthat.MyIdentity;
import com.mobicage.rogerthat.ServiceBoundActivity;
import com.mobicage.rogerthat.plugins.friends.FriendsPlugin;
import com.mobicage.rogerthat.plugins.history.HistoryItem;
import com.mobicage.rogerthat.util.RegexPatterns;
import com.mobicage.rogerthat.util.TextUtils;
import com.mobicage.rogerthat.util.logging.L;
import com.mobicage.rogerthat.util.system.SafeBroadcastReceiver;
import com.mobicage.rogerthat.util.system.SafeDialogInterfaceOnClickListener;
import com.mobicage.rogerthat.util.system.T;
import com.mobicage.rogerthat.util.ui.UIUtils;
import com.mobicage.rpc.config.CloudConstants;
import com.mobicage.to.friends.GetUserInfoRequestTO;

public class ProcessScanActivity extends ServiceBoundActivity {

    public final static String URL_ROGERTHAT_PREFIX = "rogerthat://q/i";
    public final static String URL_ROGERTHAT_SID_PREFIX = "rogerthat://q/s/";

    // /s/ (lowercase s) is probably no longer used. Certainly server doesnt serve this path
    public final static String SHORT_HTTPS_URL_PREFIX = CloudConstants.HTTPS_BASE_URL + "/s/";

    public final static String SCAN_FRIEND_INVITE_PREFIX = CloudConstants.HTTPS_BASE_URL + "/q/i";
    public final static String SCAN_SERVICE_ACTION_PREFIX = CloudConstants.HTTPS_BASE_URL + "/q/s/";

    public static final String SCAN_RESULT = "SCAN_RESULT";

    private static final String INVITATION_SECRET_ARG = "s";
    private static final String INVITATION_INVITOR_ARG = "u";

    public final static String URL_REDIRECTION_DONE = "com.mobicage.rogerthat.plugins.scan.URL_REDIRECTION_DONE";

    public final static String NAME = "name";
    public final static String AVATAR = "avatar";
    public static final String APP_ID = "appId";
    public static final String EMAIL = "email";
    public static final String TYPE = "type";
    public static final String DESCRIPTION = "description";
    public static final String DESCRIPTION_BRANDING = "decriptionBranding";
    public static final String POKE_ACTION = "action";
    public static final String POKE_DESCRIPTION = "actionDescription";
    public static final String QUALIFIED_IDENTIFIER = "qualified_identifier";
    public static final String SUCCESS = "success";
    public static final String STATIC_FLOW = "staticFlow";
    public static final String STATIC_FLOW_HASH = "staticFlowHash";
    public static final String ERROR_MESSAGE = "error_message";
    public static final String ERROR_TITLE = "error_title";
    public static final String ERROR_CAPTION = "error_caption";
    public static final String ERROR_ACTION = "error_action";

    public static final String RAWURL = "rawUrl";
    public static final String EMAILHASH = "emailHash";
    public static final String URL = "url";

    private FriendsPlugin mFriendsPlugin;
    private ScanCommunication mScanCommunication;
    private ProgressDialog mProgressDialog;

    private String mExpectedEmailHash;
    private String mExpectedAction;

    private SafeBroadcastReceiver mBroadcastReceiver;

    @Override
    protected void onServiceBound() {
        T.UI();

        mFriendsPlugin = mService.getPlugin(FriendsPlugin.class);
        mBroadcastReceiver = getBroadcastReceiver();

        final IntentFilter filter = new IntentFilter(FriendsPlugin.FRIEND_INFO_RECEIVED_INTENT);
        filter.addAction(FriendsPlugin.SERVICE_ACTION_INFO_RECEIVED_INTENT);
        filter.addAction(URL_REDIRECTION_DONE);
        registerReceiver(mBroadcastReceiver, filter);

        Intent intent = getIntent();
        final String url = intent.getStringExtra(URL);
        final String emailHash = intent.getStringExtra(EMAILHASH);

        if (url == null && emailHash == null) {
            L.bug("url == null && emailHash == null");
            finish();
        } else {
            startSpinner(intent.getBooleanExtra(SCAN_RESULT, false));
            if (url != null)
                processUrl(url);
            else
                processEmailHash(emailHash);
        }
    }

    @Override
    protected void onServiceUnbound() {
        // do nothing
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mBroadcastReceiver != null)
            unregisterReceiver(mBroadcastReceiver);
    }

    private SafeBroadcastReceiver getBroadcastReceiver() {
        return new SafeBroadcastReceiver() {
            @Override
            public String[] onSafeReceive(Context context, Intent intent) {
                T.UI();
                if (intent.getAction().equals(FriendsPlugin.FRIEND_INFO_RECEIVED_INTENT)) {
                    final String emailHash = intent.getStringExtra(EMAILHASH);
                    if (emailHash != null && emailHash.equals(mExpectedEmailHash)) {
                        abortProcessing();

                        if (intent.getBooleanExtra(ProcessScanActivity.SUCCESS, true)) {
                            final Intent inviteFriendIntent = new Intent(ProcessScanActivity.this,
                                    InviteFriendActivity.class);
                            // Copy extra from other intent
                            for (String extra : new String[] { AVATAR, DESCRIPTION, DESCRIPTION_BRANDING, EMAIL,
                                    EMAILHASH, NAME, QUALIFIED_IDENTIFIER }) {
                                inviteFriendIntent.putExtra(extra, intent.getStringExtra(extra));
                            }
                            inviteFriendIntent.putExtra(TYPE,
                                    intent.getLongExtra(TYPE, FriendsPlugin.FRIEND_TYPE_USER));
                            startActivity(inviteFriendIntent);
                            finish();
                            return new String[] { intent.getAction() };
                        } else {
                            showError(intent);
                        }

                    } else {
                        // ignore
                    }
                } else if (intent.getAction().equals(FriendsPlugin.SERVICE_ACTION_INFO_RECEIVED_INTENT)) {
                    if (mExpectedEmailHash != null && mExpectedEmailHash.equals(intent.getStringExtra(EMAILHASH))
                            && mExpectedAction != null
                            && mExpectedAction.equals(intent.getStringExtra(POKE_ACTION))) {
                        abortProcessing();

                        if (intent.getBooleanExtra(SUCCESS, true)) {
                            final Intent serviceActionIntent = new Intent(ProcessScanActivity.this,
                                    ServiceActionActivity.class);
                            // Copy extra from other intent
                            for (String extra : new String[] { AVATAR, DESCRIPTION, DESCRIPTION_BRANDING, EMAIL,
                                    NAME, POKE_DESCRIPTION, QUALIFIED_IDENTIFIER, STATIC_FLOW, STATIC_FLOW_HASH }) {
                                serviceActionIntent.putExtra(extra, intent.getStringExtra(extra));
                            }
                            serviceActionIntent.putExtra(EMAILHASH, mExpectedEmailHash);
                            serviceActionIntent.putExtra(POKE_ACTION, mExpectedAction);
                            serviceActionIntent.setAction(FriendsPlugin.SERVICE_ACTION_INFO_RECEIVED_INTENT);
                            serviceActionIntent.putExtra(SUCCESS, true);
                            startActivity(serviceActionIntent);
                            finish();
                            // TODO: set success?

                            return new String[] { intent.getAction() };
                        } else {
                            showError(intent);
                        }
                    } else {
                        // ignore
                    }
                } else if (intent.getAction().equals(URL_REDIRECTION_DONE)) {
                    final String emailHash = intent.getStringExtra(EMAILHASH);
                    if (intent.hasExtra(POKE_ACTION)) {
                        final String pokeAction = intent.getStringExtra(POKE_ACTION);
                        getServiceActionInfo(emailHash, pokeAction);
                    } else {
                        processEmailHash(emailHash);
                    }
                    return new String[] { intent.getAction() };
                }

                return null; // Intent was ignored
            }

        };
    }

    private void getServiceActionInfo(final String emailHash, final String pokeAction) {
        mExpectedEmailHash = emailHash;
        mExpectedAction = pokeAction;
        boolean success = mFriendsPlugin.getServiceActionInfo(mExpectedEmailHash, mExpectedAction);
        if (!success) {
            UIUtils.showLongToast(ProcessScanActivity.this, getString(R.string.scanner_communication_failure));
            finish();
        }
    }

    private void abortProcessing() {
        T.UI();
        if (mScanCommunication != null) {
            mScanCommunication.abort();
            mScanCommunication = null;
        }
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
        }
        mExpectedEmailHash = null;
    }

    @Override
    public void finish() {
        abortProcessing();
        super.finish();
    }

    private void scannedUnknownQR(String msg, final Intent intent) {
        final Dialog dialog = new AlertDialog.Builder(this)
                .setPositiveButton(R.string.yes, new SafeDialogInterfaceOnClickListener() {
                    @Override
                    public void safeOnClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                        startActivity(intent);
                    }
                }).setNegativeButton(R.string.no, new SafeDialogInterfaceOnClickListener() {
                    @Override
                    public void safeOnClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        finish();
                    }
                }).setMessage(getString(R.string.no_rogerthat_qr, msg, getString(R.string.app_name)))
                .setTitle(R.string.warning).setCancelable(true).create();

        dialog.show();
        abortProcessing();
    }

    private void processUrl(final String url) {
        String trimmedLowerCaseUrl = url.trim().toLowerCase(Locale.US);
        if (trimmedLowerCaseUrl.startsWith(URL_ROGERTHAT_PREFIX)) {
            if (url.contains("?")) {
                processInvitation(url);
            } else {
                processEmailHash(url.substring(URL_ROGERTHAT_PREFIX.length()));
            }

        } else if (trimmedLowerCaseUrl.startsWith(URL_ROGERTHAT_SID_PREFIX)) {
            Matcher match = RegexPatterns.SERVICE_INTERACT_URL.matcher(url);
            match.matches();
            String emailHash = match.group(1);
            String sid = match.group(2);
            getServiceActionInfo(emailHash, sid);

        } else if (trimmedLowerCaseUrl.startsWith(SHORT_HTTPS_URL_PREFIX)) {
            mScanCommunication = new ScanCommunication(mService);
            mScanCommunication.resolveUrl(url);

        } else if (trimmedLowerCaseUrl.startsWith("http://") || trimmedLowerCaseUrl.startsWith("https://")) {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            scannedUnknownQR(getString(R.string.qr_open_url, TextUtils.trimString(url, 100, true)), intent);

        } else if (trimmedLowerCaseUrl.startsWith("tel:")) {
            String number = url.substring(4);
            Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + number));
            scannedUnknownQR(getString(R.string.qr_call_tel, number), intent);

        } else {
            L.d("Cannot process url " + url);
            UIUtils.showLongToast(this, getResources().getString(R.string.unrecognized_scan_result));
            finish();
        }
    }

    private void startSpinner(boolean isScan) {
        mProgressDialog = ProgressDialog.show(this,
                isScan ? getString(R.string.processing_scan, getString(R.string.app_name))
                        : getString(R.string.processing_invitation),
                getString(R.string.retrieving_information), true, true, new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        T.UI();
                        finish();
                    }
                });
    }

    private void checkFriendByEmailHash(final String emailHash) {
        T.UI();

        final FriendsPlugin plugin = mService.getPlugin(FriendsPlugin.class);
        String email = null;

        try {
            email = plugin.getEmailByEmailHash(emailHash.getBytes("US-ASCII"));
        } catch (UnsupportedEncodingException e) {
            // should never happen
        }

        if (email != null) {
            final String friendName = plugin.getName(email);
            finish();
            if (friendName != null) {
                if (email.equals(mService.getIdentityStore().getIdentity().getEmail())) {
                    UIUtils.showLongToast(this, getString(R.string.scanned_yourself, getString(R.string.app_name)));
                } else {
                    showFriendDetailActivity(email, friendName);
                }
            } else {
                showFriendDetailActivity(email, email);
            }
        } else {
            mExpectedEmailHash = emailHash;
            requestFriendInfoByEmailHash(emailHash);
        }
    }

    private void showFriendDetailActivity(final String email, final String name) {
        mFriendsPlugin.launchDetailActivity(this, email);
        UIUtils.showLongToast(this, getString(R.string.already_friend, name));
    }

    private void requestFriendInfoByEmailHash(String emailHash) {

        final GetUserInfoRequestTO request = new GetUserInfoRequestTO();
        request.code = emailHash;
        request.allow_cross_app = false;

        final GetUserInfoResponseHandler handler = new GetUserInfoResponseHandler();
        handler.setCode(emailHash);

        try {
            com.mobicage.api.friends.Rpc.getUserInfo(handler, request);
        } catch (Exception e) {
            finish();
            mService.putInHistoryLog(getString(R.string.getuserinfo_failure), HistoryItem.ERROR);
        }

    }

    private void showErrorToast() {
        UIUtils.showLongToast(ProcessScanActivity.this, getString(R.string.scanner_communication_failure));
    }

    private void showError(Intent intent) {
        final String errorMessage = intent.getStringExtra(ERROR_MESSAGE);
        if (TextUtils.isEmptyOrWhitespace(errorMessage)) {
            finish();
            showErrorToast();
        } else {
            final String errorCaption = intent.getStringExtra(ERROR_CAPTION);
            final String errorAction = intent.getStringExtra(ERROR_ACTION);
            final String errorTitle = intent.getStringExtra(ERROR_TITLE);

            final AlertDialog.Builder builder = new AlertDialog.Builder(ProcessScanActivity.this);
            builder.setTitle(errorTitle);
            builder.setMessage(errorMessage);
            builder.setNegativeButton(R.string.rogerthat, new AlertDialog.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    finish();
                }
            });

            if (!TextUtils.isEmptyOrWhitespace(errorCaption) && !TextUtils.isEmptyOrWhitespace(errorAction)) {
                builder.setPositiveButton(errorCaption, new AlertDialog.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(errorAction));
                        startActivity(intent);
                        dialog.dismiss();
                        finish();
                    }
                });
            }

            builder.show();
        }
    }

    private void processEmailHash(final String emailHash) {
        if (emailHash != null) {
            checkFriendByEmailHash(emailHash);
        } else {
            finish();
            showErrorToast();
        }
    }

    private void processInvitation(final String url) {
        URI uri;
        try {
            uri = new URI(url);
        } catch (URISyntaxException e) {
            L.bug(e);
            return;
        }

        String secret = null;
        String invitor = null;

        for (NameValuePair arg : URLEncodedUtils.parse(uri, "UTF-8")) {
            if (INVITATION_SECRET_ARG.equals(arg.getName())) {
                secret = arg.getValue();
            } else if (INVITATION_INVITOR_ARG.equals(arg.getName())) {
                invitor = arg.getValue();
            }

            if (secret != null && invitor != null) {
                break;
            }
        }

        if (secret == null || invitor == null) {
            L.d("I don't know how to process this URL: " + url);
        } else {
            String invitorEmailHash = url.substring(URL_ROGERTHAT_PREFIX.length(), url.indexOf("?"));
            if (!isMyEmailHash(invitorEmailHash)) {
                FriendsPlugin friendsPlugin = mService.getPlugin(FriendsPlugin.class);
                if (friendsPlugin.ackInvitationBySecret(invitorEmailHash, secret)) {
                    UIUtils.showLongToast(this, getString(R.string.invitation_successfully_accepted, invitor));
                } else {
                    UIUtils.showLongToast(this, getString(R.string.invitation_acception_failure));
                }
            }
        }
        finish();
    }

    private boolean isMyEmailHash(String otherEmailHash) {
        MyIdentity me = mService.getIdentityStore().getIdentity();
        if (me == null)
            return false;

        byte[] myEmailHash = me.getEmailHash();
        if (myEmailHash == null || myEmailHash.length == 0)
            return false;

        try {
            return myEmailHash.equals(otherEmailHash.getBytes("US-ASCII"));
        } catch (UnsupportedEncodingException e) {
            L.bug(e);
            return false;
        }
    }

}