529 lines
20 KiB
Java
529 lines
20 KiB
Java
package org.supertuxkart.stk_dbg;
|
|
|
|
import org.supertuxkart.stk_dbg.STKEditText;
|
|
import org.libsdl.app.SDLActivity;
|
|
import org.libsdl.app.SDL;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.app.AlertDialog;
|
|
import android.app.AlertDialog.Builder;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.res.AssetManager;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BitmapFactory;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.graphics.Rect;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Process;
|
|
import android.text.Editable;
|
|
import android.text.TextWatcher;
|
|
import android.view.Display;
|
|
import android.view.DisplayCutout;
|
|
import android.view.Gravity;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.view.KeyEvent;
|
|
import android.view.LayoutInflater;
|
|
import android.view.MotionEvent;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewGroup.MarginLayoutParams;
|
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
|
import android.view.View;
|
|
import android.view.Window;
|
|
import android.view.WindowInsets;
|
|
import android.view.WindowManager;
|
|
import android.view.WindowManager.LayoutParams;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ProgressBar;
|
|
import android.widget.TextView;
|
|
import android.util.DisplayMetrics;
|
|
|
|
import java.io.InputStream;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.Set;
|
|
|
|
import org.minidns.hla.DnssecResolverApi;
|
|
import org.minidns.hla.ResolverResult;
|
|
import org.minidns.record.SRV;
|
|
import org.minidns.record.TXT;
|
|
|
|
public class SuperTuxKartActivity extends SDLActivity
|
|
{
|
|
private AlertDialog m_progress_dialog;
|
|
private ProgressBar m_progress_bar;
|
|
private ImageView m_splash_screen;
|
|
private STKEditText m_stk_edittext;
|
|
private int m_bottom_y;
|
|
private int m_intial_orientation;
|
|
private float m_top_padding;
|
|
private float m_bottom_padding;
|
|
private float m_left_padding;
|
|
private float m_right_padding;
|
|
private AtomicInteger m_keyboard_height;
|
|
private AtomicInteger m_moved_height;
|
|
// ------------------------------------------------------------------------
|
|
public native static void debugMsg(String msg);
|
|
// ------------------------------------------------------------------------
|
|
private native static void handlePadding(boolean val);
|
|
// ------------------------------------------------------------------------
|
|
private native static void saveKeyboardHeight(int height);
|
|
// ------------------------------------------------------------------------
|
|
private native static void saveMovedHeight(int height);
|
|
// ------------------------------------------------------------------------
|
|
private native static void addDNSSrvRecords(String name, int weight);
|
|
// ------------------------------------------------------------------------
|
|
private native static void pauseRenderingJNI();
|
|
// ------------------------------------------------------------------------
|
|
private void showExtractProgressPrivate()
|
|
{
|
|
WindowManager wm =
|
|
(WindowManager)getSystemService(Context.WINDOW_SERVICE);
|
|
DisplayMetrics display_metrics = new DisplayMetrics();
|
|
wm.getDefaultDisplay().getMetrics(display_metrics);
|
|
int padding = display_metrics.widthPixels / 64;
|
|
|
|
LinearLayout ll = new LinearLayout(this);
|
|
ll.setOrientation(LinearLayout.VERTICAL);
|
|
ll.setPadding(padding, padding, padding, padding);
|
|
ll.setGravity(Gravity.CENTER);
|
|
|
|
LinearLayout.LayoutParams ll_param = new LinearLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
ll_param.gravity = Gravity.CENTER;
|
|
TextView tv = new TextView(this);
|
|
// From values strings.xml which is generated by make.sh
|
|
tv.setText(getString(R.string.po_extract_game_data));
|
|
tv.setLayoutParams(ll_param);
|
|
|
|
ll_param = new LinearLayout.LayoutParams(
|
|
display_metrics.widthPixels,
|
|
LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
ll_param.gravity = Gravity.CENTER;
|
|
ll.setLayoutParams(ll_param);
|
|
|
|
m_progress_bar = new ProgressBar(this, null,
|
|
android.R.attr.progressBarStyleHorizontal);
|
|
m_progress_bar.setIndeterminate(false);
|
|
m_progress_bar.setPadding(0, padding, 0, padding);
|
|
m_progress_bar.setLayoutParams(ll_param);
|
|
ll.addView(tv);
|
|
ll.addView(m_progress_bar);
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
builder.setCancelable(false);
|
|
builder.setView(ll);
|
|
|
|
m_progress_dialog = builder.create();
|
|
m_progress_dialog.show();
|
|
Window window = m_progress_dialog.getWindow();
|
|
if (window != null)
|
|
{
|
|
WindowManager.LayoutParams layout_params =
|
|
new WindowManager.LayoutParams();
|
|
layout_params.copyFrom(
|
|
m_progress_dialog.getWindow().getAttributes());
|
|
layout_params.width = WindowManager.LayoutParams.MATCH_PARENT;
|
|
layout_params.height = LinearLayout.LayoutParams.WRAP_CONTENT;
|
|
m_progress_dialog.getWindow().setAttributes(layout_params);
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
private void hideKeyboardNative(final boolean clear_text)
|
|
{
|
|
if (m_stk_edittext == null)
|
|
return;
|
|
|
|
m_stk_edittext.beforeHideKeyboard(clear_text);
|
|
|
|
InputMethodManager imm = (InputMethodManager)
|
|
getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
if (imm == null)
|
|
return;
|
|
|
|
imm.hideSoftInputFromWindow(m_stk_edittext.getWindowToken(), 0);
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
private void createSTKEditText()
|
|
{
|
|
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
FrameLayout.LayoutParams.WRAP_CONTENT,
|
|
FrameLayout.LayoutParams.WRAP_CONTENT);
|
|
// We move the dummy edittext out of the android screen because we draw
|
|
// our own manually
|
|
params.setMargins(0, -100000, 1, -100010);
|
|
m_stk_edittext = new STKEditText(this);
|
|
// For some copy-and-paste text are not done by commitText in
|
|
// STKInputConnection, so we need an extra watcher
|
|
m_stk_edittext.addTextChangedListener(new TextWatcher()
|
|
{
|
|
@Override
|
|
public void onTextChanged(CharSequence s, int start, int before,
|
|
int count) {}
|
|
@Override
|
|
public void beforeTextChanged(CharSequence s, int start, int count,
|
|
int after) {}
|
|
@Override
|
|
public void afterTextChanged(Editable edit)
|
|
{
|
|
if (m_stk_edittext != null)
|
|
m_stk_edittext.updateSTKEditBox();
|
|
}
|
|
});
|
|
addContentView(m_stk_edittext, params);
|
|
// Only focus it and make visible when soft keybord is opened
|
|
m_stk_edittext.setVisibility(View.GONE);
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public void onCreate(Bundle instance)
|
|
{
|
|
super.onCreate(instance);
|
|
m_keyboard_height = new AtomicInteger();
|
|
m_moved_height = new AtomicInteger();
|
|
m_progress_dialog = null;
|
|
m_progress_bar = null;
|
|
m_splash_screen = null;
|
|
m_bottom_y = m_intial_orientation = 0;
|
|
m_top_padding = m_bottom_padding = m_left_padding = m_right_padding =
|
|
0.0f;
|
|
final View root = getWindow().getDecorView().findViewById(
|
|
android.R.id.content);
|
|
root.getViewTreeObserver().addOnGlobalLayoutListener(new
|
|
OnGlobalLayoutListener()
|
|
{
|
|
@Override
|
|
public void onGlobalLayout()
|
|
{
|
|
Rect r = new Rect();
|
|
root.getWindowVisibleDisplayFrame(r);
|
|
int screen_height = root.getRootView().getHeight();
|
|
int keyboard_height = screen_height - (r.bottom);
|
|
m_keyboard_height.set(keyboard_height);
|
|
int moved_height = 0;
|
|
int margin = screen_height - m_bottom_y;
|
|
if (keyboard_height > margin)
|
|
moved_height = -keyboard_height + margin;
|
|
m_moved_height.set(-moved_height);
|
|
SDLActivity.moveView(moved_height);
|
|
}
|
|
});
|
|
|
|
InputStream istr = null;
|
|
try
|
|
{
|
|
LinearLayout ll = new LinearLayout(this);
|
|
LinearLayout.LayoutParams ll_param = new LinearLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.MATCH_PARENT);
|
|
ll.setLayoutParams(ll_param);
|
|
|
|
WindowManager wm =
|
|
(WindowManager)getSystemService(Context.WINDOW_SERVICE);
|
|
DisplayMetrics display_metrics = new DisplayMetrics();
|
|
wm.getDefaultDisplay().getMetrics(display_metrics);
|
|
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
|
|
int w = display_metrics.widthPixels;
|
|
int h = display_metrics.heightPixels;
|
|
Bitmap scaled = Bitmap.createBitmap(w, h, conf);
|
|
|
|
Canvas canvas = new Canvas(scaled);
|
|
istr = getAssets().open("data/gui/icons/logo.png");
|
|
Bitmap logo = BitmapFactory.decodeStream(istr);
|
|
Rect src = new Rect(0, 0, logo.getWidth(), logo.getHeight());
|
|
// STK logo is a square
|
|
int target_size = w;
|
|
if (target_size > h)
|
|
target_size = h;
|
|
target_size /= 2;
|
|
Rect dest = new Rect(w / 2 - target_size / 2,
|
|
h / 2 - target_size / 2,
|
|
w / 2 - target_size / 2 + target_size,
|
|
h / 2 - target_size / 2 + target_size);
|
|
canvas.drawBitmap(logo, src, dest, null);
|
|
|
|
m_splash_screen = new ImageView(this);
|
|
m_splash_screen.setBackgroundColor(Color.argb(255, 168, 168, 168));
|
|
m_splash_screen.setImageDrawable(new BitmapDrawable(getResources(),
|
|
scaled));
|
|
addContentView(m_splash_screen, ll_param);
|
|
}
|
|
catch (Exception e) {}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
if (istr != null)
|
|
istr.close();
|
|
}
|
|
catch(Exception e) {}
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public void onStart()
|
|
{
|
|
super.onStart();
|
|
m_keyboard_height.set(0);
|
|
m_moved_height.set(0);
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public void onPause()
|
|
{
|
|
super.onPause();
|
|
hideKeyboardNative(false/*clear_text*/);
|
|
if (SDLActivity.mSDLThread != null)
|
|
pauseRenderingJNI();
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
/* SDL manually dlopen main to allow unload after main thread exit. */
|
|
protected String[] getLibraries()
|
|
{
|
|
return new String[]{ "SDL2" };
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
protected String getMainSharedObject()
|
|
{
|
|
return getContext().getApplicationInfo().nativeLibraryDir + "/libmain.so";
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void showKeyboard(final int type, final int y)
|
|
{
|
|
final Context context = this;
|
|
// Need to run in ui thread as it access the view m_stk_edittext
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
@Override
|
|
public void run()
|
|
{
|
|
m_bottom_y = y;
|
|
InputMethodManager imm = (InputMethodManager)
|
|
getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
if (imm == null)
|
|
return;
|
|
|
|
if (m_stk_edittext == null)
|
|
createSTKEditText();
|
|
|
|
m_stk_edittext.configType(type);
|
|
m_stk_edittext.setVisibility(View.VISIBLE);
|
|
m_stk_edittext.requestFocus();
|
|
|
|
imm.showSoftInput(m_stk_edittext,
|
|
InputMethodManager.SHOW_FORCED);
|
|
}
|
|
});
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
/* Called by STK in JNI. */
|
|
public void hideKeyboard(final boolean clear_text)
|
|
{
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
@Override
|
|
public void run()
|
|
{
|
|
m_bottom_y = 0;
|
|
hideKeyboardNative(clear_text);
|
|
}
|
|
});
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
/* Called by STK in JNI. */
|
|
public void fromSTKEditBox(final int widget_id, final String text,
|
|
final int selection_start,
|
|
final int selection_end, final int type)
|
|
{
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
@Override
|
|
public void run()
|
|
{
|
|
if (m_stk_edittext == null)
|
|
createSTKEditText();
|
|
m_stk_edittext.configType(type);
|
|
m_stk_edittext.setTextFromSTK(widget_id, text, selection_start,
|
|
selection_end);
|
|
}
|
|
});
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public String[] getDNSTxtRecords(String domain)
|
|
{
|
|
try
|
|
{
|
|
ResolverResult<TXT> txts =
|
|
DnssecResolverApi.INSTANCE.resolve(domain, TXT.class);
|
|
Set<TXT> ans = txts.getAnswers();
|
|
String[] result = new String[ans.size()];
|
|
int i = 0;
|
|
for (TXT t : ans)
|
|
result[i++] = t.getText();
|
|
return result;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
e.printStackTrace();
|
|
return new String[0];
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void getDNSSrvRecords(String domain)
|
|
{
|
|
try
|
|
{
|
|
ResolverResult<SRV> srvs =
|
|
DnssecResolverApi.INSTANCE.resolve(domain, SRV.class);
|
|
Set<SRV> ans = srvs.getAnswers();
|
|
for (SRV s : ans)
|
|
addDNSSrvRecords(s.target.toString() + ":" + s.port, s.weight);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public boolean isHardwareKeyboardConnected()
|
|
{
|
|
return getResources().getConfiguration()
|
|
.keyboard == Configuration.KEYBOARD_QWERTY;
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public int getScreenSize()
|
|
{
|
|
return getResources().getConfiguration().screenLayout &
|
|
Configuration.SCREENLAYOUT_SIZE_MASK;
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public float getTopPadding() { return m_top_padding; }
|
|
// ------------------------------------------------------------------------
|
|
public float getBottomPadding() { return m_bottom_padding; }
|
|
// ------------------------------------------------------------------------
|
|
public float getLeftPadding() { return m_left_padding; }
|
|
// ------------------------------------------------------------------------
|
|
public float getRightPadding() { return m_right_padding; }
|
|
// ------------------------------------------------------------------------
|
|
public int getInitialOrientation() { return m_intial_orientation; }
|
|
// ------------------------------------------------------------------------
|
|
|
|
public void showExtractProgress(final int progress)
|
|
{
|
|
runOnUiThread(new Runnable()
|
|
{
|
|
@Override
|
|
public void run()
|
|
{
|
|
if (progress == -1)
|
|
{
|
|
if (m_progress_dialog != null)
|
|
{
|
|
m_progress_dialog.dismiss();
|
|
m_progress_dialog = null;
|
|
m_progress_bar = null;
|
|
}
|
|
AlertDialog.Builder error =
|
|
new AlertDialog.Builder(SDL.getContext());
|
|
error.setMessage(getString(R.string.po_extract_error_msg));
|
|
error.setTitle(getString(R.string.po_extract_error));
|
|
error.setPositiveButton(getString(R.string.po_quit),
|
|
new DialogInterface.OnClickListener()
|
|
{
|
|
@Override
|
|
public void onClick(DialogInterface dialog,
|
|
int id)
|
|
{
|
|
android.os.Process.killProcess(
|
|
android.os.Process.myPid());
|
|
}
|
|
});
|
|
error.setCancelable(false);
|
|
error.create().show();
|
|
return;
|
|
}
|
|
if (progress == 0 && m_progress_dialog == null)
|
|
showExtractProgressPrivate();
|
|
else if (progress == 100 && m_progress_dialog != null)
|
|
{
|
|
m_progress_dialog.dismiss();
|
|
m_progress_dialog = null;
|
|
m_progress_bar = null;
|
|
}
|
|
else if (m_progress_bar != null &&
|
|
m_progress_bar.getProgress() != progress)
|
|
{
|
|
m_progress_bar.setProgress(progress);
|
|
}
|
|
}
|
|
});
|
|
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void hideSplashScreen()
|
|
{
|
|
if (m_splash_screen != null)
|
|
{
|
|
m_splash_screen.animate().setDuration(200).alpha(0).setListener(
|
|
new AnimatorListenerAdapter()
|
|
{
|
|
@Override
|
|
public void onAnimationEnd(Animator animation)
|
|
{
|
|
if (m_splash_screen.getParent() instanceof ViewGroup)
|
|
{
|
|
ViewGroup view = (ViewGroup)m_splash_screen.getParent();
|
|
view.removeView(m_splash_screen);
|
|
m_splash_screen = null;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public void onAttachedToWindow()
|
|
{
|
|
super.onAttachedToWindow();
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
|
{
|
|
DisplayCutout dc = getWindow().getDecorView().getRootWindowInsets()
|
|
.getDisplayCutout();
|
|
if (dc != null)
|
|
{
|
|
m_top_padding = (float)dc.getBoundingRectTop().height();
|
|
m_bottom_padding = (float)dc.getBoundingRectBottom().height();
|
|
m_left_padding = (float)dc.getBoundingRectLeft().width();
|
|
m_right_padding = (float)dc.getBoundingRectRight().width();
|
|
// Left or right will depend on the device initial orientation
|
|
// So save it for dealing with device rotation later
|
|
m_intial_orientation = SDLActivity.getCurrentOrientation();
|
|
}
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public void onMultiWindowModeChanged(boolean isInMultiWindowMode,
|
|
Configuration newConfig)
|
|
{
|
|
handlePadding(isInMultiWindowMode);
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public int getKeyboardHeight() { return m_keyboard_height.get(); }
|
|
// ------------------------------------------------------------------------
|
|
public int getMovedHeight() { return m_moved_height.get(); }
|
|
|
|
}
|