uk.org.rivernile.edinburghbustracker.android.fragments.general.EnterStopCodeFragment.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.rivernile.edinburghbustracker.android.fragments.general.EnterStopCodeFragment.java

Source

/*
 * Copyright (C) 2009 - 2013 Niall 'Rivernile' Scott
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors or contributors be held liable for
 * any damages arising from the use of this software.
 *
 * The aforementioned copyright holder(s) hereby grant you a
 * non-transferrable right to use this software for any purpose (including
 * commercial applications), and to modify it and redistribute it, subject to
 * the following conditions:
 *
 *  1. This notice may not be removed or altered from any file it appears in.
 *
 *  2. Any modifications made to this software, except those defined in
 *     clause 3 of this agreement, must be released under this license, and
 *     the source code of any modifications must be made available on a
 *     publically accessible (and locateable) website, or sent to the
 *     original author of this software.
 *
 *  3. Software modifications that do not alter the functionality of the
 *     software but are simply adaptations to a specific environment are
 *     exempt from clause 2.
 */

package uk.org.rivernile.edinburghbustracker.android.fragments.general;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.util.List;
import uk.org.rivernile.edinburghbustracker.android.R;

/**
 * This Fragment allows the user to manually enter a bus stop code or to
 * initiate the QR code scanning.
 * 
 * @author Niall Scott
 */
public class EnterStopCodeFragment extends Fragment implements View.OnClickListener, View.OnKeyListener {

    private static final Intent BARCODE_INTENT;

    private Callbacks callbacks;
    private EditText txt;
    private InputMethodManager imm;
    private boolean barcodePackageAvailable = false;
    private Button scanButton, submitButton;

    static {
        // Set up this Intent statically as it can be reused.
        BARCODE_INTENT = new Intent("com.google.zxing.client.android.SCAN");
        BARCODE_INTENT.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        BARCODE_INTENT.putExtra("QR_CODE_MODE", true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);

        try {
            callbacks = (Callbacks) activity;
        } catch (ClassCastException e) {
            throw new IllegalStateException(
                    activity.getClass().getName() + " does not implement " + Callbacks.class.getName());
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get the Input Method Service.
        imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        // Inflate the View from the XML resource.
        final View v = inflater.inflate(R.layout.enterstopcode, container, false);

        // Get the UI elements.
        submitButton = (Button) v.findViewById(R.id.enterstopcode_submit);
        submitButton.setOnClickListener(this);

        scanButton = (Button) v.findViewById(R.id.enterstopcode_barcode_button);
        scanButton.setOnClickListener(this);

        txt = (EditText) v.findViewById(R.id.enterstopcode_entry);
        txt.setOnKeyListener(this);
        txt.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(final Editable s) {
                // Only enable the confirm button if the length is 8 chars.
                if (s.length() == 8) {
                    submitButton.setEnabled(true);
                } else {
                    submitButton.setEnabled(false);
                }
            }

            @Override
            public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
            }

            @Override
            public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
            }
        });

        return v;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onResume() {
        super.onResume();

        // Get a list of all applications which handle the barcode intent.
        final List<ResolveInfo> packages = getActivity().getPackageManager().queryIntentActivities(BARCODE_INTENT,
                0);
        // If the list does not exist or is empty, there are no Activities to
        // handle the barcode intent.
        if (packages == null || packages.isEmpty()) {
            barcodePackageAvailable = false;
        } else {
            barcodePackageAvailable = true;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onClick(final View v) {
        if (v == scanButton) {
            if (barcodePackageAvailable) {
                try {
                    // Attempt to start the barcode scanning Activity if it is
                    // available.
                    startActivityForResult(BARCODE_INTENT, 0);
                } catch (ActivityNotFoundException e) {
                }
            } else {
                // The barcode scanning Activity is not available, alert the
                // user.
                callbacks.onAskInstallBarcodeScanner();
            }
        } else if (v == submitButton) {
            // The user typed in a stop code, load the bus times.
            task();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        final Activity activity = getActivity();

        // The result code signified success.
        if (resultCode == Activity.RESULT_OK) {
            // Make sure there is a data Intent. There have been some crashes
            // caused by this being null.
            if (data == null) {
                Toast.makeText(activity, R.string.enterstopcode_scan_error, Toast.LENGTH_LONG).show();
                return;
            }

            // Get the data from the Intent.
            final Uri uri = Uri.parse(data.getStringExtra("SCAN_RESULT"));
            // We can only handle hierarchical URIs. Make sure it is so.
            if (!uri.isHierarchical()) {
                // Tell the user the URI was invalid.
                Toast.makeText(activity, R.string.enterstopcode_invalid_qrcode, Toast.LENGTH_LONG).show();
                return;
            }

            // Get the busStopCode parameter from the URI.
            final String stopCode = uri.getQueryParameter("busStopCode");
            // Do basic sanity checking on the parameter.
            if (stopCode != null && stopCode.length() > 0) {
                // Set the EditText to the value of this stop code.
                txt.setText(stopCode);
                // Launch bus times.
                callbacks.onShowBusTimes(stopCode);
            } else {
                Toast.makeText(activity, R.string.enterstopcode_invalid_qrcode, Toast.LENGTH_LONG).show();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onKey(final View v, final int keyCode, final KeyEvent event) {
        // Grab the enter key.
        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER
                && txt.getText().length() == 8) {
            imm.hideSoftInputFromWindow(txt.getWindowToken(), 0);
            task();
        }

        return false;
    }

    /**
     * Call the DisplayStopDataActivity with the stop code given in the EditText
     * box.
     */
    private void task() {
        final Activity activity = getActivity();

        // Should never happen, but make sure there is a stop code to work with.
        if (txt.getText().length() == 0) {
            Toast.makeText(activity, R.string.enterstopcode_toast_inputerr, Toast.LENGTH_LONG).show();
        } else {
            // Load bus times.
            callbacks.onShowBusTimes(txt.getText().toString().trim());
        }
    }

    /**
     * Any Activities which host this Fragment must implement this interface to
     * handle navigation events.
     */
    public static interface Callbacks {

        /**
         * This is called when the user is asked if they want to install
         * a barcode scanner or not.
         */
        public void onAskInstallBarcodeScanner();

        /**
         * This is called when the user wishes to view bus stop times.
         * 
         * @param stopCode The bus stop to view times for.
         */
        public void onShowBusTimes(String stopCode);
    }
}