com.ntsync.android.sync.activities.PaymentVerificationService.java Source code

Java tutorial

Introduction

Here is the source code for com.ntsync.android.sync.activities.PaymentVerificationService.java

Source

package com.ntsync.android.sync.activities;

/*
 * Copyright (C) 2014 Markus Grieder
 *
 * 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.
 * 
 * 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.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>. 
 */

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.http.auth.AuthenticationException;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;

import com.ntsync.android.sync.R;
import com.ntsync.android.sync.client.NetworkUtilities;
import com.ntsync.android.sync.client.ServerException;
import com.ntsync.android.sync.platform.SystemHelper;
import com.ntsync.android.sync.shared.Constants;
import com.ntsync.android.sync.shared.LogHelper;
import com.ntsync.android.sync.shared.SyncUtils;
import com.ntsync.android.sync.shared.SyncUtils.PaymentData;
import com.ntsync.shared.PayPalConfirmationResult;

/**
 * PaymentVerification Service, which verifies a Payment with our service.
 */
public class PaymentVerificationService extends IntentService {

    /**
     * Time in Seconds for the Initial Delay to the start the Payment
     * Verification. Delay: 5 min
     */
    private static final int VERIFICATION_INITIAL_DELAY = 300;

    /**
     * Interval in Seconds when we should try a new Payment Verification. Value:
     * 40min
     */
    private static final int VERIFICATION_INTERVAL = 2400;

    private static final String TAG = "PaymentVerificationService";

    private static final AtomicReference<ScheduledExecutorService> SCHEDULER_REF = new AtomicReference<ScheduledExecutorService>();

    /** Notify user about the pending Payment Verification after 3 days */
    private static final int TIMEOUT_PENDING_PAYMENT = 3 * 24 * 60 * 60 * 1000;

    public PaymentVerificationService() {
        super(TAG);
        SystemHelper.initSystem(this);
        this.setIntentRedelivery(true);
    }

    /**
     * Starts PaymentData Verification Timer, if not already running and
     * PaymentData is open to verify
     * */
    public static void startVerificationTimer(final Context context) {
        if (SyncUtils.hasPaymentData(context)) {
            ScheduledExecutorService scheduler = SCHEDULER_REF.get();
            if (scheduler == null || scheduler.isShutdown()) {
                scheduler = Executors.newScheduledThreadPool(1);
                SCHEDULER_REF.set(scheduler);
            } else {
                // Timer aktiv
                return;
            }
            final ScheduledExecutorService sched = scheduler;

            final Runnable verifTimer = new Runnable() {
                public void run() {
                    runVerifier(context, sched);
                }
            };
            // Verificate PaymentData every 1h for

            scheduler.scheduleAtFixedRate(verifTimer, VERIFICATION_INITIAL_DELAY, VERIFICATION_INTERVAL,
                    TimeUnit.SECONDS);
        }
    }

    private static void runVerifier(final Context context, final ScheduledExecutorService sched) {
        SystemHelper.initSystem(context);
        // Check if PaymentData available -> when no cancel
        AccountManager acm = AccountManager.get(context);
        Account[] accounts = acm.getAccountsByType(Constants.ACCOUNT_TYPE);
        boolean foundPaymentData = false;
        for (Account account : accounts) {
            PaymentData paymentData = SyncUtils.getPayment(account, acm);
            if (paymentData != null) {
                if (SyncUtils.isPaymentVerificationStarted()) {
                    return;
                }

                if (System.currentTimeMillis() > paymentData.paymentSaveDate + TIMEOUT_PENDING_PAYMENT) {
                    sendNotification(context, account, R.string.shop_activity_pendingverification,
                            ShopActivity.class, false);
                }
                foundPaymentData = true;
                break;
            }
        }

        if (foundPaymentData) {
            // Check if user has to be notified

            // Start Service
            Intent verifService = new Intent(context, PaymentVerificationService.class);
            context.startService(verifService);
            LogHelper.logD(TAG, "Start PaymentVerificationService", null);
        } else {
            sched.shutdownNow();
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SystemHelper.initSystem(this, true);
    }

    @Override
    protected void onHandleIntent(Intent arg0) {
        if (SyncUtils.isNetworkConnected(this)) {
            checkForPaymentVerification(this);
        }
    }

    /**
     * Checks for a pending PaymentVerification
     */
    private void checkForPaymentVerification(Context context) {
        AccountManager acm = AccountManager.get(context);
        Account[] accounts = acm.getAccountsByType(Constants.ACCOUNT_TYPE);
        for (Account account : accounts) {
            // Don't verify is already a Verification is in Progress
            if (SyncUtils.isPaymentVerificationStarted()) {
                LogHelper.logD(TAG, "PaymentVerification skipped, because another verifcation is running", null);
                break;
            }

            PaymentData paymentData = SyncUtils.getPayment(account, acm);
            if (paymentData != null) {
                PayPalConfirmationResult result = null;
                try {
                    LogHelper.logI(TAG, "PaymentVerification started for account " + account.name);
                    String authtoken = NetworkUtilities.blockingGetAuthToken(acm, account, null);
                    if (authtoken == null) {
                        continue;
                    }
                    result = NetworkUtilities.verifyPayPalPayment(context, account, paymentData.priceId.toString(),
                            paymentData.paymentConfirmation.toString(), authtoken, acm);
                } catch (NetworkErrorException e) {
                    result = PayPalConfirmationResult.NETWORK_ERROR;
                    LogHelper.logWCause(TAG, "Verifying PayPalPayment failed.", e);
                } catch (AuthenticationException e) {
                    result = PayPalConfirmationResult.AUTHENTICATION_FAILED;
                    LogHelper.logWCause(TAG, "Verifying PayPalPayment failed.", e);
                } catch (OperationCanceledException e) {
                    result = PayPalConfirmationResult.AUTHENTICATION_FAILED;
                    LogHelper.logD(TAG, "Verifying canceled.", e);
                } catch (ServerException e) {
                    result = PayPalConfirmationResult.VERIFIER_ERROR;
                    LogHelper.logWCause(TAG, "Verifying PayPalPayment failed.", e);
                }
                if (result != null) {
                    processResult(context, acm, account, result);
                }
            }
        }
    }

    private void processResult(Context context, AccountManager acm, Account account,
            PayPalConfirmationResult result) {
        boolean removePayment = false;

        int msg = -1;
        Class<? extends Activity> activityClass = ShopActivity.class;

        LogHelper.logI(TAG, "PaymentVerification Result:  " + result);
        switch (result) {
        case SUCCESS:
            removePayment = true;
            msg = R.string.shop_activity_paymentsuccess;
            Bundle extras = new Bundle();
            extras.putBoolean(Constants.PARAM_GETRESTRICTIONS, true);
            ContentResolver.requestSync(account, Constants.CONTACT_AUTHORITY, extras);
            activityClass = ViewAccountsActivity.class;
            break;
        case INVALID_PRICE:
            removePayment = true;
            msg = R.string.shop_activity_invalidprice;
            break;
        case INVALID_SYNTAX:
            removePayment = true;
            msg = R.string.shop_activity_invalidsyntax;
            break;
        case CANCELED:
            removePayment = true;
            msg = R.string.shop_activity_paymentcanceled;
            break;
        case NOT_APPROVED:
        case SALE_NOT_COMPLETED:
        case VERIFIER_ERROR:
        case NETWORK_ERROR:
        case AUTHENTICATION_FAILED:
            // Don't show message -> try again later
            break;
        case ALREADY_PROCESSED:
            removePayment = true;
            break;
        case UNKNOWN_PAYMENT:
            removePayment = true;
            msg = R.string.shop_activity_verificationfailed;
            break;
        default:
            removePayment = true;
            LogHelper.logE(TAG, "Unknown PaymentVerificationResult:" + result, null);
            // Unknown State
            msg = R.string.shop_activity_verificationfailed;
            break;
        }

        if (removePayment) {
            SyncUtils.savePayment(account, acm, null, null);
        }
        if (msg > 0) {
            sendNotification(context, account, msg, activityClass, true);

        }
    }

    private static void sendNotification(Context context, Account account, int msg,
            Class<? extends Activity> activityClass, boolean showMsg) {
        NotificationManager notificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Intent viewIntent = new Intent(context, activityClass);
        if (ShopActivity.class.equals(activityClass)) {
            // Vollstndige Meldung in der View anzeigen
            CharSequence msgText = context.getText(msg);
            if (showMsg) {
                // Show Full Message in ShopActivity
                viewIntent.putExtra(ShopActivity.PARM_MSG, String
                        .format(context.getText(R.string.shop_activity_delayedverif_failed).toString(), msgText));
            }
            viewIntent.putExtra(ShopActivity.PARM_ACCOUNT_NAME, account.name);
        }

        // Adds the back stack
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addParentStack(activityClass);
        stackBuilder.addNextIntent(viewIntent);

        // Photo sync possible.
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setSmallIcon(Constants.NOTIF_ICON).setContentTitle(context.getText(msg))
                .setContentText(account.name).setAutoCancel(true).setOnlyAlertOnce(true)
                .setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));
        notificationManager.notify(Constants.NOTIF_PAYMENT_VERIFICATIONRESULT, builder.build());
    }
}