de.persoapp.android.core.adapter.MainViewFragment.java Source code

Java tutorial

Introduction

Here is the source code for de.persoapp.android.core.adapter.MainViewFragment.java

Source

/**
 *
 * COPYRIGHT (C) 2010, 2011, 2012, 2013, 2014 AGETO Innovation GmbH
 *
 * Authors Christian Kahlo, Ralf Wondratschek
 *
 * All Rights Reserved.
 *
 * Contact: PersoApp, http://www.persoapp.de
 *
 * @version 1.0, 30.07.2013 13:50:47
 *
 *          This file is part of PersoApp.
 *
 *          PersoApp is free software: you can redistribute it and/or modify it
 *          under the terms of the GNU Lesser General Public License as
 *          published by the Free Software Foundation, either version 3 of the
 *          License, or (at your option) any later version.
 *
 *          PersoApp 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
 *          Lesser General Public License for more details.
 *
 *          You should have received a copy of the GNU Lesser General Public
 *          License along with PersoApp. If not, see
 *          <http://www.gnu.org/licenses/>.
 *
 *          Diese Datei ist Teil von PersoApp.
 *
 *          PersoApp ist Freie Software: Sie knnen es unter den Bedingungen der
 *          GNU Lesser General Public License, wie von der Free Software
 *          Foundation, Version 3 der Lizenz oder (nach Ihrer Option) jeder
 *          spteren verffentlichten Version, weiterverbreiten und/oder
 *          modifizieren.
 *
 *          PersoApp wird in der Hoffnung, dass es ntzlich sein wird, aber OHNE
 *          JEDE GEWHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 *          Gewhrleistung der MARKTFHIGKEIT oder EIGNUNG FR EINEN BESTIMMTEN
 *          ZWECK. Siehe die GNU Lesser General Public License fr weitere
 *          Details.
 *
 *          Sie sollten eine Kopie der GNU Lesser General Public License
 *          zusammen mit diesem Programm erhalten haben. Wenn nicht, siehe
 *          <http://www.gnu.org/licenses/>.
 *
 */
package de.persoapp.android.core.adapter;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Browser;
import android.support.v4.app.Fragment;

import net.vrallev.android.base.BaseActivitySupport;
import net.vrallev.android.base.LooperMain;
import net.vrallev.android.base.util.Cat;
import net.vrallev.android.lib.crouton.extension.CroutonBuilder;

import java.net.URL;
import java.util.concurrent.CountDownLatch;

import javax.inject.Inject;

import de.keyboardsurfer.android.widget.crouton.Configuration;
import de.keyboardsurfer.android.widget.crouton.Style;
import de.persoapp.android.R;
import de.persoapp.android.activity.dialog.CanDialog;
import de.persoapp.android.activity.dialog.QuestionDialog;
import de.persoapp.core.ECardWorker;
import de.persoapp.core.client.IEAC_Info;
import de.persoapp.core.client.IMainView;
import de.persoapp.core.client.SecureHolder;
import hugo.weaving.DebugLog;

/**
 * Handles most interactions between core library and {@link android.app.Activity}s. By extending {@link de.persoapp.android.activity.AbstractNfcActivity} one
 * {@link de.persoapp.android.core.adapter.MainViewFragment} instance is already setup.
 *
 * <br>
 * <br>
 *
 * You can extend {@link de.persoapp.android.core.adapter.MainViewFragment.MainViewCallback} to receive callbacks.
 *
 * @see de.persoapp.android.activity.AuthenticateActivity
 *
 * @author Ralf Wondratschek
 */
@SuppressWarnings("ConstantConditions")
public class MainViewFragment extends Fragment implements IMainView {

    public static final String TAG = "MainViewFragmentTag";

    private static final String EXTRA_DO_REDIRECT = "net.ageto.eid.intent.extra.do_redirect";
    private static final String EXTRA_REFRESH_ADDRESS = "net.ageto.eid.intent.extra.refresh_address";

    private static final int MSG_FINISH = 1;

    public static MainViewFragment findOrCreateFragment(BaseActivitySupport activity) {
        Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag(TAG);

        if (!(fragment instanceof MainViewFragment)) {
            return forceCreateFragment(activity);
        }

        return (MainViewFragment) fragment;
    }

    public static MainViewFragment forceCreateFragment(BaseActivitySupport activity) {
        Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag(TAG);
        if (fragment != null) {
            activity.getSupportFragmentManager().beginTransaction().remove(fragment).commit();
        }

        fragment = new MainViewFragment();
        activity.getSupportFragmentManager().beginTransaction().add(fragment, TAG).commit();

        return (MainViewFragment) fragment;
    }

    @Inject
    @LooperMain
    Looper mMainLooper;

    private Handler mMainHandler;

    private String mTcTokenUrl;
    private String mRefreshAddress;

    private boolean mRefreshBrowser;

    private EventListener mEventListener;
    private final Object mEventMonitor = new Object();

    private MainViewCallback mMainViewCallback;

    private MainDialogResult mMainDialogResult;
    private CountDownLatch mCountDownLatchResult;

    private long mCroutonDismissedTime;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        setRetainInstance(true);

        ((BaseActivitySupport) activity).inject(this);

        mMainHandler = new MyHandler(mMainLooper);
        mCountDownLatchResult = new CountDownLatch(1);
    }

    @SuppressWarnings("UnusedDeclaration")
    public void startAuthentication(String tcTokenUrl) {
        startAuthentication(tcTokenUrl, null);
    }

    public void startAuthentication(String tcTokenUrl, Intent extra) {
        if (mTcTokenUrl != null) {
            throw new IllegalStateException("You can only start one authentication per session.");
        }

        mTcTokenUrl = tcTokenUrl;
        mRefreshBrowser = extra == null || extra.getBooleanExtra(EXTRA_DO_REDIRECT, true);

        new Thread() {
            @Override
            public void run() {
                try {
                    mRefreshAddress = ECardWorker.start(new URL(mTcTokenUrl));

                    if (getActivity() != null) {
                        getActivity().setResult(Activity.RESULT_CANCELED,
                                new Intent().putExtra(EXTRA_REFRESH_ADDRESS, mRefreshAddress));
                    }

                } catch (Exception e) {
                    Cat.w(e, "Bad request");
                    closeDialogs();
                }
            }
        }.start();
    }

    public void setMainViewCallback(MainViewCallback mainViewCallback) {
        mMainViewCallback = mainViewCallback;
    }

    public void setMainDialogResult(MainDialogResult mainDialogResult) {
        mMainDialogResult = mainDialogResult;
        mCountDownLatchResult.countDown();
    }

    @Override
    public void setEventLister(EventListener listener) {
        synchronized (mEventMonitor) {
            mEventListener = listener;
        }
    }

    @Override
    public Object triggerEvent(int event, Object... eventData) {
        if (mEventListener != null) {
            synchronized (mEventMonitor) {
                return mEventListener.handleEvent(event, eventData);
            }
        } else {
            Cat.w("EventListener is null.");
            return null;
        }
    }

    @Override
    public void showMainDialog(IEAC_Info eacInfo, int mode) {
        if (mMainViewCallback != null) {
            mMainViewCallback.showMainDialog(eacInfo, mode);
        }
    }

    @Override
    public MainDialogResult getMainDialogResult() {
        try {
            mCountDownLatchResult.await();
        } catch (InterruptedException e) {
            Cat.e(e);
        }

        return mMainDialogResult;
    }

    @Override
    public SecureHolder showCANDialog(String msg) {
        if (getActivity() != null) {
            return new CanDialog().askForResult((BaseActivitySupport) getActivity(),
                    getString(R.string.can_dialog_title), msg);
        } else {
            return null;
        }
    }

    @Override
    @DebugLog
    public void showChangePinDialog() {

    }

    @Override
    @DebugLog
    public void showProgress(String message, int amount, boolean enabled) {
        if (mMainViewCallback != null) {
            mMainViewCallback.showProgress(message, amount, enabled);
        }
    }

    @Override
    public boolean showQuestion(String title, String message) {
        return getActivity() != null
                && new QuestionDialog().askForResult((BaseActivitySupport) getActivity(), title, message);
    }

    @Override
    public void showError(final String title, final String message) {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                if (getActivity() != null) {
                    CroutonBuilder.showError(getActivity(), title, message);
                }
            }
        });
    }

    @Override
    public void showMessage(final String msg, final int type) {
        long time = System.currentTimeMillis();
        if (mCroutonDismissedTime < time) {
            mCroutonDismissedTime = time;
        }

        final int duration = Configuration.DURATION_SHORT;

        mCroutonDismissedTime += duration;

        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                if (getActivity() == null) {
                    return;
                }

                CroutonBuilder builder = new CroutonBuilder(getActivity()).setDuration(duration)
                        .setHideOnClick(true).setMessage(msg);

                switch (type) {
                case IMainView.ERROR:
                    builder.setColor(Style.holoRedLight);
                    break;
                case IMainView.INFO:
                case IMainView.RELOAD:
                case IMainView.QUESTION:
                    builder.setColor(Style.holoBlueLight);
                    break;
                case IMainView.SUCCESS:
                    builder.setColor(Style.holoGreenLight);
                    break;
                case IMainView.WARNING:
                    builder.setColor(Color.parseColor("#ffffbb33"));
                    break;
                }

                builder.show();
            }
        });
    }

    @Override
    @DebugLog
    public void closeDialogs() {
        boolean success = isAuthenticationSuccess();
        if (!success && getActivity() != null) {
            showMessage(getActivity().getString(R.string.authentication_failed), IMainView.ERROR);
        }

        long time = System.currentTimeMillis();
        if (mCroutonDismissedTime <= time) {
            mMainHandler.sendEmptyMessage(MSG_FINISH);
        } else {
            mMainHandler.sendEmptyMessageDelayed(MSG_FINISH, Math.min(mCroutonDismissedTime - time, 2000L));
        }

        if (mMainViewCallback != null) {
            mMainViewCallback.closeDialogs(success);
        }
    }

    @Override
    @DebugLog
    public void shutdown() {
        closeDialogs();
    }

    private class MyHandler extends Handler {

        public MyHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_FINISH:
                finish();
                break;
            }
        }
    }

    protected void finish() {
        Activity activity = getActivity();
        if (activity == null) {
            return;
        }

        excludeFromRecentAppList(activity);

        if (isAuthenticationSuccess()) {
            if (mRefreshBrowser) {
                sendIntentToBrowser();
            } else {
                activity.setResult(Activity.RESULT_OK,
                        new Intent().putExtra(EXTRA_REFRESH_ADDRESS, mRefreshAddress));
            }
        }

        activity.finish();
    }

    protected boolean isAuthenticationSuccess() {
        return mMainDialogResult != null && mMainDialogResult.getCHAT() != -1;
    }

    protected void sendIntentToBrowser() {
        if (mRefreshAddress != null) {
            final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(mRefreshAddress));

            // use this to reuse the last tab in the browser
            intent.putExtra(Browser.EXTRA_APPLICATION_ID, "com.android.browser");
            try {
                Cat.d("RefreshAddress == %b, %s", mRefreshAddress.endsWith("Major=ok"), mRefreshAddress);

                startActivity(intent);
            } catch (final Exception e) {
                Cat.w(e, "Unexpected exception");
            }
        }
    }

    protected void excludeFromRecentAppList(Activity activity) {
        // a dirty hack to exclude this activity from the recent app list after the process finished
        // since it runs in singleInstance mode onNewIntent will be called
        final Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        startActivity(intent);
    }

    /**
     * Base class for implementing an callback mechanism on specific events.
     * 
     * @author Ralf Wondratschek
     * @author Rico Klimsa - added javadoc comments.
     */
    public static abstract class MainViewCallback {

        public void showMainDialog(IEAC_Info eacInfo, int mode) {
            // override me
        }

        public void showProgress(String message, int amount, boolean enabled) {
            // override me
        }

        public void closeDialogs(boolean success) {
            // override me
        }
    }
}