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; } }
/** This method is called by SDL using JNI. */ public InputStream openAPKExtensionInputStream(String fileName) throws IOException { // Get a ZipResourceFile representing a merger of both the main and patch files if (expansionFile == null) { Integer mainVersion = Integer.valueOf(nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION")); Integer patchVersion = Integer.valueOf(nativeGetHint("SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION")); try { // To avoid direct dependency on Google APK extension library that is // not a part of Android SDK we access it using reflection expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport") .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class) .invoke(null, this, mainVersion, patchVersion); expansionFileMethod = expansionFile.getClass().getMethod("getInputStream", String.class); } catch (Exception ex) { ex.printStackTrace(); expansionFile = null; expansionFileMethod = null; } } // Get an input stream for a known file inside the expansion file ZIPs InputStream fileStream; try { fileStream = (InputStream) expansionFileMethod.invoke(expansionFile, fileName); } catch (Exception ex) { ex.printStackTrace(); fileStream = null; } if (fileStream == null) { throw new IOException(); } return fileStream; }
private String[] getCommandLine() { InputStream is; try { is = getAssets().open("_cl_"); byte[] len = new byte[4]; int r = is.read(len); if (r < 4) { Log.d("XXX", "**ERROR** Wrong cmdline length.\n"); Log.d("GODOT", "**ERROR** Wrong cmdline length.\n"); return new String[0]; } int argc = ((int) (len[3] & 0xFF) << 24) | ((int) (len[2] & 0xFF) << 16) | ((int) (len[1] & 0xFF) << 8) | ((int) (len[0] & 0xFF)); String[] cmdline = new String[argc]; for (int i = 0; i < argc; i++) { r = is.read(len); if (r < 4) { Log.d("GODOT", "**ERROR** Wrong cmdline param lenght.\n"); return new String[0]; } int strlen = ((int) (len[3] & 0xFF) << 24) | ((int) (len[2] & 0xFF) << 16) | ((int) (len[1] & 0xFF) << 8) | ((int) (len[0] & 0xFF)); if (strlen > 65535) { Log.d("GODOT", "**ERROR** Wrong command len\n"); return new String[0]; } byte[] arg = new byte[strlen]; r = is.read(arg); if (r == strlen) { cmdline[i] = new String(arg, "UTF-8"); } } return cmdline; } catch (Exception e) { e.printStackTrace(); Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage()); return new String[0]; } }
@Override protected void onCreate(Bundle icicle) { Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n"); super.onCreate(icicle); _self = this; Window window = getWindow(); window.addFlags( WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // check for apk expansion API if (true) { boolean md5mismatch = false; command_line = getCommandLine(); boolean use_apk_expansion = false; String main_pack_md5 = null; String main_pack_key = null; List<String> new_args = new LinkedList<String>(); 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")) { 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()) { command_line = null; } 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)) { Log.d("GODOT", "**ERROR! No media mounted!"); // show popup and die } // Build the full path to the app's expansion files try { expansion_pack_path = Environment.getExternalStorageDirectory().toString() + "/Android/obb/" + this.getPackageName(); expansion_pack_path += "/" + "main." + getPackageManager().getPackageInfo(getPackageName(), 0).versionCode + "." + this.getPackageName() + ".obb"; } catch (Exception e) { e.printStackTrace(); } File f = new File(expansion_pack_path); boolean pack_valid = true; Log.d("GODOT", "**PACK** - Path " + expansion_pack_path); if (!f.exists()) { pack_valid = false; Log.d("GODOT", "**PACK** - File does not exist"); } 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()); } } } } initializeGodot(); // instanceSingleton( new GodotFacebook(this) ); }