EsenthelActivity.java 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  1. /******************************************************************************/
  2. package EE_PACKAGE;
  3. import android.app.Activity;
  4. import android.app.AlertDialog;
  5. import android.app.Application;
  6. import android.app.NativeActivity;
  7. import android.app.Notification;
  8. import android.app.NotificationManager;
  9. import android.app.PendingIntent;
  10. import android.app.Service;
  11. import android.app.TaskStackBuilder;
  12. import android.content.BroadcastReceiver;
  13. import android.content.ComponentName;
  14. import android.content.DialogInterface;
  15. import android.content.DialogInterface.OnShowListener;
  16. import android.content.Context;
  17. import android.content.Intent;
  18. import android.content.pm.PackageManager;
  19. import android.content.pm.ResolveInfo;
  20. import android.content.res.Configuration;
  21. import android.content.ServiceConnection;
  22. import android.content.SharedPreferences;
  23. import android.content.SharedPreferences.Editor;
  24. import android.graphics.BitmapFactory;
  25. import android.location.Location;
  26. import android.location.LocationListener;
  27. import android.media.AudioFormat;
  28. import android.media.AudioRecord;
  29. import android.media.MediaRecorder;
  30. import android.media.MediaRecorder.AudioSource;
  31. import android.net.Uri;
  32. import android.net.wifi.WifiManager;
  33. import android.net.wifi.WifiManager.WifiLock;
  34. import android.os.Build;
  35. import android.os.Bundle;
  36. import android.os.Handler;
  37. import android.os.Looper;
  38. import android.os.IBinder;
  39. import android.os.Message;
  40. import android.os.PowerManager;
  41. import android.os.PowerManager.WakeLock;
  42. import android.os.StatFs;
  43. import android.preference.PreferenceManager;
  44. import android.provider.Settings;
  45. import android.provider.Settings.Secure;
  46. import android.text.Editable;
  47. import android.text.InputType;
  48. import android.text.TextUtils;
  49. import android.text.TextWatcher;
  50. import android.util.Log;
  51. import android.util.TypedValue;
  52. import android.view.Gravity;
  53. import android.view.inputmethod.InputMethodManager;
  54. import android.view.inputmethod.EditorInfo;
  55. import android.view.KeyEvent;
  56. import android.view.View;
  57. import android.view.ViewGroup;
  58. import android.view.ViewGroup.MarginLayoutParams;
  59. import android.view.Window;
  60. import android.view.WindowManager;
  61. import android.widget.EditText;
  62. import android.widget.FrameLayout;
  63. import android.widget.LinearLayout;
  64. import android.widget.PopupWindow;
  65. import android.widget.RelativeLayout;
  66. import android.widget.Toast;
  67. import com.android.vending.billing.IInAppBillingService;
  68. import com.chartboost.sdk.*;
  69. import com.chartboost.sdk.Model.CBError.CBImpressionError;
  70. import com.google.android.gms.ads.*;
  71. import com.facebook.android.DialogError;
  72. import com.facebook.android.Facebook;
  73. import com.facebook.android.Facebook.DialogListener;
  74. import com.facebook.android.FacebookError;
  75. import com.facebook.HttpMethod;
  76. import com.facebook.LoggingBehavior;
  77. import com.facebook.model.GraphUser;
  78. import com.facebook.model.GraphObject;
  79. import com.facebook.Response;
  80. import com.facebook.Request;
  81. import com.facebook.Request.GraphUserListCallback;
  82. import com.facebook.Session;
  83. import com.facebook.SessionState;
  84. //import com.facebook.Settings; can't import due to 'android.provider.Settings'
  85. import com.facebook.UiLifecycleHelper;
  86. import com.facebook.widget.FacebookDialog;
  87. import com.facebook.widget.WebDialog;
  88. import com.facebook.widget.WebDialog.OnCompleteListener;
  89. import java.io.File;
  90. import java.math.BigInteger;
  91. import java.nio.ByteBuffer;
  92. import java.security.KeyFactory;
  93. import java.security.MessageDigest;
  94. import java.security.PublicKey;
  95. import java.security.Signature;
  96. import java.security.spec.X509EncodedKeySpec;
  97. import java.util.ArrayList;
  98. import java.util.Arrays;
  99. import java.util.List;
  100. import org.json.JSONObject;
  101. /******************************************************************************/
  102. public class EsenthelActivity extends NativeActivity
  103. {
  104. public static class EsenthelLocationListener implements LocationListener
  105. {
  106. public boolean gps;
  107. public EsenthelLocationListener(boolean gps) {this.gps=gps;}
  108. @Override public final void onLocationChanged (Location location) {com.esenthel.Native.location(gps, location);}
  109. @Override public final void onProviderDisabled(String providerName) {}
  110. @Override public final void onProviderEnabled (String providerName) {}
  111. @Override public final void onStatusChanged (String providerName, int status, Bundle extras) {}
  112. }
  113. public static class DetectForceKill extends Service // !! if changing name of this class then update AndroidManifest.xml !!
  114. {
  115. @Override public final IBinder onBind (Intent intent) {return null;}
  116. @Override public final int onStartCommand(Intent intent, int flags, int startId) {return START_NOT_STICKY;}
  117. //@Override public final void onDestroy () {super.onDestroy();}
  118. @Override public final void onTaskRemoved (Intent rootIntent) {removeNotifications(); super.onTaskRemoved(rootIntent);} // this is called on force kill
  119. }
  120. // !! these must be equal to 'AWAKE_MODE' !!
  121. public static final int AWAKE_OFF =0;
  122. public static final int AWAKE_SYSTEM=1;
  123. public static final int AWAKE_SCREEN=2;
  124. // !! these must be equal to 'AdMobClass.BANNER_TYPE' !!
  125. public static final int AD_BANNER =0;
  126. public static final int AD_MEDIUM_RECTANGLE=1;
  127. public static final int AD_FULL_BANNER =2;
  128. public static final int AD_LEADERBOARD =3;
  129. public static final int AD_SMART_BANNER =4;
  130. public static final int AD_INTERSTITIAL =5;
  131. // !! these must be equal to 'AdMobClass.STATE' !!
  132. public static final int AD_NONE =0;
  133. public static final int AD_LOADING=1;
  134. public static final int AD_DONE =2;
  135. public static final int AD_ERROR =3;
  136. // !! these must be equal to 'ChartboostClass.RESULT' !!
  137. public static final int INTERSTITIAL_LOADED =0;
  138. public static final int INTERSTITIAL_LOAD_FAIL=1;
  139. public static final int INTERSTITIAL_DISPLAYED=2;
  140. public static final int INTERSTITIAL_CLOSED =3;
  141. public static final int INTERSTITIAL_CLICKED =4;
  142. public static final int REWARDED_VIDEO_LOADED =5;
  143. public static final int REWARDED_VIDEO_LOAD_FAIL=6;
  144. public static final int REWARDED_VIDEO_DISPLAYED=7;
  145. public static final int REWARDED_VIDEO_CLOSED =8;
  146. public static final int REWARDED_VIDEO_COMPLETED=9;
  147. public static final int REWARDED_VIDEO_CLICKED =10;
  148. // !! these must be equal to 'PlatformStore.RESULT' !!
  149. public static final int RES_OK =-1; // this is not a 'PlatformStore.RESULT' but a temp value
  150. public static final int RES_PURCHASED =0;
  151. public static final int RES_CONSUMED =1;
  152. public static final int RES_REFUND =2;
  153. public static final int RES_WAITING =3;
  154. public static final int RES_USER_CANCELED =4;
  155. public static final int RES_SERVICE_CANCELED =5;
  156. public static final int RES_SERVICE_UNAVAILABLE=6;
  157. public static final int RES_ITEM_UNAVAILABLE =7;
  158. public static final int RES_ALREADY_OWNED =8;
  159. public static final int RES_NOT_OWNED =9;
  160. public static final int RES_VERIFICATION_FAIL =10;
  161. public static final int RES_UNKNOWN =11;
  162. public static final int RES_REFRESHED_ITEMS =12;
  163. public static final int RES_REFRESHED_PURCHASES=13;
  164. // !! these must be equal to 'Facebook.RESULT' !!
  165. public static final int POST_ERROR=0;
  166. public static final int POST_CANCEL=1;
  167. public static final int POST_SUCCESS=2;
  168. public static final int POST_NOT_LOGGED_IN=3;
  169. // Billing response codes
  170. public static final int BILLING_RESPONSE_RESULT_OK = 0;
  171. public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
  172. public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
  173. public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4;
  174. public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5;
  175. public static final int BILLING_RESPONSE_RESULT_ERROR = 6;
  176. public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
  177. public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8;
  178. // Item types
  179. public static final String ITEM_TYPE_INAPP="inapp";
  180. public static final String ITEM_TYPE_SUBS ="subs";
  181. // some fields on the getSkuDetails response bundle
  182. public static final String GET_SKU_DETAILS_ITEM_LIST="ITEM_ID_LIST";
  183. // Keys for the responses from InAppBillingService
  184. public static final String RESPONSE_CODE = "RESPONSE_CODE";
  185. public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST";
  186. public static final String RESPONSE_BUY_INTENT = "BUY_INTENT";
  187. public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
  188. public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE";
  189. public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST";
  190. public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
  191. public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
  192. public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";
  193. // signature verification
  194. private static final String KEY_FACTORY_ALGORITHM="RSA";
  195. private static final String SIGNATURE_ALGORITHM="SHA1withRSA";
  196. public static final int REQUEST_CODE_IAB=0;
  197. // variables
  198. static EsenthelActivity activity;
  199. static Application application;
  200. static Context context;
  201. static Intent background_intent;
  202. static String background_text;
  203. static Handler handler;
  204. static IInAppBillingService iab_service;
  205. static ServiceConnection iab_service_conn;
  206. static PublicKey license_key;
  207. static AdRequest ad_request;
  208. AdView ad_view;
  209. static boolean ad_view_loaded=false, // if ad_view is loaded
  210. banner_visible=false, // if banner should be visible
  211. inters_show=false; // if show interstitial once it's loaded
  212. static String banner_id, // id of the banner ad, null for none
  213. inters_id; // id of the interstitial ad, null for none
  214. static int banner_type=AD_BANNER, // banner type
  215. banner_x=0, banner_y=1; // banner position, -1..1
  216. InterstitialAd interstitial;
  217. PopupWindow popup_window;
  218. LinearLayout popup_window_layout, ad_view_layout;
  219. static String android_id;
  220. EditText edit_text;
  221. TextWatcher text_watcher;
  222. static WakeLock wake_lock;
  223. static WifiLock wifi_lock;
  224. static final void log(String s) {Log.e("Esenthel", s);}
  225. static final boolean Is(String s) {return !TextUtils.isEmpty(s);}
  226. static
  227. {
  228. EE_LOAD_LIBRARIES
  229. }
  230. /******************************************************************************/
  231. // MAIN
  232. /******************************************************************************/
  233. @Override public final void onSaveInstanceState(Bundle savedInstanceState)
  234. {
  235. super.onSaveInstanceState(savedInstanceState);
  236. Session.saveSession(Session.getActiveSession(), savedInstanceState);
  237. if(ui_helper!=null)ui_helper.onSaveInstanceState(savedInstanceState);
  238. }
  239. @Override public final void onRestoreInstanceState(Bundle savedInstanceState)
  240. {
  241. super.onRestoreInstanceState(savedInstanceState);
  242. if(Is(inters_id))adCreate(inters_id, AD_INTERSTITIAL);
  243. if(Is(banner_id))adCreate(banner_id, banner_type );
  244. }
  245. @Override public final void onNewIntent(Intent intent)
  246. {
  247. super.onNewIntent(intent);
  248. checkNotification(intent, true);
  249. }
  250. @Override public final void onBackPressed()
  251. {
  252. if(!Chartboost.onBackPressed()) // this will detect if there's an interstitial and close it, otherwise process below:
  253. {
  254. super.onBackPressed();
  255. }
  256. }
  257. @Override public final void onResume()
  258. {
  259. super.onResume();
  260. if(ad_view !=null)ad_view . resume();
  261. if(ui_helper!=null)ui_helper.onResume();
  262. Chartboost.onResume(this);
  263. }
  264. @Override public final void onPause()
  265. {
  266. if(ad_view !=null)ad_view . pause();
  267. if(ui_helper!=null)ui_helper.onPause();
  268. super.onPause();
  269. Chartboost.onPause(this);
  270. }
  271. @Override public final void onStart()
  272. {
  273. super.onStart();
  274. Chartboost.onStart(this);
  275. Session session=Session.getActiveSession(); if(session!=null)session.addCallback(fb_status_callback);
  276. }
  277. @Override public final void onStop()
  278. {
  279. super.onStop();
  280. Chartboost.onStop(this);
  281. Session session=Session.getActiveSession(); if(session!=null)session.removeCallback(fb_status_callback);
  282. }
  283. @Override public final void onDestroy()
  284. {
  285. bannerHide();
  286. adViewDel();
  287. super.onDestroy();
  288. if(ui_helper!=null)ui_helper.onDestroy();
  289. Chartboost.onDestroy(this);
  290. shutIAB();
  291. context=application; activity=null; // when activity becomes unavailable, then use application context because we always need one
  292. }
  293. @Override public final void onCreate(Bundle savedInstanceState)
  294. {
  295. application=getApplication(); context=activity=this; // use activity when available, as it's more powerful - https://stackoverflow.com/questions/4128589/difference-between-activity-context-and-application-context
  296. if(handler==null)handler=new Handler()
  297. {
  298. @Override public final void handleMessage(Message message)
  299. {
  300. super.handleMessage(message);
  301. String title=message.getData().getString ("title"),
  302. text =message.getData().getString ("text" );
  303. boolean exit =message.getData().getBoolean("exit" );
  304. if(title!=null && text!=null)
  305. {
  306. AlertDialog dialog=new AlertDialog.Builder(context).setTitle(title).setMessage(text).setNeutralButton("OK", null).show();
  307. if(exit && dialog!=null)
  308. dialog.setOnDismissListener(new DialogInterface.OnDismissListener()
  309. {
  310. @Override public final void onDismiss(final DialogInterface dialog) {com.esenthel.Native.closedError();} // can't call "activity.finish();" because it may suspend the app, while we need to force close it
  311. });
  312. }
  313. }
  314. };
  315. if(android_id==null)android_id=Secure.getString(getContentResolver(), Secure.ANDROID_ID);
  316. if(wake_lock==null)
  317. {
  318. PowerManager power_manager=(PowerManager)getSystemService(POWER_SERVICE); if(power_manager!=null)
  319. {
  320. wake_lock=power_manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); // will crash if null is used
  321. if(wake_lock!=null)wake_lock.setReferenceCounted(false); // disable ref counting so one 'release' will be immediate
  322. }
  323. }
  324. if(wifi_lock==null)
  325. {
  326. WifiManager wifi_manager=(WifiManager)getSystemService(WIFI_SERVICE); if(wifi_manager!=null)
  327. {
  328. wifi_lock=wifi_manager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, ""); // will crash if null is used
  329. if(wifi_lock!=null)wifi_lock.setReferenceCounted(false); // disable ref counting so one 'release' will be immediate
  330. }
  331. }
  332. super.onCreate(savedInstanceState);
  333. startService(new Intent(this, DetectForceKill.class)); // start service that detects force kill
  334. initIAB();
  335. initFB (savedInstanceState);
  336. com.esenthel.Native.bannerSize(0, 0); // at this stage the banner is lost, but the banner size on the native size is still present, so reset it
  337. if(ad_request==null)setAdRequest(false);
  338. initChartboost();
  339. initNotification();
  340. /*log("android_id "+android_id);
  341. log("BOARD "+Build.BOARD);
  342. log("BOOTLOADER "+Build.BOOTLOADER);
  343. log("BRAND "+Build.BRAND);
  344. log("DEVICE "+Build.DEVICE);
  345. log("DISPLAY "+Build.DISPLAY);
  346. log("FINGERPRINT "+Build.FINGERPRINT);
  347. log("HARDWARE "+Build.HARDWARE);
  348. log("HOST "+Build.HOST);
  349. log("ID "+Build.ID);
  350. log("MANUFACTURER "+Build.MANUFACTURER);
  351. log("MODEL "+Build.MODEL);
  352. log("PRODUCT "+Build.PRODUCT);
  353. log("SERIAL "+Build.SERIAL);
  354. log("TAGS "+Build.TAGS);
  355. log("TIME "+Build.TIME);
  356. log("TYPE "+Build.TYPE);
  357. log("USER "+Build.USER);*/
  358. }
  359. @Override protected final void onActivityResult(int requestCode, int resultCode, Intent data)
  360. {
  361. super.onActivityResult(requestCode, resultCode, data);
  362. Session session=Session.getActiveSession(); if( session!=null) session.onActivityResult(this, requestCode, resultCode, data);
  363. if(ui_helper!=null)ui_helper.onActivityResult( requestCode, resultCode, data, fb_dialog_callback);
  364. switch(requestCode)
  365. {
  366. case REQUEST_CODE_IAB:
  367. {
  368. int responseCode=-1;
  369. long date=0;
  370. String purchaseData=null, sku=null, custom_data=null, token=null, signature=null;
  371. if(data!=null)
  372. {
  373. // data.getExtras()
  374. responseCode=getResponseCodeFromIntent(data);
  375. purchaseData=data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
  376. signature =data.getStringExtra(RESPONSE_INAPP_SIGNATURE);
  377. if(purchaseData!=null)
  378. {
  379. try
  380. {
  381. JSONObject o=new JSONObject(purchaseData);
  382. //o.optString("orderId");
  383. //o.optString("packageName");
  384. sku=o.optString("productId");
  385. date=o.optLong("purchaseTime");
  386. //o.optInt("purchaseState");
  387. custom_data=o.optString("developerPayload");
  388. token=o.optString("token", o.optString("purchaseToken"));
  389. }catch(Exception exception){} // failed to parse data
  390. }
  391. }
  392. int result=billingToEE(responseCode);
  393. if( result==RES_OK )result=((resultCode==Activity.RESULT_OK && sku!=null) ? (verifyPurchase(purchaseData, signature) ? RES_PURCHASED : RES_VERIFICATION_FAIL) : RES_UNKNOWN);
  394. if( result==RES_UNKNOWN)if(resultCode==Activity.RESULT_CANCELED)result=RES_SERVICE_CANCELED;
  395. //log("responseCode:"+responseCode+", resultCode:"+resultCode+", result:"+result);
  396. com.esenthel.Native.purchased(result, sku, custom_data, token, date);
  397. }break;
  398. }
  399. }
  400. @Override public final void onConfigurationChanged(Configuration newConfig)
  401. {
  402. super.onConfigurationChanged(newConfig);
  403. adPos(banner_x, banner_y); // reset banner position in new screen size/orientation
  404. }
  405. public static final void messageBox(String title, String text, boolean exit)
  406. {
  407. if(handler!=null)
  408. {
  409. Message message=handler.obtainMessage(); if(message!=null)
  410. {
  411. Bundle bundle=new Bundle(); if(bundle!=null)
  412. {
  413. bundle.putString ("title", title);
  414. bundle.putString ("text" , text );
  415. if(exit)bundle.putBoolean("exit" , exit );
  416. message.setData(bundle);
  417. handler.sendMessage(message);
  418. }
  419. }
  420. }
  421. }
  422. public static final void toast(final String text)
  423. {
  424. Handler handler=new Handler(Looper.getMainLooper());
  425. handler.post(new Runnable()
  426. {
  427. @Override public final void run()
  428. {
  429. Toast.makeText(context, text, Toast.LENGTH_LONG).show();
  430. }
  431. });
  432. }
  433. public static final void stayAwake(final int mode)
  434. {
  435. if(wake_lock!=null)
  436. {
  437. if(mode==AWAKE_SYSTEM)wake_lock.acquire();
  438. else wake_lock.release();
  439. }
  440. if(wifi_lock!=null)
  441. {
  442. if(mode==AWAKE_SYSTEM)wifi_lock.acquire();
  443. else wifi_lock.release();
  444. }
  445. if(activity!=null)activity.runOnUiThread(new Runnable()
  446. {
  447. @Override public final void run()
  448. {
  449. Window window=activity.getWindow();
  450. if(window!=null)window.setFlags((mode==AWAKE_SCREEN) ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  451. }
  452. });
  453. }
  454. public static final boolean openAppSettings()
  455. {
  456. Intent intent=new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
  457. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  458. intent.setData(Uri.fromParts("package", "EE_PACKAGE", null));
  459. boolean ok=true; try{context.startActivity(intent);}catch(Exception exception){ok=false;}
  460. return ok;
  461. }
  462. public static final long driveSizeFree (String path) {File file=new File(path); if(file!=null && file.exists())return file.getUsableSpace(); return -1;}
  463. public static final long driveSizeTotal(String path) {File file=new File(path); if(file!=null && file.exists())return file.getTotalSpace (); return -1;}
  464. public static final String manufacturer() {return Build.MANUFACTURER;}
  465. public static final String model () {return Build.MODEL;}
  466. public static final String serial () {return Build.SERIAL;}
  467. public static final String androidID () {return android_id;}
  468. /******************************************************************************/
  469. // KEYBOARD
  470. /******************************************************************************/
  471. @Override public final boolean dispatchKeyEvent(KeyEvent event)
  472. {
  473. if(event!=null)if(event.getAction()!=KeyEvent.ACTION_UP)
  474. {
  475. int key_code=event.getKeyCode (); // use 'getKeyCode' instead of 'getScanCode' to match 'AKeyEvent_getKeyCode' on native C++ side
  476. int unicode =event.getUnicodeChar(); if(unicode!=0)com.esenthel.Native.key(unicode, key_code);else
  477. {
  478. String s=event.getCharacters(); if(s!=null)for(int i=0; i<s.length(); i++)com.esenthel.Native.key(s.codePointAt(i), key_code);
  479. }
  480. }
  481. return super.dispatchKeyEvent(event);
  482. }
  483. public final void editTextSetDo(String text, int start, int end, boolean password)
  484. {
  485. if(edit_text!=null)
  486. {
  487. edit_text.removeTextChangedListener(text_watcher);
  488. edit_text.setText(text);
  489. edit_text.setSelection(start, end);
  490. edit_text.setInputType(password ? InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_MULTI_LINE|InputType.TYPE_TEXT_VARIATION_PASSWORD : InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_MULTI_LINE); // TYPE_TEXT_FLAG_MULTI_LINE prevents from Enter making the keyboard disappear (on Google and Samsung keyboards)
  491. edit_text.addTextChangedListener(text_watcher);
  492. }
  493. }
  494. public final void editTextSet(final String text, final int start, final int end, final boolean password)
  495. {
  496. runOnUiThread(new Runnable()
  497. {
  498. @Override public final void run()
  499. {
  500. editTextSetDo(text, start, end, password);
  501. }
  502. });
  503. }
  504. public final void editText(final String text, final int start, final int end, final boolean password)
  505. {
  506. runOnUiThread(new Runnable()
  507. {
  508. @Override public final void run()
  509. {
  510. if(edit_text==null)
  511. {
  512. if(text_watcher==null)text_watcher=new TextWatcher()
  513. {
  514. @Override public final void afterTextChanged(Editable s)
  515. {
  516. if(s!=null)
  517. {
  518. int start=0, end=0;
  519. if(edit_text!=null)
  520. {
  521. start=edit_text.getSelectionStart();
  522. end =edit_text.getSelectionEnd ();
  523. }
  524. com.esenthel.Native.text(s.toString(), start, end);
  525. }
  526. }
  527. @Override public final void beforeTextChanged(CharSequence s, int start, int count , int after) {}
  528. @Override public final void onTextChanged(CharSequence s, int start, int before, int count) {}
  529. };
  530. FrameLayout.LayoutParams layout=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
  531. edit_text=new EditText(activity);
  532. edit_text.setLayoutParams(layout);
  533. edit_text.setImeOptions(edit_text.getImeOptions()|EditorInfo.IME_FLAG_NO_FULLSCREEN);
  534. activity.addContentView(edit_text, layout);
  535. }
  536. editTextSetDo(text, start, end, password);
  537. edit_text.setVisibility(View.VISIBLE);
  538. edit_text.bringToFront();
  539. edit_text.requestFocus();
  540. InputMethodManager imm=(InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
  541. imm.showSoftInput(edit_text, 0); // use 0 instead of 'SHOW_FORCED' because that one will keep keyboard visible even when app is hidden using the Home button
  542. }
  543. });
  544. }
  545. public final void editTextHide()
  546. {
  547. runOnUiThread(new Runnable()
  548. {
  549. @Override public final void run()
  550. {
  551. Window window=activity.getWindow(); if(window!=null)
  552. {
  553. View view=window.getDecorView(); if(view!=null)
  554. {
  555. InputMethodManager imm=(InputMethodManager)activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
  556. imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
  557. }
  558. }
  559. if(edit_text!=null)edit_text.setVisibility(View.GONE);
  560. }
  561. });
  562. }
  563. /******************************************************************************/
  564. // MICROPHONE
  565. /******************************************************************************/
  566. public static class EsenthelAudioRecord extends AudioRecord
  567. {
  568. public Thread thread;
  569. EsenthelAudioRecord(int frequency, int channelConfig, int audioFormat, int minBufferSize)
  570. {
  571. super(MediaRecorder.AudioSource.MIC, frequency, channelConfig, audioFormat, minBufferSize);
  572. }
  573. }
  574. public static final boolean hasAudioRecord()
  575. {
  576. return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
  577. }
  578. public static final void delAudioRecord(EsenthelAudioRecord audioRecord)
  579. {
  580. audioRecord.stop(); // first stop recording
  581. try{audioRecord.thread.join();}catch(Exception exception){} // now wait for thread to finish
  582. audioRecord.thread=null;
  583. audioRecord.release();
  584. }
  585. public static final EsenthelAudioRecord newAudioRecord(final long sound_record, int bits, int channels, int frequency)
  586. {
  587. if(channels>=1 && channels<=2 && (bits==8 || bits==16))
  588. {
  589. int channelConfig =((channels==1) ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO ),
  590. audioFormat =((bits ==8) ? AudioFormat.ENCODING_PCM_8BIT : AudioFormat.ENCODING_PCM_16BIT),
  591. min_buffer_size=AudioRecord.getMinBufferSize(frequency, channelConfig, audioFormat); // for 44100 hz, 1 channel, 16 bits, Galaxy Note 4 returns 3840
  592. if( min_buffer_size>0)
  593. {
  594. try
  595. {
  596. final int poll_size=min_buffer_size; // this will affect latency, so don't increase this
  597. final EsenthelAudioRecord audioRecord=new EsenthelAudioRecord(frequency, channelConfig, audioFormat, min_buffer_size*2); // mul by 2 because "this size doesn't guarantee a smooth recording under load, and higher values should be chosen according to the expected frequency at which the AudioRecord instance will be polled for new data" - http://developer.android.com/reference/android/media/AudioRecord.html#getMinBufferSize(int, int, int)
  598. if(audioRecord.getState()==AudioRecord.STATE_INITIALIZED)
  599. {
  600. audioRecord.startRecording(); // start recording before starting the thread, because inside it we're checking for RECORDSTATE_RECORDING
  601. audioRecord.thread=new Thread()
  602. {
  603. @Override public final void run()
  604. {
  605. ByteBuffer buf=ByteBuffer.allocateDirect(poll_size);
  606. if(buf!=null)for(; audioRecord.getRecordingState()==AudioRecord.RECORDSTATE_RECORDING; )
  607. {
  608. int read=audioRecord.read(buf, poll_size); // this is a blocking call, it will wait until data is available
  609. if( read>0)com.esenthel.Native.audioRecord(sound_record, buf, read);else
  610. if( read<0)break; // error
  611. }
  612. }
  613. };
  614. audioRecord.thread.setPriority(Thread.MAX_PRIORITY);
  615. audioRecord.thread.start();
  616. return audioRecord;
  617. }
  618. }catch(Exception exception){}
  619. }
  620. }
  621. return null;
  622. }
  623. /******************************************************************************/
  624. // ADMOB
  625. /******************************************************************************/
  626. public static final void setAdRequest(boolean test_mode)
  627. {
  628. AdRequest.Builder builder=new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
  629. if(test_mode)
  630. {
  631. String android_id_md5;
  632. try
  633. {
  634. MessageDigest md5=MessageDigest.getInstance("MD5");
  635. md5.update(android_id.getBytes(), 0, android_id.length());
  636. android_id_md5=String.format("%032X", new Object[]{new BigInteger(1, md5.digest())});
  637. }catch(Exception exception){android_id_md5=android_id.substring(0, 32);}
  638. builder.addTestDevice(android_id_md5);
  639. }
  640. ad_request=builder.build();
  641. }
  642. public final void bannerHide()
  643. {
  644. if(popup_window!=null)
  645. {
  646. popup_window.dismiss();
  647. popup_window=null;
  648. }
  649. if(popup_window_layout!=null)
  650. {
  651. ViewGroup parent=(ViewGroup)popup_window_layout.getParent(); if(parent!=null)parent.removeView(popup_window_layout);
  652. popup_window_layout.removeAllViews();
  653. popup_window_layout=null;
  654. }
  655. if(ad_view_layout!=null)
  656. {
  657. ViewGroup parent=(ViewGroup)ad_view_layout.getParent(); if(parent!=null)parent.removeView(ad_view_layout);
  658. ad_view_layout.removeAllViews();
  659. ad_view_layout=null;
  660. }
  661. }
  662. public final void adViewDel()
  663. {
  664. if(ad_view!=null)
  665. {
  666. ad_view.destroy(); ad_view=null; ad_view_loaded=false;
  667. }
  668. }
  669. public final void adDel(final boolean banner)
  670. {
  671. runOnUiThread(new Runnable()
  672. {
  673. @Override public final void run()
  674. {
  675. if(banner)
  676. {
  677. banner_id=null;
  678. bannerHide();
  679. adViewDel();
  680. }else
  681. {
  682. inters_id=null;
  683. interstitial=null;
  684. }
  685. }
  686. });
  687. }
  688. public final void adCreate(final String unit_id, final int type)
  689. {
  690. runOnUiThread(new Runnable()
  691. {
  692. @Override public final void run()
  693. {
  694. if(ad_request!=null)
  695. {
  696. AdSize ad_size=null;
  697. switch(type)
  698. {
  699. case AD_BANNER : ad_size=AdSize.BANNER ; break;
  700. case AD_MEDIUM_RECTANGLE: ad_size=AdSize.MEDIUM_RECTANGLE; break;
  701. case AD_FULL_BANNER : ad_size=AdSize.FULL_BANNER ; break;
  702. case AD_LEADERBOARD : ad_size=AdSize.LEADERBOARD ; break;
  703. case AD_SMART_BANNER : ad_size=AdSize.SMART_BANNER ; break;
  704. case AD_INTERSTITIAL :
  705. {
  706. inters_id=unit_id;
  707. interstitial=new InterstitialAd(activity);
  708. interstitial.setAdUnitId(unit_id);
  709. interstitial.setAdListener(new AdListener()
  710. {
  711. @Override public final void onAdLoaded ( ) {com.esenthel.Native.adState(false, AD_DONE ); if(inters_show){inters_show=false; adVisible(false, true);}}
  712. @Override public final void onAdFailedToLoad (int errorCode) {com.esenthel.Native.adState(false, AD_ERROR );}
  713. @Override public final void onAdOpened ( ) {}
  714. @Override public final void onAdClosed ( ) {com.esenthel.Native.adState(false, AD_LOADING); adCreate(unit_id, type);} // when ad is closed, it cannot be displayed again, so reload again
  715. @Override public final void onAdLeftApplication( ) {}
  716. });
  717. interstitial.loadAd(ad_request);
  718. }break;
  719. }
  720. if(ad_size!=null)
  721. {
  722. banner_id =unit_id;
  723. banner_type=type;
  724. bannerHide();
  725. adViewDel();
  726. ad_view=new AdView(activity);
  727. ad_view.setAdSize(ad_size);
  728. ad_view.setAdUnitId(unit_id);
  729. ad_view.setAdListener(new AdListener()
  730. {
  731. @Override public final void onAdFailedToLoad (int errorCode) {com.esenthel.Native.adState(true, AD_ERROR);}
  732. @Override public final void onAdOpened ( ) {}
  733. @Override public final void onAdClosed ( ) {}
  734. @Override public final void onAdLeftApplication( ) {}
  735. @Override public final void onAdLoaded ( )
  736. {
  737. if(ad_view!=null)
  738. {
  739. AdSize ad_size=ad_view.getAdSize();
  740. if(ad_size!=null)com.esenthel.Native.bannerSize(ad_size.getWidthInPixels (activity),
  741. ad_size.getHeightInPixels(activity));
  742. }
  743. com.esenthel.Native.adState(true, AD_DONE);
  744. ad_view_loaded=true; if(banner_visible)adVisible(true, true);
  745. }
  746. });
  747. ad_view.loadAd(ad_request);
  748. }
  749. }
  750. }
  751. });
  752. }
  753. public final float dipToPx(float f) {return f*getResources().getDisplayMetrics().density;}
  754. public final float pxToDip(float f) {return f/getResources().getDisplayMetrics().density;}
  755. public final int screenW() {return getWindowManager().getDefaultDisplay().getWidth ();}
  756. public final int screenH() {return getWindowManager().getDefaultDisplay().getHeight();}
  757. public final int popupWindowW() {return (popup_window!=null) ? (int)dipToPx(popup_window.getWidth ()) : 0;}
  758. public final int popupWindowH() {return (popup_window!=null) ? (int)dipToPx(popup_window.getHeight()) : 0;}
  759. public final int bannerX() {int w=popupWindowW(); return (banner_x<0) ? 0 : (banner_x>0) ? screenW()-w : (screenW()-w)/2;}
  760. public final int bannerY() {int h=popupWindowH(); return (banner_y>0) ? 0 : (banner_y<0) ? screenH()-h : (screenH()-h)/2;}
  761. public final void adVisible(final boolean banner, final boolean visible)
  762. {
  763. runOnUiThread(new Runnable()
  764. {
  765. @Override public final void run()
  766. {
  767. if(banner) // operate on banner
  768. {
  769. banner_visible=visible;
  770. if(visible)
  771. {
  772. if(ad_view!=null && ad_view_loaded)
  773. {
  774. AdSize ad_size=ad_view.getAdSize();
  775. if(ad_size!=null && popup_window==null)
  776. {
  777. MarginLayoutParams params=new MarginLayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  778. params.setMargins(0, 0, 0, 0);
  779. popup_window=new PopupWindow(activity);
  780. popup_window.setWindowLayoutMode(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  781. ad_view_layout=new LinearLayout(activity);
  782. popup_window_layout=new LinearLayout(activity);
  783. ad_view_layout.setPadding(-11, -11, -11, -11); // these values are required for ads to display on high resolution screens like 2560x1440 (Galaxy Note 4), this was also tested on 1280x720 (Galaxy Note 2), if values are bigger then the ad will not display complaining it has not enough space
  784. popup_window.setContentView( ad_view_layout);
  785. activity.setContentView(popup_window_layout, params);
  786. ad_view_layout.addView (ad_view, params);
  787. popup_window.setWidth (ad_size.getWidth ());
  788. popup_window.setHeight(ad_size.getHeight());
  789. popup_window.showAtLocation(popup_window_layout, Gravity.LEFT|Gravity.TOP, bannerX(), bannerY());
  790. popup_window.update();
  791. }
  792. }
  793. }else
  794. {
  795. bannerHide();
  796. }
  797. }else // operate on interstitial
  798. {
  799. if(visible)
  800. {
  801. if(interstitial!=null && interstitial.isLoaded())interstitial.show();
  802. else inters_show=true; // show next time
  803. }else
  804. {
  805. inters_show=false; // disable showing next time
  806. // there's no method to hide
  807. }
  808. }
  809. }
  810. });
  811. }
  812. public final void adPos(int x, int y)
  813. {
  814. banner_x=x;
  815. banner_y=y;
  816. if(popup_window!=null)runOnUiThread(new Runnable()
  817. {
  818. @Override public final void run()
  819. {
  820. if(popup_window!=null)popup_window.update(bannerX(), bannerY(), -1, -1);
  821. }
  822. });
  823. }
  824. /******************************************************************************/
  825. // IAB - In App Billing
  826. /******************************************************************************/
  827. final void initIAB()
  828. {
  829. if(iab_service_conn==null)
  830. {
  831. iab_service_conn=new ServiceConnection()
  832. {
  833. @Override public final void onServiceDisconnected(ComponentName name) {iab_service=null;}
  834. @Override public final void onServiceConnected(ComponentName name, IBinder binder)
  835. {
  836. iab_service=IInAppBillingService.Stub.asInterface(binder);
  837. boolean inapp_supported=false, subs_supported=false;
  838. try
  839. {
  840. inapp_supported=(iab_service.isBillingSupported(3, "EE_PACKAGE", ITEM_TYPE_INAPP)==BILLING_RESPONSE_RESULT_OK);
  841. subs_supported=(iab_service.isBillingSupported(3, "EE_PACKAGE", ITEM_TYPE_SUBS )==BILLING_RESPONSE_RESULT_OK);
  842. }catch(Exception exception){}
  843. com.esenthel.Native.connected(inapp_supported, subs_supported);
  844. }
  845. };
  846. Intent serviceIntent=new Intent("com.android.vending.billing.InAppBillingService.BIND");
  847. serviceIntent.setPackage("com.android.vending");
  848. List<ResolveInfo> services=getPackageManager().queryIntentServices(serviceIntent, 0);
  849. if(services!=null && !services.isEmpty())bindService(serviceIntent, iab_service_conn, Context.BIND_AUTO_CREATE);
  850. }
  851. }
  852. final void shutIAB()
  853. {
  854. if(iab_service_conn!=null){unbindService(iab_service_conn); iab_service_conn=null;}
  855. }
  856. static final int billingToEE(int result)
  857. {
  858. switch(result)
  859. {
  860. case BILLING_RESPONSE_RESULT_OK : return RES_OK;
  861. case BILLING_RESPONSE_RESULT_USER_CANCELED : return RES_USER_CANCELED;
  862. case BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE: return RES_SERVICE_UNAVAILABLE;
  863. case BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE : return RES_ITEM_UNAVAILABLE;
  864. case BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED : return RES_ALREADY_OWNED;
  865. case BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED : return RES_NOT_OWNED;
  866. default : return RES_UNKNOWN;
  867. }
  868. }
  869. static final int getResponseCodeFromObject(Object o)
  870. {
  871. if(o==null)return BILLING_RESPONSE_RESULT_OK;
  872. if(o instanceof Integer)return ((Integer)o). intValue();
  873. if(o instanceof Long )return (int)((Long )o).longValue();
  874. return BILLING_RESPONSE_RESULT_ERROR; // Unexpected type for bundle response code
  875. }
  876. static final int getResponseCodeFromBundle(Bundle b) {return getResponseCodeFromObject(b. get(RESPONSE_CODE));}
  877. static final int getResponseCodeFromIntent(Intent i) {return getResponseCodeFromObject(i.getExtras().get(RESPONSE_CODE));}
  878. static final PublicKey generatePublicKey(String encodedPublicKey)
  879. {
  880. if(Is(encodedPublicKey))
  881. {
  882. try
  883. {
  884. byte[] decodedKey=com.esenthel.Base64.decode(encodedPublicKey); if(decodedKey==null)return null;
  885. KeyFactory keyFactory=KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
  886. return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
  887. }catch(Exception exception){}
  888. }
  889. return null;
  890. }
  891. static final boolean verifyPurchase(String data, String signature)
  892. {
  893. if(license_key==null)
  894. {
  895. if(!Is("EE_LICENSE_KEY"))return true; // no license key specified, so always succeed
  896. license_key=generatePublicKey("EE_LICENSE_KEY");
  897. if(license_key==null)return false; // failed to generate license key
  898. }
  899. if(!Is(data) || !Is(signature))return false;
  900. try
  901. {
  902. Signature sig=Signature.getInstance(SIGNATURE_ALGORITHM);
  903. sig.initVerify(license_key);
  904. sig.update(data.getBytes());
  905. byte[] decodedKey=com.esenthel.Base64.decode(signature); if(decodedKey==null)return false;
  906. if(!sig.verify(decodedKey))return false;
  907. return true;
  908. }catch(Exception exception){}
  909. return false;
  910. }
  911. public static final boolean getItemDetails(boolean regular_items, boolean subs, int item_ids_elms, long item_ids, long user)
  912. {
  913. if(iab_service==null)return false;
  914. ArrayList<String> skuList=new ArrayList<String>();
  915. for(int i=0; i<item_ids_elms; i++)skuList.add(com.esenthel.Native.getStr(item_ids, i));
  916. Bundle querySkus=new Bundle(); querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList);
  917. for(int i=0; i<2; i++)
  918. {
  919. boolean sub=(i!=0);
  920. if(sub ? subs : regular_items)
  921. {
  922. String itemType=(sub ? ITEM_TYPE_SUBS : ITEM_TYPE_INAPP);
  923. try
  924. {
  925. Bundle skuDetails=iab_service.getSkuDetails(3, "EE_PACKAGE", itemType, querySkus);
  926. if(skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST))
  927. {
  928. ArrayList<String> responseList=skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST);
  929. for(String json:responseList)
  930. {
  931. String sku, name, desc, price;
  932. try
  933. {
  934. JSONObject o=new JSONObject(json);
  935. sku =o.optString("productId");
  936. //o.optString("type");
  937. price=o.optString("price");
  938. name =o.optString("title");
  939. desc =o.optString("description");
  940. }catch(Exception exception){continue;} // failed to parse data, proceed to next one
  941. if(sku!=null)com.esenthel.Native.listItem(user, sku, name, desc, price, sub);
  942. }
  943. }
  944. }catch(Exception exception){}
  945. }
  946. }
  947. return true;
  948. }
  949. public static final boolean getPurchases(boolean sub, long user)
  950. {
  951. if(iab_service==null)return false;
  952. String itemType=(sub ? ITEM_TYPE_SUBS : ITEM_TYPE_INAPP), continueToken=null;
  953. do
  954. {
  955. try
  956. {
  957. Bundle ownedItems=iab_service.getPurchases(3, "EE_PACKAGE", itemType, continueToken);
  958. int response =getResponseCodeFromBundle(ownedItems);
  959. if( response!=BILLING_RESPONSE_RESULT_OK)return false;
  960. if(!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST )
  961. || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST)
  962. || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST ))return false; // Bundle doesn't contain required fields
  963. ArrayList<String> ownedSkus =ownedItems.getStringArrayList(RESPONSE_INAPP_ITEM_LIST);
  964. ArrayList<String> purchaseDataList=ownedItems.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST);
  965. ArrayList<String> signatureList =ownedItems.getStringArrayList(RESPONSE_INAPP_SIGNATURE_LIST);
  966. for(int i=0; i<purchaseDataList.size(); i++)
  967. {
  968. String purchaseData=purchaseDataList.get(i),
  969. signature =signatureList .get(i),
  970. sku =ownedSkus .get(i),
  971. custom_data=null, token=null;
  972. long date =0;
  973. if(purchaseData!=null)
  974. {
  975. try
  976. {
  977. JSONObject o=new JSONObject(purchaseData);
  978. //o.optString("orderId");
  979. //o.optString("packageName");
  980. //sku=o.optString("productId");
  981. date=o.optLong("purchaseTime");
  982. //o.optInt("purchaseState");
  983. custom_data=o.optString("developerPayload");
  984. token=o.optString("token", o.optString("purchaseToken"));
  985. }catch(Exception exception){} // failed to parse data
  986. }
  987. if(verifyPurchase(purchaseData, signature))com.esenthel.Native.listPurchase(user, sku, custom_data, token, date);
  988. }
  989. continueToken=ownedItems.getString(INAPP_CONTINUATION_TOKEN);
  990. }catch(Exception exception){return false;}
  991. }while(Is(continueToken));
  992. return true;
  993. }
  994. public static final int buy(String id, String data, boolean subscription)
  995. {
  996. if(iab_service==null || activity==null)return RES_SERVICE_UNAVAILABLE;
  997. int result;
  998. try
  999. {
  1000. Bundle buyIntentBundle=iab_service.getBuyIntent(3, "EE_PACKAGE", id, subscription ? ITEM_TYPE_SUBS : ITEM_TYPE_INAPP, data);
  1001. result=billingToEE(getResponseCodeFromBundle(buyIntentBundle));
  1002. if(result==RES_OK)
  1003. {
  1004. result=RES_WAITING; // we're not done yet
  1005. PendingIntent pendingIntent=buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
  1006. activity.startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_CODE_IAB, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
  1007. }
  1008. }catch(Exception exception){result=RES_UNKNOWN;}
  1009. return result;
  1010. }
  1011. public static final int consume(String token)
  1012. {
  1013. if(iab_service==null)return RES_SERVICE_UNAVAILABLE;
  1014. int result;
  1015. try
  1016. {
  1017. result=billingToEE(iab_service.consumePurchase(3, "EE_PACKAGE", token));
  1018. if(result==RES_OK)result=RES_CONSUMED;
  1019. }catch(Exception exception){result=RES_UNKNOWN;}
  1020. return result;
  1021. }
  1022. /******************************************************************************/
  1023. // FB - Facebook
  1024. /******************************************************************************/
  1025. volatile static Bundle facebook_post;
  1026. private static boolean facebook_get_name=false, facebook_get_friends=false, facebook_want_post=false;
  1027. private UiLifecycleHelper ui_helper;
  1028. private final Session.StatusCallback ui_helper_callback=new Session.StatusCallback()
  1029. {
  1030. @Override public final void call(Session session, SessionState state, Exception exception) {}
  1031. };
  1032. private final FacebookDialog.Callback fb_dialog_callback=new FacebookDialog.Callback()
  1033. {
  1034. @Override public final void onError (FacebookDialog.PendingCall pendingCall, Exception error, Bundle data) {com.esenthel.Native.facebookPost(POST_ERROR);}
  1035. @Override public final void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data)
  1036. {
  1037. int result=POST_ERROR;
  1038. if(data!=null)
  1039. {
  1040. String gesture=FacebookDialog.getNativeDialogCompletionGesture(data);
  1041. if(gesture!=null)
  1042. {
  1043. if(gesture.equals("post" ))result=POST_SUCCESS;else
  1044. if(gesture.equals("cancel"))result=POST_CANCEL ;
  1045. }else result=POST_NOT_LOGGED_IN;
  1046. }
  1047. com.esenthel.Native.facebookPost(result);
  1048. }
  1049. };
  1050. private final Session.StatusCallback fb_status_callback=new Session.StatusCallback()
  1051. {
  1052. @Override public final void call(Session session, SessionState state, Exception exception)
  1053. {
  1054. if(facebookLoggedIn())
  1055. {
  1056. if(facebook_get_name ){facebook_get_name =false; facebookGetMeDo ();}
  1057. if(facebook_get_friends){facebook_get_friends=false; facebookGetFriendsDo();}
  1058. if(facebook_want_post ){facebook_want_post =false; if(!facebookCanPost())facebookWantPost ();}
  1059. facebookPostDo ();
  1060. }
  1061. }
  1062. };
  1063. final void initFB(Bundle savedInstanceState)
  1064. {
  1065. com.facebook.Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
  1066. Session session=Session.getActiveSession();
  1067. if(session==null)
  1068. {
  1069. if(savedInstanceState!=null)session=Session.restoreSession(this, null, fb_status_callback, savedInstanceState);
  1070. if(session==null)session=new Session(this);
  1071. Session.setActiveSession(session);
  1072. if(session.getState().equals(SessionState.CREATED_TOKEN_LOADED))session.openForRead(new Session.OpenRequest(this).setPermissions(Arrays.asList("public_profile", "email", "user_friends")).setCallback(fb_status_callback));
  1073. }
  1074. ui_helper=new UiLifecycleHelper(this, ui_helper_callback);
  1075. ui_helper.onCreate(savedInstanceState);
  1076. }
  1077. public static final boolean facebookLoggedIn()
  1078. {
  1079. Session session=Session.getActiveSession(); return session!=null && session.isOpened();
  1080. }
  1081. public static final boolean facebookCanPost()
  1082. {
  1083. Session session=Session.getActiveSession(); return session!=null && session.getPermissions().contains("publish_actions");
  1084. }
  1085. public static final void facebookWantPost()
  1086. {
  1087. Session session=Session.getActiveSession(); if(session!=null)session.requestNewPublishPermissions(new Session.NewPermissionsRequest(activity, "publish_actions"));
  1088. }
  1089. public static final void facebookLogOut()
  1090. {
  1091. Session session=Session.getActiveSession(); if(session!=null && !session.isClosed())session.closeAndClearTokenInformation();
  1092. }
  1093. public final void facebookLogIn()
  1094. {
  1095. Session session=Session.getActiveSession();
  1096. if(session==null || session.isClosed())
  1097. {
  1098. session=new Session(this);
  1099. Session.setActiveSession(session);
  1100. }
  1101. if(!session.isOpened())session.openForRead(new Session.OpenRequest(this).setPermissions(Arrays.asList("public_profile", "email", "user_friends")).setCallback(fb_status_callback));
  1102. }
  1103. public static final void facebookGetMeDo()
  1104. {
  1105. if(facebookLoggedIn())Request.newMeRequest(Session.getActiveSession(), new Request.GraphUserCallback()
  1106. {
  1107. @Override public final void onCompleted(GraphUser user, Response response)
  1108. {
  1109. if(user!=null)com.esenthel.Native.facebookMe(user.getId(), user.getName(), (String)user.getProperty("email"));
  1110. }
  1111. }).executeAsync();
  1112. }
  1113. public static final void facebookGetFriendsDo()
  1114. {
  1115. if(facebookLoggedIn())
  1116. {
  1117. Request request=Request.newMyFriendsRequest(Session.getActiveSession(), new GraphUserListCallback()
  1118. {
  1119. @Override public final void onCompleted(List<GraphUser> users, Response response)
  1120. {
  1121. if(users!=null)
  1122. {
  1123. ArrayList<String> ids=new ArrayList<String>();
  1124. ArrayList<String> names=new ArrayList<String>();
  1125. for(int i=0; i<users.size(); i++)
  1126. {
  1127. GraphUser user=users.get(i);
  1128. ids.add(user.getId ());
  1129. names.add(user.getName());
  1130. }
  1131. com.esenthel.Native.facebookFriends(ids, names);
  1132. }
  1133. }
  1134. });
  1135. Bundle params=new Bundle(); params.putString("fields", "id, name");
  1136. request.setParameters(params);
  1137. request.executeAsync();
  1138. }
  1139. }
  1140. public static final void facebookPostDo() // this does not require POST permission as it uses built-in Facebook app or WebView which handle this permission
  1141. {
  1142. Bundle post=facebook_post; facebook_post=null; if(post!=null && facebookLoggedIn())
  1143. {
  1144. WebDialog dialog=(new WebDialog.FeedDialogBuilder(activity, Session.getActiveSession(), post))
  1145. .setOnCompleteListener(new OnCompleteListener()
  1146. {
  1147. @Override public final void onComplete(Bundle values, com.facebook.FacebookException error)
  1148. {
  1149. int result=POST_CANCEL;
  1150. if(error!=null)
  1151. {
  1152. if(!(error instanceof com.facebook.FacebookOperationCanceledException))result=POST_ERROR;
  1153. }else
  1154. if(values!=null && values.getString("post_id")!=null)result=POST_SUCCESS;
  1155. com.esenthel.Native.facebookPost(result);
  1156. }
  1157. }).build();
  1158. dialog.show();
  1159. }
  1160. }
  1161. public final void facebookGetMe () {if(facebookLoggedIn())runOnUiThread(new Runnable(){@Override public final void run(){facebookGetMeDo ();}});else{facebook_get_name =true; facebookLogIn();}}
  1162. public final void facebookGetFriends() {if(facebookLoggedIn())runOnUiThread(new Runnable(){@Override public final void run(){facebookGetFriendsDo();}});else{facebook_get_friends=true; facebookLogIn();}}
  1163. public final void facebookPost(String message, String url, String image_url, String title, String desc, String caption)
  1164. {
  1165. if(ui_helper!=null && FacebookDialog.canPresentShareDialog(this, FacebookDialog.ShareDialogFeature.SHARE_DIALOG)) // this does not require being logged in
  1166. {
  1167. FacebookDialog shareDialog=new FacebookDialog.ShareDialogBuilder(this)
  1168. .setName (title)
  1169. .setLink (url)
  1170. .setPicture (image_url)
  1171. .setDescription(desc)
  1172. .setCaption (caption)
  1173. .build();
  1174. ui_helper.trackPendingDialogCall(shareDialog.present());
  1175. }else
  1176. {
  1177. Bundle post=new Bundle();
  1178. post.putString("message" , message);
  1179. post.putString("link" , url);
  1180. post.putString("picture" , image_url);
  1181. post.putString("name" , title);
  1182. post.putString("description", desc);
  1183. post.putString("caption" , caption);
  1184. facebook_post=post;
  1185. if(facebookLoggedIn())runOnUiThread(new Runnable(){@Override public final void run(){facebookPostDo();}});else facebookLogIn();
  1186. }
  1187. }
  1188. /******************************************************************************/
  1189. // CHARTBOOST
  1190. /******************************************************************************/
  1191. public static final boolean chartboostVisible() {return Chartboost.isAnyViewVisible();}
  1192. public static final void chartboostInterstitialLoad () { Chartboost.cacheInterstitial(CBLocation.LOCATION_DEFAULT);}
  1193. public static final void chartboostInterstitialShow () { Chartboost. showInterstitial(CBLocation.LOCATION_DEFAULT);}
  1194. public static final boolean chartboostInterstitialAvailable() {return Chartboost. hasInterstitial(CBLocation.LOCATION_DEFAULT);}
  1195. public static final void chartboostRewardedVideoLoad () { Chartboost.cacheRewardedVideo(CBLocation.LOCATION_DEFAULT);}
  1196. public static final void chartboostRewardedVideoShow () { Chartboost. showRewardedVideo(CBLocation.LOCATION_DEFAULT);}
  1197. public static final boolean chartboostRewardedVideoAvailable() {return Chartboost. hasRewardedVideo(CBLocation.LOCATION_DEFAULT);}
  1198. final void initChartboost()
  1199. {
  1200. if(EE_INIT_CHARTBOOST)
  1201. {
  1202. Chartboost.startWithAppId(this, "EE_CHARTBOOST_APP_ID", "EE_CHARTBOOST_APP_SIGNATURE");
  1203. Chartboost.setDelegate(new ChartboostDelegate() { // it must be called between 'Chartboost.startWithAppId' and 'Chartboost.onCreate'
  1204. //@Override public final boolean shouldRequestInterstitial(String location) {return true;}
  1205. //@Override public final boolean shouldDisplayInterstitial(String location) {return true;}
  1206. @Override public final void didCacheInterstitial(String location) {com.esenthel.Native.chartboost(INTERSTITIAL_LOADED);}
  1207. @Override public final void didFailToLoadInterstitial(String location, CBImpressionError error) {com.esenthel.Native.chartboost(INTERSTITIAL_LOAD_FAIL);}
  1208. @Override public final void didDisplayInterstitial(String location) {com.esenthel.Native.chartboost(INTERSTITIAL_DISPLAYED);}
  1209. @Override public final void didDismissInterstitial(String location) {com.esenthel.Native.chartboost(INTERSTITIAL_CLOSED);}
  1210. //@Override public final void didCloseInterstitial(String location) {com.esenthel.Native.chartboost(INTERSTITIAL_CLOSED);} this doesn't get called when interstitial is closed through clicking
  1211. @Override public final void didClickInterstitial(String location) {com.esenthel.Native.chartboost(INTERSTITIAL_CLICKED);}
  1212. //@Override public final boolean shouldDisplayRewardedVideo(String location) {return true;}
  1213. @Override public final void didCacheRewardedVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_LOADED);}
  1214. @Override public final void didFailToLoadRewardedVideo(String location, CBImpressionError error) {com.esenthel.Native.chartboost(REWARDED_VIDEO_LOAD_FAIL);}
  1215. @Override public final void didDisplayRewardedVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_DISPLAYED);}
  1216. //@Override public final void willDisplayVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_DISPLAYED);} this gets called everytime 'didDisplayRewardedVideo' gets called too, no need for 2 notifications
  1217. @Override public final void didDismissRewardedVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_CLOSED);}
  1218. //@Override public final void didCloseRewardedVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_CLOSED);} this gets called everytime 'didDismissRewardedVideo' gets called too, no need for 2 notifications
  1219. @Override public final void didClickRewardedVideo(String location) {com.esenthel.Native.chartboost(REWARDED_VIDEO_CLICKED);}
  1220. @Override public final void didCompleteRewardedVideo(String location, int reward) {com.esenthel.Native.chartboost(REWARDED_VIDEO_COMPLETED);}
  1221. });
  1222. Chartboost.setImpressionsUseActivities(true); // this is required due to OpenGL usage, it must be called between 'Chartboost.startWithAppId' and 'Chartboost.onCreate'
  1223. Chartboost.onCreate(this);
  1224. }
  1225. }
  1226. /******************************************************************************/
  1227. // NOTIFICATIONS
  1228. /******************************************************************************/
  1229. public static class NotificationDismissed extends BroadcastReceiver
  1230. {
  1231. @Override public final void onReceive(Context context, Intent intent) {checkNotification(intent, false);}
  1232. }
  1233. public static final String NOTIFICATION_CHANNEL_ID="ID";
  1234. public static final String NOTIFICATION_ID ="EsenthelNotificationID";
  1235. public static final int BACKGROUND_NOTIFICATION_ID =-1; // must not be 0 because 'startForeground' does not accept 0, use -1 because 0..+ are used by custom Notifications !! if this is changed then adjust 'Application.backgroundText' !!
  1236. public static final void initNotification()
  1237. {
  1238. if(Build.VERSION.SDK_INT>=26)
  1239. {
  1240. /*Use this code and below 'getNotification'
  1241. NotificationManager manager=(NotificationManager)activity.getSystemService(Context.NOTIFICATION_SERVICE);
  1242. if(manager!=null)
  1243. {
  1244. android.app.NotificationChannel channel=new android.app.NotificationChannel(NOTIFICATION_CHANNEL_ID, "Name", NotificationManager.IMPORTANCE_DEFAULT);
  1245. //channel.setDescription("Description");
  1246. manager.createNotificationChannel(channel);
  1247. }*/
  1248. }
  1249. if(Build.VERSION.SDK_INT>=23)
  1250. {
  1251. //NotificationManager manager=(NotificationManager)activity.getSystemService(Context.NOTIFICATION_SERVICE);
  1252. //android.service.notification.StatusBarNotification[] notifications=manager.getActiveNotifications();
  1253. }
  1254. }
  1255. public static final void checkNotification(Intent intent, boolean selected)
  1256. {
  1257. if(intent!=null)
  1258. {
  1259. int notification_id=intent.getIntExtra(NOTIFICATION_ID, -1); // -1=default value
  1260. if( notification_id>=0)com.esenthel.Native.notification(notification_id, selected);
  1261. }
  1262. }
  1263. public static final Notification getNotification(int id, String title, String text, boolean dismissable)
  1264. {
  1265. Notification.Builder builder;
  1266. //if(Build.VERSION.SDK_INT>=26)builder=new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);else
  1267. builder=new Notification.Builder(context);
  1268. if(builder!=null)
  1269. {
  1270. Intent intent=new Intent(context, EsenthelActivity.class);
  1271. if(id>=0)intent.putExtra (NOTIFICATION_ID, id); // store NOTIFICATION_ID only for regular notifications
  1272. intent.addCategory(Intent.CATEGORY_LAUNCHER);
  1273. intent.setAction (Intent.ACTION_MAIN);
  1274. if(dismissable && id>=0)
  1275. {
  1276. Intent intent_dismiss=new Intent(context, NotificationDismissed.class);
  1277. intent_dismiss.putExtra(NOTIFICATION_ID, id);
  1278. PendingIntent pending_intent_dismiss=PendingIntent.getBroadcast(context, id*2+1, intent_dismiss, PendingIntent.FLAG_UPDATE_CURRENT); // use id*2+1 to make unique
  1279. builder.setDeleteIntent(pending_intent_dismiss);
  1280. }
  1281. PendingIntent pending_intent=PendingIntent.getActivity(context, id*2, intent, PendingIntent.FLAG_UPDATE_CURRENT); // use id*2 to make unique
  1282. return builder.setContentTitle(title).setContentText(text).setSmallIcon(R.drawable.notification).setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon)).setOngoing(!dismissable).setContentIntent(pending_intent).build();
  1283. }
  1284. return null;
  1285. }
  1286. public static final void setNotification(int id, String title, String text, boolean dismissable)
  1287. {
  1288. if(id==BACKGROUND_NOTIFICATION_ID && background_intent==null)return; // don't adjust background notification if we're not actually in background (can happen if we call this in InitPre, when application hasn't finished initializing but it's also not in the background)
  1289. NotificationManager manager=(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); if(manager!=null)
  1290. {
  1291. Notification notification=getNotification(id, title, text, dismissable);
  1292. if(notification!=null)manager.notify(id, notification);
  1293. }
  1294. }
  1295. public static final void removeNotification(int id)
  1296. {
  1297. NotificationManager manager=(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); if(manager!=null)manager.cancel(id);
  1298. }
  1299. public static final void removeNotifications()
  1300. {
  1301. NotificationManager manager=(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); if(manager!=null)manager.cancelAll();
  1302. }
  1303. /******************************************************************************/
  1304. // BACKGROUND SERVICE
  1305. /******************************************************************************/
  1306. public static class BackgroundService extends Service // !! if changing name of this class then update AndroidManifest.xml !!
  1307. {
  1308. @Override public final IBinder onBind (Intent intent) {return null;}
  1309. //@Override public final void onCreate ( ) {super.onCreate(); background_service=this;}
  1310. //@Override public final void onDestroy ( ) {background_service=null; super.onDestroy();}
  1311. @Override public final int onStartCommand(Intent intent, int flags, int startId)
  1312. {
  1313. Notification notification=getNotification(BACKGROUND_NOTIFICATION_ID, "EE_APP_NAME", background_text, false);
  1314. if(notification!=null)startForeground(BACKGROUND_NOTIFICATION_ID, notification);
  1315. return START_STICKY; // restart if got killed
  1316. }
  1317. }
  1318. public final void startBackgroundService(String text)
  1319. {
  1320. if(background_intent==null)
  1321. {
  1322. background_text=text;
  1323. background_intent=new Intent(this, BackgroundService.class);
  1324. startService(background_intent);
  1325. }
  1326. }
  1327. public final void stopBackgroundService()
  1328. {
  1329. if(background_intent!=null)
  1330. {
  1331. stopService(background_intent);
  1332. background_intent=null;
  1333. }
  1334. }
  1335. }
  1336. /******************************************************************************/