package com.mojang.minecraftpe;
import java.io.*;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.net.*;
import java.util.*;
import javax.net.ssl.*;
import java.lang.reflect.Field;
import android.annotation.SuppressLint;
import android.app.NativeActivity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface;
import android.content.pm.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.ColorDrawable;
import android.media.MediaScannerConnection;
import android.media.AudioManager;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.ClipboardManager;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.view.*;
import android.view.inputmethod.*;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.webkit.*;
import android.widget.*;
import org.mozilla.javascript.RhinoException;
import net.zhuoweizhang.mcpelauncher.*;
import static net.zhuoweizhang.mcpelauncher.Utils.isSafeMode;
import net.zhuoweizhang.mcpelauncher.patch.PatchUtils;
import net.zhuoweizhang.mcpelauncher.ui.AboutAppActivity;
import net.zhuoweizhang.mcpelauncher.ui.HoverCar;
import net.zhuoweizhang.mcpelauncher.ui.MainMenuOptionsActivity;
import net.zhuoweizhang.mcpelauncher.ui.ManagePatchesActivity;
import net.zhuoweizhang.mcpelauncher.ui.ManageScriptsActivity;
import net.zhuoweizhang.mcpelauncher.ui.NerdyStuffActivity;
import net.zhuoweizhang.mcpelauncher.ui.NoMinecraftActivity;
import net.zhuoweizhang.pokerface.PokerFace;
@SuppressLint("SdCardPath")
@SuppressWarnings("deprecation")
public class MainActivity extends NativeActivity {
public static final String TAG = "BlockLauncher/MainActivity";
public static final int INPUT_STATUS_IN_PROGRESS = -1;
public static final int INPUT_STATUS_OK = 1;
public static final int INPUT_STATUS_CANCELLED = 0;
public static final int DIALOG_CREATE_WORLD = 1;
public static final int DIALOG_SETTINGS = 3;
public static final int DIALOG_COPY_WORLD = 4;
public static final String MOJANG_ACCOUNT_LOGIN_URL = "https://account.mojang.com/m/login?app=mcpe";
/* private dialogs start here */
public static final int DIALOG_CRASH_SAFE_MODE = 0x1000;
public static final int DIALOG_RUNTIME_OPTIONS = 0x1001;
public static final int DIALOG_INVALID_PATCHES = 0x1002;
public static final int DIALOG_FIRST_LAUNCH = 0x1003;
public static final int DIALOG_VERSION_MISMATCH_SAFE_MODE = 0x1004;
public static final int DIALOG_NOT_SUPPORTED = 0x1005;
public static final int DIALOG_UPDATE_TEXTURE_PACK = 0x1006;
public static final int DIALOG_INSERT_TEXT = 0x1007;
public static final int DIALOG_MULTIPLAYER_DISABLE_SCRIPTS = 0x1008;
public static final int DIALOG_RUNTIME_OPTIONS_WITH_INSERT_TEXT = 0x1009;
public static final int DIALOG_SELINUX_BROKE_EVERYTHING = 0x1000 + 10;
protected DisplayMetrics displayMetrics;
protected TexturePack texturePack;
protected Context minecraftApkContext;
protected boolean fakePackage = false;
public static final String[] GAME_MODES = { "creative", "survival" };
private static String MC_NATIVE_LIBRARY_DIR = "/data/data/com.mojang.minecraftpe/lib/";
private static String MC_NATIVE_LIBRARY_LOCATION = "/data/data/com.mojang.minecraftpe/lib/libminecraftpe.so";
public static final String PT_PATCHES_DIR = "ptpatches";
protected int inputStatus = INPUT_STATUS_IN_PROGRESS;
protected String[] userInputStrings = null;
public static ByteBuffer minecraftLibBuffer;
public static boolean hasPrePatched = false;
public static boolean libLoaded = false;
public boolean forceFallback = false;
public boolean requiresGuiBlocksPatch = false;
private HoverCar hoverCar = null;
public static WeakReference<MainActivity> currentMainActivity = null;
public static Set<String> loadedAddons = new HashSet<String>();
public ApplicationInfo mcAppInfo;
public static List<String> failedPatches = new ArrayList<String>();
public List<TexturePack> textureOverrides = new ArrayList<TexturePack>();
public boolean minecraftApkForwardLocked = false;
public static boolean tempSafeMode = false;
public String session = "";
public String refreshToken = "";
private PackageInfo mcPkgInfo;
private WebView loginWebView;
private Dialog loginDialog;
private SparseArray<HurlRunner> requestMap = new SparseArray<HurlRunner>();
protected MinecraftVersion minecraftVersion;
private boolean overlyZealousSELinuxSafeMode = false;
private PopupWindow hiddenTextWindow;
private TextView hiddenTextView;
private boolean hiddenTextDismissAfterOneLine = false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
File lockFile = new File(getFilesDir(), "running.lock");
if (lockFile.exists()) {
Utils.getPrefs(0).edit().putBoolean("zz_safe_mode", true).apply();
}
try {
lockFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
MinecraftVersion.context = this.getApplicationContext();
try {
mcPkgInfo = getPackageManager().getPackageInfo("com.mojang.minecraftpe", 0);
mcAppInfo = mcPkgInfo.applicationInfo;
MC_NATIVE_LIBRARY_DIR = mcAppInfo.nativeLibraryDir;
MC_NATIVE_LIBRARY_LOCATION = MC_NATIVE_LIBRARY_DIR + "/libminecraftpe.so";
System.out.println("libminecraftpe.so is at " + MC_NATIVE_LIBRARY_LOCATION);
minecraftApkForwardLocked = !mcAppInfo.sourceDir.equals(mcAppInfo.publicSourceDir);
int minecraftVersionCode = mcPkgInfo.versionCode;
minecraftVersion = MinecraftVersion.getRaw(minecraftVersionCode);
if (minecraftVersion == null) {
tempSafeMode = true;
showDialog(DIALOG_VERSION_MISMATCH_SAFE_MODE);
minecraftVersion = MinecraftVersion.getDefault();
}
if (minecraftVersion.needsWarning) {
Log.w(TAG, "OMG hipster version code found - breaking mod compat before it's cool");
}
net.zhuoweizhang.mcpelauncher.patch.PatchUtils.minecraftVersion = minecraftVersion;
migrateToPatchManager();
SharedPreferences myprefs = Utils.getPrefs(1);
int prepatchedVersionCode = myprefs.getInt("prepatch_version", -1);
if (prepatchedVersionCode != minecraftVersionCode) {
System.out.println("Version updated; forcing prepatch");
myprefs.edit().putBoolean("force_prepatch", true).apply();
disableAllPatches();
if (myprefs.getString("texturePack", "").indexOf("minecraft.apk") >= 0) {
showDialog(DIALOG_UPDATE_TEXTURE_PACK);
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
finish();
startActivity(new Intent(this, NoMinecraftActivity.class));
try {
Thread.sleep(100);
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Throwable t) {
}
return;
}
try {
if (this.getPackageName().equals("com.mojang.minecraftpe")) {
minecraftApkContext = this;
} else {
minecraftApkContext = createPackageContext("com.mojang.minecraftpe",
Context.CONTEXT_IGNORE_SECURITY);
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Can't create package context for the original APK",
Toast.LENGTH_LONG).show();
finish();
}
Utils.setLanguageOverride();
forceFallback = Utils.getPrefs(0).getBoolean("zz_texture_pack_demo", false);
loadTexturePack();
textureOverrides.clear();
textureOverrides.add(new SkinTextureOverride());
if (allowScriptOverrideTextures()) {
textureOverrides.add(new ScriptOverrideTexturePack(this));
}
ScriptTextureDownloader.attachCache(this);
requiresGuiBlocksPatch = doesRequireGuiBlocksPatch();
try {
if (!isSafeMode() && Utils.getPrefs(0).getBoolean("zz_manage_patches", true)) {
prePatch();
}
} catch (Exception e) {
e.printStackTrace();
// showDialog(DIALOG_UNABLE_TO_PATCH);
}
try {
System.load(MC_NATIVE_LIBRARY_LOCATION);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Can't load libminecraftpe.so from the original APK",
Toast.LENGTH_LONG).show();
finish();
}
libLoaded = true;
try {
if (!isSafeMode()) {
initPatching();
if (minecraftLibBuffer != null) {
ScriptManager.nativePrePatch();
}
}
} catch (Exception e) {
e.printStackTrace();
reportError(e);
}
displayMetrics = new DisplayMetrics();
setVolumeControlStream(AudioManager.STREAM_MUSIC);
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
addLibraryDirToPath(MC_NATIVE_LIBRARY_DIR);
setFakePackage(true);
super.onCreate(savedInstanceState);
nativeRegisterThis();
setFakePackage(false);
try {
boolean shouldLoadScripts = false;
if (!isSafeMode() && minecraftLibBuffer != null) {
loadNativeAddons();
applyBuiltinPatches();
if (Utils.getPrefs(0).getBoolean("zz_script_enable", true))
ScriptManager.init(this);
}
if (isSafeMode() || !shouldLoadScripts) {
ScriptManager.loadEnabledScriptsNames(this);
// in safe mode, script names, but not the actual scripts,
// should be loaded
}
} catch (Exception e) {
e.printStackTrace();
reportError(e);
}
enableSoftMenuKey();
java.net.CookieManager cookieManager = new java.net.CookieManager();
java.net.CookieHandler.setDefault(cookieManager);
if (isSafeMode()) {
if (overlyZealousSELinuxSafeMode) {
showDialog(DIALOG_SELINUX_BROKE_EVERYTHING);
} else {
showDialog(DIALOG_CRASH_SAFE_MODE);
}
}
System.gc();
currentMainActivity = new WeakReference<MainActivity>(this);
}
@Override
protected void onResume() {
super.onResume();
File lockFile = new File(getFilesDir(), "running.lock");
try {
lockFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
if (hoverCar == null) {
getWindow().getDecorView().post(new Runnable() {
public void run() {
try {
setupHoverCar();
} catch (Exception e) {
e.printStackTrace();
} // don't force close on hover car fail
}
});
} else {
hoverCar.setVisible(!Utils.getPrefs(0).getBoolean("zz_hovercar_hide", false));
}
}
@Override
protected void onPause() {
nativeSuspend();
super.onPause();
File lockFile = new File(getFilesDir(), "running.lock");
try {
lockFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
hideKeyboardView();
}
public void onDestroy() {
nativeUnregisterThis();
super.onDestroy();
File lockFile = new File(getFilesDir(), "running.lock");
if (lockFile.exists())
lockFile.delete();
if (hoverCar != null) {
hoverCar.dismiss();
hoverCar = null;
}
ScriptManager.destroy();
}
public void onStop() {
nativeStopThis();
super.onStop();
ScriptTextureDownloader.flushCache();
System.gc();
}
private void setFakePackage(boolean enable) {
fakePackage = enable;
}
@Override
public PackageManager getPackageManager() {
if (fakePackage) {
return new RedirectPackageManager(super.getPackageManager(), MC_NATIVE_LIBRARY_DIR);
}
return super.getPackageManager();
}
private void prePatch() throws Exception {
File patched = getDir("patched", 0);
File originalLibminecraft = new File(mcAppInfo.nativeLibraryDir + "/libminecraftpe.so");
File newMinecraft = new File(patched, "libminecraftpe.so");
boolean forcePrePatch = Utils.getPrefs(1).getBoolean("force_prepatch", true);
if (!hasPrePatched && (!newMinecraft.exists() || forcePrePatch)) {
System.out.println("Forcing new prepatch");
byte[] libBytes = new byte[(int) originalLibminecraft.length()];
ByteBuffer libBuffer = ByteBuffer.wrap(libBytes);
InputStream is = new FileInputStream(originalLibminecraft);
is.read(libBytes);
is.close();
int patchedCount = 0;
int maxPatchNum = getMaxNumPatches();
Set<String> patchLocs = Utils.getEnabledPatches();
for (String patchLoc : patchLocs) {
if (maxPatchNum >= 0 && patchedCount >= maxPatchNum)
break;
File patchFile = new File(patchLoc);
if (!patchFile.exists())
continue;
try {
com.joshuahuelsman.patchtool.PTPatch patch = new com.joshuahuelsman.patchtool.PTPatch();
patch.loadPatch(patchFile);
if (!patch.checkMagic()) {
failedPatches.add(patchFile.getName());
continue;
}
// patch.applyPatch(libBytes);
PatchUtils.patch(libBuffer, patch);
patchedCount++;
} catch (Exception e) {
e.printStackTrace();
failedPatches.add(patchFile.getName());
}
}
/*
* patchedCount = prePatchDir(libBytes, patchesDir, patchMgr,
* patchedCount, maxPatchNum); patchedCount = prePatchDir(libBytes,
* new File(Environment.getExternalStorageDirectory(),
* "Android/data/com.snowbound.pockettool.free/Patches"), patchMgr,
* patchedCount, maxPatchNum); patchedCount = prePatchDir(libBytes,
* new File(Environment.getExternalStorageDirectory(),
* "Android/data/com.snowbound.pockettool.free/Patches"), patchMgr,
* patchedCount, maxPatchNum);
*/
/* patching specific built-in patches */
if (requiresGuiBlocksPatch) {
System.out.println("Patching guiblocks");
com.joshuahuelsman.patchtool.PTPatch patch = new com.joshuahuelsman.patchtool.PTPatch();
if (minecraftVersion.guiBlocksPatch != null) {
patch.loadPatch(minecraftVersion.guiBlocksPatch);
// patch.applyPatch(libBytes);
PatchUtils.patch(libBuffer, patch);
} // TODO: load patches from assets
}
OutputStream os = new FileOutputStream(newMinecraft);
os.write(libBytes);
os.close();
hasPrePatched = true;
Utils.getPrefs(1).edit().putBoolean("force_prepatch", false)
.putInt("prepatch_version", mcPkgInfo.versionCode).apply();
if (failedPatches.size() > 0) {
showDialog(DIALOG_INVALID_PATCHES);
}
}
MC_NATIVE_LIBRARY_DIR = patched.getCanonicalPath();
MC_NATIVE_LIBRARY_LOCATION = newMinecraft.getCanonicalPath();
}
/*
* private int prePatchDir(byte[] libBytes, File patchesDir, PatchManager
* patchMgr, int patchedCount, int maxPatchNum) throws Exception { if
* (!patchesDir.exists()) return patchedCount; File[] patches =
* patchesDir.listFiles();
*
* for (File f: patches) { if (maxPatchNum >= 0 && patchedCount >=
* maxPatchNum) break; if (!patchMgr.isEnabled(f)) continue;
* com.joshuahuelsman.patchtool.PTPatch patch = new
* com.joshuahuelsman.patchtool.PTPatch(); patch.loadPatch(f);
* patch.applyPatch(libBytes); patchedCount++; } return patchedCount; }
*/
public native void nativeRegisterThis();
public native void nativeUnregisterThis();
// added in 0.7.0:
// sig changed in 0.7.3. :(
public native void nativeLoginData(String session, String param2, String refreshToken,
String user);
public native void nativeStopThis();
public native void nativeWebRequestCompleted(int requestId, long param2, int param3,
String param4);
// added in 0.7.2
public native void nativeTypeCharacter(String character);
// added in 0.8.0
public native void nativeSuspend();
public native void nativeSetTextboxText(String text);
public native void nativeBackPressed();
public native void nativeBackSpacePressed();
public native void nativeReturnKeyPressed();
public void buyGame() {
}
public int checkLicense() {
return 0;
}
/** displays a dialog. Not called from UI thread. */
public void displayDialog(int dialogId) {
System.out.println("displayDialog: " + dialogId);
inputStatus = INPUT_STATUS_CANCELLED;
switch (dialogId) {
case DIALOG_CREATE_WORLD:
System.out.println("World creation");
inputStatus = INPUT_STATUS_IN_PROGRESS;
runOnUiThread(new Runnable() {
public void run() {
showDialog(DIALOG_CREATE_WORLD);
}
});
break;
case DIALOG_SETTINGS:
System.out.println("Settings");
inputStatus = INPUT_STATUS_IN_PROGRESS;
Intent intent = getOptionsActivityIntent();
startActivityForResult(intent, 1234);
break;
case DIALOG_COPY_WORLD:
System.out.println("Copy world");
inputStatus = INPUT_STATUS_IN_PROGRESS;
runOnUiThread(new Runnable() {
public void run() {
showDialog(DIALOG_COPY_WORLD);
}
});
break;
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == 1234) {
inputStatus = INPUT_STATUS_OK;
System.out.println("Settings OK");
loadTexturePack();
if (!isSafeMode()) {
applyBuiltinPatches();
}
}
}
public Dialog onCreateDialog(int dialogId) {
switch (dialogId) {
case DIALOG_CREATE_WORLD:
return createCreateWorldDialog();
case DIALOG_COPY_WORLD:
return createCopyWorldDialog();
case DIALOG_CRASH_SAFE_MODE:
return createSafeModeDialog(R.string.manage_patches_crash_safe_mode);
case DIALOG_RUNTIME_OPTIONS:
return createRuntimeOptionsDialog(false);
case DIALOG_INVALID_PATCHES:
return createInvalidPatchesDialog();
case DIALOG_FIRST_LAUNCH:
return createFirstLaunchDialog();
case DIALOG_VERSION_MISMATCH_SAFE_MODE:
return createSafeModeDialog(R.string.version_mismatch_message);
case DIALOG_NOT_SUPPORTED:
return createNotSupportedDialog();
case DIALOG_UPDATE_TEXTURE_PACK:
return createUpdateTexturePackDialog();
case DIALOG_INSERT_TEXT:
return createInsertTextDialog();
case DIALOG_MULTIPLAYER_DISABLE_SCRIPTS:
return createMultiplayerDisableScriptsDialog();
case DIALOG_RUNTIME_OPTIONS_WITH_INSERT_TEXT:
return createRuntimeOptionsDialog(true);
case DIALOG_SELINUX_BROKE_EVERYTHING:
return createSELinuxBrokeEverythingDialog();
default:
return super.onCreateDialog(dialogId);
}
}
protected Dialog createCreateWorldDialog() {
final View textEntryView = getLayoutInflater().inflate(R.layout.create_world_dialog, null);
return new AlertDialog.Builder(this)
.setTitle(R.string.world_create_title)
.setView(textEntryView)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
AlertDialog dialog = (AlertDialog) dialogI;
String worldName = ((TextView) dialog.findViewById(R.id.world_name_entry))
.getText().toString();
String worldSeed = ((TextView) dialog.findViewById(R.id.world_seed_entry))
.getText().toString();
String worldGameMode = GAME_MODES[((Spinner) dialog
.findViewById(R.id.world_gamemode_spinner))
.getSelectedItemPosition()];
userInputStrings = new String[] { worldName, worldSeed, worldGameMode };
inputStatus = INPUT_STATUS_OK;
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
inputStatus = INPUT_STATUS_CANCELLED;
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialogI) {
inputStatus = INPUT_STATUS_CANCELLED;
}
}).create();
}
protected Dialog createSafeModeDialog(int messageRes) {
return new AlertDialog.Builder(this).setMessage(messageRes)
.setPositiveButton(R.string.safe_mode_exit, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
turnOffSafeMode();
}
}).setNegativeButton(R.string.safe_mode_continue, null).create();
}
protected Dialog createRuntimeOptionsDialog(final boolean hasInsertText) {
CharSequence livePatch = getResources().getString(R.string.hovercar_live_patch);
CharSequence optionMenu = getResources().getString(R.string.hovercar_options);
CharSequence insertText = getResources().getString(R.string.hovercar_insert_text);
CharSequence manageModPEScripts = getResources().getString(R.string.pref_zz_manage_scripts);
CharSequence takeScreenshot = getResources().getString(R.string.take_screenshot);
CharSequence[] options = null;
if (hasInsertText) {
options = new CharSequence[] { livePatch, manageModPEScripts, takeScreenshot,
optionMenu, insertText };
} else {
options = new CharSequence[] { livePatch, manageModPEScripts, takeScreenshot,
optionMenu };
}
return new AlertDialog.Builder(this).setTitle(R.string.app_name)
.setItems(options, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
if (button == 0) {
if (minecraftLibBuffer == null) {
startActivity(getOptionsActivityIntent());
return;
}
Intent intent = new Intent(MainActivity.this,
ManagePatchesActivity.class);
intent.putExtra("prePatchConfigure", false);
startActivity(intent);
} else if (button == 1) {
Intent intent = new Intent(MainActivity.this,
ManageScriptsActivity.class);
startActivity(intent);
} else if (button == 2) {
boolean hasLoadedScripts = Utils.getPrefs(0).getBoolean(
"zz_script_enable", true)
&& !isSafeMode();
if (hasLoadedScripts) {
ScriptManager.takeScreenshot("screenshot");
} else {
new AlertDialog.Builder(MainActivity.this)
.setMessage(R.string.take_screenshot_requires_modpe_script)
.setPositiveButton(android.R.string.ok, null).show();
}
} else if (button == 3) {
startActivity(getOptionsActivityIntent());
} else if (button == 4 && hasInsertText) {
showDialog(DIALOG_INSERT_TEXT);
}
}
}).create();
}
protected Dialog createInvalidPatchesDialog() {
return new AlertDialog.Builder(this)
.setMessage(
getResources().getString(R.string.manage_patches_invalid_patches)
+ "\n"
+ PatchManager.join(failedPatches.toArray(PatchManager.blankArray),
"\n")).setPositiveButton(android.R.string.ok, null)
.create();
}
protected Dialog createFirstLaunchDialog() {
StringBuilder dialogMsg = new StringBuilder();
dialogMsg.append(getResources().getString(R.string.firstlaunch_generic_intro)).append(
"\n\n");
if (minecraftApkForwardLocked) {
dialogMsg.append(getResources().getString(R.string.firstlaunch_jelly_bean)).append(
"\n\n");
}
dialogMsg.append(getResources().getString(R.string.firstlaunch_see_options)).append("\n\n");
return new AlertDialog.Builder(this).setTitle(R.string.firstlaunch_title)
.setMessage(dialogMsg.toString()).setPositiveButton(android.R.string.ok, null)
.setNeutralButton(R.string.firstlaunch_help, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(AboutAppActivity.FORUMS_PAGE_URL));
startActivity(intent);
}
}).create();
}
protected Dialog createCopyWorldDialog() {
final View textEntryView = getLayoutInflater().inflate(R.layout.copy_world_dialog, null);
return new AlertDialog.Builder(this)
.setTitle(R.string.copy_world_title)
.setView(textEntryView)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
AlertDialog dialog = (AlertDialog) dialogI;
String worldName = ((TextView) dialog.findViewById(R.id.world_name_entry))
.getText().toString();
userInputStrings = new String[] { worldName };
inputStatus = INPUT_STATUS_OK;
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
inputStatus = INPUT_STATUS_CANCELLED;
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialogI) {
inputStatus = INPUT_STATUS_CANCELLED;
}
}).create();
}
protected Dialog createNotSupportedDialog() {
return new AlertDialog.Builder(this).setMessage(R.string.feature_not_supported)
.setPositiveButton(android.R.string.ok, null).create();
}
protected Dialog createUpdateTexturePackDialog() {
return new AlertDialog.Builder(this).setMessage(R.string.extract_textures_need_update)
.setPositiveButton(android.R.string.ok, null).create();
}
protected Dialog createBackupsNotSupportedDialog() {
return new AlertDialog.Builder(this)
.setMessage(
"Backed up versions of BlockLauncher are not supported, as"
+ " BlockLauncher depends on updates from the application store. "
+ " Please reinstall BlockLauncher. If you believe you received this message in error, contact zhuowei_applications@yahoo.com")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
finish();
}
}).setCancelable(false).create();
}
protected Dialog createInsertTextDialog() {
final EditText editText = new EditText(this);
editText.setSingleLine(false);
final LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.addView(editText, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
Button back = new Button(this);
back.setText(R.string.hovercar_insert_text_backspace);
back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
nativeTypeCharacter("" + ((char) 0x08)); // is this the
// correct
// method of
// backspace?
} catch (Exception e) {
showDialog(DIALOG_NOT_SUPPORTED);
}
}
});
ll.addView(back, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
return new AlertDialog.Builder(this).setTitle(R.string.hovercar_insert_text).setView(ll)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogI, int button) {
try {
String[] lines = editText.getText().toString().split("\n");
for (int line = 0; line < lines.length; line++) {
if (line != 0)
nativeTypeCharacter("" + ((char) 0x0A));
// I am not sure if keyboard-entered "enter" is
// 0x0A
nativeTypeCharacter(lines[line]);
}
editText.setText("");
} catch (UnsatisfiedLinkError e) {
showDialog(DIALOG_NOT_SUPPORTED);
}
}
}).setNegativeButton(android.R.string.cancel, null).create();
}
protected Dialog createMultiplayerDisableScriptsDialog() {
return new AlertDialog.Builder(this).setMessage(R.string.script_disabled_in_multiplayer)
.setPositiveButton(android.R.string.ok, null).create();
}
protected Dialog createSELinuxBrokeEverythingDialog() {
return new AlertDialog.Builder(this).setMessage(R.string.selinux_broke_everything)
.setPositiveButton(android.R.string.ok, null).create();
}
/**
* @param time
* Unix timestamp
* @returns a formatted time value
*/
public String getDateString(int time) {
System.out.println("getDateString: " + time);
return DateFormat.getDateInstance(DateFormat.SHORT, Locale.US).format(
new Date(((long) time) * 1000));
}
public byte[] getFileDataBytes(String name) {
System.out.println("Get file data: " + name);
try {
InputStream is = getInputStreamForAsset(name);
if (is == null)
return null;
// can't always find length - use the method from
// http://www.velocityreviews.com/forums/t136788-store-whole-inputstream-in-a-string.html
// instead
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
int len = is.read(buffer);
if (len < 0) {
break;
}
bout.write(buffer, 0, len);
}
byte[] retval = bout.toByteArray();
return retval;
} catch (Exception e) {
return null;
}
}
protected InputStream getInputStreamForAsset(String name) {
InputStream is = null;
try {
for (int i = 0; i < textureOverrides.size(); i++) {
try {
is = textureOverrides.get(i).getInputStream(name);
if (is != null)
return is;
} catch (IOException e) {
}
}
if (texturePack == null) {
return getLocalInputStreamForAsset(name);
} else {
System.out.println("Trying to load " + name + "from tp");
is = texturePack.getInputStream(name);
if (is == null) {
System.out.println("Can't load " + name + " from tp");
return getLocalInputStreamForAsset(name);
}
}
return is;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
protected InputStream getLocalInputStreamForAsset(String name) {
InputStream is = null;
try {
if (forceFallback) {
return getAssets().open(name);
}
try {
is = minecraftApkContext.getAssets().open(name);
} catch (Exception e) {
// e.printStackTrace();
System.out.println("Attempting to load fallback");
is = getAssets().open(name);
}
if (is == null) {
System.out.println("Can't find it in the APK - attempting to load fallback");
is = getAssets().open(name);
}
return is;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public int[] getImageData(String name) {
System.out.println("Get image data: " + name);
try {
InputStream is = getInputStreamForAsset(name);
if (is == null)
return null;
Bitmap bmp = BitmapFactory.decodeStream(is);
int[] retval = new int[(bmp.getWidth() * bmp.getHeight()) + 2];
retval[0] = bmp.getWidth();
retval[1] = bmp.getHeight();
bmp.getPixels(retval, 2, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());
is.close();
bmp.recycle();
return retval;
} catch (Exception e) {
e.printStackTrace();
return null;
}
/* format: width, height, each integer a pixel */
/* 0 = white, full transparent */
}
public String[] getOptionStrings() {
System.err.println("OptionStrings");
SharedPreferences sharedPref = Utils.getPrefs(0);
Map prefsMap = sharedPref.getAll();
Set<Map.Entry> prefsSet = prefsMap.entrySet();
List<String> retval = new ArrayList<String>();
for (Map.Entry<String, ?> e : prefsSet) {
String key = e.getKey();
if (key.indexOf("zz_") == 0)
continue;
retval.add(key);
if (key.equals("ctrl_sensitivity")) {
retval.add(Double.toString(Integer.parseInt(e.getValue().toString()) / 100.0));
} else {
retval.add(e.getValue().toString());
}
}
retval.add("game_difficulty");
if (sharedPref.getBoolean("game_difficultypeaceful", false)) {
retval.add("0");
} else {
retval.add("2");
}
System.out.println(retval.toString());
return retval.toArray(new String[0]);
}
public float getPixelsPerMillimeter() {
System.out.println("Pixels per mm");
float val = ((float) displayMetrics.densityDpi) / 25.4f;
String custom = Utils.getPrefs(0).getString("zz_custom_dpi", null);
if (custom != null && custom.length() > 0) {
try {
val = Float.parseFloat(custom) / 25.4f;
} catch (Exception e) {
e.printStackTrace();
}
}
return val;
}
public String getPlatformStringVar(int a) {
System.out.println("getPlatformStringVar: " + a);
return "";
}
public int getScreenHeight() {
System.out.println("height");
return displayMetrics.heightPixels;
}
public int getScreenWidth() {
System.out.println("width");
return displayMetrics.widthPixels;
}
public int getUserInputStatus() {
System.out.println("User input status: " + inputStatus);
return inputStatus;
}
public String[] getUserInputString() {
System.out.println("User input string");
/* for the seed input: name, world type, seed */
return userInputStrings;
}
public boolean hasBuyButtonWhenInvalidLicense() {
return false;
}
/** Seems to be called whenever displayDialog is called. Not on UI thread. */
public void initiateUserInput(int a) {
System.out.println("initiateUserInput: " + a);
}
public boolean isNetworkEnabled(boolean a) {
System.out.println("Network?:" + a);
return true;
}
public boolean isTouchscreen() {
return Utils.getPrefs(0).getBoolean("ctrl_usetouchscreen", true);
}
public void postScreenshotToFacebook(String name, int firstInt, int secondInt, int[] thatArray) {
}
public void quit() {
finish();
}
public void setIsPowerVR(boolean powerVR) {
System.out.println("PowerVR: " + powerVR);
}
public void tick() {
}
public void vibrate(int duration) {
if (Utils.getPrefs(0).getBoolean("zz_longvibration", false)) {
duration *= 5;
}
((Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(duration);
}
public int getKeyFromKeyCode(int keyCode, int metaState, int deviceId) {
if (BuildConfig.DEBUG)
Log.i(TAG, "getKey: " + keyCode + ":" + metaState + ":" + deviceId);
KeyCharacterMap characterMap = KeyCharacterMap.load(deviceId);
return characterMap.get(keyCode, metaState);
}
public static void saveScreenshot(String name, int firstInt, int secondInt, int[] thatArray) {
}
// added in 0.7.0
public int abortWebRequest(int requestId) {
Log.i(TAG, "Abort web request: " + requestId);
HurlRunner runner = requestMap.get(requestId);
if (runner != null)
runner.isValid = false;
return 0;
}
public String getRefreshToken() {
Log.i(TAG, "Get Refresh token");
return Utils.getPrefs(0).getString("refreshToken", "");
}
public String getSession() {
Log.i(TAG, "Get Session");
return Utils.getPrefs(0).getString("sessionId", "");
}
public String getWebRequestContent(int requestId) {
Log.i(TAG, "Get web request content: " + requestId);
return "ThisIsSparta";
}
public int getWebRequestStatus(int requestId) {
Log.i(TAG, "Get web request status: " + requestId);
return 0;
}
public void openLoginWindow() {
Log.i(TAG, "Open login window");
this.runOnUiThread(new Runnable() {
@SuppressLint("SetJavaScriptEnabled")
public void run() {
loginWebView = new WebView(MainActivity.this);
loginWebView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
loginWebView.setWebViewClient(new LoginWebViewClient());
WebSettings settings = loginWebView.getSettings();
settings.setJavaScriptEnabled(true); // at least on Firefox, the
// webview tries to do
// some Ajax stuff
/*
* loginPopup = new PopupWindow(loginWebView,
* ViewGroup.LayoutParams.FILL_PARENT,
* ViewGroup.LayoutParams.FILL_PARENT);
* loginPopup.showAtLocation(getWindow().getDecorView(),
* Gravity.CENTER, 0, 0);
*/
loginDialog = new Dialog(MainActivity.this);
loginDialog.setCancelable(true);
loginDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
loginDialog.setContentView(loginWebView);
loginDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
loginDialog.show();
loginWebView.loadUrl(getRealmsRedirectInfo().loginUrl);
}
});
// nativeLoginData("Spartan", "Warrior", "Peacock");
}
public void setRefreshToken(String token) {
Utils.getPrefs(0).edit().putString("refreshToken", token).apply();
}
public void setSession(String session) {
Utils.getPrefs(0).edit().putString("sessionId", session).apply();
}
public boolean supportsNonTouchscreen() {
boolean xperia = false;
boolean play = false;
String[] data = new String[3];
data[0] = Build.MODEL.toLowerCase(Locale.ENGLISH);
data[1] = Build.DEVICE.toLowerCase(Locale.ENGLISH);
data[2] = Build.PRODUCT.toLowerCase(Locale.ENGLISH);
for (String s : data) {
if (s.indexOf("xperia") >= 0)
xperia = true;
if (s.indexOf("play") >= 0)
play = true;
}
return xperia && play;
}
public void webRequest(int requestId, long timestamp, String url, String method, String cookies) {
this.webRequest(requestId, timestamp, url, method, cookies, "");
}
// signature change in 0.7.3
public void webRequest(int requestId, long timestamp, String url, String method,
String cookies, String extraParam) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Web request: " + requestId + ": " + timestamp + " :" + url + ":" + method
+ ":" + cookies + ":" + extraParam);
// nativeWebRequestCompleted(requestId, timestamp, 200, "SPARTA");
url = filterUrl(url);
if (BuildConfig.DEBUG)
Log.i(TAG, url);
new Thread(new HurlRunner(requestId, timestamp, url, method, cookies)).start();
}
protected String filterUrl(String url) {
return url;
// String peoapiRedirect =
// Utils.getPrefs(0).getString("zz_redirect_mco_address", "NONE");
// if (peoapiRedirect.equals("NONE"))
// return url;
// RealmsRedirectInfo info = getRealmsRedirectInfo();
// if (info.accountUrl != null) {
// url.replace("account.mojang.com", info.accountUrl);
// // TODO: better system
// }
// return url.replace("peoapi.minecraft.net", peoapiRedirect);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (BuildConfig.DEBUG)
Log.i(TAG, event.toString());
if (event.getAction() == KeyEvent.ACTION_MULTIPLE
&& event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
try {
nativeTypeCharacter(event.getCharacters());
return true;
} catch (UnsatisfiedLinkError e) {
// Do nothing
}
}
return super.dispatchKeyEvent(event);
}
// added in 0.7.2
public void showKeyboardView() {
Log.i(TAG, "Show keyboard view");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(getWindow().getDecorView(), InputMethodManager.SHOW_FORCED);
}
// added in 0.7.3
public String getAccessToken() {
Log.i(TAG, "Get access token");
return Utils.getPrefs(0).getString("accessToken", "");
}
public String getClientId() {
Log.i(TAG, "Get client ID");
return Utils.getPrefs(0).getString("clientId", "");
}
public String getProfileId() {
Log.i(TAG, "Get profile ID");
return Utils.getPrefs(0).getString("profileUuid", "");
}
public String getProfileName() {
Log.i(TAG, "Get profile name");
return Utils.getPrefs(0).getString("profileName", "");
}
public void statsTrackEvent(String firstEvent, String secondEvent) {
Log.i(TAG, "Stats track: " + firstEvent + ":" + secondEvent);
}
public void statsUpdateUserData(String firstEvent, String secondEvent) {
Log.i(TAG, "Stats update user data: " + firstEvent + ":" + secondEvent);
}
public boolean isDemo() {
Log.i(TAG, "Is demo");
return false;
}
public void setLoginInformation(String accessToken, String clientId, String profileUuid,
String profileName) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Login info: " + accessToken + ":" + clientId + ":" + profileUuid + ":"
+ profileName);
Utils.getPrefs(0).edit().putString("accessToken", accessToken)
.putString("clientId", clientId).putString("profileUuid", profileUuid)
.putString("profileName", profileName).apply();
}
public void clearLoginInformation() {
Log.i(TAG, "Clear login info");
Utils.getPrefs(0).edit().putString("accessToken", "").putString("clientId", "")
.putString("profileUuid", "").putString("profileName", "").apply();
}
// added in 0.8.0
public void showKeyboard(final String mystr, final int maxLength, final boolean mybool) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Show keyboard: " + mystr + ":" + maxLength + ":" + mybool);
if (useLegacyKeyboardInput()) {
showKeyboardView();
return;
}
this.runOnUiThread(new Runnable() {
public void run() {
showHiddenTextbox(mystr, maxLength, mybool);
}
});
}
public void hideKeyboard() {
if (BuildConfig.DEBUG)
Log.i(TAG, "Hide keyboard");
if (useLegacyKeyboardInput()) {
hideKeyboardView();
return;
}
this.runOnUiThread(new Runnable() {
public void run() {
dismissHiddenTextbox();
}
});
}
public void updateTextboxText(final String text) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Update text to " + text);
if (hiddenTextView == null)
return;
hiddenTextView.post(new Runnable() {
public void run() {
hiddenTextView.setText(text);
}
});
}
public void showHiddenTextbox(String text, int maxLength, boolean dismissAfterOneLine) {
int IME_FLAG_NO_FULLSCREEN = 0x02000000;
if (hiddenTextWindow == null) {
hiddenTextView = new EditText(this);
PopupTextWatcher whoWatchesTheWatcher = new PopupTextWatcher();
hiddenTextView.addTextChangedListener(whoWatchesTheWatcher);
hiddenTextView.setOnEditorActionListener(whoWatchesTheWatcher);
hiddenTextView.setSingleLine(true);
hiddenTextView.setImeOptions(EditorInfo.IME_ACTION_NEXT
| EditorInfo.IME_FLAG_NO_EXTRACT_UI | IME_FLAG_NO_FULLSCREEN);
hiddenTextView.setInputType(InputType.TYPE_CLASS_TEXT);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(hiddenTextView);
hiddenTextWindow = new PopupWindow(linearLayout);
hiddenTextWindow.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
hiddenTextWindow.setFocusable(true);
hiddenTextWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
hiddenTextWindow.setBackgroundDrawable(new ColorDrawable());
// To get back button handling for free
hiddenTextWindow.setClippingEnabled(false);
hiddenTextWindow.setTouchable(false);
hiddenTextWindow.setOutsideTouchable(true);
// These flags were taken from a dumpsys window output of Mojang's
// window
hiddenTextWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
public void onDismiss() {
nativeBackPressed();
}
});
}
hiddenTextView.setText(text);
Selection.setSelection((Spannable) hiddenTextView.getText(), text.length());
this.hiddenTextDismissAfterOneLine = dismissAfterOneLine;
hiddenTextWindow.showAtLocation(this.getWindow().getDecorView(),
Gravity.LEFT | Gravity.TOP, -10000, 0);
hiddenTextView.requestFocus();
showKeyboardView();
}
public void dismissHiddenTextbox() {
if (hiddenTextWindow == null)
return;
hiddenTextWindow.dismiss();
hideKeyboardView();
}
private boolean useLegacyKeyboardInput() {
return Utils.getPrefs(0).getBoolean("zz_legacy_keyboard_input", false);
}
public void initPatching() throws Exception {
long minecraftLibLength = findMinecraftLibLength();
boolean success = MaraudersMap.initPatching(this, minecraftLibLength);
if (!success) {
System.out.println("Well, that sucks!");
tempSafeMode = true;
overlyZealousSELinuxSafeMode = true;
return;
}
}
public static long findMinecraftLibLength() throws Exception {
return new File(MC_NATIVE_LIBRARY_LOCATION).length();
// TODO: don't hardcode the 0x1000 page for relocation data.rel.ro.local
}
public int getMaxNumPatches() {
return this.getResources().getInteger(R.integer.max_num_patches);
}
public boolean doesRequireGuiBlocksPatch() {
if (forceFallback)
return true;
if (texturePack != null) {
try {
InputStream instr = texturePack.getInputStream("gui/gui_blocks.png");
if (instr != null)
instr.close();
return instr == null;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
try {
InputStream instr = minecraftApkContext.getAssets().open("gui/gui_blocks.png");
instr.close();
return false;
} catch (Exception e) {
e.printStackTrace();
return true;
}
}
}
protected void setupHoverCar() {
hoverCar = new HoverCar(this);
hoverCar.show(getWindow().getDecorView());
hoverCar.setVisible(!Utils.getPrefs(0).getBoolean("zz_hovercar_hide", false));
hoverCar.mainButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
boolean showInsertText = Utils.getPrefs(0).getBoolean("zz_show_insert_text", false);
showDialog(showInsertText ? DIALOG_RUNTIME_OPTIONS_WITH_INSERT_TEXT
: DIALOG_RUNTIME_OPTIONS);
resetOrientation();
// for sensor controls. TODO: better place to do this?
}
});
}
protected void loadNativeAddons() {
if (!Utils.getPrefs(0).getBoolean("zz_load_native_addons", false))
return;
PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo app : apps) {
if (app.metaData == null)
continue;
String nativeLibName = app.metaData
.getString("net.zhuoweizhang.mcpelauncher.api.nativelibname");
if (nativeLibName != null
&& pm.checkPermission("net.zhuoweizhang.mcpelauncher.ADDON", app.packageName) == PackageManager.PERMISSION_GRANTED) {
try {
System.load(app.nativeLibraryDir + "/lib" + nativeLibName + ".so");
loadedAddons.add(app.packageName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
protected void migrateToPatchManager() {
try {
boolean enabledPatchMgr = Utils.getPrefs(1).getInt("patchManagerVersion", -1) > 0;
if (enabledPatchMgr)
return;
showDialog(DIALOG_FIRST_LAUNCH);
File patchesDir = this.getDir(PT_PATCHES_DIR, 0);
PatchManager.getPatchManager(this).setEnabled(patchesDir.listFiles(), true);
System.out.println(Utils.getPrefs(1).getString("enabledPatches", "LOL"));
} catch (Exception e) {
e.printStackTrace();
}
}
protected void applyBuiltinPatches() {
//do nothing
}
protected void loadTexturePack() {
try {
boolean loadTexturePack = Utils.getPrefs(0).getBoolean("zz_texture_pack_enable", false);
String filePath = Utils.getPrefs(1).getString("texturePack", null);
if (loadTexturePack && (filePath != null)) {
File file = new File(filePath);
if (BuildConfig.DEBUG)
System.out.println("File!! " + file);
if (!file.exists()) {
texturePack = null;
} else {
texturePack = new ZipTexturePack(file);
}
} else {
texturePack = null;
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, R.string.texture_pack_unable_to_load, Toast.LENGTH_LONG).show();
}
}
/**
* enables the on-screen menu key on devices without a dedicated menu key,
* needed because target SDK is v15
*/
private void enableSoftMenuKey() {
int flag = Build.VERSION.SDK_INT >= 19 ? 0x40000000 : 0x08000000; // FLAG_NEEDS_MENU_KEY
getWindow().addFlags(flag);
// KitKat reused old show menu key flag for transparent navbars
}
private void disableAllPatches() {
if (BuildConfig.DEBUG)
Log.i(TAG, "Disabling all patches");
PatchManager.getPatchManager(this).disableAllPatches();
}
protected void loginLaunchCallback(Uri launchUri) {
loginDialog.dismiss();
String session = launchUri.getQueryParameter("sessionId");
if (session == null)
return;
String profileName = launchUri.getQueryParameter("profileName");
String refreshToken = launchUri.getQueryParameter("identity");
String accessToken = launchUri.getQueryParameter("accessToken");
String clientToken = launchUri.getQueryParameter("clientToken");
String profileUuid = launchUri.getQueryParameter("profileUuid");
nativeLoginData(accessToken, clientToken, profileUuid, profileName);
}
protected Intent getOptionsActivityIntent() {
return new Intent(this, MainMenuOptionsActivity.class);
}
public boolean isRedirectingRealms() {
// String peoapiRedirect =
// PreferenceManager.getDefaultSharedPreferences(this).getString("zz_redirect_mco_address",
// "NONE");
// return !peoapiRedirect.equals("NONE");
return false;
}
public RealmsRedirectInfo getRealmsRedirectInfo() {
// String peoapiRedirect =
// PreferenceManager.getDefaultSharedPreferences(this).getString("zz_redirect_mco_address",
// "NONE");
return RealmsRedirectInfo.targets.get("NONE");
}
private void turnOffSafeMode() {
Utils.getPrefs(0).edit().putBoolean("zz_safe_mode", false).commit();
Utils.getPrefs(1).edit().putBoolean("force_prepatch", true).commit();
finish();
NerdyStuffActivity.forceRestart(this);
}
protected void hideKeyboardView() {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindow().getDecorView().getWindowToken(), 0);
}
/**
* Called by the ScriptManager when a new level is loaded. This is for
* subclasses to do cleanup/disable menu items that cannot be used
* ingame/show ads, etc
*/
public void setLevelCallback(boolean isRemote) {
if (isRemote && ScriptManager.scripts.size() > 0) {
this.runOnUiThread(new Runnable() {
public void run() {
showDialog(DIALOG_MULTIPLAYER_DISABLE_SCRIPTS);
}
});
}
}
/**
* Called by the ScriptManager when exiting to the main menu. This is for
* subclasses to do cleanup/disable menu items that cannot be used
* ingame/show ads, etc
*/
public void leaveGameCallback() {
}
public void scriptPrintCallback(final String message, final String scriptName) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "Script " + scriptName + ": " + message,
Toast.LENGTH_SHORT).show();
}
});
}
public void scriptOverrideTexture(final String theOverridden, final String url) {
forceTextureReload();
}
public void scriptResetImages() {
forceTextureReload();
}
public void forceTextureReload() {
ScriptManager.nativeOnGraphicsReset();
}
private static String stringFromInputStream(InputStream in, int startingLength)
throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream(startingLength);
try {
byte[] buffer = new byte[1024];
int count;
while ((count = in.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toString("UTF-8");
} finally {
bytes.close();
}
}
private void reportError(final Throwable t) {
this.runOnUiThread(new Runnable() {
public void run() {
final StringWriter strWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(strWriter);
t.printStackTrace(pWriter);
new AlertDialog.Builder(MainActivity.this)
.setTitle("Oh nose everything broke")
.setMessage(strWriter.toString())
.setPositiveButton(android.R.string.ok, null)
.setNeutralButton(android.R.string.copy,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface aDialog, int button) {
ClipboardManager mgr = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mgr.setText(strWriter.toString());
}
}).
show();
}
});
}
public void scriptErrorCallback(final String scriptName, final Throwable t) {
this.runOnUiThread(new Runnable() {
public void run() {
final StringWriter strWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(strWriter);
pWriter.println("Error occurred in script: " + scriptName);
if (t instanceof RhinoException) {
String lineSource = ((RhinoException) t).lineSource();
if (lineSource != null)
pWriter.println(lineSource);
}
t.printStackTrace(pWriter);
new AlertDialog.Builder(MainActivity.this)
.setTitle(R.string.script_execution_error)
.setMessage(strWriter.toString())
.setPositiveButton(android.R.string.ok, null)
.setNeutralButton(android.R.string.copy,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface aDialog, int button) {
ClipboardManager mgr = (ClipboardManager) MainActivity.this
.getSystemService(CLIPBOARD_SERVICE);
mgr.setText(strWriter.toString());
}
}).show();
}
});
}
protected void resetOrientation() {
// for sensor controls
}
public void scriptTooManyErrorsCallback(final String scriptName) {
this.runOnUiThread(new Runnable() {
public void run() {
new AlertDialog.Builder(MainActivity.this)
.setTitle(R.string.script_execution_error)
.setMessage(
scriptName + " "
+ getResources().getString(R.string.script_too_many_errors))
.setPositiveButton(android.R.string.ok, null).show();
}
});
}
public void screenshotCallback(final File file) {
this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(
MainActivity.this,
getResources().getString(R.string.screenshot_saved_as) + " "
+ file.getAbsolutePath(), Toast.LENGTH_LONG).show();
MediaScannerConnection.scanFile(MainActivity.this,
new String[] { file.getAbsolutePath() }, new String[] { "image/png" }, null);
}
});
}
protected boolean allowScriptOverrideTextures() {
return true; // Let's do this! Leeroy Jenkins!
}
private void addLibraryDirToPath(String path) {
try {
ClassLoader classLoader = getClassLoader();
Class<? extends ClassLoader> clazz = classLoader.getClass();
Field field = Utils.getDeclaredFieldRecursive(clazz, "pathList");
field.setAccessible(true);
Object pathListObj = field.get(classLoader);
Class<? extends Object> pathListClass = pathListObj.getClass();
Field natfield = Utils.getDeclaredFieldRecursive(pathListClass,
"nativeLibraryDirectories");
natfield.setAccessible(true);
File[] fileList = (File[]) natfield.get(pathListObj);
File[] newList = addToFileList(fileList, new File(path));
if (fileList != newList)
natfield.set(pathListObj, newList);
// check
// System.out.println("Class loader shenanigans: " +
// ((PathClassLoader) getClassLoader()).findLibrary("minecraftpe"));
} catch (Exception e) {
e.printStackTrace();
}
}
private File[] addToFileList(File[] files, File toAdd) {
boolean needsAdding = true;
for (File f : files) {
if (f.equals(toAdd)) {
// System.out.println("Already added path to list");
return files;
}
}
File[] retval = new File[files.length + 1];
System.arraycopy(files, 0, retval, 1, files.length);
retval[0] = toAdd;
return retval;
}
private class PopupTextWatcher implements TextWatcher, TextView.OnEditorActionListener {
public void afterTextChanged(Editable e) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Text changed: " + e.toString());
nativeSetTextboxText(e.toString());
}
public void beforeTextChanged(CharSequence c, int start, int count, int after) {
}
public void onTextChanged(CharSequence c, int start, int count, int after) {
}
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (BuildConfig.DEBUG)
Log.i(TAG, "Editor action: " + actionId);
if (hiddenTextDismissAfterOneLine) {
hiddenTextWindow.dismiss();
} else {
nativeReturnKeyPressed();
}
return true;
}
}
private class LoginWebViewClient extends WebViewClient {
boolean hasFiredLaunchEvent = false;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri tempUri = Uri.parse(url);
if (BuildConfig.DEBUG)
Log.i(TAG, tempUri.toString());
String endHost = getRealmsRedirectInfo().accountUrl;
if (endHost == null)
endHost = "account.mojang.com";
if (tempUri.getHost().equals(endHost)) {
if (tempUri.getPath().equals("/m/launch")) {
loginLaunchCallback(tempUri);
hasFiredLaunchEvent = true;
} else {
view.loadUrl(url);
}
return true;
} else {
return false;
}
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
if (isRedirectingRealms()) {
handler.proceed();
return;
}
super.onReceivedSslError(view, handler, error);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Uri tempUri = Uri.parse(url);
if (BuildConfig.DEBUG)
Log.i(TAG, "PageStarted: " + tempUri.toString());
String endHost = getRealmsRedirectInfo().accountUrl;
if (endHost == null)
endHost = "account.mojang.com";
if (tempUri.getHost().equals(endHost)) {
if (tempUri.getPath().equals("/m/launch") && !hasFiredLaunchEvent) {
loginLaunchCallback(tempUri);
hasFiredLaunchEvent = true;
}
}
}
}
private class HurlRunner implements Runnable {
private URL url;
private String method, cookies, strurl;
private int requestId;
private long timestamp;
private boolean isValid = true;
private HttpURLConnection conn;
public HurlRunner(int requestId, long timestamp, String url, String method, String cookies) {
this.requestId = requestId;
this.timestamp = timestamp;
this.strurl = url;
this.method = method;
this.cookies = cookies;
synchronized (requestMap) {
requestMap.put(requestId, this);
}
}
@SuppressWarnings("resource")
public void run() {
InputStream is = null;
String content = null;
int response = 0;
try {
url = new URL(strurl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("User-Agent", "MCPE/Curl");
conn.setUseCaches(false);
conn.setDoInput(true);
if (conn instanceof HttpsURLConnection && isRedirectingRealms()) {
TrustModifier.relaxHostChecking(conn);
}
conn.connect();
try {
response = conn.getResponseCode();
is = conn.getInputStream();
} catch (Exception e) {
try {
is = conn.getErrorStream();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (is != null) {
content = stringFromInputStream(is,
conn.getContentLength() < 0 ? 1024 : conn.getContentLength());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
}
}
}
if (content != null && BuildConfig.DEBUG)
Log.i(TAG, url + ":" + response + ":" + content);
if (isValid) {
nativeWebRequestCompleted(requestId, timestamp, response, content);
}
synchronized (requestMap) {
requestMap.remove(requestMap.indexOfValue(this));
}
}
}
}