diff options
Diffstat (limited to 'platform/android/java')
17 files changed, 1096 insertions, 163 deletions
diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png Binary files differindex 050a1cf930..013632ddf1 100644 --- a/platform/android/java/res/drawable/icon.png +++ b/platform/android/java/res/drawable/icon.png diff --git a/platform/android/java/res/layout/downloading_expansion.xml b/platform/android/java/res/layout/downloading_expansion.xml new file mode 100644 index 0000000000..553155dcd3 --- /dev/null +++ b/platform/android/java/res/layout/downloading_expansion.xml @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="0" + android:orientation="vertical" > + + <TextView + android:id="@+id/statusText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="10dp" + android:layout_marginLeft="5dp" + android:layout_marginTop="10dp" + android:textStyle="bold" /> + + <LinearLayout + android:id="@+id/downloaderDashboard" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/statusText" + android:orientation="vertical" > + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" > + + <TextView + android:id="@+id/progressAsFraction" + style="@android:style/TextAppearance.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_marginLeft="5dp" + android:text="0MB / 0MB" > + </TextView> + + <TextView + android:id="@+id/progressAsPercentage" + style="@android:style/TextAppearance.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignRight="@+id/progressBar" + android:text="0%" /> + + <ProgressBar + android:id="@+id/progressBar" + style="?android:attr/progressBarStyleHorizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/progressAsFraction" + android:layout_marginBottom="10dp" + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" + android:layout_marginTop="10dp" + android:layout_weight="1" /> + + <TextView + android:id="@+id/progressAverageSpeed" + style="@android:style/TextAppearance.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_below="@+id/progressBar" + android:layout_marginLeft="5dp" /> + + <TextView + android:id="@+id/progressTimeRemaining" + style="@android:style/TextAppearance.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignRight="@+id/progressBar" + android:layout_below="@+id/progressBar" /> + </RelativeLayout> + + <LinearLayout + android:id="@+id/downloaderDashboard" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <Button + android:id="@+id/pauseButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginBottom="10dp" + android:layout_marginLeft="10dp" + android:layout_marginRight="5dp" + android:layout_marginTop="10dp" + android:layout_weight="0" + android:minHeight="40dp" + android:minWidth="94dp" + android:text="@string/text_button_pause" /> + + <Button + android:id="@+id/cancelButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginBottom="10dp" + android:layout_marginLeft="5dp" + android:layout_marginRight="5dp" + android:layout_marginTop="10dp" + android:layout_weight="0" + android:minHeight="40dp" + android:minWidth="94dp" + android:text="@string/text_button_cancel" + android:visibility="gone" /> + </LinearLayout> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/approveCellular" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="vertical" + android:visibility="gone" > + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:id="@+id/textPausedParagraph1" + android:text="@string/text_paused_cellular" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:id="@+id/textPausedParagraph2" + android:text="@string/text_paused_cellular_2" /> + + <LinearLayout + android:id="@+id/buttonRow" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <Button + android:id="@+id/resumeOverCellular" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_margin="10dp" + android:text="@string/text_button_resume_cellular" /> + + <Button + android:id="@+id/wifiSettingsButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_margin="10dp" + android:text="@string/text_button_wifi_settings" /> + </LinearLayout> + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/platform/android/java/res/values-fa/strings.xml b/platform/android/java/res/values-fa/strings.xml new file mode 100644 index 0000000000..450f9fe212 --- /dev/null +++ b/platform/android/java/res/values-fa/strings.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="godot_project_name_string">godot-project-name-fa</string> + <string name="testuf8">سلام</string> + <string name="text_paused_cellular">آیا می خواهید بر روی اتصال داده همراه دانلود را شروع کنید؟ بر اساس نوع سطح داده شما این ممکن است برای شما هزینه مالی داشته باشد.</string> + <string name="text_paused_cellular_2">اگر نمی خواهید بر روی اتصال داده همراه دانلود را شروع کنید ، دانلود به صورت خودکار در زمان دسترسی به وای-فای شروع می شود.</string> + <string name="text_button_resume_cellular">ادامه دانلود</string> + <string name="text_button_wifi_settings">تنظیمات وای-فای</string> + <string name="text_verifying_download">درحال تایید دانلود</string> + <string name="text_validation_complete">تایید فایل XAPK تکمیل شد. برای خروج تایید کنید.</string> + <string name="text_validation_failed">اعتبارسنجی فایل XAPK ناموق.</string> + <string name="text_button_pause">توقف دانلود</string> + <string name="text_button_resume">ادامه دانلود</string> + <string name="text_button_cancel">انصراف</string> + <string name="text_button_cancel_verify">انصراف از تایید شدن</string> +</resources> diff --git a/platform/android/java/res/values/strings.xml b/platform/android/java/res/values/strings.xml index 3a38d40599..49ebcc06f9 100644 --- a/platform/android/java/res/values/strings.xml +++ b/platform/android/java/res/values/strings.xml @@ -3,5 +3,15 @@ <string name="godot_project_name_string">godot-project-name</string> <string name="testuf8">元気です</string> <string name="testuf2">元気です元気です元気です</string> - + <string name="text_paused_cellular">Would you like to enable downloading over cellular connections? Depending on your data plan, this may cost you money.</string> + <string name="text_paused_cellular_2">If you choose not to enable downloading over cellular connections, the download will automatically resume when wi-fi is available.</string> + <string name="text_button_resume_cellular">Resume download</string> + <string name="text_button_wifi_settings">Wi-Fi settings</string> + <string name="text_verifying_download">Verifying Download</string> + <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string> + <string name="text_validation_failed">XAPK File Validation Failed.</string> + <string name="text_button_pause">Pause Download</string> + <string name="text_button_resume">Resume Download</string> + <string name="text_button_cancel">Cancel</string> + <string name="text_button_cancel_verify">Cancel Verification</string> </resources> diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java index 658c272321..4c5a313576 100644 --- a/platform/android/java/src/com/android/godot/Godot.java +++ b/platform/android/java/src/com/android/godot/Godot.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,16 +28,20 @@ /*************************************************************************/ package com.android.godot; +import android.R; import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.LinearLayout; +import android.widget.TextView; import android.view.ViewGroup.LayoutParams; - - import android.app.*; import android.content.*; +import android.content.SharedPreferences.Editor; import android.view.*; import android.view.inputmethod.InputMethodManager; import android.os.*; @@ -48,33 +52,84 @@ import android.text.*; import android.media.*; import android.hardware.*; import android.content.*; - +import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.media.MediaPlayer; import java.lang.reflect.Method; import java.util.List; import java.util.ArrayList; + import com.android.godot.payments.PaymentsManager; + import java.io.IOException; + import android.provider.Settings.Secure; import android.widget.FrameLayout; + import com.android.godot.input.*; -import java.io.InputStream; +import java.io.InputStream; import javax.microedition.khronos.opengles.GL10; import java.security.MessageDigest; import java.io.File; import java.io.FileInputStream; import java.util.LinkedList; -public class Godot extends Activity implements SensorEventListener +import com.google.android.vending.expansion.downloader.Constants; +import com.google.android.vending.expansion.downloader.DownloadProgressInfo; +import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; +import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller; +import com.google.android.vending.expansion.downloader.Helpers; +import com.google.android.vending.expansion.downloader.IDownloaderClient; +import com.google.android.vending.expansion.downloader.IDownloaderService; +import com.google.android.vending.expansion.downloader.IStub; + +import android.os.Bundle; +import android.os.Messenger; +import android.os.SystemClock; + + +public class Godot extends Activity implements SensorEventListener, IDownloaderClient { static final int MAX_SINGLETONS = 64; - + private IStub mDownloaderClientStub; + private IDownloaderService mRemoteService; + private TextView mStatusText; + private TextView mProgressFraction; + private TextView mProgressPercent; + private TextView mAverageSpeed; + private TextView mTimeRemaining; + private ProgressBar mPB; + + private View mDashboard; + private View mCellMessage; + + private Button mPauseButton; + private Button mWiFiSettingsButton; + + private boolean use_32_bits=false; + private boolean use_immersive=false; + private boolean mStatePaused; + private int mState; + + private void setState(int newState) { + if (mState != newState) { + mState = newState; + mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState)); + } + } + + private void setButtonPausedState(boolean paused) { + mStatePaused = paused; + int stringResourceID = paused ? com.godot.game.R.string.text_button_resume : + com.godot.game.R.string.text_button_pause; + mPauseButton.setText(stringResourceID); + } + static public class SingletonBase { - + protected void registerClass(String p_name, String[] p_methods) { GodotLib.singleton(p_name,this); @@ -83,20 +138,20 @@ public class Godot extends Activity implements SensorEventListener Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { boolean found=false; - System.out.printf("METHOD: %s\n",method.getName()); + Log.d("XXX","METHOD: %s\n" + method.getName()); for (String s : p_methods) { - System.out.printf("METHOD CMP WITH: %s\n",s); + Log.d("XXX", "METHOD CMP WITH: %s\n" + s); if (s.equals(method.getName())) { found=true; - System.out.printf("METHOD CMP VALID"); + Log.d("XXX","METHOD CMP VALID"); break; } } if (!found) continue; - System.out.printf("METHOD FOUND: %s\n",method.getName()); + Log.d("XXX","METHOD FOUND: %s\n" + method.getName()); List<String> ptr = new ArrayList<String>(); @@ -202,7 +257,7 @@ public class Godot extends Activity implements SensorEventListener // ...add to FrameLayout layout.addView(edittext); - mView = new GodotView(getApplication(),io,use_gl2, this); + mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this); layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); mView.setKeepScreenOn(true); @@ -230,7 +285,7 @@ public class Godot extends Activity implements SensorEventListener byte[] len = new byte[4]; int r = is.read(len); if (r<4) { - System.out.printf("**ERROR** Wrong cmdline length.\n"); + Log.d("XXX","**ERROR** Wrong cmdline length.\n"); Log.d("GODOT", "**ERROR** Wrong cmdline length.\n"); return new String[0]; } @@ -258,7 +313,6 @@ public class Godot extends Activity implements SensorEventListener return cmdline; } catch (Exception e) { e.printStackTrace(); - System.out.printf("**ERROR** No commandline.\n"); Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage()); return new String[0]; } @@ -277,12 +331,14 @@ public class Godot extends Activity implements SensorEventListener String[] new_cmdline; int cll=0; if (command_line!=null) { + Log.d("GODOT", "initializeGodot: command_line: is not null" ); new_cmdline = new String[ command_line.length + 2 ]; cll=command_line.length; for(int i=0;i<command_line.length;i++) { new_cmdline[i]=command_line[i]; } } else { + Log.d("GODOT", "initializeGodot: command_line: is null" ); new_cmdline = new String[ 2 ]; } @@ -294,10 +350,17 @@ public class Godot extends Activity implements SensorEventListener io = new GodotIO(this); io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID); GodotLib.io=io; - GodotLib.initialize(this,io.needsReloadHooks(),command_line); + Log.d("GODOT", "command_line is null? " + ((command_line == null)?"yes":"no")); + /*if(command_line != null){ + Log.d("GODOT", "Command Line:"); + for(int w=0;w <command_line.length;w++){ + Log.d("GODOT"," " + command_line[w]); + } + }*/ + GodotLib.initialize(this,io.needsReloadHooks(),command_line,getAssets()); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); + mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); result_callback = null; @@ -306,10 +369,18 @@ public class Godot extends Activity implements SensorEventListener } + @Override + public void onServiceConnected(Messenger m) { + mRemoteService = DownloaderServiceMarshaller.CreateProxy(m); + mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger()); + } - @Override protected void onCreate(Bundle icicle) { - System.out.printf("** GODOT ACTIVITY CREATED HERE ***\n"); + + @Override + protected void onCreate(Bundle icicle) { + + Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n"); super.onCreate(icicle); _self = this; @@ -319,7 +390,8 @@ public class Godot extends Activity implements SensorEventListener //check for apk expansion API - if (!true) { + if (true) { + boolean md5mismatch = false; command_line = getCommandLine(); boolean use_apk_expansion=false; String main_pack_md5=null; @@ -331,24 +403,45 @@ public class Godot extends Activity implements SensorEventListener for(int i=0;i<command_line.length;i++) { boolean has_extra = i< command_line.length -1; - if (command_line[i].equals("-use_apk_expansion")) { + if (command_line[i].equals("-use_depth_32")) { + use_32_bits=true; + } else if (command_line[i].equals("-use_immersive")) { + use_immersive=true; + if(Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+ + window.getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + + UiChangeListener(); + } + } else if (command_line[i].equals("-use_apk_expansion")) { use_apk_expansion=true; } else if (has_extra && command_line[i].equals("-apk_expansion_md5")) { main_pack_md5=command_line[i+1]; i++; } else if (has_extra && command_line[i].equals("-apk_expansion_key")) { main_pack_key=command_line[i+1]; + SharedPreferences prefs = getSharedPreferences("app_data_keys", MODE_PRIVATE); + Editor editor = prefs.edit(); + editor.putString("store_public_key", main_pack_key); + + editor.commit(); i++; } else if (command_line[i].trim().length()!=0){ new_args.add(command_line[i]); } } - if (new_args.isEmpty()) + if (new_args.isEmpty()){ command_line=null; - else - command_line = new_args.toArray(new String[new_args.size()]); + }else{ + command_line = new_args.toArray(new String[new_args.size()]); + } if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) { //check that environment is ok! if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED )) { @@ -374,49 +467,62 @@ public class Godot extends Activity implements SensorEventListener pack_valid=false; Log.d("GODOT","**PACK** - File does not exist"); - } else { - try { - - InputStream fis = new FileInputStream(expansion_pack_path); - - // Create MD5 Hash - byte[] buffer = new byte[16384]; - - MessageDigest complete = MessageDigest.getInstance("MD5"); - int numRead; - do { - numRead = fis.read(buffer); - if (numRead > 0) { - complete.update(buffer, 0, numRead); - } - } while (numRead != -1); - - - fis.close(); - byte[] messageDigest = complete.digest(); - - // Create Hex String - StringBuffer hexString = new StringBuffer(); - for (int i=0; i<messageDigest.length; i++) - hexString.append(Integer.toHexString(0xFF & messageDigest[i])); - String md5str = hexString.toString(); - - Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5); - if (!hexString.equals(main_pack_md5)) { - pack_valid=false; - } - } catch (Exception e) { - e.printStackTrace(); - Log.d("GODOT","**PACK FAIL**"); - pack_valid=false; + } else if( obbIsCorrupted(expansion_pack_path, main_pack_md5)){ + Log.d("GODOT", "**PACK** - Expansion pack (obb) is corrupted"); + pack_valid = false; + try{ + f.delete(); + }catch(Exception e){ + Log.d("GODOT", "**PACK** - Error deleting corrupted expansion pack (obb)"); } - - } if (!pack_valid) { - - + Log.d("GODOT", "Pack Invalid, try re-downloading."); + + Intent notifierIntent = new Intent(this, this.getClass()); + notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_CLEAR_TOP); + + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, + notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + int startResult; + try { + Log.d("GODOT", "INITIALIZING DOWNLOAD"); + startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( + getApplicationContext(), + pendingIntent, + GodotDownloaderService.class); + Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult); + + if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { + Log.d("GODOT", "DOWNLOAD REQUIRED"); + // This is where you do set up to display the download + // progress (next step) + mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this, + GodotDownloaderService.class); + + setContentView(com.godot.game.R.layout.downloading_expansion); + mPB = (ProgressBar) findViewById(com.godot.game.R.id.progressBar); + mStatusText = (TextView) findViewById(com.godot.game.R.id.statusText); + mProgressFraction = (TextView) findViewById(com.godot.game.R.id.progressAsFraction); + mProgressPercent = (TextView) findViewById(com.godot.game.R.id.progressAsPercentage); + mAverageSpeed = (TextView) findViewById(com.godot.game.R.id.progressAverageSpeed); + mTimeRemaining = (TextView) findViewById(com.godot.game.R.id.progressTimeRemaining); + mDashboard = findViewById(com.godot.game.R.id.downloaderDashboard); + mCellMessage = findViewById(com.godot.game.R.id.approveCellular); + mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton); + mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton); + + return; + } else{ + Log.d("GODOT", "NO DOWNLOAD REQUIRED"); + } + } catch (NameNotFoundException e) { + // TODO Auto-generated catch block + Log.d("GODOT", "Error downloading expansion package:" + e.getMessage()); + } } @@ -431,6 +537,7 @@ public class Godot extends Activity implements SensorEventListener } + @Override protected void onDestroy(){ if(mPaymentsManager != null ) mPaymentsManager.destroy(); @@ -442,8 +549,12 @@ public class Godot extends Activity implements SensorEventListener @Override protected void onPause() { super.onPause(); - if (!godot_initialized) + if (!godot_initialized){ + if (null != mDownloaderClientStub) { + mDownloaderClientStub.disconnect(this); + } return; + } mView.onPause(); mSensorManager.unregisterListener(this); GodotLib.focusout(); @@ -455,24 +566,73 @@ public class Godot extends Activity implements SensorEventListener @Override protected void onResume() { super.onResume(); - if (!godot_initialized) + if (!godot_initialized){ + if (null != mDownloaderClientStub) { + mDownloaderClientStub.connect(this); + } return; + } mView.onResume(); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); GodotLib.focusin(); + if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+ + Window window = getWindow(); + window.getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } for(int i=0;i<singleton_count;i++) { singletons[i].onMainResume(); } + + + + } + public void UiChangeListener() { + final View decorView = getWindow().getDecorView(); + decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() { + @Override + public void onSystemUiVisibilityChange(int visibility) { + if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + decorView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + } + }); } @Override public void onSensorChanged(SensorEvent event) { - float x = event.values[0]; - float y = event.values[1]; - float z = event.values[2]; + Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); + int displayRotation = display.getRotation(); + + float[] adjustedValues = new float[3]; + final int axisSwap[][] = { + { 1, -1, 0, 1 }, // ROTATION_0 + {-1, -1, 1, 0 }, // ROTATION_90 + {-1, 1, 0, 1 }, // ROTATION_180 + { 1, 1, 1, 0 } }; // ROTATION_270 + + final int[] as = axisSwap[displayRotation]; + adjustedValues[0] = (float)as[0] * event.values[ as[2] ]; + adjustedValues[1] = (float)as[1] * event.values[ as[3] ]; + adjustedValues[2] = event.values[2]; + + float x = adjustedValues[0]; + float y = adjustedValues[1]; + float z = adjustedValues[2]; GodotLib.accelerometer(x,y,z); } @@ -508,6 +668,54 @@ public class Godot extends Activity implements SensorEventListener } + + private boolean obbIsCorrupted(String f, String main_pack_md5){ + + try { + + InputStream fis = new FileInputStream(f); + + // Create MD5 Hash + byte[] buffer = new byte[16384]; + + MessageDigest complete = MessageDigest.getInstance("MD5"); + int numRead; + do { + numRead = fis.read(buffer); + if (numRead > 0) { + complete.update(buffer, 0, numRead); + } + } while (numRead != -1); + + + fis.close(); + byte[] messageDigest = complete.digest(); + + // Create Hex String + StringBuffer hexString = new StringBuffer(); + for (int i=0; i<messageDigest.length; i++) { + String s = Integer.toHexString(0xFF & messageDigest[i]); + + if (s.length()==1) { + s="0"+s; + } + hexString.append(s); + } + String md5str = hexString.toString(); + + //Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5); + if (!md5str.equals(main_pack_md5)) { + Log.d("GODOT","**PACK MD5 MISMATCH???** - MD5 Found: "+md5str+" "+Integer.toString(md5str.length())+" - MD5 Expected: "+main_pack_md5+" "+Integer.toString(main_pack_md5.length())); + return true; + } + return false; + } catch (Exception e) { + e.printStackTrace(); + Log.d("GODOT","**PACK FAIL**"); + return true; + } + } + //@Override public boolean dispatchTouchEvent (MotionEvent event) { public boolean gotTouchEvent(MotionEvent event) { @@ -539,7 +747,8 @@ public class Godot extends Activity implements SensorEventListener //} } break; case MotionEvent.ACTION_POINTER_UP: { - int pointer_idx = event.getActionIndex(); + final int indexPointUp = event.getActionIndex(); + final int pointer_idx = event.getPointerId(indexPointUp); GodotLib.touch(4,pointer_idx,evcount,arr); //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx)); } break; @@ -602,5 +811,115 @@ public class Godot extends Activity implements SensorEventListener // Audio - + /** + * The download state should trigger changes in the UI --- it may be useful + * to show the state as being indeterminate at times. This sample can be + * considered a guideline. + */ + @Override + public void onDownloadStateChanged(int newState) { + Log.d("GODOT", "onDownloadStateChanged:" + newState); + setState(newState); + boolean showDashboard = true; + boolean showCellMessage = false; + boolean paused; + boolean indeterminate; + switch (newState) { + case IDownloaderClient.STATE_IDLE: + Log.d("GODOT", "STATE IDLE"); + // STATE_IDLE means the service is listening, so it's + // safe to start making calls via mRemoteService. + paused = false; + indeterminate = true; + break; + case IDownloaderClient.STATE_CONNECTING: + case IDownloaderClient.STATE_FETCHING_URL: + Log.d("GODOT", "STATE CONNECTION / FETCHING URL"); + showDashboard = true; + paused = false; + indeterminate = true; + break; + case IDownloaderClient.STATE_DOWNLOADING: + Log.d("GODOT", "STATE DOWNLOADING"); + paused = false; + showDashboard = true; + indeterminate = false; + break; + + case IDownloaderClient.STATE_FAILED_CANCELED: + case IDownloaderClient.STATE_FAILED: + case IDownloaderClient.STATE_FAILED_FETCHING_URL: + case IDownloaderClient.STATE_FAILED_UNLICENSED: + Log.d("GODOT", "MANY TYPES OF FAILING"); + paused = true; + showDashboard = false; + indeterminate = false; + break; + case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION: + case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION: + Log.d("GODOT", "PAUSED FOR SOME STUPID REASON"); + showDashboard = false; + paused = true; + indeterminate = false; + showCellMessage = true; + break; + + case IDownloaderClient.STATE_PAUSED_BY_REQUEST: + Log.d("GODOT", "PAUSED BY STUPID USER"); + paused = true; + indeterminate = false; + break; + case IDownloaderClient.STATE_PAUSED_ROAMING: + case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE: + Log.d("GODOT", "PAUSED BY ROAMING WTF!?"); + paused = true; + indeterminate = false; + break; + case IDownloaderClient.STATE_COMPLETED: + Log.d("GODOT", "COMPLETED"); + showDashboard = false; + paused = false; + indeterminate = false; +// validateXAPKZipFiles(); + initializeGodot(); + return; + default: + Log.d("GODOT", "DEFAULT ????"); + paused = true; + indeterminate = true; + showDashboard = true; + } + int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE; + if (mDashboard.getVisibility() != newDashboardVisibility) { + mDashboard.setVisibility(newDashboardVisibility); + } + int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE; + if (mCellMessage.getVisibility() != cellMessageVisibility) { + mCellMessage.setVisibility(cellMessageVisibility); + } + + mPB.setIndeterminate(indeterminate); + setButtonPausedState(paused); + } + + + @Override + public void onDownloadProgress(DownloadProgressInfo progress) { + mAverageSpeed.setText(getString(com.godot.game.R.string.kilobytes_per_second, + Helpers.getSpeedString(progress.mCurrentSpeed))); + mTimeRemaining.setText(getString(com.godot.game.R.string.time_remaining, + Helpers.getTimeRemaining(progress.mTimeRemaining))); + + progress.mOverallTotal = progress.mOverallTotal; + mPB.setMax((int) (progress.mOverallTotal >> 8)); + mPB.setProgress((int) (progress.mOverallProgress >> 8)); + mProgressPercent.setText(Long.toString(progress.mOverallProgress + * 100 / + progress.mOverallTotal) + "%"); + mProgressFraction.setText(Helpers.getDownloadProgressString + (progress.mOverallProgress, + progress.mOverallTotal)); + + } + } diff --git a/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java index d945a8b192..e82c3eb0fe 100644 --- a/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java +++ b/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java @@ -6,6 +6,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; +import android.util.Log; /** * You should start your derived downloader class when this receiver gets the message @@ -18,10 +19,12 @@ public class GodotDownloaderAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + Log.d("GODOT", "Alarma recivida"); try { DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, GodotDownloaderService.class); } catch (NameNotFoundException e) { e.printStackTrace(); + Log.d("GODOT", "Exception: " + e.getClass().getName() + ":" + e.getMessage()); } } } diff --git a/platform/android/java/src/com/android/godot/GodotDownloaderService.java b/platform/android/java/src/com/android/godot/GodotDownloaderService.java index e0fe95ad96..2657edc1d2 100644 --- a/platform/android/java/src/com/android/godot/GodotDownloaderService.java +++ b/platform/android/java/src/com/android/godot/GodotDownloaderService.java @@ -1,5 +1,9 @@ package com.android.godot; +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + import com.google.android.vending.expansion.downloader.impl.DownloaderService; /** @@ -21,7 +25,11 @@ public class GodotDownloaderService extends DownloaderService { */ @Override public String getPublicKey() { - return BASE64_PUBLIC_KEY; + SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE); + Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null)); + return prefs.getString("store_public_key", null); + +// return BASE64_PUBLIC_KEY; } /** @@ -41,7 +49,8 @@ public class GodotDownloaderService extends DownloaderService { */ @Override public String getAlarmReceiverClassName() { - return GodotDownloaderAlarmReceiver.class.getName(); + Log.d("GODOT", "getAlarmReceiverClassName()"); + return GodotDownloaderAlarmReceiver.class.getName(); } } diff --git a/platform/android/java/src/com/android/godot/GodotIO.java b/platform/android/java/src/com/android/godot/GodotIO.java index fad489721c..a7dc0c2f75 100644 --- a/platform/android/java/src/com/android/godot/GodotIO.java +++ b/platform/android/java/src/com/android/godot/GodotIO.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -94,6 +94,7 @@ public class GodotIO { //System.out.printf("file_open: Attempt to Open %s\n",path); + //Log.v("MyApp", "TRYING TO OPEN FILE: " + path); if (write) return -1; @@ -105,7 +106,7 @@ public class GodotIO { } catch (Exception e) { - //System.out.printf("Exception on file_open: %s\n",e); + //System.out.printf("Exception on file_open: %s\n",path); return -1; } @@ -113,7 +114,7 @@ public class GodotIO { ad.len=ad.is.available(); } catch (Exception e) { - System.out.printf("Exception availabling on file_open: %s\n",e); + System.out.printf("Exception availabling on file_open: %s\n",path); return -1; } @@ -271,6 +272,7 @@ public class GodotIO { public String[] files; public int current; + public String path; } public int last_dir_id=1; @@ -281,6 +283,7 @@ public class GodotIO { AssetDir ad = new AssetDir(); ad.current=0; + ad.path=path; try { ad.files = am.list(path); @@ -290,6 +293,7 @@ public class GodotIO { return -1; } + //System.out.printf("Opened dir: %s\n",path); ++last_dir_id; dirs.put(last_dir_id,ad); @@ -297,6 +301,32 @@ public class GodotIO { } + public boolean dir_is_dir(int id) { + if (!dirs.containsKey(id)) { + System.out.printf("dir_next: invalid dir id: %d\n",id); + return false; + } + AssetDir ad = dirs.get(id); + //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); + int idx = ad.current; + if (idx>0) + idx--; + + if (idx>=ad.files.length) + return false; + String fname = ad.files[idx]; + + try { + if (ad.path.equals("")) + am.open(fname); + else + am.open(ad.path+"/"+fname); + return false; + } catch (Exception e) { + return true; + } + } + public String dir_next(int id) { if (!dirs.containsKey(id)) { @@ -305,8 +335,12 @@ public class GodotIO { } AssetDir ad = dirs.get(id); - if (ad.current>=ad.files.length) + //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); + + if (ad.current>=ad.files.length) { + ad.current++; return ""; + } String r = ad.files[ad.current]; ad.current++; return r; @@ -438,8 +472,26 @@ public class GodotIO { try { Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri); - Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(p_uri)); - activity.startActivity(myIntent); + String path = p_uri; + String type=""; + if (path.startsWith("/")) { + //absolute path to filesystem, prepend file:// + path="file://"+path; + if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) { + + type="image/*"; + } + } + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + if (!type.equals("")) { + intent.setDataAndType(Uri.parse(path), type); + } else { + intent.setData(Uri.parse(path)); + } + + activity.startActivity(intent); return 0; } catch (ActivityNotFoundException e) { @@ -557,6 +609,58 @@ public class GodotIO { } } + + public static final int SYSTEM_DIR_DESKTOP=0; + public static final int SYSTEM_DIR_DCIM=1; + public static final int SYSTEM_DIR_DOCUMENTS=2; + public static final int SYSTEM_DIR_DOWNLOADS=3; + public static final int SYSTEM_DIR_MOVIES=4; + public static final int SYSTEM_DIR_MUSIC=5; + public static final int SYSTEM_DIR_PICTURES=6; + public static final int SYSTEM_DIR_RINGTONES=7; + + + public String getSystemDir(int idx) { + + String what=""; + switch(idx) { + case SYSTEM_DIR_DESKTOP: { + //what=Environment.DIRECTORY_DOCUMENTS; + what=Environment.DIRECTORY_DOWNLOADS; + } break; + case SYSTEM_DIR_DCIM: { + what=Environment.DIRECTORY_DCIM; + + } break; + case SYSTEM_DIR_DOCUMENTS: { + what=Environment.DIRECTORY_DOWNLOADS; + //what=Environment.DIRECTORY_DOCUMENTS; + } break; + case SYSTEM_DIR_DOWNLOADS: { + what=Environment.DIRECTORY_DOWNLOADS; + + } break; + case SYSTEM_DIR_MOVIES: { + what=Environment.DIRECTORY_MOVIES; + + } break; + case SYSTEM_DIR_MUSIC: { + what=Environment.DIRECTORY_MUSIC; + } break; + case SYSTEM_DIR_PICTURES: { + what=Environment.DIRECTORY_PICTURES; + } break; + case SYSTEM_DIR_RINGTONES: { + what=Environment.DIRECTORY_RINGTONES; + + } break; + } + + if (what.equals("")) + return ""; + return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath(); + } + protected static final String PREFS_FILE = "device_id.xml"; protected static final String PREFS_DEVICE_ID = "device_id"; diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java index 6e2462b4f1..3d870b3b1f 100644 --- a/platform/android/java/src/com/android/godot/GodotLib.java +++ b/platform/android/java/src/com/android/godot/GodotLib.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,9 +44,9 @@ public class GodotLib { * @param height the current view height */ - public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline); + public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline,Object p_asset_manager); public static native void resize(int width, int height,boolean reload); - public static native void newcontext(); + public static native void newcontext(boolean p_32_bits); public static native void quit(); public static native void step(); public static native void touch(int what,int pointer,int howmany, int[] arr); diff --git a/platform/android/java/src/com/android/godot/GodotPaymentV3.java b/platform/android/java/src/com/android/godot/GodotPaymentV3.java index dba4a9a774..0799e1e83d 100644 --- a/platform/android/java/src/com/android/godot/GodotPaymentV3.java +++ b/platform/android/java/src/com/android/godot/GodotPaymentV3.java @@ -1,8 +1,6 @@ package com.android.godot; - -import org.json.JSONObject; - +import com.android.godot.Dictionary; import android.app.Activity; import android.util.Log; @@ -29,7 +27,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase { activity.getPaymentsManager().requestPurchase(sku, transactionId); } }); - }; + } /* public string requestPurchasedTicket(){ activity.getPaymentsManager() @@ -44,10 +42,19 @@ public class GodotPaymentV3 extends Godot.SingletonBase { public GodotPaymentV3(Activity p_activity) { - registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature"}); + registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume"}); activity=(Godot) p_activity; } + public void consumeUnconsumedPurchases(){ + activity.getPaymentsManager().setBaseSingleton(this); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getPaymentsManager().consumeUnconsumedPurchases(); + } + }); + } private String signature; public String getSignature(){ @@ -55,15 +62,26 @@ public class GodotPaymentV3 extends Godot.SingletonBase { } - public void callbackSuccess(String ticket, String signature){ - Log.d(this.getClass().getName(), "PRE-Send callback to purchase success"); - GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature}); - Log.d(this.getClass().getName(), "POST-Send callback to purchase success"); + public void callbackSuccess(String ticket, String signature, String sku){ +// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success"); + GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku}); +// Log.d(this.getClass().getName(), "POST-Send callback to purchase success"); +} + + public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){ +// Log.d(this.getClass().getName(), "PRE-Send callback to consume success"); + Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > "+ticket+","+signature+","+sku); + GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku}); +// Log.d(this.getClass().getName(), "POST-Send callback to consume success"); + } + + public void callbackSuccessNoUnconsumedPurchases(){ + GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{}); } public void callbackFail(){ - GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{}); -// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{}); + GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{}); +// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{}); } public void callbackCancel(){ @@ -71,6 +89,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase { // GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{}); } + public void callbackAlreadyOwned(String sku){ + GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku}); + } + public int getPurchaseCallbackId() { return purchaseCallbackId; } @@ -79,8 +101,6 @@ public class GodotPaymentV3 extends Godot.SingletonBase { this.purchaseCallbackId = purchaseCallbackId; } - - public String getPurchaseValidationUrlPrefix(){ return this.purchaseValidationUrlPrefix ; } @@ -89,12 +109,10 @@ public class GodotPaymentV3 extends Godot.SingletonBase { this.purchaseValidationUrlPrefix = url; } - public String getAccessToken() { return accessToken; } - public void setAccessToken(String accessToken) { this.accessToken = accessToken; } @@ -107,4 +125,30 @@ public class GodotPaymentV3 extends Godot.SingletonBase { return this.transactionId; } + // request purchased items are not consumed + public void requestPurchased(){ + activity.getPaymentsManager().setBaseSingleton(this); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getPaymentsManager().requestPurchased(); + } + }); + } + + // callback for requestPurchased() + public void callbackPurchased(String receipt, String signature, String sku){ + GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku}); + } + + // consume item automatically after purchase. default is true. + public void setAutoConsume(boolean autoConsume){ + activity.getPaymentsManager().setAutoConsume(autoConsume); + } + + // consume a specific item + public void consume(String sku){ + activity.getPaymentsManager().consume(sku); + } } + diff --git a/platform/android/java/src/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java index f62431b94b..bc249d46c6 100644 --- a/platform/android/java/src/com/android/godot/GodotView.java +++ b/platform/android/java/src/com/android/godot/GodotView.java @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -71,14 +71,16 @@ public class GodotView extends GLSurfaceView { private static GodotIO io; private static boolean firsttime=true; private static boolean use_gl2=false; + private static boolean use_32=false; private Godot activity; - public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, Godot p_activity) { + public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, boolean p_use_32_bits, Godot p_activity) { super(context); ctx=context; io=p_io; use_gl2=p_use_gl2; + use_32=p_use_32_bits; activity = p_activity; @@ -366,9 +368,17 @@ public class GodotView extends GLSurfaceView { * custom config chooser. See ConfigChooser class definition * below. */ - setEGLConfigChooser( translucent ? - new ConfigChooser(8, 8, 8, 8, depth, stencil) : - new ConfigChooser(5, 6, 5, 0, depth, stencil) ); + + if (use_32) { + setEGLConfigChooser( translucent ? + new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(8, 8, 8, 8, 16, stencil)) : + new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(5, 6, 5, 0, 16, stencil)) ); + + } else { + setEGLConfigChooser( translucent ? + new ConfigChooser(8, 8, 8, 8, 16, stencil) : + new ConfigChooser(5, 6, 5, 0, 16, stencil) ); + } /* Set the renderer responsible for frame rendering */ setRenderer(new Renderer()); @@ -400,6 +410,26 @@ public class GodotView extends GLSurfaceView { Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); } } + /* Fallback if 32bit View is not supported*/ + private static class FallbackConfigChooser extends ConfigChooser { + private ConfigChooser fallback; + + public FallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, ConfigChooser fallback) { + super(r, g, b, a, depth, stencil); + this.fallback = fallback; + } + + @Override + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { + EGLConfig ec = super.chooseConfig(egl, display, configs); + if (ec == null) { + Log.w(TAG, "Trying ConfigChooser fallback"); + ec = fallback.chooseConfig(egl, display, configs); + use_32=false; + } + return ec; + } + } private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { @@ -625,7 +655,7 @@ public class GodotView extends GLSurfaceView { } public void onSurfaceCreated(GL10 gl, EGLConfig config) { - GodotLib.newcontext(); + GodotLib.newcontext(use_32); } } } diff --git a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java new file mode 100644 index 0000000000..d68f029246 --- /dev/null +++ b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java @@ -0,0 +1,53 @@ +package com.android.godot.payments; + +import com.android.vending.billing.IInAppBillingService; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.RemoteException; +import android.util.Log; + +abstract public class GenericConsumeTask extends AsyncTask<String, String, String>{ + + private Context context; + private IInAppBillingService mService; + + + + + public GenericConsumeTask(Context context, IInAppBillingService mService, String sku, String receipt, String signature, String token){ + this.context = context; + this.mService = mService; + this.sku = sku; + this.receipt = receipt; + this.signature = signature; + this.token = token; + } + + private String sku; + private String receipt; + private String signature; + private String token; + + @Override + protected String doInBackground(String... params) { + try { +// Log.d("godot", "Requesting to consume an item with token ." + token); + int response = mService.consumePurchase(3, context.getPackageName(), token); +// Log.d("godot", "consumePurchase response: " + response); + if(response == 0 || response == 8){ + return null; + } + } catch (Exception e) { + Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage()); + } + return null; + } + + protected void onPostExecute(String sarasa){ + onSuccess(sku, receipt, signature, token); + } + + abstract public void onSuccess(String sku, String receipt, String signature, String token); + +} diff --git a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java index a810ac40ae..4c31704cc8 100644 --- a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java +++ b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java @@ -28,19 +28,19 @@ abstract public class HandlePurchaseTask { public void handlePurchaseRequest(int resultCode, Intent data){ - Log.d("XXX", "Handling purchase response"); +// Log.d("XXX", "Handling purchase response"); // int responseCode = data.getIntExtra("RESPONSE_CODE", 0); PaymentsCache pc = new PaymentsCache(context); String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); - Log.d("XXX", "Purchase data:" + purchaseData); +// Log.d("XXX", "Purchase data:" + purchaseData); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); - Log.d("XXX", "Purchase signature:" + dataSignature); + //Log.d("XXX", "Purchase signature:" + dataSignature); if (resultCode == Activity.RESULT_OK) { try { - Log.d("SARLANGA", purchaseData); +// Log.d("SARLANGA", purchaseData); JSONObject jo = new JSONObject(purchaseData); @@ -58,13 +58,13 @@ abstract public class HandlePurchaseTask { error("Untrusted callback"); return; } - Log.d("XXX", "Este es el product ID:" + productId); +// Log.d("XXX", "Este es el product ID:" + productId); pc.setConsumableValue("ticket_signautre", productId, dataSignature); pc.setConsumableValue("ticket", productId, purchaseData); pc.setConsumableFlag("block", productId, true); pc.setConsumableValue("token", productId, purchaseToken); - success(productId, dataSignature); + success(productId, dataSignature, purchaseData); return; } catch (JSONException e) { error(e.getMessage()); @@ -74,7 +74,7 @@ abstract public class HandlePurchaseTask { } } - abstract protected void success(String ticket, String signature); + abstract protected void success(String sku, String signature, String ticket); abstract protected void error(String message); abstract protected void canceled(); diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java index 7337acc0b8..1de772bf28 100644 --- a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java +++ b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java @@ -31,14 +31,14 @@ public class PaymentsCache { SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(sku, value); - Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); +// Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); editor.commit(); } public String getConsumableValue(String set, String sku){ SharedPreferences sharedPref = context.getSharedPreferences( "consumables_" + set, Context.MODE_PRIVATE); - Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); +// Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); return sharedPref.getString(sku, null); } diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java index d85a8ea8ea..189f7108c1 100644 --- a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java @@ -1,5 +1,9 @@ package com.android.godot.payments; +import java.util.ArrayList; +import java.util.List; + +import android.os.RemoteException; import android.app.Activity; import android.content.ComponentName; import android.content.Context; @@ -7,7 +11,13 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.util.Log; +import android.os.Bundle; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; +import com.android.godot.Dictionary; import com.android.godot.Godot; import com.android.godot.GodotPaymentV3; import com.android.vending.billing.IInAppBillingService; @@ -15,15 +25,12 @@ import com.android.vending.billing.IInAppBillingService; public class PaymentsManager { public static final int BILLING_RESPONSE_RESULT_OK = 0; - - public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001; - + private static boolean auto_consume = true; private Activity activity; IInAppBillingService mService; - public void setActivity(Activity activity){ this.activity = activity; } @@ -38,8 +45,10 @@ public class PaymentsManager { } public PaymentsManager initService(){ + Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); + intent.setPackage("com.android.vending"); activity.bindService( - new Intent("com.android.vending.billing.InAppBillingService.BIND"), + intent, mServiceConn, Context.BIND_AUTO_CREATE); return this; @@ -58,13 +67,12 @@ public class PaymentsManager { } @Override - public void onServiceConnected(ComponentName name, - IBinder service) { - mService = IInAppBillingService.Stub.asInterface(service); + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IInAppBillingService.Stub.asInterface(service); } }; - public void requestPurchase(String sku, String transactionId){ + public void requestPurchase(final String sku, String transactionId){ new PurchaseTask(mService, Godot.getInstance()) { @Override @@ -77,33 +85,116 @@ public class PaymentsManager { protected void canceled() { godotPaymentV3.callbackCancel(); } + + @Override + protected void alreadyOwned() { + godotPaymentV3.callbackAlreadyOwned(sku); + } + }.purchase(sku, transactionId); } + public void consumeUnconsumedPurchases(){ + new ReleaseAllConsumablesTask(mService, activity) { + + @Override + protected void success(String sku, String receipt, String signature, String token) { + godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku); + } + + @Override + protected void error(String message) { + godotPaymentV3.callbackFail(); + + } + + @Override + protected void notRequired() { + godotPaymentV3.callbackSuccessNoUnconsumedPurchases(); + + } + }.consumeItAll(); + } + + public void requestPurchased(){ + try{ + PaymentsCache pc = new PaymentsCache(Godot.getInstance()); + +// Log.d("godot", "requestPurchased for " + activity.getPackageName()); + Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp",null); + +/* + for (String key : bundle.keySet()) { + Object value = bundle.get(key); + Log.d("godot", String.format("%s %s (%s)", key, value.toString(), value.getClass().getName())); + } +*/ + + if (bundle.getInt("RESPONSE_CODE") == 0){ + + final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); + final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); + + + if (myPurchases == null || myPurchases.size() == 0){ +// Log.d("godot", "No purchases!"); + godotPaymentV3.callbackPurchased("", "", ""); + return; + } + +// Log.d("godot", "# products are purchased:" + myPurchases.size()); + for (int i=0;i<myPurchases.size();i++) + { + + try{ + String receipt = myPurchases.get(i); + JSONObject inappPurchaseData = new JSONObject(receipt); + String sku = inappPurchaseData.getString("productId"); + String token = inappPurchaseData.getString("purchaseToken"); + String signature = mySignatures.get(i); +// Log.d("godot", "purchased item:" + token + "\n" + receipt); + + pc.setConsumableValue("ticket_signautre", sku, signature); + pc.setConsumableValue("ticket", sku, receipt); + pc.setConsumableFlag("block", sku, true); + pc.setConsumableValue("token", sku, token); + + godotPaymentV3.callbackPurchased(receipt, signature, sku); + } catch (JSONException e) { + } + } + + } + }catch(Exception e){ + Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage()); + } + } + public void processPurchaseResponse(int resultCode, Intent data) { new HandlePurchaseTask(activity){ @Override - protected void success(final String sku, final String signature) { - new ConsumeTask(mService, activity) { + protected void success(final String sku, final String signature, final String ticket) { + godotPaymentV3.callbackSuccess(ticket, signature, sku); + + if (auto_consume){ + new ConsumeTask(mService, activity) { - @Override - protected void success(String ticket) { -// godotPaymentV3.callbackSuccess(""); - Log.d("XXX", "calling success:" + signature); - godotPaymentV3.callbackSuccess(ticket, signature); - } + @Override + protected void success(String ticket) { +// godotPaymentV3.callbackSuccess(""); + } - @Override - protected void error(String message) { - godotPaymentV3.callbackFail(); + @Override + protected void error(String message) { + godotPaymentV3.callbackFail(); - } - }.consume(sku); - - + } + }.consume(sku); + } +// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature); // godotPaymentV3.callbackSuccess(ticket); //validatePurchase(purchaseToken, sku); } @@ -119,7 +210,7 @@ public class PaymentsManager { godotPaymentV3.callbackCancel(); } - }.handlePurchaseRequest(resultCode, data); + }.handlePurchaseRequest(resultCode, data); } public void validatePurchase(String purchaseToken, final String sku){ @@ -133,7 +224,7 @@ public class PaymentsManager { @Override protected void success(String ticket) { - godotPaymentV3.callbackSuccess(ticket, null); + godotPaymentV3.callbackSuccess(ticket, null, sku); } @@ -160,11 +251,32 @@ public class PaymentsManager { }.validatePurchase(sku); } + public void setAutoConsume(boolean autoConsume){ + auto_consume = autoConsume; + } + + public void consume(final String sku){ + new ConsumeTask(mService, activity) { + + @Override + protected void success(String ticket) { + godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku); + + } + + @Override + protected void error(String message) { + godotPaymentV3.callbackFail(); + + } + }.consume(sku); + } + private GodotPaymentV3 godotPaymentV3; public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) { this.godotPaymentV3 = godotPaymentV3; - } + } diff --git a/platform/android/java/src/com/android/godot/payments/PurchaseTask.java b/platform/android/java/src/com/android/godot/payments/PurchaseTask.java index 0856b4e900..c1f9d164a1 100644 --- a/platform/android/java/src/com/android/godot/payments/PurchaseTask.java +++ b/platform/android/java/src/com/android/godot/payments/PurchaseTask.java @@ -62,33 +62,13 @@ abstract public class PurchaseTask { // Log.d("XXX", "Buy intent response code: " + responseCode); if(responseCode == 1 || responseCode == 3 || responseCode == 4){ canceled(); - return ; + return; } if(responseCode == 7){ - new ConsumeTask(mService, context) { - - @Override - protected void success(String ticket) { -// Log.d("XXX", "Product was erroniously purchased!"); - if(isLooping){ -// Log.d("XXX", "It is looping"); - error("Error while purchasing product"); - return; - } - isLooping=true; - PurchaseTask.this.purchase(sku, transactionId); - - } - - @Override - protected void error(String message) { - PurchaseTask.this.error(message); - - } - }.consume(sku); + alreadyOwned(); return; } - + PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); pc.setConsumableValue("validation_hash", sku, hash); @@ -116,6 +96,6 @@ abstract public class PurchaseTask { abstract protected void error(String message); abstract protected void canceled(); - + abstract protected void alreadyOwned(); } diff --git a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java new file mode 100644 index 0000000000..c1a9c5d421 --- /dev/null +++ b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java @@ -0,0 +1,87 @@ +package com.android.godot.payments; + +import java.util.ArrayList; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.android.godot.Dictionary; +import com.android.godot.Godot; +import com.android.vending.billing.IInAppBillingService; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; + +abstract public class ReleaseAllConsumablesTask { + + private Context context; + private IInAppBillingService mService; + + public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context ){ + this.context = context; + this.mService = mService; + } + + + public void consumeItAll(){ + try{ +// Log.d("godot", "consumeItall for " + context.getPackageName()); + Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null); + + for (String key : bundle.keySet()) { + Object value = bundle.get(key); +// Log.d("godot", String.format("%s %s (%s)", key, +// value.toString(), value.getClass().getName())); + } + + + if (bundle.getInt("RESPONSE_CODE") == 0){ + + final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); + final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); + + + if (myPurchases == null || myPurchases.size() == 0){ +// Log.d("godot", "No purchases!"); + notRequired(); + return; + } + + +// Log.d("godot", "# products to be consumed:" + myPurchases.size()); + for (int i=0;i<myPurchases.size();i++) + { + + try{ + String receipt = myPurchases.get(i); + JSONObject inappPurchaseData = new JSONObject(receipt); + String sku = inappPurchaseData.getString("productId"); + String token = inappPurchaseData.getString("purchaseToken"); + String signature = mySignatures.get(i); +// Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); + new GenericConsumeTask(context, mService, sku, receipt,signature, token) { + + @Override + public void onSuccess(String sku, String receipt, String signature, String token) { + ReleaseAllConsumablesTask.this.success(sku, receipt, signature, token); + } + }.execute(); + + } catch (JSONException e) { + } + } + + } + }catch(Exception e){ + Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage()); + } + } + + abstract protected void success(String sku, String receipt, String signature, String token); + abstract protected void error(String message); + abstract protected void notRequired(); + +} |