Android Open Source - coloring-book-android Shop Activity






From Project

Back to project page coloring-book-android.

License

The source code is released under:

GNU General Public License

If you think the Android project coloring-book-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2013 Byron Sanchez (hackbytes.com)
 * www.chompix.com/*www .  j  ava 2  s .  c  om*/
 *
 * This file is part of "Coloring Book for Android."
 *
 * "Coloring Book for Android" 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, version 2 of the
 * license.
 *
 * "Coloring Book for Android" 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 "Coloring Book for Android."  If not, see
 * <http://www.gnu.org/licenses/>.
 */

package net.globide.coloring_book_08;

import java.util.ArrayList;
import java.util.HashMap;

import net.globide.coloring_book_08.util.IabHelper;
import net.globide.coloring_book_08.util.IabResult;
import net.globide.coloring_book_08.util.Inventory;
import net.globide.coloring_book_08.util.Purchase;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Outputs a list of items that can be bought via the marketplace as well as
 * corresponding buy buttons.
 */

public class ShopActivity extends Activity implements OnClickListener {

    // Define whether or not this activity continues music from the
    // MusicManager.
    private boolean mContinueMusic = true;

    // Define our small db API object for database interaction.
    private NodeDatabase mDbNodeHelper = null;
    // Define a category object that will store the category data from the
    // database.
    private Category[] mCategoryData;

    // (arbitrary) request code for the purchase flow
    private static final int RC_REQUEST = 10001;

    // The helper object
    private IabHelper mHelper;

    // Boolean check for whether or not the user is currently online.
    // TODO: private boolean mIsOnline;

    // Does the user have the second coloring book?
    private HashMap<String, Boolean> mHas = new HashMap<String, Boolean>();
    
    // Declare hashmaps for the dynamically generated data.
    private HashMap<String, RelativeLayoutHolder> mRlHashMap = new HashMap<String, RelativeLayoutHolder>();
    private HashMap<String, TextViewHolder> mTvHashMap = new HashMap<String, TextViewHolder>();
    private HashMap<String, ImageButtonHolder> mIbHashMap = new HashMap<String, ImageButtonHolder>();
    
    // Define the necessary views.
    private LinearLayout mLlShopScrollView;
    private RelativeLayout mRlShopProgress;
    public ProgressBar pbShopQuery;
    private RelativeLayout mRlTemplate;
    private TextView mTvTemplate;
    private ImageButton mIbTemplate;
    
    // Tablet vs. phone boolean. Defaults to phone.
    public static boolean sIsTablet = false;
    public static boolean sIsSmall = false;
    public static boolean sIsNormal = false;
    public static boolean sIsLarge = false;
    public static boolean sIsExtraLarge = false;

    /**
     *  Holders for dynamically generated relative layouts.
     */
    private class RelativeLayoutHolder {

        // Tag so we can access each view when updating the UI.
        private String tag;
        private String sku;

    }

    /**
     *  Holders for dynamically generated textviews.
     */
    private class TextViewHolder {

        // Tag so we can access each view when updating the UI.
        private String tag;
        private String sku;

    }

    /**
     * Holders for dynamically generated image buttons.
     */
    private class ImageButtonHolder {

        // Tag so we can access each view when updating the UI.
        private String tag;
        private String sku;

    }

    /**
     * Implements onCreate().
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set the activity to full screen mode.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Add default content.
        setContentView(R.layout.activity_shop);
        
        // Determine whether or not the current device is a tablet.
        ShopActivity.sIsTablet = getResources().getBoolean(R.bool.isTablet);
        ShopActivity.sIsSmall = getResources().getBoolean(R.bool.isSmall);
        ShopActivity.sIsNormal = getResources().getBoolean(R.bool.isNormal);
        ShopActivity.sIsLarge = getResources().getBoolean(R.bool.isLarge);
        ShopActivity.sIsExtraLarge = getResources().getBoolean(R.bool.isExtraLarge);

        // Attach views to their corresponding resource ids.
        mLlShopScrollView = (LinearLayout) findViewById(R.id.llShopScrollView);
        mRlShopProgress = (RelativeLayout) findViewById(R.id.rlShopProgress);

        // Create the progressbar view
        pbShopQuery = new ProgressBar(this, null, android.R.attr.progressBarStyleLargeInverse);

        // Give the progressbar some parameters.
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);

        pbShopQuery.setLayoutParams(params);
        pbShopQuery.setIndeterminate(true);

        // Add the view to the layout.
        mRlShopProgress.addView(pbShopQuery);

        // load state data
        loadData();

        // Create all buttons based on the data in the categories table in the
        // db.
        createButtons();

        // Find out whether or not the user is currently online.
        // TODO: mIsOnline = isOnline();

        /*
         * base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY (that
         * you got from the Google Play developer console). This is not your
         * developer public key, it's the *app-specific* public key.
         * Instead of just storing the entire literal string here embedded in
         * the program, construct the key at runtime from pieces or use bit
         * manipulation (for example, XOR with some other string) to hide the
         * actual key. The key itself is not secret information, but we don't
         * want to make it easy for an attacker to replace the public key with
         * one of their own and then fake messages from the server.
         */
        String base64EncodedPublicKey = "YOUR_BILL_KEY_HERE";

        // TODO: Implement the preceeding comment in some way.

        // Create the helper, passing it our context and the public key to
        // verify signatures with
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        // enable debug logging (for a production application, you should
        // set this to false).
        mHelper.enableDebugLogging(false);

        // Start setup. This is asynchronous and the specified listener
        // will be called once setup completes.
        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {

                if (!result.isSuccess()) {
                    // Oh noes, there was a problem.
                    return;
                }

                // Hooray, IAB is fully set up. Now, let's get an inventory of
                // stuff we own.
                mHelper.queryInventoryAsync(mGotInventoryListener);
            }
        });
    }
    
    /**
     * Listener that's called when we finish querying the items we own
     */
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            if (result.isFailure()) {
                return;
            }

            // Do we have the items.
            for (Category category : mCategoryData) {
                mHas.put(category.sku, inventory.hasPurchase(category.sku));
            }

            // If we can't find it via the inventory, we might not have an
            // internet connection, so check the database.

            // Ensure that the database contains the purchase information.
            checkDatabase();

            updateUi();
            setWaitScreen(false);
        }
    };

    /**
     * Callback for when a purchase is finished
     */
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            if (result.isFailure()) {
                // Oh noes!
                setWaitScreen(false);
                return;
            }

            for (Category category : mCategoryData) {
                if (purchase.getSku().equals(category.sku)) {
                    // bought a coloring book!
                    alert(category.category + " pack has been added! Access it via the main menu.");
                    mHas.put(category.sku, true);

                    // Ensure that the database contains the purchase
                    // information.
                    checkDatabase();

                    updateUi();
                    setWaitScreen(false);
                }
            }
        }
    };

    /**
     * Updates UI to reflect model
     */
    public void updateUi() {

        // update the shop buttons to reflect whether or not the user has bought
        // the item.
        for (String sku : mIbHashMap.keySet()) {
            
            // Store a reference to the current iteration's Image Holder.
            ImageButtonHolder ibHolder = mIbHashMap.get(sku);
            
            ImageButton currentImageButton = (ImageButton) mLlShopScrollView.findViewWithTag(ibHolder.tag);

            // The buy button should only work when this product has not yet
            // been purchased.
            currentImageButton.setBackgroundResource(mHas.get(sku) ? R.drawable.button_shop_disabled
                    : R.drawable.button_shop);

            currentImageButton.setEnabled(mHas.get(sku) ? false : true);
        }

        // Redraw the view.
        mLlShopScrollView.invalidate();
    }

    /**
     * Enables or disables the "please wait" screen.
     */
    void setWaitScreen(boolean set) {
        // Update the views.
        findViewById(R.id.svShop).setVisibility(set ? View.GONE : View.VISIBLE);
        findViewById(R.id.rlShopProgress).setVisibility(set ? View.VISIBLE : View.GONE);

        // Invalidate to redraw them
        findViewById(R.id.svShop).invalidate();
        findViewById(R.id.rlShopProgress).invalidate();
    }

    /**
     * Creates buttons for all coloring books in the categories table.
     */
    private void createButtons() {

        // Attach views to their corresponding resource ids.
        mRlTemplate = (RelativeLayout) findViewById(R.id.rlTemplate);
        mTvTemplate = (TextView) findViewById(R.id.tvTemplate);
        mIbTemplate = (ImageButton) findViewById(R.id.ibTemplate);

        // Retrieve the layout parameters for each view.
        LinearLayout.LayoutParams rlTemplateParams = (LinearLayout.LayoutParams) mRlTemplate
                .getLayoutParams();
        RelativeLayout.LayoutParams tvTemplateParams = (RelativeLayout.LayoutParams) mTvTemplate
                .getLayoutParams();
        RelativeLayout.LayoutParams ibTemplateParams = (RelativeLayout.LayoutParams) mIbTemplate
                .getLayoutParams();

        // Iterate through each category row.
        for (Category category : mCategoryData) {
            
            /*
             * RelativeLayout
             */
            // Create a new relative layout and add it to the main ScrollView.
            RelativeLayout newRelativeLayout = new RelativeLayout(this);
            newRelativeLayout.setLayoutParams(rlTemplateParams);
            
            // Set view styles
            if (ShopActivity.sIsTablet) {
                if (ShopActivity.sIsSmall) {
                    newRelativeLayout.setPadding(0, 12, 0, 12);
                }
                else if (ShopActivity.sIsNormal) {
                    newRelativeLayout.setPadding(0, 15, 0, 15);
                }
                else if (ShopActivity.sIsLarge) {
                    newRelativeLayout.setPadding(0, 18, 0, 18);
                }
                else if (ShopActivity.sIsExtraLarge) {
                    newRelativeLayout.setPadding(0, 20, 0, 20);
                }
            } else {
                newRelativeLayout.setPadding(0, 8, 0, 8);
            }

            // Set tag as the viewtype _ sku
            newRelativeLayout.setTag("RelativeLayout_" + category.sku);
            
            // Store this data in the corresponding holder hash map
            RelativeLayoutHolder rlHolder = new RelativeLayoutHolder();
            rlHolder.sku = category.sku;
            rlHolder.tag = "RelativeLayout_" + category.sku;
            mRlHashMap.put(category.sku, rlHolder);

            mLlShopScrollView.addView(newRelativeLayout);
            
            /*
             * TextView
             */

            // Create a new textview and add it to the relative layout.
            TextView newTextView = new TextView(this);
            newTextView.setLayoutParams(tvTemplateParams);
            newTextView.setText(category.category + " Pack");
            newTextView.setTextColor(Color.WHITE);
            
            // Set view styles
            if (ShopActivity.sIsTablet) {
                if (ShopActivity.sIsSmall) {
                    newTextView.setTextSize(24);
                }
                else if (ShopActivity.sIsNormal) {
                    newTextView.setTextSize(30);
                }
                else if (ShopActivity.sIsLarge) {
                    newTextView.setTextSize(36);
                }
                else if (ShopActivity.sIsExtraLarge) {
                    newTextView.setTextSize(40);
                }
            } else {
                newTextView.setTextSize(16);
            }

            // Set tag as the viewtype _ sku
            newTextView.setTag("TextView_" + category.sku);
            
            // Store this data in the corresponding holder hash map
            TextViewHolder tvHolder = new TextViewHolder();
            tvHolder.sku = category.sku;
            tvHolder.tag = "TextView_" + category.sku;
            mTvHashMap.put(category.sku, tvHolder);

            newRelativeLayout.addView(newTextView);
            
            /*
             * ImageButton.
             */

            // Create a new imagebutton and add it to the relative layout.
            ImageButton newImageButton = new ImageButton(this);
            newImageButton.setLayoutParams(ibTemplateParams);
            newImageButton.setOnClickListener(this);

            // Set tag as the viewtype _ sku
            newImageButton.setTag("ImageButton_" + category.sku);
            
            // Store this data in the corresponding holder hash map
            ImageButtonHolder ibHolder = new ImageButtonHolder();
            ibHolder.sku = category.sku;
            ibHolder.tag = "ImageButton_" + category.sku;
            mIbHashMap.put(category.sku, ibHolder);

            newRelativeLayout.addView(newImageButton);
        }

        // Remove the template views from the layout.
        mLlShopScrollView.removeView(mRlTemplate);
        
        // Redraw the views.
        mLlShopScrollView.invalidate();
    }

    /**
     * Checks whether or not the user currently has internet access.
     */
    //public boolean isOnline() {
     //   ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

     //   NetworkInfo netInfo = cm.getActiveNetworkInfo();

     //   if (netInfo != null && netInfo.isConnected()) {
     //       return true;
     //   }

    //   return false;
    //}

    /**
     * Renders a message to the screen for user confirmation.
     */
    private void alert(String message) {
        AlertDialog.Builder bld = new AlertDialog.Builder(this);
        bld.setMessage(message);
        bld.setNeutralButton("OK", null);
        bld.create().show();
    }

    /**
     * Checks to see if the database contains the purchase information.
     */
    private void checkDatabase() {
        // Check to see if the corresponding row exists in the database
        // and is enabled. If not, we need to enable it.
        for (Category category : mCategoryData) {

            // If the user doesn't have it in the data base but has it in
            // the inventory, the product hasn't yet been locally registered
            // so register it.
            if (category.isAvailable == 0) {
                if (mHas.get(category.sku)) {
                    // Database check!

                    // Create our database access object.
                    mDbNodeHelper = new NodeDatabase(this);

                    // Call the create method right just in case the user
                    // has
                    // never run the app before. If a database does not
                    // exist,
                    // the prepopulated one will be copied from the assets
                    // folder. Else, a connection is established.
                    mDbNodeHelper.createDatabase();
                    // Enable the coloring book in the database.
                    mDbNodeHelper.updateCategory(category.id, "isAvailable", 1);
                    // Update the local cache for consistency
                    category.isAvailable = 1;

                    // Flush the buffer.
                    mDbNodeHelper.flushQuery();

                    // This activity no longer needs the connection, so
                    // close
                    // it.
                    mDbNodeHelper.close();
                    
                    // A quick toast to confirm updated content in cases where a new purchase has just occurred or a previous purchase has been reinstated.
                    // TODO: Decouple both cases and display an alert dialog for each case so its more obvious.
                    Toast.makeText(this, "Your content has been updated.", Toast.LENGTH_LONG).show();
                }
            }
            // Else the product has been locally registered, so just set the
            // local boolean to match correspondingly.
            else if (category.isAvailable == 1) {
                mHas.put(category.sku, true);
            }
        }
    }

    /**
     * Loads current category status from the database.
     */
    private void loadData() {
        // Database check!

        // Create our database access object.
        mDbNodeHelper = new NodeDatabase(this);

        // Call the create method right just in case the user has never run the
        // app before. If a database does not exist, the prepopulated one will
        // be copied from the assets folder. Else, a connection is established.
        mDbNodeHelper.createDatabase();

        // Query the database for all purchased categories.

        // Set a conditional buffer. Internally, the orderby is set to _id ASC
        // (NodeDatabase.java).
        mDbNodeHelper.setConditions("sku", "'000_default'", "!=");
        // Execute the query.
        mCategoryData = mDbNodeHelper.getCategoryListData();
        // Flush the buffer.
        mDbNodeHelper.flushQuery();

        // This activity no longer needs the connection, so close it.
        mDbNodeHelper.close();
    }

    /**
     * Implements onActivityResult();
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        // Pass on the activity result to the helper for handling
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
        }
        else {
            //Log.d(TAG, "onActivityResult handled by IABUtil.");
        }
    }

    /**
     * Implements onBackPressed().
     */
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        // Ensure that the music will continue to play when the user returns to
        // another activity.
        mContinueMusic = true;
    }

    /**
     * Implements onPause().
     */
    @Override
    protected void onPause() {
        super.onPause();

        // If the music should not continue playing when leaving this activity,
        // pause it.
        if (!mContinueMusic) {
            MusicManager.pause();
        }
    }

    /**
     * Implements onResume().
     */
    @Override
    protected void onResume() {
        super.onResume();

        // If this activity continues playing the music, start the mediaplayer.
        mContinueMusic = false;
        MusicManager.start(this, MusicManager.MUSIC_A);
    }

    /**
     * Implements onDestroyed().
     */
    @Override
    public void onDestroy() {
        // very important:
        if (mHelper != null) {
            mHelper.dispose();
        }
        mHelper = null;

        super.onDestroy();
    }

    /**
     * Implements onClick().
     */
    @Override
    public void onClick(View view) {
        
        // Iterate through the views.
        // update the shop buttons to reflect whether or not the user has bought
        // the item.
        for (String sku : mIbHashMap.keySet()) {
            
            // Store a reference to the current iteration's Image Holder.
            ImageButtonHolder ibHolder = mIbHashMap.get(sku);

            // If the clicked view tag matches this iteration's view tag, launch the purchase flow for this item.
            if (view.getTag().equals(ibHolder.tag)) {
                setWaitScreen(true);
                mHelper.launchPurchaseFlow(this, ibHolder.sku, RC_REQUEST,
                        mPurchaseFinishedListener);
            }
        }
    }
}




Java Source Code List

net.globide.coloring_book_08.Category.java
net.globide.coloring_book_08.ColorActivity.java
net.globide.coloring_book_08.ColorGFX.java
net.globide.coloring_book_08.ColorGfxData.java
net.globide.coloring_book_08.ColorPalette.java
net.globide.coloring_book_08.CreditsActivity.java
net.globide.coloring_book_08.FixedSpeedScroller.java
net.globide.coloring_book_08.HelpActivity.java
net.globide.coloring_book_08.MainActivity.java
net.globide.coloring_book_08.MainPagerAdapter.java
net.globide.coloring_book_08.MainPanelFragment.java
net.globide.coloring_book_08.MusicManager.java
net.globide.coloring_book_08.NodeDatabase.java
net.globide.coloring_book_08.Node.java
net.globide.coloring_book_08.OnMainPanelTouchListener.java
net.globide.coloring_book_08.SettingsActivity.java
net.globide.coloring_book_08.ShopActivity.java
net.globide.coloring_book_08.SplashActivity.java
net.globide.coloring_book_08.util.Base64DecoderException.java
net.globide.coloring_book_08.util.Base64.java
net.globide.coloring_book_08.util.IabException.java
net.globide.coloring_book_08.util.IabHelper.java
net.globide.coloring_book_08.util.IabResult.java
net.globide.coloring_book_08.util.Inventory.java
net.globide.coloring_book_08.util.Purchase.java
net.globide.coloring_book_08.util.Security.java
net.globide.coloring_book_08.util.SkuDetails.java