mirror of
https://github.com/xoureldeen/Vectras-VM-Android.git
synced 2026-05-02 00:00:25 +00:00
2214 lines
78 KiB
Java
2214 lines
78 KiB
Java
package com.vectras.qemu;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.Activity;
|
|
import androidx.appcompat.app.AlertDialog;
|
|
import android.app.Dialog;
|
|
import android.app.ProgressDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.Point;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.media.AudioManager;
|
|
import android.os.AsyncTask;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.Vibrator;
|
|
import android.util.Log;
|
|
import android.view.Display;
|
|
import android.view.GestureDetector;
|
|
import android.view.Gravity;
|
|
import android.view.InputDevice;
|
|
import android.view.KeyCharacterMap;
|
|
import android.view.KeyEvent;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.MotionEvent;
|
|
import android.view.SurfaceHolder;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.Window;
|
|
import android.view.WindowManager;
|
|
import android.widget.AdapterView;
|
|
import android.widget.ArrayAdapter;
|
|
import android.widget.Button;
|
|
import android.widget.ImageButton;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ListView;
|
|
import android.widget.RelativeLayout;
|
|
import android.widget.ScrollView;
|
|
import android.widget.SeekBar;
|
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.appcompat.app.ActionBar;
|
|
import androidx.core.view.GravityCompat;
|
|
import androidx.core.view.MenuItemCompat;
|
|
import androidx.drawerlayout.widget.DrawerLayout;
|
|
import androidx.fragment.app.FragmentTransaction;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.vectras.qemu.utils.FileUtils;
|
|
import com.vectras.qemu.utils.Machine;
|
|
import com.vectras.qemu.utils.QmpClient;
|
|
import com.vectras.vm.Fragment.ControlersOptionsFragment;
|
|
import com.vectras.vm.MainActivity;
|
|
import com.vectras.vm.R;
|
|
import com.vectras.vm.adapter.LogsAdapter;
|
|
import com.vectras.vm.utils.UIUtils;
|
|
|
|
import java.io.File;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.microedition.khronos.egl.EGLConfig;
|
|
import javax.microedition.khronos.egl.EGLContext;
|
|
import javax.microedition.khronos.egl.EGLDisplay;
|
|
import javax.microedition.khronos.egl.EGLSurface;
|
|
|
|
import org.json.JSONObject;
|
|
import org.libsdl.app.SDLActivity;
|
|
import org.libsdl.app.SDLControllerManager;
|
|
import org.libsdl.app.SDLSurface;
|
|
|
|
/**
|
|
* SDL Activity
|
|
*/
|
|
public class MainSDLActivity extends SDLActivity {
|
|
public static final String TAG = "MainSDLActivity";
|
|
|
|
public static MainSDLActivity activity ;
|
|
|
|
public static final int KEYBOARD = 10000;
|
|
public static final int QUIT = 10001;
|
|
public static final int HELP = 10002;
|
|
|
|
private boolean monitorMode = false;
|
|
private boolean mouseOn = false;
|
|
private Object lockTime = new Object();
|
|
private boolean timeQuit = false;
|
|
private boolean once = true;
|
|
private boolean zoomable = false;
|
|
private String status = null;
|
|
|
|
public static int vm_width;
|
|
public static int vm_height;
|
|
|
|
|
|
private Thread timeListenerThread;
|
|
|
|
private ProgressDialog progDialog;
|
|
protected static ViewGroup mMainLayout;
|
|
|
|
public String cd_iso_path = null;
|
|
|
|
// HDD
|
|
public String hda_img_path = null;
|
|
public String hdb_img_path = null;
|
|
public String hdc_img_path = null;
|
|
public String hdd_img_path = null;
|
|
|
|
public String fda_img_path = null;
|
|
public String fdb_img_path = null;
|
|
public String cpu = null;
|
|
|
|
// Default Settings
|
|
public int memory = 128;
|
|
public String bootdevice = null;
|
|
|
|
// net
|
|
public String net_cfg = "None";
|
|
public int nic_num = 1;
|
|
public String vga_type = "std";
|
|
public String hd_cache = "default";
|
|
public String nic_driver = null;
|
|
public String soundcard = null;
|
|
public String lib = "liblimbo.so";
|
|
public String lib_path = null;
|
|
public String snapshot_name = "limbo";
|
|
public int disableacpi = 0;
|
|
public int disablehpet = 0;
|
|
public int disabletsc = 0;
|
|
public int enableqmp = 0;
|
|
public int enablevnc = 0;
|
|
public String vnc_passwd = null;
|
|
public int vnc_allow_external = 0;
|
|
public String qemu_dev = null;
|
|
public String qemu_dev_value = null;
|
|
|
|
public String dns_addr = null;
|
|
public int restart = 0;
|
|
|
|
// This is what SDL runs in. It invokes SDL_main(), eventually
|
|
private static Thread mSDLThread;
|
|
|
|
// EGL private objects
|
|
private static EGLContext mEGLContext;
|
|
private static EGLSurface mEGLSurface;
|
|
private static EGLDisplay mEGLDisplay;
|
|
private static EGLConfig mEGLConfig;
|
|
private static int mGLMajor, mGLMinor;
|
|
|
|
|
|
private static Activity activity1;
|
|
|
|
// public static void showTextInput(int x, int y, int w, int h) {
|
|
// // Transfer the task to the main thread as a Runnable
|
|
// // mSingleton.commandHandler.post(new ShowTextInputHandler(x, y, w, h));
|
|
// }
|
|
|
|
public static void singleClick(final MotionEvent event, final int pointer_id) {
|
|
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
// Log.d("SDL", "Mouse Single Click");
|
|
try {
|
|
Thread.sleep(50);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("singletap", "Could not sleep");
|
|
}
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_DOWN, 1,0, 0);
|
|
try {
|
|
Thread.sleep(50);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("singletap", "Could not sleep");
|
|
}
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_UP, 1, 0, 0);
|
|
}
|
|
});
|
|
t.start();
|
|
}
|
|
|
|
public void setParams() {
|
|
|
|
if (MainActivity.vmexecutor == null) {
|
|
return;
|
|
}
|
|
memory = MainActivity.vmexecutor.memory;
|
|
vga_type = MainActivity.vmexecutor.vga_type;
|
|
hd_cache = MainActivity.vmexecutor.hd_cache;
|
|
snapshot_name = MainActivity.vmexecutor.snapshot_name;
|
|
disableacpi = MainActivity.vmexecutor.disableacpi;
|
|
disablehpet = MainActivity.vmexecutor.disablehpet;
|
|
disabletsc = MainActivity.vmexecutor.disabletsc;
|
|
enableqmp = MainActivity.vmexecutor.enableqmp;
|
|
enablevnc = MainActivity.vmexecutor.enablevnc;
|
|
|
|
if (MainActivity.vmexecutor.cpu.endsWith("(64Bit)")) {
|
|
cpu = MainActivity.vmexecutor.cpu.split(" ")[0];
|
|
} else {
|
|
cpu = MainActivity.vmexecutor.cpu;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.cd_iso_path == null || MainActivity.vmexecutor.cd_iso_path.equals("None")) {
|
|
cd_iso_path = null;
|
|
} else {
|
|
cd_iso_path = MainActivity.vmexecutor.cd_iso_path;
|
|
}
|
|
if (MainActivity.vmexecutor.hda_img_path == null || MainActivity.vmexecutor.hda_img_path.equals("None")) {
|
|
hda_img_path = null;
|
|
} else {
|
|
hda_img_path = MainActivity.vmexecutor.hda_img_path;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.hdb_img_path == null || MainActivity.vmexecutor.hdb_img_path.equals("None")) {
|
|
hdb_img_path = null;
|
|
} else {
|
|
hdb_img_path = MainActivity.vmexecutor.hdb_img_path;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.hdc_img_path == null || MainActivity.vmexecutor.hdc_img_path.equals("None")) {
|
|
hdc_img_path = null;
|
|
} else {
|
|
hdc_img_path = MainActivity.vmexecutor.hdc_img_path;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.hdd_img_path == null || MainActivity.vmexecutor.hdd_img_path.equals("None")) {
|
|
hdd_img_path = null;
|
|
} else {
|
|
hdd_img_path = MainActivity.vmexecutor.hdd_img_path;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.fda_img_path == null || MainActivity.vmexecutor.fda_img_path.equals("None")) {
|
|
fda_img_path = null;
|
|
} else {
|
|
fda_img_path = MainActivity.vmexecutor.fda_img_path;
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.fdb_img_path == null || MainActivity.vmexecutor.fdb_img_path.equals("None")) {
|
|
fdb_img_path = null;
|
|
} else {
|
|
fdb_img_path = MainActivity.vmexecutor.fdb_img_path;
|
|
}
|
|
if (MainActivity.vmexecutor.bootdevice == null) {
|
|
bootdevice = null;
|
|
} else if (MainActivity.vmexecutor.bootdevice.equals("Default")) {
|
|
bootdevice = null;
|
|
} else if (MainActivity.vmexecutor.bootdevice.equals("CD Rom")) {
|
|
bootdevice = "d";
|
|
} else if (MainActivity.vmexecutor.bootdevice.equals("Floppy")) {
|
|
bootdevice = "a";
|
|
} else if (MainActivity.vmexecutor.bootdevice.equals("Hard Disk")) {
|
|
bootdevice = "c";
|
|
}
|
|
|
|
if (MainActivity.vmexecutor.net_cfg == null || MainActivity.vmexecutor.net_cfg.equals("None")) {
|
|
net_cfg = "none";
|
|
nic_driver = null;
|
|
} else if (MainActivity.vmexecutor.net_cfg.equals("User")) {
|
|
net_cfg = "user";
|
|
nic_driver = MainActivity.vmexecutor.nic_card;
|
|
}
|
|
|
|
soundcard = MainActivity.vmexecutor.sound_card;
|
|
|
|
}
|
|
|
|
public static void delayKey(int ms) {
|
|
try {
|
|
Thread.sleep(ms);
|
|
} catch (InterruptedException e) {
|
|
// TODO Auto-generated catch block
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
public static void sendCtrlAltKey(int code) {
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ALT_LEFT);
|
|
delayKey(100);
|
|
if(code>=0) {
|
|
SDLActivity.onNativeKeyDown(code);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyUp(code);
|
|
delayKey(100);
|
|
}
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_ALT_LEFT);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
}
|
|
|
|
public void stopTimeListener() {
|
|
Log.v("SaveVM", "Stopping Listener");
|
|
synchronized (this.lockTime) {
|
|
this.timeQuit = true;
|
|
this.lockTime.notifyAll();
|
|
}
|
|
}
|
|
|
|
public void onDestroy() {
|
|
|
|
// Now wait for the SDL thread to quit
|
|
Log.v("MainSDL", "Waiting for SDL thread to quit");
|
|
if (mSDLThread != null) {
|
|
try {
|
|
mSDLThread.join();
|
|
} catch (Exception e) {
|
|
Log.v("SDL", "Problem stopping thread: " + e);
|
|
}
|
|
mSDLThread = null;
|
|
|
|
Log.v("SDL", "Finished waiting for SDL thread");
|
|
}
|
|
this.stopTimeListener();
|
|
|
|
MainActivity.vmexecutor.doStopVM(0);
|
|
super.onDestroy();
|
|
}
|
|
|
|
|
|
public void checkStatus() {
|
|
while (timeQuit != true) {
|
|
MainActivity.VMStatus status = Machine.checkSaveVMStatus(activity);
|
|
Log.v(TAG, "Status: " + status);
|
|
if (status == MainActivity.VMStatus.Unknown
|
|
|| status == MainActivity.VMStatus.Completed
|
|
|| status == MainActivity.VMStatus.Failed
|
|
) {
|
|
Log.v("Inside", "Saving state is done: " + status);
|
|
stopTimeListener();
|
|
return;
|
|
}
|
|
try {
|
|
Thread.sleep(1000);
|
|
} catch (InterruptedException ex) {
|
|
Log.w("SaveVM", "Interrupted");
|
|
}
|
|
}
|
|
Log.v("SaveVM", "Save state complete");
|
|
|
|
}
|
|
|
|
|
|
public void startTimeListener() {
|
|
this.stopTimeListener();
|
|
timeQuit = false;
|
|
try {
|
|
Log.v("Listener", "Time Listener Started...");
|
|
checkStatus();
|
|
synchronized (lockTime) {
|
|
while (timeQuit == false) {
|
|
lockTime.wait();
|
|
}
|
|
lockTime.notifyAll();
|
|
}
|
|
} catch (Exception ex) {
|
|
ex.printStackTrace();
|
|
Log.v("SaveVM", "Time listener thread error: " + ex.getMessage());
|
|
}
|
|
Log.v("Listener", "Time listener thread exited...");
|
|
|
|
}
|
|
|
|
public static boolean toggleKeyboardFlag = true;
|
|
|
|
@Override
|
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
|
// Log.v("Limbo", "Inside Options Check");
|
|
super.onOptionsItemSelected(item);
|
|
if (item.getItemId() == R.id.itemReset) {
|
|
Machine.resetVM(activity);
|
|
} else if (item.getItemId() == R.id.itemShutdown) {
|
|
UIUtils.hideKeyboard(this, mSurface);
|
|
Machine.stopVM(activity);
|
|
} else if (item.getItemId() == R.id.itemMouse) {
|
|
onMouseMode();
|
|
} else if (item.getItemId() == this.KEYBOARD || item.getItemId() == R.id.itemKeyboard) {
|
|
//XXX: need to post after delay to work correctly
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
toggleKeyboardFlag = UIUtils.onKeyboard(activity, toggleKeyboardFlag, mSurface);
|
|
}
|
|
}, 200);
|
|
|
|
}
|
|
else if (item.getItemId() == R.id.itemMonitor) {
|
|
if (this.monitorMode) {
|
|
this.onVMConsole();
|
|
} else {
|
|
this.onMonitor();
|
|
}
|
|
} else if (item.getItemId() == R.id.itemVolume) {
|
|
this.onSelectMenuVol();
|
|
} else if (item.getItemId() == R.id.itemSaveState) {
|
|
this.promptPause(activity);
|
|
} else if (item.getItemId() == R.id.itemSaveSnapshot) {
|
|
//TODO:
|
|
//this.promptStateName(activity);
|
|
} else if (item.getItemId() == R.id.itemFitToScreen) {
|
|
onFitToScreen();
|
|
} else if (item.getItemId() == R.id.itemStretchToScreen) {
|
|
onStretchToScreen();
|
|
} else if (item.getItemId() == R.id.itemZoomIn) {
|
|
this.setZoomIn();
|
|
} else if (item.getItemId() == R.id.itemZoomOut) {
|
|
this.setZoomOut();
|
|
} else if (item.getItemId() == R.id.itemCtrlAltDel) {
|
|
this.onCtrlAltDel();
|
|
} else if (item.getItemId() == R.id.itemCtrlC) {
|
|
this.onCtrlC();
|
|
} else if (item.getItemId() == R.id.itemOneToOne) {
|
|
this.onNormalScreen();
|
|
} else if (item.getItemId() == R.id.itemZoomable) {
|
|
this.setZoomable();
|
|
} else if (item.getItemId() == this.QUIT) {
|
|
} else if (item.getItemId() == R.id.itemHelp) {
|
|
|
|
} else if (item.getItemId() == R.id.itemHideToolbar) {
|
|
this.onHideToolbar();
|
|
} else if (item.getItemId() == R.id.itemDisplay) {
|
|
this.onSelectMenuSDLDisplay();
|
|
} else if (item.getItemId() == R.id.itemViewLog) {
|
|
this.onViewLog();
|
|
}
|
|
// this.canvas.requestFocus();
|
|
|
|
|
|
this.invalidateOptionsMenu();
|
|
return true;
|
|
}
|
|
|
|
public void onViewLog() {
|
|
FileUtils.viewVectrasLog(this);
|
|
}
|
|
|
|
public void onHideToolbar(){
|
|
ActionBar bar = this.getSupportActionBar();
|
|
if (bar != null) {
|
|
bar.hide();
|
|
}
|
|
}
|
|
|
|
|
|
private void onMouseMode() {
|
|
|
|
String [] items = {"Trackpad Mouse (Phone)",
|
|
"Bluetooth/USB Mouse (Desktop mode)", //Physical mouse for Chromebook, Android x86 PC, or Bluetooth Mouse
|
|
};
|
|
final AlertDialog.Builder mBuilder = new AlertDialog.Builder(this);
|
|
mBuilder.setTitle("Mouse");
|
|
mBuilder.setSingleChoiceItems(items, Config.mouseMode.ordinal(), new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int i) {
|
|
switch(i){
|
|
case 0:
|
|
setUIModeMobile(true);
|
|
break;
|
|
case 1:
|
|
promptSetUIModeDesktop(false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dialog.dismiss();
|
|
}
|
|
});
|
|
final AlertDialog alertDialog = mBuilder.create();
|
|
alertDialog.show();
|
|
|
|
}
|
|
|
|
public boolean checkVMResolutionFits() {
|
|
int width = mLayout.getWidth();
|
|
int height = mLayout.getHeight();
|
|
ActionBar bar = activity.getSupportActionBar();
|
|
|
|
if (!MainSettingsManager.getAlwaysShowMenuToolbar(MainSDLActivity.this)
|
|
&& bar != null && bar.isShowing()) {
|
|
height += bar.getHeight();
|
|
}
|
|
|
|
if(vm_width < width && vm_height < height)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public void calibration() {
|
|
//XXX: No need to calibrate for SDL trackpad.
|
|
}
|
|
|
|
private void setUIModeMobile(boolean fitToScreen){
|
|
|
|
try {
|
|
UIUtils.setOrientation(this);
|
|
MotionEvent a = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
|
|
|
//TODO: needed?
|
|
//MainSDLActivity.singleClick(a, 0);
|
|
Config.mouseMode = Config.MouseMode.Trackpad;
|
|
MainSettingsManager.setDesktopMode(this, false);
|
|
MainActivity.vmexecutor.setRelativeMouseMode(1);
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(this.getApplicationContext(), "Trackpad Enabled");
|
|
if(fitToScreen)
|
|
onFitToScreen();
|
|
else
|
|
onNormalScreen();
|
|
calibration();
|
|
invalidateOptionsMenu();
|
|
}catch (Exception ex){
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
}
|
|
|
|
private void promptSetUIModeDesktop(final boolean mouseMethodAlt) {
|
|
|
|
|
|
final AlertDialog alertDialog;
|
|
alertDialog = new AlertDialog.Builder(activity).create();
|
|
alertDialog.setTitle("Desktop Mode");
|
|
|
|
LinearLayout mLayout = new LinearLayout(this);
|
|
mLayout.setPadding(20,20,20,20);
|
|
mLayout.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
TextView textView = new TextView(activity);
|
|
textView.setVisibility(View.VISIBLE);
|
|
String desktopInstructions = this.getString(R.string.desktopInstructions);
|
|
if(!checkVMResolutionFits()){
|
|
String resolutionWarning = "Warning: MainActivity.vmexecutor resolution "
|
|
+ vm_width+ "x" + vm_height +
|
|
" is too high for Desktop Mode. " +
|
|
"Scaling will be used and Mouse Alignment will not be accurate. " +
|
|
"Reduce display resolution within the Guest OS for better experience.\n\n";
|
|
desktopInstructions = resolutionWarning + desktopInstructions;
|
|
}
|
|
textView.setText(desktopInstructions);
|
|
|
|
ScrollView scrollView = new ScrollView(this);
|
|
scrollView.addView(textView);
|
|
|
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
mLayout.addView(scrollView, params);
|
|
|
|
alertDialog.setView(mLayout);
|
|
|
|
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
setUIModeDesktop();
|
|
alertDialog.dismiss();
|
|
}
|
|
});
|
|
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
alertDialog.dismiss();
|
|
}
|
|
});
|
|
alertDialog.show();
|
|
|
|
}
|
|
|
|
private void setUIModeDesktop() {
|
|
|
|
try {
|
|
MotionEvent a = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
|
|
|
//TODO: needed?
|
|
//MainSDLActivity.singleClick(a, 0);
|
|
|
|
//TODO: not needed?
|
|
//SDLActivity.onNativeMouseReset(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
|
|
//SDLActivity.onNativeMouseReset(0, 0, MotionEvent.ACTION_MOVE, vm_width, vm_height, 0);
|
|
|
|
Config.mouseMode = Config.MouseMode.External;
|
|
MainSettingsManager.setDesktopMode(this, true);
|
|
MainActivity.vmexecutor.setRelativeMouseMode(0);
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(MainSDLActivity.this, "External Mouse Enabled");
|
|
onNormalScreen();
|
|
calibration();
|
|
invalidateOptionsMenu();
|
|
}catch (Exception ex){
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private void onCtrlAltDel() {
|
|
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_CTRL_RIGHT);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ALT_RIGHT);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_FORWARD_DEL);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_FORWARD_DEL);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_ALT_RIGHT);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_RIGHT);
|
|
}
|
|
|
|
private void onCtrlC() {
|
|
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_CTRL_RIGHT);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_C);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_C);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_RIGHT);
|
|
}
|
|
|
|
|
|
//TODO: not working
|
|
private void onStretchToScreen() {
|
|
|
|
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
Log.d(TAG, "onStretchToScreen");
|
|
screenMode = SDLScreenMode.Fullscreen;
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_F); // not working
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(activity, "Resizing, Please Wait");
|
|
resize(null);
|
|
|
|
}
|
|
}).start();
|
|
|
|
}
|
|
|
|
private void onFitToScreen() {
|
|
try {
|
|
UIUtils.setOrientation(this);
|
|
ActionBar bar = MainSDLActivity.this.getSupportActionBar();
|
|
if (bar != null && !MainSettingsManager.getAlwaysShowMenuToolbar(this)) {
|
|
bar.hide();
|
|
}
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
Log.d(TAG, "onFitToScreen");
|
|
screenMode = SDLScreenMode.FitToScreen;
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(activity, "Resizing, Please Wait");
|
|
resize(null);
|
|
|
|
}
|
|
}).start();
|
|
}catch (Exception ex){
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
}
|
|
|
|
private void onNormalScreen() {
|
|
try {
|
|
ActionBar bar = MainSDLActivity.this.getSupportActionBar();
|
|
if (bar != null && !MainSettingsManager.getAlwaysShowMenuToolbar(this)) {
|
|
bar.hide();
|
|
}
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
Log.d(TAG, "onNormalScreen");
|
|
screenMode = SDLScreenMode.Normal;
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(activity, "Resizing, Please Wait");
|
|
resize(null);
|
|
|
|
}
|
|
}).start();
|
|
}catch (Exception ex){
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
}
|
|
|
|
public void resize(final Configuration newConfig) {
|
|
|
|
//XXX: flag so no mouse events are processed
|
|
isResizing = true;
|
|
|
|
//XXX: This is needed so Nougat+ devices will update their layout
|
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
((MainSDLSurface) mSurface).getHolder().setFixedSize(1, 1);
|
|
setLayout(newConfig);
|
|
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
((MainSDLSurface) mSurface).doResize(false, newConfig);
|
|
}
|
|
}, 1000);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
private void setZoomIn() {
|
|
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
screenMode = SDLScreenMode.Normal;
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_4);
|
|
}
|
|
}).start();
|
|
|
|
}
|
|
|
|
private void setZoomOut() {
|
|
|
|
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
screenMode = SDLScreenMode.Normal;
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_3);
|
|
|
|
}
|
|
}).start();
|
|
|
|
}
|
|
|
|
private void setZoomable() {
|
|
|
|
zoomable = true;
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
menu.clear();
|
|
return this.setupMenu(menu);
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
menu.clear();
|
|
return this.setupMenu(menu);
|
|
}
|
|
|
|
public boolean setupMenu(Menu menu) {
|
|
// Log.v("Limbo", "Inside Options Created");
|
|
getMenuInflater().inflate(R.menu.sdlactivitymenu, menu);
|
|
|
|
int maxMenuItemsShown = 4;
|
|
int actionShow = MenuItemCompat.SHOW_AS_ACTION_IF_ROOM;
|
|
if(UIUtils.isLandscapeOrientation(this)) {
|
|
maxMenuItemsShown = 6;
|
|
actionShow = MenuItemCompat.SHOW_AS_ACTION_ALWAYS;
|
|
}
|
|
|
|
// if (vncCanvas.scaling != null) {
|
|
// menu.findItem(vncCanvas.scaling.getId()).setChecked(true);
|
|
// }
|
|
|
|
// Remove snapshots for now
|
|
menu.removeItem(menu.findItem(R.id.itemSaveSnapshot).getItemId());
|
|
|
|
// Remove Monitor console for SDL2 it creates 2 SDL windows and SDL for
|
|
// android supports only 1
|
|
menu.removeItem(menu.findItem(R.id.itemMonitor).getItemId());
|
|
|
|
// Remove scaling for now
|
|
menu.removeItem(menu.findItem(R.id.itemScaling).getItemId());
|
|
|
|
// Remove external mouse for now
|
|
menu.removeItem(menu.findItem(R.id.itemExternalMouse).getItemId());
|
|
//menu.removeItem(menu.findItem(R.id.itemUIMode).getItemId());
|
|
|
|
menu.removeItem(menu.findItem(R.id.itemCtrlAltDel).getItemId());
|
|
menu.removeItem(menu.findItem(R.id.itemCtrlC).getItemId());
|
|
|
|
if (MainSettingsManager.getAlwaysShowMenuToolbar(activity) || Config.mouseMode == Config.MouseMode.External) {
|
|
menu.removeItem(menu.findItem(R.id.itemHideToolbar).getItemId());
|
|
maxMenuItemsShown--;
|
|
}
|
|
|
|
if (soundcard==null || soundcard.equals("None")) {
|
|
menu.removeItem(menu.findItem(R.id.itemVolume).getItemId());
|
|
maxMenuItemsShown--;
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < menu.size() && i < maxMenuItemsShown; i++) {
|
|
MenuItemCompat.setShowAsAction(menu.getItem(i), actionShow);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
private void onMonitor() {
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
monitorMode = true;
|
|
// final KeyEvent altDown = new KeyEvent(downTime, eventTime,
|
|
// KeyEvent.ACTION_DOWN,
|
|
// KeyEvent.KEYCODE_2, 1, KeyEvent.META_ALT_LEFT_ON);
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_2);
|
|
// sendCtrlAltKey(altDown);
|
|
Log.v("Limbo", "Monitor On");
|
|
}
|
|
}).start();
|
|
|
|
}
|
|
|
|
private void onVMConsole() {
|
|
monitorMode = false;
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_1);
|
|
}
|
|
|
|
|
|
// FIXME: We need this to able to catch complex characters strings like
|
|
// grave and send it as text
|
|
@Override
|
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
if (event.getAction() == KeyEvent.ACTION_MULTIPLE && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
|
|
sendText(event.getCharacters().toString());
|
|
return true;
|
|
} else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
this.onBackPressed();
|
|
return true;
|
|
} if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
|
// We emulate right click with volume down
|
|
if(event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
MotionEvent e = MotionEvent.obtain(1000, 1000, MotionEvent.ACTION_DOWN, 0, 0, 0, 0, 0, 0, 0,
|
|
InputDevice.SOURCE_TOUCHSCREEN, 0);
|
|
rightClick(e, 0);
|
|
}
|
|
return true;
|
|
} else if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
|
|
// We emulate middle click with volume up
|
|
if(event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
MotionEvent e = MotionEvent.obtain(1000, 1000, MotionEvent.ACTION_DOWN, 0, 0, 0, 0, 0, 0, 0,
|
|
InputDevice.SOURCE_TOUCHSCREEN, 0);
|
|
middleClick(e, 0);
|
|
}
|
|
return true;
|
|
} else {
|
|
return super.dispatchKeyEvent(event);
|
|
}
|
|
|
|
}
|
|
|
|
private static void sendText(String string) {
|
|
|
|
// Log.v("sendText", string);
|
|
KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
|
KeyEvent[] keyEvents = keyCharacterMap.getEvents(string.toCharArray());
|
|
if (keyEvents != null)
|
|
for (int i = 0; i < keyEvents.length; i++) {
|
|
|
|
if (keyEvents[i].getAction() == KeyEvent.ACTION_DOWN) {
|
|
// Log.v("sendText", "Up: " + keyEvents[i].getKeyCode());
|
|
SDLActivity.onNativeKeyDown(keyEvents[i].getKeyCode());
|
|
} else if (keyEvents[i].getAction() == KeyEvent.ACTION_UP) {
|
|
// Log.v("sendText", "Down: " + keyEvents[i].getKeyCode());
|
|
SDLActivity.onNativeKeyUp(keyEvents[i].getKeyCode());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
String[] functionsArray = {"F1", "F2", "F3", "F4",
|
|
"F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"};
|
|
|
|
View view;
|
|
private final String CREDENTIAL_SHARED_PREF = "settings_prefs";
|
|
private LogsAdapter mLogAdapter;
|
|
private RecyclerView logList;
|
|
private Timer _timer = new Timer();
|
|
private TimerTask t;
|
|
public boolean ctrlClicked = false;
|
|
public boolean altClicked = false;
|
|
// Setup
|
|
@SuppressLint("UseCompatLoadingForDrawables")
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
// Log.v("SDL", "onCreate()");
|
|
activity = this;
|
|
|
|
if (MainSettingsManager.getFullscreen(this))
|
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
|
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
|
|
super.onCreate(savedInstanceState);
|
|
setupVolume();
|
|
|
|
mSingleton = this;
|
|
|
|
Log.v("SDL", "Max Mem = " + Runtime.getRuntime().maxMemory());
|
|
|
|
this.activity1 = this;
|
|
|
|
// So we can call stuff from static callbacks
|
|
mSingleton = this;
|
|
|
|
createUI(0, 0);
|
|
|
|
UIUtils.showHints(this);
|
|
|
|
this.resumeVM();
|
|
|
|
UIUtils.setOrientation(this);
|
|
|
|
|
|
View decorView = getWindow().getDecorView();
|
|
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
|
decorView.setSystemUiVisibility(uiOptions);
|
|
|
|
onFitToScreen();
|
|
|
|
ImageButton shutdownBtn = findViewById(R.id.shutdownBtn);
|
|
ImageButton settingBtn = findViewById(R.id.btnSettings);
|
|
ImageButton keyboardBtn = findViewById(R.id.kbdBtn);
|
|
ImageButton controllersBtn = findViewById(R.id.btnMode);
|
|
ImageButton upBtn = findViewById(R.id.upBtn);
|
|
ImageButton leftBtn = findViewById(R.id.leftBtn);
|
|
ImageButton downBtn = findViewById(R.id.downBtn);
|
|
ImageButton rightBtn = findViewById(R.id.rightBtn);
|
|
ImageButton enterBtn = findViewById(R.id.enterBtn);
|
|
ImageButton escBtn = findViewById(R.id.escBtn);
|
|
ImageButton ctrlBtn = findViewById(R.id.ctrlBtn);
|
|
ImageButton altBtn = findViewById(R.id.altBtn);
|
|
ImageButton delBtn = findViewById(R.id.delBtn);
|
|
Button ctrlAltDelBtn = findViewById(R.id.ctrlAltDelBtn);
|
|
ImageButton qmpBtn = findViewById(R.id.btnQmp);
|
|
ImageButton btnLogs = findViewById(R.id.btnLogs);
|
|
btnLogs.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
FileUtils.viewVectrasLog(activity);
|
|
}
|
|
});
|
|
shutdownBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
Machine.stopVM(activity);
|
|
}
|
|
});
|
|
keyboardBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
toggleKeyboardFlag = UIUtils.onKeyboard(activity, toggleKeyboardFlag, mSurface);
|
|
}
|
|
}, 200);
|
|
}
|
|
});
|
|
controllersBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
|
// Create and show the dialog.
|
|
ControlersOptionsFragment newFragment = new ControlersOptionsFragment();
|
|
newFragment.show(ft, "Controllers");
|
|
}
|
|
});
|
|
settingBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
final Dialog alertDialog = new Dialog(activity, R.style.MainDialogTheme);
|
|
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
alertDialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
|
|
alertDialog.setContentView(R.layout.dialog_setting);
|
|
alertDialog.show();
|
|
}
|
|
});
|
|
upBtn.setOnTouchListener(new View.OnTouchListener() {
|
|
@Override
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DPAD_UP);
|
|
return true;
|
|
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_DPAD_UP);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
leftBtn.setOnTouchListener(new View.OnTouchListener() {
|
|
@Override
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DPAD_LEFT);
|
|
return true;
|
|
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_DPAD_LEFT);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
downBtn.setOnTouchListener(new View.OnTouchListener() {
|
|
@Override
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DPAD_DOWN);
|
|
return true;
|
|
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_DPAD_DOWN);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
rightBtn.setOnTouchListener(new View.OnTouchListener() {
|
|
@Override
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT);
|
|
return true;
|
|
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_DPAD_RIGHT);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
escBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ESCAPE);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_ESCAPE);
|
|
}
|
|
});
|
|
enterBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ENTER);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ENTER);
|
|
}
|
|
});
|
|
ctrlBtn.setOnClickListener(new View.OnClickListener() {
|
|
@SuppressLint("UseCompatLoadingForDrawables")
|
|
@Override
|
|
public void onClick(View v) {
|
|
if (!ctrlClicked) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
ctrlBtn.setBackground(getResources().getDrawable(R.drawable.controls_button2));
|
|
ctrlClicked = true;
|
|
} else {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
ctrlBtn.setBackground(getResources().getDrawable(R.drawable.controls_button1));
|
|
ctrlClicked = false;
|
|
}
|
|
}
|
|
});
|
|
altBtn.setOnClickListener(new View.OnClickListener() {
|
|
@SuppressLint("UseCompatLoadingForDrawables")
|
|
@Override
|
|
public void onClick(View v) {
|
|
if (!altClicked) {
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ALT_LEFT);
|
|
altBtn.setBackground(getResources().getDrawable(R.drawable.controls_button2));
|
|
altClicked = true;
|
|
} else {
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_ALT_LEFT);
|
|
altBtn.setBackground(getResources().getDrawable(R.drawable.controls_button1));
|
|
altClicked = false;
|
|
}
|
|
}
|
|
});
|
|
delBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DEL);
|
|
delayKey(100);
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_DEL);
|
|
}
|
|
});
|
|
ctrlAltDelBtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
sendCtrlAltKey(KeyEvent.KEYCODE_DEL);
|
|
}
|
|
});
|
|
qmpBtn.setVisibility(View.GONE);
|
|
if (monitorMode) {
|
|
qmpBtn.setImageDrawable(getResources().getDrawable(R.drawable.round_terminal_24));
|
|
} else {
|
|
qmpBtn.setImageDrawable(getResources().getDrawable(R.drawable.round_computer_24));
|
|
}
|
|
|
|
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
|
|
R.layout.container_function, functionsArray);
|
|
|
|
ListView listView = findViewById(R.id.functions);
|
|
listView.setAdapter(adapter);
|
|
/*listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
@Override
|
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
if (position == 0) {
|
|
keyDownUp(KeyEvent.KEYCODE_F1);
|
|
} else if (position == 1) {
|
|
keyDownUp(KeyEvent.KEYCODE_F2);
|
|
} else if (position == 2) {
|
|
keyDownUp(KeyEvent.KEYCODE_F3);
|
|
} else if (position == 3) {
|
|
keyDownUp(KeyEvent.KEYCODE_F4);
|
|
} else if (position == 4) {
|
|
keyDownUp(KeyEvent.KEYCODE_F5);
|
|
} else if (position == 5) {
|
|
keyDownUp(KeyEvent.KEYCODE_F6);
|
|
} else if (position == 6) {
|
|
keyDownUp(KeyEvent.KEYCODE_F7);
|
|
} else if (position == 7) {
|
|
keyDownUp(KeyEvent.KEYCODE_F8);
|
|
} else if (position == 8) {
|
|
keyDownUp(KeyEvent.KEYCODE_F9);
|
|
} else if (position == 9) {
|
|
keyDownUp(KeyEvent.KEYCODE_F10);
|
|
} else if (position == 10) {
|
|
keyDownUp(KeyEvent.KEYCODE_F11);
|
|
} else if (position == 11) {
|
|
keyDownUp(KeyEvent.KEYCODE_F12);
|
|
}
|
|
}
|
|
});*/
|
|
}
|
|
|
|
private void createUI(int w, int h) {
|
|
mSurface = new MainSDLSurface(this);
|
|
|
|
int width = w;
|
|
int height = h;
|
|
if (width == 0) {
|
|
width = RelativeLayout.LayoutParams.WRAP_CONTENT;
|
|
}
|
|
if (height == 0) {
|
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT;
|
|
}
|
|
|
|
setContentView(R.layout.activity_sdl);
|
|
|
|
//TODO:
|
|
mLayout = (RelativeLayout) activity.findViewById(R.id.sdl_layout);
|
|
mMainLayout = (LinearLayout) activity.findViewById(R.id.main_layout);
|
|
|
|
RelativeLayout mLayout = (RelativeLayout) findViewById(R.id.sdl);
|
|
RelativeLayout.LayoutParams surfaceParams = new RelativeLayout.LayoutParams(width, height);
|
|
surfaceParams.addRule(RelativeLayout.CENTER_IN_PARENT);
|
|
|
|
mLayout.addView(mSurface, surfaceParams);
|
|
|
|
}
|
|
|
|
protected void onPause() {
|
|
Log.v("SDL", "onPause()");
|
|
MainService.updateServiceNotification("Vectras VM Suspended");
|
|
super.onPause();
|
|
|
|
}
|
|
|
|
|
|
public void onSelectMenuVol() {
|
|
|
|
final AlertDialog alertDialog;
|
|
alertDialog = new AlertDialog.Builder(activity).create();
|
|
alertDialog.setTitle("Volume");
|
|
|
|
LinearLayout.LayoutParams volParams = new LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
|
|
LinearLayout t = createVolumePanel();
|
|
t.setLayoutParams(volParams);
|
|
|
|
ScrollView s = new ScrollView(activity);
|
|
s.addView(t);
|
|
alertDialog.setView(s);
|
|
alertDialog.setButton(Dialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
alertDialog.cancel();
|
|
}
|
|
});
|
|
alertDialog.show();
|
|
|
|
}
|
|
|
|
public LinearLayout createVolumePanel() {
|
|
LinearLayout layout = new LinearLayout (this);
|
|
layout.setPadding(20, 20, 20, 20);
|
|
|
|
LinearLayout.LayoutParams volparams = new LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
|
|
|
SeekBar vol = new SeekBar(this);
|
|
|
|
int volume = 0;
|
|
|
|
//TODO:
|
|
vol.setMax(maxVolume);
|
|
volume = getCurrentVolume();
|
|
|
|
vol.setProgress(volume);
|
|
vol.setLayoutParams(volparams);
|
|
|
|
((SeekBar) vol).setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
|
|
|
public void onProgressChanged(SeekBar s, int progress, boolean touch) {
|
|
//TODO:
|
|
setVolume(progress);
|
|
}
|
|
|
|
public void onStartTrackingTouch(SeekBar arg0) {
|
|
|
|
}
|
|
|
|
public void onStopTrackingTouch(SeekBar arg0) {
|
|
|
|
}
|
|
});
|
|
|
|
layout.addView(vol);
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
protected void onResume() {
|
|
Log.v("SDL", "onResume()");
|
|
MainService.updateServiceNotification("Vectras VM Running");
|
|
super.onResume();
|
|
}
|
|
|
|
// Messages from the SDLMain thread
|
|
static int COMMAND_CHANGE_TITLE = 1;
|
|
static int COMMAND_SAVEVM = 2;
|
|
|
|
public void loadLibraries() {
|
|
//XXX: override for the specific arch
|
|
}
|
|
|
|
|
|
public void promptPause(final Activity activity) {
|
|
|
|
final AlertDialog alertDialog;
|
|
alertDialog = new AlertDialog.Builder(activity).create();
|
|
alertDialog.setTitle("Pause VM");
|
|
TextView stateView = new TextView(activity);
|
|
stateView.setText("This make take a while depending on the RAM size used");
|
|
stateView.setPadding(20, 20, 20, 20);
|
|
alertDialog.setView(stateView);
|
|
|
|
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Pause", new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
onPauseVM();
|
|
return;
|
|
}
|
|
});
|
|
alertDialog.show();
|
|
}
|
|
|
|
private void onPauseVM() {
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
// Delete any previous state file
|
|
if (MainActivity.vmexecutor.save_state_name != null) {
|
|
File file = new File(MainActivity.vmexecutor.save_state_name);
|
|
if (file.exists()) {
|
|
file.delete();
|
|
}
|
|
}
|
|
if(Config.showToast)
|
|
UIUtils.toastShort(getApplicationContext(), "Please wait while saving VM State");
|
|
MainActivity.vmexecutor.current_fd = MainActivity.vmexecutor.get_fd(MainActivity.vmexecutor.save_state_name);
|
|
|
|
String uri = "fd:" + MainActivity.vmexecutor.current_fd;
|
|
String command = QmpClient.stop();
|
|
String msg = QmpClient.sendCommand(command);
|
|
command = QmpClient.migrate(false, false, uri);
|
|
msg = QmpClient.sendCommand(command);
|
|
if (msg != null) {
|
|
processMigrationResponse(msg);
|
|
}
|
|
|
|
// XXX: Instead we poll to see if migration is complete
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
VMListener a = new VMListener();
|
|
a.execute();
|
|
}
|
|
}, 0);
|
|
}
|
|
});
|
|
t.start();
|
|
|
|
}
|
|
|
|
private void processMigrationResponse(String response) {
|
|
String errorStr = null;
|
|
try {
|
|
JSONObject object = new JSONObject(response);
|
|
errorStr = object.getString("error");
|
|
}catch (Exception ex) {
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
if (errorStr != null) {
|
|
String descStr = null;
|
|
|
|
try {
|
|
JSONObject descObj = new JSONObject(errorStr);
|
|
descStr = descObj.getString("desc");
|
|
}catch (Exception ex) {
|
|
if(Config.debug)
|
|
ex.printStackTrace();
|
|
}
|
|
final String descStr1 = descStr;
|
|
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
Machine.pausedErrorVM(activity, descStr1);
|
|
}
|
|
}, 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private class VMListener extends AsyncTask<Void, Void, Void> {
|
|
|
|
@Override
|
|
protected Void doInBackground(Void... arg0) {
|
|
startTimeListener();
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(Void test) {
|
|
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
boolean res = false;
|
|
if(Config.mouseMode == Config.MouseMode.External){
|
|
return res;
|
|
}
|
|
//TODO:
|
|
res = ((MainSDLSurface) this.mSurface).onTouchProcess(this.mSurface, event);
|
|
res = ((MainSDLSurface) this.mSurface).onTouchEventProcess(event);
|
|
return true;
|
|
}
|
|
|
|
private void resumeVM() {
|
|
if(MainActivity.vmexecutor == null){
|
|
return;
|
|
}
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
if (MainActivity.vmexecutor.paused == 1) {
|
|
|
|
try {
|
|
Thread.sleep(4000);
|
|
} catch (InterruptedException ex) {
|
|
Logger.getLogger(MainVNCActivity.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
MainActivity.vmexecutor.paused = 0;
|
|
|
|
String command = QmpClient.cont();
|
|
String msg = QmpClient.sendCommand(command);
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if(Config.mouseMode == Config.MouseMode.External)
|
|
setUIModeDesktop();
|
|
else
|
|
setUIModeMobile(screenMode == SDLScreenMode.FitToScreen);
|
|
}
|
|
}, 500);
|
|
}
|
|
}
|
|
});
|
|
t.start();
|
|
|
|
}
|
|
|
|
public void onBackPressed() {
|
|
super.onBackPressed();
|
|
UIUtils.hideKeyboard(this, mSurface);
|
|
Machine.stopVM(activity);
|
|
return;
|
|
}
|
|
|
|
@Override
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
super.onConfigurationChanged(newConfig);
|
|
this.invalidateOptionsMenu();
|
|
}
|
|
|
|
public void onSelectMenuSDLDisplay() {
|
|
|
|
final AlertDialog alertDialog;
|
|
alertDialog = new AlertDialog.Builder(activity).create();
|
|
alertDialog.setTitle("Display");
|
|
|
|
LinearLayout.LayoutParams volParams = new LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
|
|
LinearLayout t = createSDLDisplayPanel();
|
|
t.setLayoutParams(volParams);
|
|
|
|
ScrollView s = new ScrollView(activity);
|
|
s.addView(t);
|
|
alertDialog.setView(s);
|
|
alertDialog.setButton(Dialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
alertDialog.cancel();
|
|
}
|
|
});
|
|
alertDialog.show();
|
|
|
|
}
|
|
|
|
|
|
public LinearLayout createSDLDisplayPanel() {
|
|
LinearLayout layout = new LinearLayout(this);
|
|
layout.setOrientation(LinearLayout.VERTICAL);
|
|
layout.setPadding(20, 20, 20, 20);
|
|
|
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
int currRate = getCurrentSDLRefreshRate();
|
|
|
|
LinearLayout buttonsLayout = new LinearLayout(this);
|
|
buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);
|
|
buttonsLayout.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
Button displayMode = new Button (this);
|
|
|
|
displayMode.setText("Display Mode");
|
|
displayMode.setOnClickListener(new View.OnClickListener() {
|
|
public void onClick(View view) {
|
|
onDisplayMode();
|
|
}
|
|
});
|
|
buttonsLayout.addView(displayMode);
|
|
layout.addView(buttonsLayout);
|
|
|
|
final TextView value = new TextView(this);
|
|
value.setText("Idle Refresh Rate: " + currRate+" Hz");
|
|
layout.addView(value);
|
|
value.setLayoutParams(params);
|
|
|
|
SeekBar rate = new SeekBar(this);
|
|
rate.setMax(Config.MAX_DISPLAY_REFRESH_RATE);
|
|
|
|
rate.setProgress(currRate);
|
|
rate.setLayoutParams(params);
|
|
|
|
((SeekBar) rate).setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
|
|
|
public void onProgressChanged(SeekBar s, int progress, boolean touch) {
|
|
value.setText("Idle Refresh Rate: " + (progress+1)+" Hz");
|
|
}
|
|
|
|
public void onStartTrackingTouch(SeekBar arg0) {
|
|
|
|
}
|
|
|
|
public void onStopTrackingTouch(SeekBar arg0) {
|
|
int progress = arg0.getProgress()+1;
|
|
int refreshMs = 1000 / progress;
|
|
Log.v(TAG, "Changing idle refresh rate: (ms)" + refreshMs);
|
|
MainActivity.vmexecutor.setsdlrefreshrate(refreshMs);
|
|
}
|
|
});
|
|
|
|
|
|
layout.addView(rate);
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
public int getCurrentSDLRefreshRate() {
|
|
return 1000 / MainActivity.vmexecutor.getsdlrefreshrate();
|
|
}
|
|
|
|
|
|
|
|
private void onDisplayMode() {
|
|
|
|
String [] items = {
|
|
"Normal (One-To-One)",
|
|
"Fit To Screen"
|
|
// ,"Stretch To Screen" //Stretched
|
|
};
|
|
int currentScaleType = 0;
|
|
if(screenMode == SDLScreenMode.FitToScreen){
|
|
currentScaleType = 1;
|
|
} else if(screenMode == SDLScreenMode.Fullscreen)
|
|
currentScaleType = 2;
|
|
|
|
final AlertDialog.Builder mBuilder = new AlertDialog.Builder(this);
|
|
mBuilder.setTitle("Display Mode");
|
|
mBuilder.setSingleChoiceItems(items, currentScaleType, new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int i) {
|
|
switch(i){
|
|
case 0:
|
|
onNormalScreen();
|
|
break;
|
|
case 1:
|
|
if(Config.mouseMode == Config.MouseMode.External){
|
|
UIUtils.toastShort(MainSDLActivity.this, "Fit to Screen Disabled under Desktop Mode");
|
|
dialog.dismiss();
|
|
return;
|
|
}
|
|
onFitToScreen();
|
|
break;
|
|
case 2:
|
|
if(Config.mouseMode == Config.MouseMode.External){
|
|
UIUtils.toastShort(MainSDLActivity.this, "Stretch Screen Disabled under Desktop Mode");
|
|
dialog.dismiss();
|
|
return;
|
|
}
|
|
onStretchToScreen();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dialog.dismiss();
|
|
}
|
|
});
|
|
final AlertDialog alertDialog = mBuilder.create();
|
|
alertDialog.show();
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
protected synchronized void runSDLMain(){
|
|
|
|
//We go through the vm executor
|
|
MainActivity.startvm(this, Config.UI_SDL);
|
|
|
|
//XXX: we hold the thread because SDLActivity will exit
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public static void onVMResolutionChanged(int w, int h)
|
|
{
|
|
boolean refreshDisplay = false;
|
|
|
|
if(w!=vm_width || h!=vm_height)
|
|
refreshDisplay = true;
|
|
vm_width = w;
|
|
vm_height = h;
|
|
|
|
Log.v(TAG, "VM resolution changed to " + vm_width + "x" + vm_height);
|
|
|
|
|
|
if(refreshDisplay) {
|
|
activity.resize(null);
|
|
}
|
|
|
|
}
|
|
|
|
public static boolean isResizing = false;
|
|
|
|
public enum SDLScreenMode {
|
|
Normal,
|
|
FitToScreen,
|
|
Fullscreen //fullscreen not implemented yet
|
|
}
|
|
|
|
public SDLScreenMode screenMode = SDLScreenMode.FitToScreen;
|
|
|
|
private void setLayout(Configuration newConfig) {
|
|
|
|
boolean isLanscape =
|
|
(newConfig!=null && newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
|
|
|| UIUtils.isLandscapeOrientation(this);
|
|
|
|
View vnc_canvas_layout = (View) this.findViewById(R.id.sdl_layout);
|
|
RelativeLayout.LayoutParams vnc_canvas_layout_params = null;
|
|
//normal 1-1
|
|
if(screenMode == SDLScreenMode.Normal) {
|
|
if (isLanscape) {
|
|
vnc_canvas_layout_params = new RelativeLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
);
|
|
// vnc_canvas_layout_params.addRule(RelativeLayout.CENTER_IN_PARENT);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.CENTER_HORIZONTAL);
|
|
|
|
} else {
|
|
vnc_canvas_layout_params = new RelativeLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.CENTER_HORIZONTAL);
|
|
}
|
|
} else {
|
|
//fittoscreen
|
|
if (isLanscape) {
|
|
vnc_canvas_layout_params = new RelativeLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.CENTER_IN_PARENT);
|
|
} else {
|
|
|
|
vnc_canvas_layout_params = new RelativeLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
|
vnc_canvas_layout_params.addRule(RelativeLayout.CENTER_HORIZONTAL);
|
|
}
|
|
}
|
|
vnc_canvas_layout.setLayoutParams(vnc_canvas_layout_params);
|
|
|
|
this.invalidateOptionsMenu();
|
|
}
|
|
|
|
public class MainSDLSurface extends ExSDLSurface implements View.OnKeyListener, View.OnTouchListener {
|
|
|
|
public boolean initialized = false;
|
|
|
|
public MainSDLSurface(Context context) {
|
|
super(context);
|
|
setOnKeyListener(this);
|
|
setOnTouchListener(this);
|
|
gestureDetector = new GestureDetector(activity, new GestureListener());
|
|
setOnGenericMotionListener(new SDLGenericMotionListener_API12());
|
|
}
|
|
|
|
public void surfaceChanged(SurfaceHolder holder,
|
|
int format, int width, int height) {
|
|
super.surfaceChanged(holder, format, width, height);
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
|
|
SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_LEFT);
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
@Override
|
|
public void surfaceCreated(SurfaceHolder holder) {
|
|
super.surfaceCreated(holder);
|
|
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
|
|
if(Config.mouseMode == Config.MouseMode.External)
|
|
setUIModeDesktop();
|
|
else
|
|
setUIModeMobile(screenMode == SDLScreenMode.FitToScreen);
|
|
}
|
|
},1000);
|
|
}
|
|
|
|
@Override
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
super.onConfigurationChanged(newConfig);
|
|
Log.d(TAG,"Configuration changed");
|
|
resize(newConfig);
|
|
}
|
|
|
|
|
|
|
|
public synchronized void doResize(boolean reverse, final Configuration newConfig) {
|
|
//XXX: notify the UI not to process mouse motion
|
|
isResizing = true;
|
|
Log.v(TAG, "Resizing Display");
|
|
Display display = SDLActivity.mSingleton.getWindowManager().getDefaultDisplay();
|
|
int height = 0;
|
|
int width = 0;
|
|
|
|
Point size = new Point();
|
|
display.getSize(size);
|
|
int screen_width = size.x;
|
|
int screen_height = size.y;
|
|
|
|
final ActionBar bar = ((SDLActivity) activity).getSupportActionBar();
|
|
|
|
if(MainSDLActivity.mLayout != null) {
|
|
width = MainSDLActivity.mLayout.getWidth();
|
|
height = MainSDLActivity.mLayout.getHeight();
|
|
}
|
|
|
|
//native resolution for use with external mouse
|
|
if(screenMode != SDLScreenMode.Fullscreen && screenMode != SDLScreenMode.FitToScreen) {
|
|
width = MainSDLActivity.vm_width;
|
|
height = MainSDLActivity.vm_height;
|
|
}
|
|
|
|
if(reverse){
|
|
int temp = width;
|
|
width = height;
|
|
height = temp;
|
|
}
|
|
|
|
boolean portrait = SDLActivity.mSingleton.getResources()
|
|
.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
|
|
|
|
if (portrait) {
|
|
if(Config.mouseMode != Config.MouseMode.External) {
|
|
int height_n = (int) (width / (MainSDLActivity.vm_width / (float) MainSDLActivity.vm_height));
|
|
Log.d(TAG, "Resizing portrait: " + width + " x " + height_n);
|
|
getHolder().setFixedSize(width, height_n);
|
|
}
|
|
} else {
|
|
if ( (screenMode == SDLScreenMode.Fullscreen || screenMode == SDLScreenMode.FitToScreen)
|
|
&& !MainSettingsManager.getAlwaysShowMenuToolbar(MainSDLActivity.this)
|
|
&& bar != null && bar.isShowing()) {
|
|
height += bar.getHeight();
|
|
}
|
|
Log.d(TAG, "Resizing landscape: " + width + " x " + height);
|
|
getHolder().setFixedSize(width, height);
|
|
}
|
|
initialized = true;
|
|
|
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
isResizing = false;
|
|
}
|
|
}, 1000);
|
|
|
|
|
|
|
|
}
|
|
|
|
// XXX: SDL is missing some key codes in sdl2-keymap.h
|
|
// So we create them with a Shift Modifier
|
|
private boolean handleMissingKeys(int keyCode, int action) {
|
|
|
|
int keyCodeTmp = keyCode;
|
|
switch (keyCode) {
|
|
case 77:
|
|
keyCodeTmp = 9;
|
|
break;
|
|
case 81:
|
|
keyCodeTmp = 70;
|
|
break;
|
|
case 17:
|
|
keyCodeTmp = 15;
|
|
break;
|
|
case 18:
|
|
keyCodeTmp = 10;
|
|
break;
|
|
default:
|
|
return false;
|
|
|
|
}
|
|
if (action == KeyEvent.ACTION_DOWN) {
|
|
SDLActivity.onNativeKeyDown(59);
|
|
SDLActivity.onNativeKeyDown(keyCodeTmp);
|
|
} else {
|
|
SDLActivity.onNativeKeyUp(59);
|
|
SDLActivity.onNativeKeyUp(keyCodeTmp);
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
|
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
|
// dismiss android back and forward keys
|
|
return true;
|
|
} else if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
|
|
return false;
|
|
} else if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
//Log.v("SDL", "key down: " + keyCode);
|
|
if (!handleMissingKeys(keyCode, event.getAction()))
|
|
SDLActivity.onNativeKeyDown(keyCode);
|
|
return true;
|
|
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
//Log.v("SDL", "key up: " + keyCode);
|
|
if (!handleMissingKeys(keyCode, event.getAction()))
|
|
SDLActivity.onNativeKeyUp(keyCode);
|
|
return true;
|
|
} else {
|
|
return super.onKey(v, keyCode, event);
|
|
}
|
|
|
|
}
|
|
|
|
// Touch events
|
|
public boolean onTouchProcess(View v, MotionEvent event) {
|
|
int action = event.getAction();
|
|
float x = event.getX(0);
|
|
float y = event.getY(0);
|
|
float p = event.getPressure(0);
|
|
|
|
int relative = Config.mouseMode == Config.MouseMode.External? 0: 1;
|
|
|
|
int sdlMouseButton = 0;
|
|
if(event.getButtonState() == MotionEvent.BUTTON_PRIMARY)
|
|
sdlMouseButton = Config.SDL_MOUSE_LEFT;
|
|
else if(event.getButtonState() == MotionEvent.BUTTON_SECONDARY)
|
|
sdlMouseButton = Config.SDL_MOUSE_RIGHT;
|
|
else if(event.getButtonState() == MotionEvent.BUTTON_TERTIARY)
|
|
sdlMouseButton = Config.SDL_MOUSE_MIDDLE;
|
|
|
|
|
|
if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
|
|
|
if (mouseUp) {
|
|
old_x = x;
|
|
old_y = y;
|
|
mouseUp = false;
|
|
}
|
|
if (action == MotionEvent.ACTION_MOVE) {
|
|
if(Config.mouseMode == Config.MouseMode.External) {
|
|
//Log.d("SDL", "onTouch Absolute Move by=" + action + ", X,Y=" + (x) + "," + (y) + " P=" + p);
|
|
MainActivity.vmexecutor.onVectrasMouse(0, MotionEvent.ACTION_MOVE,0, x , y );
|
|
}else {
|
|
//Log.d("SDL", "onTouch Relative Moving by=" + action + ", X,Y=" + (x -
|
|
// old_x) + "," + (y - old_y) + " P=" + p);
|
|
MainActivity.vmexecutor.onVectrasMouse(0, MotionEvent.ACTION_MOVE,1, (x - old_x) * sensitivity_mult, (y - old_y) * sensitivity_mult);
|
|
}
|
|
|
|
}
|
|
// save current
|
|
old_x = x;
|
|
old_y = y;
|
|
|
|
}
|
|
else if (event.getAction() == event.ACTION_UP ) {
|
|
//Log.d("SDL", "onTouch Up: " + sdlMouseButton);
|
|
//XXX: it seems that the Button state is not available when Button up so
|
|
// we should release all mouse buttons to be safe since we don't know which one fired the event
|
|
if(sdlMouseButton == Config.SDL_MOUSE_MIDDLE
|
|
||sdlMouseButton == Config.SDL_MOUSE_RIGHT
|
|
) {
|
|
MainActivity.vmexecutor.onVectrasMouse(sdlMouseButton, MotionEvent.ACTION_UP, relative, x, y);
|
|
} else if (sdlMouseButton != 0) {
|
|
MainActivity.vmexecutor.onVectrasMouse(sdlMouseButton, MotionEvent.ACTION_UP, relative, x, y);
|
|
} else { // if we don't have inforamtion about which button we can make some guesses
|
|
|
|
//Or only the last one pressed
|
|
if (lastMouseButtonDown > 0) {
|
|
if(lastMouseButtonDown == Config.SDL_MOUSE_MIDDLE
|
|
||lastMouseButtonDown == Config.SDL_MOUSE_RIGHT
|
|
) {
|
|
MainActivity.vmexecutor.onVectrasMouse(lastMouseButtonDown, MotionEvent.ACTION_UP, relative,x, y);
|
|
}else
|
|
MainActivity.vmexecutor.onVectrasMouse(lastMouseButtonDown, MotionEvent.ACTION_UP, relative, x, y);
|
|
} else {
|
|
//ALl buttons
|
|
if (Config.mouseMode == Config.MouseMode.Trackpad) {
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_UP, 1, 0, 0);
|
|
} else if (Config.mouseMode == Config.MouseMode.External) {
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_UP, 0, x, y);
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_RIGHT, MotionEvent.ACTION_UP, 0, x, y);
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_MIDDLE, MotionEvent.ACTION_UP, 0, x, y);
|
|
}
|
|
}
|
|
}
|
|
lastMouseButtonDown = -1;
|
|
mouseUp = true;
|
|
}
|
|
else if (event.getAction() == event.ACTION_DOWN
|
|
&& Config.mouseMode == Config.MouseMode.External
|
|
) {
|
|
|
|
//XXX: Some touch events for touchscreen mode are primary so we force left mouse button
|
|
if(sdlMouseButton == 0 && MotionEvent.TOOL_TYPE_FINGER == event.getToolType(0)) {
|
|
sdlMouseButton = Config.SDL_MOUSE_LEFT;
|
|
}
|
|
|
|
MainActivity.vmexecutor.onVectrasMouse(sdlMouseButton, MotionEvent.ACTION_DOWN, relative, x, y);
|
|
lastMouseButtonDown = sdlMouseButton;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
boolean res = false;
|
|
if(Config.mouseMode == Config.MouseMode.External){
|
|
res = onTouchProcess(v,event);
|
|
res = onTouchEventProcess(event);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
return false;
|
|
}
|
|
|
|
public boolean onTouchEventProcess(MotionEvent event) {
|
|
// Log.v("onTouchEvent",
|
|
// "Action=" + event.getAction() + ", X,Y=" + event.getX() + ","
|
|
// + event.getY() + " P=" + event.getPressure());
|
|
// MK
|
|
if (event.getAction() == MotionEvent.ACTION_CANCEL)
|
|
return true;
|
|
|
|
if (!firstTouch) {
|
|
firstTouch = true;
|
|
}
|
|
if (event.getPointerCount() > 1) {
|
|
|
|
// XXX: Limbo Legacy enable Right Click with 2 finger touch
|
|
// Log.v("Right Click",
|
|
// "Action=" + event.getAction() + ", X,Y=" + event.getX()
|
|
// + "," + event.getY() + " P=" + event.getPressure());
|
|
// rightClick(event);
|
|
return true;
|
|
} else
|
|
return gestureDetector.onTouchEvent(event);
|
|
}
|
|
}
|
|
|
|
public AudioManager am;
|
|
protected int maxVolume;
|
|
|
|
protected void setupVolume() {
|
|
if (am == null) {
|
|
am = (AudioManager) mSingleton.getSystemService(Context.AUDIO_SERVICE);
|
|
maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
|
}
|
|
}
|
|
|
|
public void setVolume(int volume) {
|
|
if(am!=null)
|
|
am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
|
|
}
|
|
|
|
protected int getCurrentVolume() {
|
|
int volumeTmp = 0;
|
|
if(am!=null)
|
|
volumeTmp = am.getStreamVolume(AudioManager.STREAM_MUSIC);
|
|
return volumeTmp;
|
|
}
|
|
|
|
|
|
//XXX: We want to suspend only when app is calling onPause()
|
|
@Override
|
|
public void onWindowFocusChanged(boolean hasFocus) {
|
|
|
|
}
|
|
|
|
public boolean rightClick(final MotionEvent e, final int i) {
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
Log.d("SDL", "Mouse Right Click");
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_RIGHT, MotionEvent.ACTION_DOWN, 1, -1, -1);
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("SDLSurface", "Interrupted: " + ex);
|
|
}
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_RIGHT, MotionEvent.ACTION_UP, 1, -1, -1);
|
|
}
|
|
});
|
|
t.start();
|
|
return true;
|
|
|
|
}
|
|
|
|
public boolean middleClick(final MotionEvent e, final int i) {
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
Log.d("SDL", "Mouse Middle Click");
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_MIDDLE, MotionEvent.ACTION_DOWN, 1,-1, -1);
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("SDLSurface", "Interrupted: " + ex);
|
|
}
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_MIDDLE, MotionEvent.ACTION_UP, 1,-1, -1);
|
|
}
|
|
});
|
|
t.start();
|
|
return true;
|
|
|
|
}
|
|
|
|
private void doubleClick(final MotionEvent event, final int pointer_id) {
|
|
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
//Log.d("SDL", "Mouse Double Click");
|
|
for (int i = 0; i < 2; i++) {
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_DOWN, 1, 0, 0);
|
|
try {
|
|
Thread.sleep(50);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("doubletap", "Could not sleep");
|
|
}
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_UP, 1,0, 0);
|
|
try {
|
|
Thread.sleep(50);
|
|
} catch (InterruptedException ex) {
|
|
// Log.v("doubletap", "Could not sleep");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
t.start();
|
|
}
|
|
|
|
|
|
int lastMouseButtonDown = -1;
|
|
public float old_x = 0;
|
|
public float old_y = 0;
|
|
private boolean mouseUp = true;
|
|
private float sensitivity_mult = (float) 1.0;
|
|
private boolean firstTouch = false;
|
|
|
|
|
|
|
|
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
|
|
|
|
@Override
|
|
public boolean onDown(MotionEvent event) {
|
|
// Log.v("onDown", "Action=" + event.getAction() + ", X,Y=" + event.getX()
|
|
// + "," + event.getY() + " P=" + event.getPressure());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void onLongPress(MotionEvent event) {
|
|
// Log.d("SDL", "Long Press Action=" + event.getAction() + ", X,Y="
|
|
// + event.getX() + "," + event.getY() + " P="
|
|
// + event.getPressure());
|
|
if(Config.mouseMode == Config.MouseMode.External)
|
|
return;
|
|
|
|
if(Config.enableDragOnLongPress)
|
|
dragPointer(event);
|
|
}
|
|
|
|
public boolean onSingleTapConfirmed(MotionEvent event) {
|
|
float x1 = event.getX();
|
|
float y1 = event.getY();
|
|
|
|
if(Config.mouseMode == Config.MouseMode.External)
|
|
return true;
|
|
|
|
// Log.d("onSingleTapConfirmed", "Tapped at: (" + x1 + "," + y1 +
|
|
// ")");
|
|
|
|
for (int i = 0; i < event.getPointerCount(); i++) {
|
|
int action = event.getAction();
|
|
float x = event.getX(i);
|
|
float y = event.getY(i);
|
|
float p = event.getPressure(i);
|
|
|
|
//Log.v("onSingleTapConfirmed", "Action=" + action + ", X,Y=" + x + "," + y + " P=" + p);
|
|
if (event.getAction() == event.ACTION_DOWN
|
|
&& MotionEvent.TOOL_TYPE_FINGER == event.getToolType(0)) {
|
|
//Log.d("SDL", "onTouch Down: " + event.getButtonState());
|
|
MainSDLActivity.singleClick(event, i);
|
|
}
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
// event when double tap occurs
|
|
@Override
|
|
public boolean onDoubleTap(MotionEvent event) {
|
|
// Log.d("onDoubleTap", "Tapped at: (" + event.getX() + "," + event.getY() + ")");
|
|
|
|
if(Config.mouseMode == Config.MouseMode.External
|
|
//&& MotionEvent.TOOL_TYPE_MOUSE == event.getToolType(0)
|
|
)
|
|
return true;
|
|
|
|
if(!Config.enableDragOnLongPress)
|
|
processDoubleTap(event);
|
|
else
|
|
doubleClick(event, 0);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void dragPointer(MotionEvent event) {
|
|
|
|
MainActivity.vmexecutor.onVectrasMouse(Config.SDL_MOUSE_LEFT, MotionEvent.ACTION_DOWN, 1, 0, 0);
|
|
Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
|
|
if (v.hasVibrator()) {
|
|
v.vibrate(100);
|
|
}
|
|
}
|
|
|
|
private void processDoubleTap(final MotionEvent event) {
|
|
|
|
Thread t = new Thread(new Runnable() {
|
|
public void run() {
|
|
try {
|
|
Thread.sleep(400);
|
|
} catch (InterruptedException e1) {
|
|
e1.printStackTrace();
|
|
}
|
|
|
|
if (!mouseUp) {
|
|
dragPointer(event);
|
|
} else {
|
|
// Log.v("onDoubleTap", "Action=" + action + ", X,Y=" + x + "," + y + " P=" + p);
|
|
doubleClick(event, 0);
|
|
}
|
|
|
|
}
|
|
});
|
|
t.start();
|
|
|
|
}
|
|
|
|
class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
|
|
private MainSDLSurface mSurface;
|
|
|
|
@Override
|
|
public boolean onGenericMotion(View v, MotionEvent event) {
|
|
float x, y;
|
|
int action;
|
|
|
|
switch (event.getSource()) {
|
|
case InputDevice.SOURCE_JOYSTICK:
|
|
case InputDevice.SOURCE_GAMEPAD:
|
|
case InputDevice.SOURCE_DPAD:
|
|
SDLControllerManager.handleJoystickMotionEvent(event);
|
|
return true;
|
|
|
|
case InputDevice.SOURCE_MOUSE:
|
|
if(Config.mouseMode == Config.MouseMode.Trackpad)
|
|
break;
|
|
|
|
action = event.getActionMasked();
|
|
// Log.d("SDL", "onGenericMotion, action = " + action + "," + event.getX() + ", " + event.getY());
|
|
switch (action) {
|
|
case MotionEvent.ACTION_SCROLL:
|
|
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
|
|
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
|
|
// Log.d("SDL", "Mouse Scroll: " + x + "," + y);
|
|
MainActivity.vmexecutor.onVectrasMouse(0, action, 0, x, y);
|
|
return true;
|
|
|
|
case MotionEvent.ACTION_HOVER_MOVE:
|
|
if(Config.processMouseHistoricalEvents) {
|
|
final int historySize = event.getHistorySize();
|
|
for (int h = 0; h < historySize; h++) {
|
|
float ex = event.getHistoricalX(h);
|
|
float ey = event.getHistoricalY(h);
|
|
float ep = event.getHistoricalPressure(h);
|
|
processHoverMouse(ex, ey, ep, action);
|
|
}
|
|
}
|
|
|
|
float ex = event.getX();
|
|
float ey = event.getY();
|
|
float ep = event.getPressure();
|
|
processHoverMouse(ex, ey, ep, action);
|
|
return true;
|
|
|
|
case MotionEvent.ACTION_UP:
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Event was not managed
|
|
return false;
|
|
}
|
|
|
|
private void processHoverMouse(float x,float y,float p, int action) {
|
|
|
|
|
|
|
|
if(Config.mouseMode == Config.MouseMode.External) {
|
|
//Log.d("SDL", "Mouse Hover: " + x + "," + y);
|
|
MainActivity.vmexecutor.onVectrasMouse(0, action, 0, x, y);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
GestureDetector gestureDetector;
|
|
|
|
}
|