/******************************************************************************/ package EE_PACKAGE; import android.app.Activity; import android.app.AlertDialog; import android.app.Application; import android.app.NativeActivity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.app.TaskStackBuilder; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.DialogInterface; import android.content.DialogInterface.OnShowListener; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.BitmapFactory; import android.location.Location; import android.location.LocationListener; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.media.MediaRecorder.AudioSource; import android.net.Uri; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.StatFs; import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.Secure; import android.text.Editable; import android.text.InputType; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.EditorInfo; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; import android.view.Window; import android.view.WindowManager; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.Toast; import com.android.vending.billing.IInAppBillingService; import com.chartboost.sdk.*; import com.chartboost.sdk.Model.CBError.CBImpressionError; import com.google.android.gms.ads.*; import com.facebook.android.DialogError; import com.facebook.android.Facebook; import com.facebook.android.Facebook.DialogListener; import com.facebook.android.FacebookError; import com.facebook.HttpMethod; import com.facebook.LoggingBehavior; import com.facebook.model.GraphUser; import com.facebook.model.GraphObject; import com.facebook.Response; import com.facebook.Request; import com.facebook.Request.GraphUserListCallback; import com.facebook.Session; import com.facebook.SessionState; //import com.facebook.Settings; can't import due to 'android.provider.Settings' import com.facebook.UiLifecycleHelper; import com.facebook.widget.FacebookDialog; import com.facebook.widget.WebDialog; import com.facebook.widget.WebDialog.OnCompleteListener; import java.io.File; import java.math.BigInteger; import java.nio.ByteBuffer; import java.security.KeyFactory; import java.security.MessageDigest; import java.security.PublicKey; import java.security.Signature; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.json.JSONObject; /******************************************************************************/ public class EsenthelActivity extends NativeActivity { public static class EsenthelLocationListener implements LocationListener { public boolean gps; public EsenthelLocationListener(boolean gps) {this.gps=gps;} @Override public final void onLocationChanged (Location location) {com.esenthel.Native.location(gps, location);} @Override public final void onProviderDisabled(String providerName) {} @Override public final void onProviderEnabled (String providerName) {} @Override public final void onStatusChanged (String providerName, int status, Bundle extras) {} } public static class DetectForceKill extends Service // !! if changing name of this class then update AndroidManifest.xml !! { @Override public final IBinder onBind (Intent intent) {return null;} @Override public final int onStartCommand(Intent intent, int flags, int startId) {return START_NOT_STICKY;} //@Override public final void onDestroy () {super.onDestroy();} @Override public final void onTaskRemoved (Intent rootIntent) {removeNotifications(); super.onTaskRemoved(rootIntent);} // this is called on force kill } // !! these must be equal to 'AWAKE_MODE' !! public static final int AWAKE_OFF =0; public static final int AWAKE_SYSTEM=1; public static final int AWAKE_SCREEN=2; // !! these must be equal to 'AdMobClass.BANNER_TYPE' !! public static final int AD_BANNER =0; public static final int AD_MEDIUM_RECTANGLE=1; public static final int AD_FULL_BANNER =2; public static final int AD_LEADERBOARD =3; public static final int AD_SMART_BANNER =4; public static final int AD_INTERSTITIAL =5; // !! these must be equal to 'AdMobClass.STATE' !! public static final int AD_NONE =0; public static final int AD_LOADING=1; public static final int AD_DONE =2; public static final int AD_ERROR =3; // !! these must be equal to 'ChartboostClass.RESULT' !! public static final int INTERSTITIAL_LOADED =0; public static final int INTERSTITIAL_LOAD_FAIL=1; public static final int INTERSTITIAL_DISPLAYED=2; public static final int INTERSTITIAL_CLOSED =3; public static final int INTERSTITIAL_CLICKED =4; public static final int REWARDED_VIDEO_LOADED =5; public static final int REWARDED_VIDEO_LOAD_FAIL=6; public static final int REWARDED_VIDEO_DISPLAYED=7; public static final int REWARDED_VIDEO_CLOSED =8; public static final int REWARDED_VIDEO_COMPLETED=9; public static final int REWARDED_VIDEO_CLICKED =10; // !! these must be equal to 'PlatformStore.RESULT' !! public static final int RES_OK =-1; // this is not a 'PlatformStore.RESULT' but a temp value public static final int RES_PURCHASED =0; public static final int RES_CONSUMED =1; public static final int RES_REFUND =2; public static final int RES_WAITING =3; public static final int RES_USER_CANCELED =4; public static final int RES_SERVICE_CANCELED =5; public static final int RES_SERVICE_UNAVAILABLE=6; public static final int RES_ITEM_UNAVAILABLE =7; public static final int RES_ALREADY_OWNED =8; public static final int RES_NOT_OWNED =9; public static final int RES_VERIFICATION_FAIL =10; public static final int RES_UNKNOWN =11; public static final int RES_REFRESHED_ITEMS =12; public static final int RES_REFRESHED_PURCHASES=13; // !! these must be equal to 'Facebook.RESULT' !! public static final int POST_ERROR=0; public static final int POST_CANCEL=1; public static final int POST_SUCCESS=2; public static final int POST_NOT_LOGGED_IN=3; // Billing response codes public static final int BILLING_RESPONSE_RESULT_OK = 0; public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1; public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3; public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4; public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5; public static final int BILLING_RESPONSE_RESULT_ERROR = 6; public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8; // Item types public static final String ITEM_TYPE_INAPP="inapp"; public static final String ITEM_TYPE_SUBS ="subs"; // some fields on the getSkuDetails response bundle public static final String GET_SKU_DETAILS_ITEM_LIST="ITEM_ID_LIST"; // Keys for the responses from InAppBillingService public static final String RESPONSE_CODE = "RESPONSE_CODE"; public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST"; public static final String RESPONSE_BUY_INTENT = "BUY_INTENT"; public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE"; public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST"; public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; // signature verification private static final String KEY_FACTORY_ALGORITHM="RSA"; private static final String SIGNATURE_ALGORITHM="SHA1withRSA"; public static final int REQUEST_CODE_IAB=0; // variables static EsenthelActivity activity; static Application application; static Context context; static Intent background_intent; static String background_text; static Handler handler; static IInAppBillingService iab_service; static ServiceConnection iab_service_conn; static PublicKey license_key; static AdRequest ad_request; AdView ad_view; static boolean ad_view_loaded=false, // if ad_view is loaded banner_visible=false, // if banner should be visible inters_show=false; // if show interstitial once it's loaded static String banner_id, // id of the banner ad, null for none inters_id; // id of the interstitial ad, null for none static int banner_type=AD_BANNER, // banner type banner_x=0, banner_y=1; // banner position, -1..1 InterstitialAd interstitial; PopupWindow popup_window; LinearLayout popup_window_layout, ad_view_layout; static String android_id; EditText edit_text; TextWatcher text_watcher; static WakeLock wake_lock; static WifiLock wifi_lock; static final void log(String s) {Log.e("Esenthel", s);} static final boolean Is(String s) {return !TextUtils.isEmpty(s);} static { EE_LOAD_LIBRARIES } /******************************************************************************/ // MAIN /******************************************************************************/ @Override public final void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); Session.saveSession(Session.getActiveSession(), savedInstanceState); if(ui_helper!=null)ui_helper.onSaveInstanceState(savedInstanceState); } @Override public final void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if(Is(inters_id))adCreate(inters_id, AD_INTERSTITIAL); if(Is(banner_id))adCreate(banner_id, banner_type ); } @Override public final void onNewIntent(Intent intent) { super.onNewIntent(intent); checkNotification(intent, true); } @Override public final void onBackPressed() { if(!Chartboost.onBackPressed()) // this will detect if there's an interstitial and close it, otherwise process below: { super.onBackPressed(); } } @Override public final void onResume() { super.onResume(); if(ad_view !=null)ad_view . resume(); if(ui_helper!=null)ui_helper.onResume(); Chartboost.onResume(this); } @Override public final void onPause() { if(ad_view !=null)ad_view . pause(); if(ui_helper!=null)ui_helper.onPause(); super.onPause(); Chartboost.onPause(this); } @Override public final void onStart() { super.onStart(); Chartboost.onStart(this); Session session=Session.getActiveSession(); if(session!=null)session.addCallback(fb_status_callback); } @Override public final void onStop() { super.onStop(); Chartboost.onStop(this); Session session=Session.getActiveSession(); if(session!=null)session.removeCallback(fb_status_callback); } @Override public final void onDestroy() { bannerHide(); adViewDel(); super.onDestroy(); if(ui_helper!=null)ui_helper.onDestroy(); Chartboost.onDestroy(this); shutIAB(); context=application; activity=null; // when activity becomes unavailable, then use application context because we always need one } @Override public final void onCreate(Bundle savedInstanceState) { 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 if(handler==null)handler=new Handler() { @Override public final void handleMessage(Message message) { super.handleMessage(message); String title=message.getData().getString ("title"), text =message.getData().getString ("text" ); boolean exit =message.getData().getBoolean("exit" ); if(title!=null && text!=null) { AlertDialog dialog=new AlertDialog.Builder(context).setTitle(title).setMessage(text).setNeutralButton("OK", null).show(); if(exit && dialog!=null) dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @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 }); } } }; if(android_id==null)android_id=Secure.getString(getContentResolver(), Secure.ANDROID_ID); if(wake_lock==null) { PowerManager power_manager=(PowerManager)getSystemService(POWER_SERVICE); if(power_manager!=null) { wake_lock=power_manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); // will crash if null is used if(wake_lock!=null)wake_lock.setReferenceCounted(false); // disable ref counting so one 'release' will be immediate } } if(wifi_lock==null) { WifiManager wifi_manager=(WifiManager)getSystemService(WIFI_SERVICE); if(wifi_manager!=null) { wifi_lock=wifi_manager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, ""); // will crash if null is used if(wifi_lock!=null)wifi_lock.setReferenceCounted(false); // disable ref counting so one 'release' will be immediate } } super.onCreate(savedInstanceState); startService(new Intent(this, DetectForceKill.class)); // start service that detects force kill initIAB(); initFB (savedInstanceState); 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 if(ad_request==null)setAdRequest(false); initChartboost(); initNotification(); /*log("android_id "+android_id); log("BOARD "+Build.BOARD); log("BOOTLOADER "+Build.BOOTLOADER); log("BRAND "+Build.BRAND); log("DEVICE "+Build.DEVICE); log("DISPLAY "+Build.DISPLAY); log("FINGERPRINT "+Build.FINGERPRINT); log("HARDWARE "+Build.HARDWARE); log("HOST "+Build.HOST); log("ID "+Build.ID); log("MANUFACTURER "+Build.MANUFACTURER); log("MODEL "+Build.MODEL); log("PRODUCT "+Build.PRODUCT); log("SERIAL "+Build.SERIAL); log("TAGS "+Build.TAGS); log("TIME "+Build.TIME); log("TYPE "+Build.TYPE); log("USER "+Build.USER);*/ } @Override protected final void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Session session=Session.getActiveSession(); if( session!=null) session.onActivityResult(this, requestCode, resultCode, data); if(ui_helper!=null)ui_helper.onActivityResult( requestCode, resultCode, data, fb_dialog_callback); switch(requestCode) { case REQUEST_CODE_IAB: { int responseCode=-1; long date=0; String purchaseData=null, sku=null, custom_data=null, token=null, signature=null; if(data!=null) { // data.getExtras() responseCode=getResponseCodeFromIntent(data); purchaseData=data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); signature =data.getStringExtra(RESPONSE_INAPP_SIGNATURE); if(purchaseData!=null) { try { JSONObject o=new JSONObject(purchaseData); //o.optString("orderId"); //o.optString("packageName"); sku=o.optString("productId"); date=o.optLong("purchaseTime"); //o.optInt("purchaseState"); custom_data=o.optString("developerPayload"); token=o.optString("token", o.optString("purchaseToken")); }catch(Exception exception){} // failed to parse data } } int result=billingToEE(responseCode); if( result==RES_OK )result=((resultCode==Activity.RESULT_OK && sku!=null) ? (verifyPurchase(purchaseData, signature) ? RES_PURCHASED : RES_VERIFICATION_FAIL) : RES_UNKNOWN); if( result==RES_UNKNOWN)if(resultCode==Activity.RESULT_CANCELED)result=RES_SERVICE_CANCELED; //log("responseCode:"+responseCode+", resultCode:"+resultCode+", result:"+result); com.esenthel.Native.purchased(result, sku, custom_data, token, date); }break; } } @Override public final void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); adPos(banner_x, banner_y); // reset banner position in new screen size/orientation } public static final void messageBox(String title, String text, boolean exit) { if(handler!=null) { Message message=handler.obtainMessage(); if(message!=null) { Bundle bundle=new Bundle(); if(bundle!=null) { bundle.putString ("title", title); bundle.putString ("text" , text ); if(exit)bundle.putBoolean("exit" , exit ); message.setData(bundle); handler.sendMessage(message); } } } } public static final void toast(final String text) { Handler handler=new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public final void run() { Toast.makeText(context, text, Toast.LENGTH_LONG).show(); } }); } public static final void stayAwake(final int mode) { if(wake_lock!=null) { if(mode==AWAKE_SYSTEM)wake_lock.acquire(); else wake_lock.release(); } if(wifi_lock!=null) { if(mode==AWAKE_SYSTEM)wifi_lock.acquire(); else wifi_lock.release(); } if(activity!=null)activity.runOnUiThread(new Runnable() { @Override public final void run() { Window window=activity.getWindow(); if(window!=null)window.setFlags((mode==AWAKE_SCREEN) ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }); } public static final boolean openAppSettings() { Intent intent=new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setData(Uri.fromParts("package", "EE_PACKAGE", null)); boolean ok=true; try{context.startActivity(intent);}catch(Exception exception){ok=false;} return ok; } public static final long driveSizeFree (String path) {File file=new File(path); if(file!=null && file.exists())return file.getUsableSpace(); return -1;} public static final long driveSizeTotal(String path) {File file=new File(path); if(file!=null && file.exists())return file.getTotalSpace (); return -1;} public static final String manufacturer() {return Build.MANUFACTURER;} public static final String model () {return Build.MODEL;} public static final String serial () {return Build.SERIAL;} public static final String androidID () {return android_id;} /******************************************************************************/ // KEYBOARD /******************************************************************************/ @Override public final boolean dispatchKeyEvent(KeyEvent event) { if(event!=null)if(event.getAction()!=KeyEvent.ACTION_UP) { int key_code=event.getKeyCode (); // use 'getKeyCode' instead of 'getScanCode' to match 'AKeyEvent_getKeyCode' on native C++ side int unicode =event.getUnicodeChar(); if(unicode!=0)com.esenthel.Native.key(unicode, key_code);else { String s=event.getCharacters(); if(s!=null)for(int i=0; i