Monkey2IAP.java 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. package com.monkey2.lib;
  2. import android.os.*;
  3. import android.app.*;
  4. import android.content.*;
  5. import java.util.*;
  6. import com.android.vending.billing.*;
  7. import org.json.*;
  8. public class Monkey2IAP extends Monkey2Activity.Delegate implements ServiceConnection{
  9. private static final String TAG = "Monkey2IAP";
  10. private static final int ACTIVITY_RESULT_REQUEST_CODE=101;
  11. public static class Product{
  12. public boolean valid;
  13. public String title;
  14. public String identifier;
  15. public String description;
  16. public String price;
  17. public int type;
  18. public boolean owned;
  19. public boolean interrupted;
  20. Product( String identifier,int type ){
  21. this.identifier=identifier;
  22. this.type=type;
  23. }
  24. }
  25. public Monkey2IAP(){
  26. //Log.v( TAG,"Monkey2IAP()" );
  27. _activity=Monkey2Activity.instance();
  28. Intent intent=new Intent( "com.android.vending.billing.InAppBillingService.BIND" );
  29. intent.setPackage( "com.android.vending" );
  30. _activity.bindService( intent,this,Context.BIND_AUTO_CREATE );
  31. }
  32. public boolean OpenStoreAsync( Product[] products ){
  33. if( _running ) return false;
  34. _products=products;
  35. OpenStoreThread thread=new OpenStoreThread();
  36. _running=true;
  37. _result=-1;
  38. thread.start();
  39. return true;
  40. }
  41. public boolean BuyProductAsync( Product p ){
  42. if( _running ) return false;
  43. _result=-1;
  44. try{
  45. Bundle buy=_service.getBuyIntent( 3,_activity.getPackageName(),p.identifier,"inapp","NOP" );
  46. int response=buy.getInt( "RESPONSE_CODE" );
  47. if( response==0 ){
  48. PendingIntent intent=buy.getParcelable( "BUY_INTENT" );
  49. if( intent!=null ){
  50. Integer zero=Integer.valueOf( 0 );
  51. _activity.startIntentSenderForResult( intent.getIntentSender(),ACTIVITY_RESULT_REQUEST_CODE,new Intent(),zero,zero,zero );
  52. _running=true;
  53. return true;
  54. }
  55. }
  56. switch( response ){
  57. case 1:
  58. _result=1; //cancelled
  59. break;
  60. case 7:
  61. _result=0; //already purchased
  62. break;
  63. }
  64. }catch( IntentSender.SendIntentException ex ){
  65. }catch( RemoteException ex ){
  66. }
  67. return true;
  68. }
  69. public boolean GetOwnedProductsAsync(){
  70. if( _running ) return false;
  71. _result=0;
  72. return true;
  73. }
  74. public boolean IsRunning(){
  75. return _running;
  76. }
  77. public int GetResult(){
  78. return _result;
  79. }
  80. // ***** PRIVATE *****
  81. Activity _activity;
  82. IInAppBillingService _service;
  83. Object _mutex=new Object();
  84. boolean _running;
  85. int _result=-1;
  86. Product[] _products;
  87. ArrayList unconsumed=new ArrayList();
  88. Product FindProduct( String id ){
  89. for( int i=0;i<_products.length;++i ){
  90. if( id.equals( _products[i].identifier ) ) return _products[i];
  91. }
  92. return null;
  93. }
  94. class OpenStoreThread extends Thread{
  95. public void run(){
  96. //wait for service to start
  97. synchronized( _mutex ){
  98. while( _service==null ){
  99. try{
  100. _mutex.wait();
  101. }catch( InterruptedException ex ){
  102. }catch( IllegalMonitorStateException ex ){
  103. }
  104. }
  105. }
  106. int i0=0;
  107. while( i0<_products.length ){
  108. ArrayList list=new ArrayList();
  109. for( int i1=Math.min( i0+20,_products.length );i0<i1;++i0 ){
  110. list.add( _products[i0].identifier );
  111. }
  112. Bundle query=new Bundle();
  113. query.putStringArrayList( "ITEM_ID_LIST",list );
  114. _result=0;
  115. try{
  116. //Get product details
  117. Bundle details=_service.getSkuDetails( 3,_activity.getPackageName(),"inapp",query );
  118. ArrayList detailsList=details.getStringArrayList( "DETAILS_LIST" );
  119. if( detailsList==null ){
  120. _result=-1;
  121. _running=false;
  122. return;
  123. }
  124. for( int i=0;i<detailsList.size();++i ){
  125. JSONObject jobj=new JSONObject( (String)detailsList.get( i ) );
  126. Product p=FindProduct( jobj.getString( "productId" ) );
  127. if( p==null ) continue;
  128. //strip (APP_NAME) from end of title
  129. String title=jobj.getString( "title" );
  130. if( title.endsWith( ")" ) ){
  131. int j=title.lastIndexOf( " (" );
  132. if( j!=-1 ) title=title.substring( 0,j );
  133. }
  134. p.valid=true;
  135. p.title=title;
  136. p.description=jobj.getString( "description" );
  137. p.price=jobj.getString( "price" );
  138. }
  139. //Get owned products and consume consumables
  140. Bundle owned=_service.getPurchases( 3,_activity.getPackageName(),"inapp",null );
  141. ArrayList itemList=owned.getStringArrayList( "INAPP_PURCHASE_ITEM_LIST" );
  142. ArrayList dataList=owned.getStringArrayList( "INAPP_PURCHASE_DATA_LIST" );
  143. if( itemList==null || dataList==null ){
  144. _result=-1;
  145. _running=false;
  146. return;
  147. }
  148. //consume consumables
  149. for( int i=0;i<itemList.size();++i ){
  150. Product p=FindProduct( (String)itemList.get( i ) );
  151. if( p==null ) continue;
  152. if( p.type==1 ){
  153. JSONObject jobj=new JSONObject( (String)dataList.get( i ) );
  154. int response=_service.consumePurchase( 3,_activity.getPackageName(),jobj.getString( "purchaseToken" ) );
  155. if( response!=0 ){
  156. p.valid=false;
  157. _result=-1;
  158. break;
  159. }
  160. p.interrupted=true;
  161. }else if( p.type==2 ){
  162. p.owned=true;
  163. }
  164. }
  165. }catch( RemoteException ex ){
  166. _result=-1;
  167. }catch( JSONException ex ){
  168. _result=-1;
  169. }
  170. }
  171. _running=false;
  172. }
  173. }
  174. class ConsumeProductThread extends Thread{
  175. String _token;
  176. ConsumeProductThread( String token ){
  177. _token=token;
  178. }
  179. public void run(){
  180. try{
  181. int response=_service.consumePurchase( 3,_activity.getPackageName(),_token );
  182. if( response==0 ) _result=0;
  183. }catch( RemoteException ex ){
  184. }
  185. _running=false;
  186. }
  187. }
  188. @Override
  189. public void onServiceDisconnected( ComponentName name ){
  190. _service=null;
  191. }
  192. @Override
  193. public void onServiceConnected( ComponentName name,IBinder service ){
  194. _service=IInAppBillingService.Stub.asInterface( service );
  195. Monkey2Activity.addDelegate( this );
  196. synchronized( _mutex ){
  197. try{
  198. _mutex.notify();
  199. }catch( IllegalMonitorStateException ex ){
  200. }
  201. }
  202. }
  203. @Override
  204. public void onActivityResult( int requestCode,int resultCode,Intent data ){
  205. if( requestCode!=ACTIVITY_RESULT_REQUEST_CODE ) return;
  206. int response=data.getIntExtra( "RESPONSE_CODE",0 );
  207. switch( response ){
  208. case 0:
  209. try{
  210. JSONObject pdata=new JSONObject( data.getStringExtra( "INAPP_PURCHASE_DATA" ) );
  211. Product p=FindProduct( pdata.getString( "productId" ) );
  212. if( p!=null ){
  213. if( p.type==1 ){
  214. ConsumeProductThread thread=new ConsumeProductThread( pdata.getString( "purchaseToken" ) );
  215. thread.start();
  216. return;
  217. }else if( p.type==2 ){
  218. p.owned=true;
  219. _result=0;
  220. }
  221. }
  222. }catch( JSONException ex ){
  223. }
  224. break;
  225. case 1:
  226. _result=1; //cancelled
  227. break;
  228. case 7:
  229. _result=0; //already purchased
  230. break;
  231. }
  232. _running=false;
  233. }
  234. }