fr.bde_eseo.eseomega.lydia.LydiaActivity.java Source code

Java tutorial

Introduction

Here is the source code for fr.bde_eseo.eseomega.lydia.LydiaActivity.java

Source

/**
 * Copyright (C) 2016 - Franois LEPAROUX
 * <p/>
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <p/>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <p/>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.bde_eseo.eseomega.lydia;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.Theme;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;

import fr.bde_eseo.eseomega.Constants;
import fr.bde_eseo.eseomega.R;
import fr.bde_eseo.eseomega.profile.UserProfile;
import fr.bde_eseo.eseomega.utils.ConnexionUtils;
import fr.bde_eseo.eseomega.utils.EncryptUtils;
import fr.bde_eseo.eseomega.utils.Utilities;

/**
 * Created by Franois L. on 05/01/2016.
 * Activit permettant de vrifier si, lors du retour de l'app Lydia, la commande a bien t passe
 * + galement passer une demande de paiement + redir Lydia
 * V1.2
 * Sous la forme d'un dialogue ? tests
 */
public class LydiaActivity extends AppCompatActivity {

    // Android lifecycle objects
    private Context context;

    // Our dialog
    private MaterialDialog md;
    private MaterialDialog.Builder mdb;

    // Our dialog's elements
    private EditText etPhone;
    private CheckBox checkRememberPhone;
    private View mdView;
    private TextView tvStatus;
    private ProgressBar progressStatus;

    // Divers
    private UserProfile userProfile;
    private String clientPhone;
    private boolean hasBeenPaused = false;
    private SharedPreferences prefsUser;

    // Intent-from
    private String orderType = "";
    private int orderID = -1;

    // Returns
    private static int LAST_STATUS = 0;
    private String MOBILE_URL;
    //private String LYDIA_PACKAGE;
    private String LYDIA_INTENT;

    // Types de requtes qui ont lieu lors du onCreate (premire ouverture de l'app)
    private enum INTENT_REQUEST {
        FROM_LYDIA, // Via URL Scheme
        FROM_APP, // Via Intent interne
        ERROR // Aucun des deux prcdents
    }

    // Getteur
    public static int LAST_STATUS() {
        return LAST_STATUS;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // Set view / call parent
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lydia);
        context = this;

        // Init intent flag
        INTENT_REQUEST intent_request = INTENT_REQUEST.ERROR;

        // Get intent parameters
        if (savedInstanceState == null) {
            Intent intent = getIntent();
            Bundle extras = intent.getExtras();
            String action = intent.getAction();

            if (action != null) {

                // Check if intent's action is correct (obviously yes, but prevents Manifest modifications)
                if (action.equals(Intent.ACTION_VIEW)) {

                    // Intent depuis Lydia
                    intent_request = INTENT_REQUEST.FROM_LYDIA;

                    // Get all parameters
                    Uri qUri = intent.getData();

                    // Order ID
                    String sOrderID = qUri.getQueryParameter("id");

                    if (sOrderID != null) {
                        orderID = Integer.parseInt(sOrderID);
                    }

                    orderType = qUri.getQueryParameter("cat");
                }

            } else if (extras != null) {

                // Intent interne
                intent_request = INTENT_REQUEST.FROM_APP;
                orderID = extras.getInt(Constants.KEY_LYDIA_ORDER_ID);
                orderType = extras.getString(Constants.KEY_LYDIA_ORDER_TYPE);

                // Demande de check ?  donc ask dj effectu
                if (extras.getBoolean(Constants.KEY_LYDIA_ORDER_ASKED)) {
                    intent_request = INTENT_REQUEST.FROM_LYDIA;
                }
            }
        }

        // No intent received
        if (intent_request == INTENT_REQUEST.ERROR || orderID == -1) {
            Toast.makeText(context, "Erreur de l'application (c'est pas normal)", Toast.LENGTH_SHORT).show();
            close();
        }

        // Get objects
        userProfile = new UserProfile();
        userProfile.readProfilePromPrefs(context);
        prefsUser = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

        // Init dialog
        dialogInit();

        // Get intent type
        if (intent_request == INTENT_REQUEST.FROM_APP) {

            /**
             * FROM_APP : On doit demander le numro de tlphone du client, puis lorsqu'il clique sur "Payer", effectuer une demande de paiement auprs de Lydia.
             * Il faut ensuite lancer l'Intent vers Lydia avec le bon numro de requte.
             *
             * A afficher :
             * - InputText tlphone
             * - Checkbox mmorisation numro
             * - Texte "lgal" sur le numro de tlphone
             * - Boutons Annuler / Valider  AsyncTask ask.php
             */
            dialogFromApp();

        } else {

            /**
             * FROM_LYDIA : L'activit vient d'tre ouverte aprs que le client ait cliqu sur "Accepter" depuis l'app Lydia.
             * Dans 100% des cas, le retour  notre activit se fait si il a eu un paiement valid.
             * Cependant, on vrifiera le statut de la commande auprs de notre serveur malgr tout.
             *
             * A afficher :
             * - Texte "tat de votre commande"  titre dialogue
             * - Texte status : actualis toutes les 3 secondes  asyncTask
             * - Bouton Fermer si status diffrent de "en cours"
             */
            dialogFromLydia();
        }
    }

    /**
     * Initialise un dialogue avec une entre texte tlphone
     * Les boutons Annuler / Payer permettent de fermer l'activit et d'effectuer une demande de paiement auprs de Lydia
     *  passage direct  l'AsyncTask si tlphone dj renseign  ok done
     */
    void dialogFromApp() {

        // If phone number already present, skip renseignements
        if (userProfile.verifyPhoneNumber(userProfile.getPhoneNumber())) {

            // Send request to server
            AsyncRequestLydia asyncRequestLydia = new AsyncRequestLydia();
            asyncRequestLydia.execute();

        } else {

            // Current title
            mdb.title("Paiement par Lydia");

            // Current content
            mdb.customView(R.layout.dialog_lydia, false);

            // Customize
            mdb.positiveText("Payer");
            mdb.negativeText("Annuler");
            mdb.cancelable(false);
            mdb.autoDismiss(false);

            // Events
            mdb.callback(new MaterialDialog.ButtonCallback() {
                @Override
                public void onPositive(MaterialDialog dialog) {
                    super.onPositive(dialog);

                    clientPhone = etPhone.getText().toString();

                    // Check if phone is correct
                    if (userProfile.verifyPhoneNumber(clientPhone)) {

                        userProfile.setPhoneNumber(clientPhone); // bug correction 3.+

                        // Save it to preferences if checkbox checked
                        if (checkRememberPhone.isChecked()) {
                            userProfile.registerProfileInPrefs(context);
                        }

                        // Send request to server
                        AsyncRequestLydia asyncRequestLydia = new AsyncRequestLydia();
                        asyncRequestLydia.execute();

                    } else {
                        // Phone syntax is bad
                        new MaterialDialog.Builder(context).title("Numro incorrect")
                                .content("Vous pouvez crire votre tlphone sous la forme +33 ou 06")
                                .negativeText("Fermer").show();
                    }
                }

                @Override
                public void onNegative(MaterialDialog dialog) {
                    super.onNegative(dialog);
                    close();
                }
            });

            // Dialog view
            md = mdb.build();
            mdView = md.getCustomView();

            // Dialog's elements
            etPhone = (EditText) mdView.findViewById(R.id.etLydiaPhone);
            checkRememberPhone = (CheckBox) mdView.findViewById(R.id.checkRememberPhone);

            // Set values
            etPhone.setText(userProfile.getPhoneNumber());

            // Show dialog
            md.show();
        }
    }

    /**
     * Initialise un dialogue avec un texte affichant le statut de la commande
     */
    void dialogFromLydia() {

        // Current title
        mdb.title("tat du paiement Lydia");

        // Current content
        mdb.customView(R.layout.dialog_lydia_check, false);

        // Customize
        mdb.negativeText(R.string.dialog_close);
        mdb.cancelable(false);

        // Events
        mdb.callback(new MaterialDialog.ButtonCallback() {
            @Override
            public void onNegative(MaterialDialog dialog) {
                super.onNegative(dialog);

                if (LAST_STATUS == 1) {
                    // Retry (cause payment is pending)
                    intentToLydia();
                } else {
                    // Close only (success / fail)
                    close();
                }
            }
        });

        // Dialog view
        md = mdb.build();
        mdView = md.getCustomView();

        // Dialog's elements
        tvStatus = (TextView) mdView.findViewById(R.id.tvStatusLydia);
        progressStatus = (ProgressBar) mdView.findViewById(R.id.progressCheckLydia);
        progressStatus.getIndeterminateDrawable().setColorFilter(getResources().getColor(R.color.md_blue_800),
                PorterDuff.Mode.SRC_IN);

        // Set values
        progressStatus.setVisibility(View.GONE);

        // Start asyncTask
        AsyncStatusLydia asyncStatusLydia = new AsyncStatusLydia();
        asyncStatusLydia.execute();

        // Show dialog
        md.show();

    }

    /**
     * Closes the dialog / activity
     */
    void close() {
        Intent data = new Intent();
        data.putExtra(Constants.RESULT_LYDIA_VALUE, 2);
        if (getParent() == null) {
            setResult(Activity.RESULT_OK, data);
        } else {
            getParent().setResult(Activity.RESULT_OK, data);
        }
        LydiaActivity.this.finish();
    }

    /**
     * Class to create request to server (Lydia - ESEOmega)
     */
    private class AsyncRequestLydia extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... params) {
            String resp = null;
            try {
                String b64phone = Base64.encodeToString(userProfile.getPhoneNumber().getBytes("UTF-8"),
                        Base64.NO_WRAP);
                String strOrder = String.valueOf(orderID);
                HashMap<String, String> pairs = new HashMap<>();
                pairs.put("username", userProfile.getId());
                pairs.put("password", userProfile.getPassword());
                pairs.put("phone", b64phone);
                pairs.put("idcmd", strOrder);
                pairs.put("cat_order", orderType);
                pairs.put("os", Constants.APP_ID); // Pour recevoir un Intent ddi  Android, sinon c'est iOS
                pairs.put("hash", EncryptUtils.sha256(userProfile.getId() + userProfile.getPassword() + b64phone
                        + strOrder + orderType + "Paiement effectu !"));
                resp = ConnexionUtils.postServerData(Constants.URL_API_LYDIA_ASK, pairs, context);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return resp;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            if (md != null) {
                md.dismiss();
            }
            md = new MaterialDialog.Builder(context).title("Demande de paiement").content("Veuillez patienter ...")
                    .cancelable(false).progressIndeterminateStyle(false).progress(true, 0, false).show();
        }

        @Override
        protected void onPostExecute(String data) {
            super.onPostExecute(data);
            md.hide();
            int result = 0;
            String msg = "Erreur rseau / serveur";

            // Check data
            if (Utilities.isNetworkDataValid(data)) {

                try {
                    // Get object
                    JSONObject obj = new JSONObject(data);
                    result = obj.getInt("status");
                    msg = obj.getString("cause");

                    // Get error-status
                    if (result == 1) {

                        // Get shared data
                        JSONObject sharedData = obj.getJSONObject("data");

                        // Get Lydia pay values
                        MOBILE_URL = sharedData.getString("lydia_url"); // IMPORTANT : Utiliser si app Lydia non installe !
                        //LYDIA_PACKAGE = sharedData.getString("lydia_package");
                        LYDIA_INTENT = sharedData.getString("lydia_intent");

                        // Configure and make Lydia Intent
                        intentToLydia();
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            if (result != 1) {
                md = new MaterialDialog.Builder(context).title("Erreur")
                        .content("Cause : " + msg + "\n(code : " + result + ")").negativeText("Fermer").show();
            }
        }
    }

    /**
     * Make an Intent to Lydia App / Web navigator if app is not found
     */
    void intentToLydia() {

        // Configure and make Lydia Intent
        //String intentUri;
        boolean closeAfter = false;

        // Package Lydia exists ?
        //intentUri = LYDIA_INTENT; // suppose yes

        /*if (Utilities.isPackageExisted(context, LYDIA_PACKAGE)) {
        intentUri = LYDIA_INTENT;
        } else {
        intentUri = MOBILE_URL; // Package doesn't exists : open URL
        closeAfter = true; // @see comment below
        Toast.makeText(context, "Le navigateur va tre ouvert.", Toast.LENGTH_SHORT).show();
        }*/

        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(LYDIA_INTENT));

        PackageManager packageManager = context.getPackageManager();
        if (i.resolveActivity(packageManager) != null) {
            startActivity(i);
        } else { // Package doesn't exists : open URL
            Intent iweb = new Intent();
            closeAfter = true; // @see comment below
            Toast.makeText(context, "Le navigateur va tre ouvert.", Toast.LENGTH_SHORT).show();
            iweb.setData(Uri.parse(MOBILE_URL));
            startActivity(iweb);
        }

        if (closeAfter) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    md.dismiss();
                    close(); // prevent app-resume with null orderID
                    Toast.makeText(context, "Closing LydiaActivity ...", Toast.LENGTH_SHORT).show();
                }
            }, 1000);
        }
    }

    /**
     * If the user come back to the Activity without Intent :
     * It means that the payment has failed / was cancelled
     * We have to show a Dialog which checks order status from server and then show status to user
     */
    @Override
    public void onResume() {
        super.onResume();

        if (hasBeenPaused) {
            hasBeenPaused = false;

            dialogInit();
            dialogFromLydia();
        }
    }

    /**
     * On pause : just save the app has been paused
     */
    @Override
    protected void onPause() {
        super.onPause();
        hasBeenPaused = true;
    }

    /**
     * AsyncTask inside check sub dialog (Lydia callback intent)
     */
    private class AsyncStatusLydia extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... params) {
            String strOrder = String.valueOf(orderID);
            HashMap<String, String> pairs = new HashMap<>();
            pairs.put("username", userProfile.getId());
            pairs.put("password", userProfile.getPassword());
            pairs.put("idcmd", strOrder);
            pairs.put("cat_order", orderType);
            pairs.put("hash", EncryptUtils.sha256(userProfile.getId() + userProfile.getPassword() + strOrder
                    + orderType + "Paiement refus par votre banque"));
            return ConnexionUtils.postServerData(Constants.URL_API_LYDIA_CHECK, pairs, context);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressStatus.setVisibility(View.VISIBLE);
            updateTextStatus("Vrification ...", 0, true);
        }

        @Override
        protected void onPostExecute(final String data) {
            super.onPostExecute(data);

            new Handler().postDelayed(new Runnable() {

                @Override
                public void run() {
                    progressStatus.setVisibility(View.GONE);

                    int result = 0;
                    String msg = "Erreur rseau / serveur";

                    // Check data
                    if (Utilities.isNetworkDataValid(data)) {

                        try {
                            // Get object
                            JSONObject obj = new JSONObject(data);
                            result = obj.getInt("status");
                            msg = obj.getString("cause");

                            // Get error-status
                            if (result == 1) {

                                // Get shared data
                                JSONObject sharedData = obj.getJSONObject("data");

                                // Get Lydia order status
                                int status = sharedData.getInt("status");
                                String info = sharedData.getString("info");

                                // Ok ?
                                updateTextStatus(info, status, false);

                                // Save result
                                LAST_STATUS = status;

                                // If status is 1 (pending payment)
                                if (status == 1) {

                                    // Then set close button value : Fermer  Ressayer
                                    md.setActionButton(DialogAction.NEGATIVE, R.string.dialog_retry);

                                } else {

                                    // Then set close button value : Fermer
                                    md.setActionButton(DialogAction.NEGATIVE, R.string.dialog_close);

                                }

                            } else {
                                LAST_STATUS = result;
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                    if (result != 1) {
                        updateTextStatus("Erreur : " + msg, -1, false);
                    }
                }
            }, 2000);
        }
    }

    /**
     * Set TextView status text and color
     */
    void updateTextStatus(String text, int status, boolean isLoading) {

        tvStatus.setText(text);

        if (isLoading) {
            tvStatus.setTextColor(context.getResources().getColor(R.color.md_blue_800));
        } else {
            if (status == 0) {
                tvStatus.setTextColor(context.getResources().getColor(R.color.md_prim_dark_yellow));
            } else if (status == 1) {
                tvStatus.setTextColor(context.getResources().getColor(R.color.md_blue_800));
            } else if (status == 2) {
                tvStatus.setTextColor(context.getResources().getColor(R.color.circle_ready));
            } else {
                tvStatus.setTextColor(context.getResources().getColor(R.color.md_prim_dark_red));
            }
        }
    }

    /**
     * Init the dialog for the current session
     */
    void dialogInit() {
        mdb = new MaterialDialog.Builder(context);
        mdb.theme(Theme.LIGHT);
        mdb.titleColor(getResources().getColor(R.color.md_blue_800));
    }
}