Android Open Source - RingMyPhoneAndroid Billing Activity






From Project

Back to project page RingMyPhoneAndroid.

License

The source code is released under:

MIT License

If you think the Android project RingMyPhoneAndroid 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

package com.darkrockstudios.apps.ringmyphone;
//from   w  w  w .ja  v a  2  s .c om
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;

import com.android.vending.billing.IInAppBillingService;

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

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by Adam on 12/10/13.
 */
public abstract class BillingActivity extends ActionBarActivity
{
  private static final String TAG             = BillingActivity.class.getSimpleName();
  private static final String PRODUCT_SKU_PRO = "ringmyphone_pro";
  //private static final String PRODUCT_SKU_PRO = "android.test.purchased";

  private static final String EENY  =
      "ZVVOVwNAOtxduxvT9j0ONDRSNNBPND8NZVVOPtXPNDRNu3DWq6bksuJveGDE9cTgSksf4ltOtL/Dcu7sZ7sEA/N0Enkh2EqVGk";
  private static final String MEENY =
      "k1WaYqzbwOK9t4W1ylLD+XC0z+v8ZxuvYf5VXYs2wc2/OaztopRb3I5OL0UO4zWdFuwYV8RYaT9lsvBdNThGgXD8oCnm9PjzVE";

  private boolean m_isPro;

  private IInAppBillingService     m_service;
  private BillingServiceConnection m_serviceConn;

  private ProStatusListener m_statusListener;

  private String m_devPayload;

  public static interface ProStatusListener
  {
    public void onProStatusUpdate( final boolean isPro );
  }

  private class BillingServiceConnection implements ServiceConnection
  {
    @Override
    public void onServiceDisconnected( final ComponentName name )
    {
      m_service = null;
    }

    @Override
    public void onServiceConnected( final ComponentName name,
                                    final IBinder service )
    {
      m_service = IInAppBillingService.Stub.asInterface( service );

      Log.d( TAG, "Billing service connected." );

      if( !m_isPro )
      {
        runProCheck();
      }

      onBillingServiceConnected();
    }
  }

  protected abstract void onBillingServiceConnected();

  public void setProStatusListener( final ProStatusListener listener )
  {
    m_statusListener = listener;
  }

  @Override
  protected void onCreate( final Bundle savedInstanceState )
  {
    super.onCreate( savedInstanceState );

    BillingSecurity.updateInstallDate( this );

    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this );
    m_isPro = settings.getBoolean( Preferences.KEY_IS_PRO, false );

    m_serviceConn = new BillingServiceConnection();
    connectToService();
  }

  private void connectToService()
  {
    Intent intent = new Intent( "com.android.vending.billing.InAppBillingService.BIND" );
    intent.setPackage( "com.android.vending" );
    bindService( intent, m_serviceConn, Context.BIND_AUTO_CREATE );
  }

  @Override
  public void onDestroy()
  {
    super.onDestroy();
    if( m_serviceConn != null )
    {
      unbindService( m_serviceConn );
    }
  }

  public boolean isPro()
  {
    return m_isPro;
  }

  public void runProCheck()
  {
    ProCheckThread proCheckThread = new ProCheckThread();
    proCheckThread.start();
  }

  private class ProCheckThread extends Thread
  {
    @Override
    public void run()
    {
      checkForPro();

      if( m_statusListener != null )
      {
        m_statusListener.onProStatusUpdate( isPro() );
      }
    }
  }

  private void checkForPro()
  {
    Log.d( TAG, "Checking pro purchase status..." );

    if( m_service != null )
    {
      try
      {
        Log.d( TAG, "sending request..." );
        Bundle ownedItems = m_service.getPurchases( 3, getPackageName(), "inapp", null );
        Log.d( TAG, "Request received!" );
        int response = ownedItems.getInt( "RESPONSE_CODE" );
        if( response == 0 )
        {
          ArrayList<String> ownedSkus = ownedItems.getStringArrayList( "INAPP_PURCHASE_ITEM_LIST" );
          ArrayList<String> purchaseDataList = ownedItems.getStringArrayList( "INAPP_PURCHASE_DATA_LIST" );
          ArrayList<String> signatureList = ownedItems.getStringArrayList( "INAPP_DATA_SIGNATURE_LIST" );
          //String continuationToken = ownedItems.getString( "INAPP_CONTINUATION_TOKEN" );

          for( int ii = 0; ii < purchaseDataList.size(); ++ii )
          {
            String purchaseData = purchaseDataList.get( ii );
            String dataSignature = signatureList.get( ii );
            String sku = ownedSkus.get( ii );

            if( sku.equals( PRODUCT_SKU_PRO ) && verifyPurchase( purchaseData, dataSignature ) )
            {
              Log.d( TAG, "Holy crap we're pro!" );
              cacheProLocally();
              m_isPro = true;

              // Uncomment to consume your purchase, this is only for testing the purchase process
              //Debug.consumePurchase( purchaseData, m_service, getPackageName() );
            }
          }
        }

        if( !m_isPro )
        {
          Log.d( TAG, "I don't think we're pro :(" );
        }
      }
      catch( RemoteException e )
      {
        e.printStackTrace();
      }
    }
  }

  public boolean purchasePro()
  {
    boolean shown = false;

    if( m_service != null )
    {
      try
      {
        m_devPayload = generateNewDevPayload();
        Bundle buyIntentBundle =
            m_service.getBuyIntent( 3, getPackageName(), PRODUCT_SKU_PRO, "inapp", m_devPayload );

        int responseCode = buyIntentBundle.getInt( "RESPONSE_CODE", 0 );
        if( responseCode == 0 )
        {
          PendingIntent pendingIntent = buyIntentBundle.getParcelable( "BUY_INTENT" );

          startIntentSenderForResult( pendingIntent.getIntentSender(),
                                      1001, new Intent(),
                                      0,
                                      0,
                                      0 );
          shown = true;
        }
      }
      catch( RemoteException | IntentSender.SendIntentException e )
      {
        e.printStackTrace();
      }
    }

    return shown;
  }

  @Override
  protected void onActivityResult( final int requestCode, final int resultCode, final Intent data )
  {
    if( requestCode == 1001 )
    {
      int responseCode = data.getIntExtra( "RESPONSE_CODE", 0 );
      String purchaseData = data.getStringExtra( "INAPP_PURCHASE_DATA" );
      String dataSignature = data.getStringExtra( "INAPP_DATA_SIGNATURE" );

      if( resultCode == RESULT_OK && responseCode == 0 )
      {
        try
        {
          JSONObject jo = new JSONObject( purchaseData );
          String sku = jo.getString( "productId" );
          String devPayload = jo.getString( "developerPayload" );

          if( PRODUCT_SKU_PRO.equals( sku ) &&
              verifyPurchase( purchaseData, dataSignature ) &&
              m_devPayload != null &&
              m_devPayload.equals( devPayload ) )
          {
            Log.d( TAG, "You have bought " + sku );

            cacheProLocally();
            if( m_statusListener != null )
            {
              m_statusListener.onProStatusUpdate( true );
            }
          }
          else
          {
            Log.e( TAG, "Purchase failed." );
          }
        }
        catch( JSONException e )
        {
          Log.d( TAG, "Failed to parse purchase data." );
          e.printStackTrace();
        }
      }
    }
  }

  private String generateNewDevPayload()
  {
    final Date now = new Date();
    final long fudge = now.getTime() / 7l;
    return BillingSecurity.sha1Hash( fudge + "noh4xplz" );
  }

  @SuppressLint("CommitPrefEdits")
  private void cacheProLocally()
  {
    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences( this );
    settings.edit().putBoolean( Preferences.KEY_IS_PRO, true ).commit();
  }

  private String assemblePublicKey()
  {
    return BillingSecurity.superSecureCrypto( EENY ) +
           BillingSecurity.superSecureCrypto( MEENY ) +
           BillingSecurity.superSecureCrypto( getString( R.string.miny ) ) +
           BillingSecurity.superSecureCrypto( getString( R.string.moe ) );
  }

  private boolean verifyPurchase( final String data, final String signature )
  {
    return BillingSecurity.verifySignature( assemblePublicKey(), data, signature );
  }
}




Java Source Code List

com.darkrockstudios.apps.ringmyphone.AboutFragment.java
com.darkrockstudios.apps.ringmyphone.BillingActivity.java
com.darkrockstudios.apps.ringmyphone.BillingSecurity.java
com.darkrockstudios.apps.ringmyphone.Debug.java
com.darkrockstudios.apps.ringmyphone.MainActivity.java
com.darkrockstudios.apps.ringmyphone.NotificationId.java
com.darkrockstudios.apps.ringmyphone.OsUtil.java
com.darkrockstudios.apps.ringmyphone.PebbleApp.java
com.darkrockstudios.apps.ringmyphone.PebbleMessageReceiver.java
com.darkrockstudios.apps.ringmyphone.PreferencesBackupAgent.java
com.darkrockstudios.apps.ringmyphone.Preferences.java
com.darkrockstudios.apps.ringmyphone.Purchase.java
com.darkrockstudios.apps.ringmyphone.RingerService.java
com.darkrockstudios.apps.ringmyphone.SettingsActivity.java
com.darkrockstudios.apps.ringmyphone.SettingsFragment.java
com.darkrockstudios.apps.ringmyphone.StopRingingReceiver.java
com.darkrockstudios.apps.ringmyphone.UpgradeReceiver.java