mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-02-16 10:31:07 +00:00
add virtual controller element abstraction class
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 21
|
||||
|
||||
versionName "3.0.3"
|
||||
versionCode = 49
|
||||
versionName "3.1-beta1"
|
||||
versionCode = 50
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
|
||||
Binary file not shown.
@@ -68,7 +68,7 @@
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.Connection" />
|
||||
android:value="com.limelight.AppView" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".binding.input.virtual_controller.VirtualControllerConfiguration"
|
||||
@@ -79,7 +79,7 @@
|
||||
<activity
|
||||
android:name=".binding.input.virtual_controller.VirtualControllerSettings"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@style/StreamTheme"
|
||||
android:theme="@android:style/Theme.Holo.Dialog"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
|
||||
</activity>
|
||||
<service
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@@ -13,27 +14,34 @@ import com.limelight.grid.AppGridAdapter;
|
||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.preferences.PreferenceConfiguration;
|
||||
import com.limelight.ui.AdapterFragment;
|
||||
import com.limelight.ui.AdapterFragmentCallbacks;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.SpinnerDialog;
|
||||
import com.limelight.utils.UiHelper;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
|
||||
public class AppView extends Activity {
|
||||
public class AppView extends Activity implements AdapterFragmentCallbacks {
|
||||
private AppGridAdapter appGridAdapter;
|
||||
private InetAddress ipAddress;
|
||||
private String uniqueId;
|
||||
@@ -52,6 +60,14 @@ public class AppView extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String locale = PreferenceConfiguration.readPreferences(this).language;
|
||||
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
|
||||
Configuration config = new Configuration(getResources().getConfiguration());
|
||||
config.locale = new Locale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_app_view);
|
||||
|
||||
UiHelper.notifyNewRootView(this);
|
||||
@@ -76,35 +92,19 @@ public class AppView extends Activity {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the list view
|
||||
GridView appGrid = (GridView) findViewById(R.id.appGridView);
|
||||
|
||||
try {
|
||||
appGridAdapter = new AppGridAdapter(this, ipAddress, uniqueId);
|
||||
appGridAdapter = new AppGridAdapter(this,
|
||||
PreferenceConfiguration.readPreferences(this).listMode,
|
||||
ipAddress, uniqueId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
appGrid.setAdapter(appGridAdapter);
|
||||
appGrid.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||
long id) {
|
||||
AppObject app = (AppObject) appGridAdapter.getItem(pos);
|
||||
if (app == null || app.app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only open the context menu if something is running, otherwise start it
|
||||
if (getRunningAppId() != -1) {
|
||||
openContextMenu(arg1);
|
||||
} else {
|
||||
doStart(app.app);
|
||||
}
|
||||
}
|
||||
});
|
||||
registerForContextMenu(appGrid);
|
||||
getFragmentManager().beginTransaction()
|
||||
.add(R.id.appFragmentContainer, new AdapterFragment()).commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,8 +283,37 @@ public class AppView extends Activity {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public class AppObject {
|
||||
|
||||
@Override
|
||||
public int getAdapterFragmentLayoutId() {
|
||||
return PreferenceConfiguration.readPreferences(this).listMode ?
|
||||
R.layout.list_view : R.layout.app_grid_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveAbsListView(AbsListView listView) {
|
||||
listView.setAdapter(appGridAdapter);
|
||||
listView.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||
long id) {
|
||||
AppObject app = (AppObject) appGridAdapter.getItem(pos);
|
||||
if (app == null || app.app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only open the context menu if something is running, otherwise start it
|
||||
if (getRunningAppId() != -1) {
|
||||
openContextMenu(arg1);
|
||||
} else {
|
||||
doStart(app.app);
|
||||
}
|
||||
}
|
||||
});
|
||||
registerForContextMenu(listView);
|
||||
}
|
||||
|
||||
public class AppObject {
|
||||
public NvApp app;
|
||||
|
||||
public AppObject(NvApp app) {
|
||||
|
||||
@@ -17,18 +17,23 @@ import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||
import com.limelight.nvstream.input.KeyboardPacket;
|
||||
import com.limelight.nvstream.input.MouseButtonPacket;
|
||||
import com.limelight.preferences.PreferenceConfiguration;
|
||||
import com.limelight.ui.GameGestures;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.SpinnerDialog;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.media.AudioManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.Display;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
@@ -43,12 +48,15 @@ import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener,
|
||||
OnSystemUiVisibilityChangeListener
|
||||
OnSystemUiVisibilityChangeListener, GameGestures
|
||||
{
|
||||
private int lastMouseX = Integer.MIN_VALUE;
|
||||
private int lastMouseY = Integer.MIN_VALUE;
|
||||
@@ -56,6 +64,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
// Only 2 touches are supported
|
||||
private TouchContext[] touchContextMap = new TouchContext[2];
|
||||
private long threeFingerDownTime = 0;
|
||||
|
||||
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
|
||||
|
||||
private ControllerHandler controllerHandler;
|
||||
private VirtualController virtualController;
|
||||
@@ -89,6 +100,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String locale = PreferenceConfiguration.readPreferences(this).language;
|
||||
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
|
||||
Configuration config = new Configuration(getResources().getConfiguration());
|
||||
config.locale = new Locale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
// We don't want a title bar
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
@@ -180,7 +198,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
// Initialize the connection
|
||||
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
|
||||
keybTranslator = new KeyboardTranslator(conn);
|
||||
controllerHandler = new ControllerHandler(conn, prefConfig.deadzonePercentage);
|
||||
controllerHandler = new ControllerHandler(conn, this, prefConfig.deadzonePercentage);
|
||||
|
||||
SurfaceHolder sh = sv.getHolder();
|
||||
if (prefConfig.stretchVideo || !decoderRenderer.isHardwareAccelerated()) {
|
||||
@@ -478,6 +496,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showKeyboard() {
|
||||
LimeLog.info("Showing keyboard overlay");
|
||||
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||
}
|
||||
|
||||
// Returns true if the event was consumed
|
||||
private boolean handleMotionEvent(MotionEvent event) {
|
||||
// Pass through keyboard input if we're not grabbing
|
||||
@@ -499,7 +524,22 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
int actionIndex = event.getActionIndex();
|
||||
|
||||
int eventX = (int)event.getX(actionIndex);
|
||||
int eventY = (int)event.getY(actionIndex);
|
||||
int eventY = (int)event.getY(actionIndex);
|
||||
|
||||
// Special handling for 3 finger gesture
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN &&
|
||||
event.getPointerCount() == 3) {
|
||||
// Three fingers down
|
||||
threeFingerDownTime = SystemClock.uptimeMillis();
|
||||
|
||||
// Cancel the first and second touches to avoid
|
||||
// erroneous events
|
||||
for (TouchContext aTouchContext : touchContextMap) {
|
||||
aTouchContext.cancelTouch();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TouchContext context = getTouchContext(actionIndex);
|
||||
if (context == null) {
|
||||
@@ -514,8 +554,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (event.getPointerCount() == 1) {
|
||||
// All fingers up
|
||||
if (SystemClock.uptimeMillis() - threeFingerDownTime < THREE_FINGER_TAP_THRESHOLD) {
|
||||
// This is a 3 finger tap to bring up the keyboard
|
||||
showKeyboard();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
context.touchUpEvent(eventX, eventY);
|
||||
if (actionIndex == 0 && event.getPointerCount() > 1) {
|
||||
if (actionIndex == 0 && event.getPointerCount() > 1 && !context.isCancelled()) {
|
||||
// The original secondary touch now becomes primary
|
||||
context.touchDownEvent((int)event.getX(1), (int)event.getY(1));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.binding.crypto.AndroidCryptoProvider;
|
||||
@@ -16,15 +17,20 @@ import com.limelight.nvstream.http.PairingManager;
|
||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||
import com.limelight.preferences.AddComputerManually;
|
||||
import com.limelight.preferences.PreferenceConfiguration;
|
||||
import com.limelight.preferences.StreamSettings;
|
||||
import com.limelight.ui.AdapterFragment;
|
||||
import com.limelight.ui.AdapterFragmentCallbacks;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.UiHelper;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -35,15 +41,18 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
|
||||
public class PcView extends Activity {
|
||||
public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
private AdapterFragment adapterFragment;
|
||||
private RelativeLayout noPcFoundLayout;
|
||||
private PcGridAdapter pcGridAdapter;
|
||||
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
||||
@@ -102,27 +111,6 @@ public class PcView extends Activity {
|
||||
ImageButton settingsButton = (ImageButton) findViewById(R.id.settingsButton);
|
||||
ImageButton addComputerButton = (ImageButton) findViewById(R.id.manuallyAddPc);
|
||||
|
||||
GridView pcGrid = (GridView) findViewById(R.id.pcGridView);
|
||||
pcGrid.setAdapter(pcGridAdapter);
|
||||
pcGrid.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||
long id) {
|
||||
ComputerObject computer = (ComputerObject) pcGridAdapter.getItem(pos);
|
||||
if (computer.details.reachability == ComputerDetails.Reachability.UNKNOWN) {
|
||||
// Do nothing
|
||||
} else if (computer.details.reachability == ComputerDetails.Reachability.OFFLINE) {
|
||||
// Open the context menu if a PC is offline
|
||||
openContextMenu(arg1);
|
||||
} else if (computer.details.pairState != PairState.PAIRED) {
|
||||
// Pair an unpaired machine by default
|
||||
doPair(computer.details);
|
||||
} else {
|
||||
doAppList(computer.details);
|
||||
}
|
||||
}
|
||||
});
|
||||
registerForContextMenu(pcGrid);
|
||||
settingsButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -137,6 +125,15 @@ public class PcView extends Activity {
|
||||
}
|
||||
});
|
||||
|
||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
||||
if (adapterFragment != null) {
|
||||
// Remove the old fragment
|
||||
transaction.remove(adapterFragment);
|
||||
}
|
||||
adapterFragment = new AdapterFragment();
|
||||
transaction.add(R.id.pcFragmentContainer, adapterFragment);
|
||||
transaction.commitAllowingStateLoss();
|
||||
|
||||
noPcFoundLayout = (RelativeLayout) findViewById(R.id.no_pc_found_layout);
|
||||
if (pcGridAdapter.getCount() == 0) {
|
||||
noPcFoundLayout.setVisibility(View.VISIBLE);
|
||||
@@ -150,12 +147,20 @@ public class PcView extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String locale = PreferenceConfiguration.readPreferences(this).language;
|
||||
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
|
||||
Configuration config = new Configuration(getResources().getConfiguration());
|
||||
config.locale = new Locale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
// Bind to the computer manager service
|
||||
bindService(new Intent(PcView.this, ComputerManagerService.class), serviceConnection,
|
||||
Service.BIND_AUTO_CREATE);
|
||||
|
||||
pcGridAdapter = new PcGridAdapter(this);
|
||||
pcGridAdapter = new PcGridAdapter(this,
|
||||
PreferenceConfiguration.readPreferences(this).listMode);
|
||||
|
||||
initializeViews();
|
||||
}
|
||||
@@ -561,8 +566,38 @@ public class PcView extends Activity {
|
||||
// Notify the view that the data has changed
|
||||
pcGridAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public class ComputerObject {
|
||||
|
||||
@Override
|
||||
public int getAdapterFragmentLayoutId() {
|
||||
return PreferenceConfiguration.readPreferences(this).listMode ?
|
||||
R.layout.list_view : R.layout.pc_grid_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveAbsListView(AbsListView listView) {
|
||||
listView.setAdapter(pcGridAdapter);
|
||||
listView.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||
long id) {
|
||||
ComputerObject computer = (ComputerObject) pcGridAdapter.getItem(pos);
|
||||
if (computer.details.reachability == ComputerDetails.Reachability.UNKNOWN) {
|
||||
// Do nothing
|
||||
} else if (computer.details.reachability == ComputerDetails.Reachability.OFFLINE) {
|
||||
// Open the context menu if a PC is offline
|
||||
openContextMenu(arg1);
|
||||
} else if (computer.details.pairState != PairState.PAIRED) {
|
||||
// Pair an unpaired machine by default
|
||||
doPair(computer.details);
|
||||
} else {
|
||||
doAppList(computer.details);
|
||||
}
|
||||
}
|
||||
});
|
||||
registerForContextMenu(listView);
|
||||
}
|
||||
|
||||
public class ComputerObject {
|
||||
public ComputerDetails details;
|
||||
|
||||
public ComputerObject(ComputerDetails details) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.view.MotionEvent;
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.NvConnection;
|
||||
import com.limelight.nvstream.input.ControllerPacket;
|
||||
import com.limelight.ui.GameGestures;
|
||||
import com.limelight.utils.Vector2d;
|
||||
|
||||
public class ControllerHandler {
|
||||
@@ -30,6 +31,9 @@ public class ControllerHandler {
|
||||
private long lastLbUpTime = 0;
|
||||
private long lastRbUpTime = 0;
|
||||
private static final int MAXIMUM_BUMPER_UP_DELAY_MS = 100;
|
||||
|
||||
private long startDownTime = 0;
|
||||
private static final int START_DOWN_TIME_KEYB_MS = 750;
|
||||
|
||||
private static final int MINIMUM_BUTTON_DOWN_TIME_MS = 25;
|
||||
|
||||
@@ -46,10 +50,12 @@ public class ControllerHandler {
|
||||
private NvConnection conn;
|
||||
private double stickDeadzone;
|
||||
private final ControllerMapping defaultMapping = new ControllerMapping();
|
||||
private GameGestures gestures;
|
||||
private boolean hasGameController;
|
||||
|
||||
public ControllerHandler(NvConnection conn, int deadzonePercentage) {
|
||||
public ControllerHandler(NvConnection conn, GameGestures gestures, int deadzonePercentage) {
|
||||
this.conn = conn;
|
||||
this.gestures = gestures;
|
||||
|
||||
// HACK: For now we're hardcoding a 10% deadzone. Some deadzone
|
||||
// is required for controller batching support to work.
|
||||
@@ -513,6 +519,9 @@ public class ControllerHandler {
|
||||
break;
|
||||
case KeyEvent.KEYCODE_BUTTON_START:
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
if (SystemClock.uptimeMillis() - startDownTime > ControllerHandler.START_DOWN_TIME_KEYB_MS) {
|
||||
gestures.showKeyboard();
|
||||
}
|
||||
inputMap &= ~ControllerPacket.PLAY_FLAG;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
@@ -621,6 +630,9 @@ public class ControllerHandler {
|
||||
break;
|
||||
case KeyEvent.KEYCODE_BUTTON_START:
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
if (event.getRepeatCount() == 0) {
|
||||
startDownTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
inputMap |= ControllerPacket.PLAY_FLAG;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
|
||||
@@ -9,6 +9,7 @@ public class TouchContext {
|
||||
private int originalTouchX = 0;
|
||||
private int originalTouchY = 0;
|
||||
private long originalTouchTime = 0;
|
||||
private boolean cancelled;
|
||||
|
||||
private NvConnection conn;
|
||||
private int actionIndex;
|
||||
@@ -56,12 +57,17 @@ public class TouchContext {
|
||||
originalTouchX = lastTouchX = eventX;
|
||||
originalTouchY = lastTouchY = eventY;
|
||||
originalTouchTime = System.currentTimeMillis();
|
||||
|
||||
return true;
|
||||
cancelled = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void touchUpEvent(int eventX, int eventY)
|
||||
{
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTap())
|
||||
{
|
||||
byte buttonIndex = getMouseButtonIndex();
|
||||
@@ -81,8 +87,8 @@ public class TouchContext {
|
||||
}
|
||||
|
||||
public boolean touchMoveEvent(int eventX, int eventY)
|
||||
{
|
||||
if (eventX != lastTouchX || eventY != lastTouchY)
|
||||
{
|
||||
if (eventX != lastTouchX || eventY != lastTouchY)
|
||||
{
|
||||
// We only send moves for the primary touch point
|
||||
if (actionIndex == 0) {
|
||||
@@ -102,4 +108,12 @@ public class TouchContext {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void cancelTouch() {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class EvdevReader {
|
||||
// 4.4 and later to do live SELinux policy changes.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
EvdevShell shell = EvdevShell.getInstance();
|
||||
shell.runCommand("supolicy --live \"allow untrusted_app input_device dir getattr\" " +
|
||||
shell.runCommand("supolicy --live \"allow untrusted_app input_device dir { getattr read search }\" " +
|
||||
"\"allow untrusted_app input_device chr_file { open read write ioctl }\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,106 +5,56 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Karim Mreisi on 30.11.2014.
|
||||
*/
|
||||
public class AnalogStick extends View
|
||||
public class AnalogStick extends VirtualControllerElement
|
||||
{
|
||||
private enum _STICK_STATE
|
||||
{
|
||||
NO_MOVEMENT,
|
||||
MOVED
|
||||
}
|
||||
protected static boolean _PRINT_DEBUG_INFORMATION = true;
|
||||
|
||||
private enum _CLICK_STATE
|
||||
{
|
||||
SINGLE,
|
||||
DOUBLE
|
||||
}
|
||||
float radius_complete = 0;
|
||||
float radius_dead_zone = 0;
|
||||
float radius_analog_stick = 0;
|
||||
float position_stick_x = 0;
|
||||
float position_stick_y = 0;
|
||||
|
||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
boolean viewPressed = false;
|
||||
boolean analogStickActive = false;
|
||||
|
||||
public interface AnalogStickListener
|
||||
{
|
||||
void onMovement(float x, float y);
|
||||
void onClick();
|
||||
void onRevoke();
|
||||
void onDoubleClick();
|
||||
}
|
||||
_STICK_STATE stick_state = _STICK_STATE.NO_MOVEMENT;
|
||||
_CLICK_STATE click_state = _CLICK_STATE.SINGLE;
|
||||
|
||||
public void addAnalogStickListener (AnalogStickListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
onTouchListener = listener;
|
||||
}
|
||||
|
||||
private static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("AnalogStick: " + text);
|
||||
}
|
||||
}
|
||||
|
||||
private int normalColor = 0xF0888888;
|
||||
private int pressedColor = 0xF00000FF;
|
||||
|
||||
private long timeoutDoubleClick = 250;
|
||||
private long timeLastClick = 0;
|
||||
|
||||
float radius_complete = 0;
|
||||
float radius_dead_zone = 0;
|
||||
float radius_analog_stick = 0;
|
||||
|
||||
float position_stick_x = 0;
|
||||
float position_stick_y = 0;
|
||||
|
||||
boolean viewPressed = false;
|
||||
boolean analogStickActive = false;
|
||||
_STICK_STATE stick_state = _STICK_STATE.NO_MOVEMENT;
|
||||
_CLICK_STATE click_state = _CLICK_STATE.SINGLE;
|
||||
|
||||
List<AnalogStickListener> listeners = new ArrayList<AnalogStickListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
List<AnalogStickListener> listeners = new ArrayList<AnalogStickListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
private long timeoutDoubleClick = 250;
|
||||
private long timeLastClick = 0;
|
||||
|
||||
public AnalogStick(Context context)
|
||||
{
|
||||
super(context);
|
||||
|
||||
position_stick_x = getWidth() / 2;
|
||||
position_stick_y = getHeight() / 2;
|
||||
|
||||
stick_state = _STICK_STATE.NO_MOVEMENT;
|
||||
click_state = _CLICK_STATE.SINGLE;
|
||||
viewPressed = false;
|
||||
analogStickActive = false;
|
||||
|
||||
position_stick_x = getWidth() / 2;
|
||||
position_stick_y = getHeight() / 2;
|
||||
}
|
||||
|
||||
public void setColors(int normalColor, int pressedColor)
|
||||
{
|
||||
this.normalColor = normalColor;
|
||||
this.pressedColor = pressedColor;
|
||||
}
|
||||
|
||||
private float getPercent(float value, int percent)
|
||||
public void addAnalogStickListener(AnalogStickListener listener)
|
||||
{
|
||||
return value / 100 * percent;
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
private int getCorrectWidth()
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
return getWidth() > getHeight() ? getHeight() : getWidth();
|
||||
onTouchListener = listener;
|
||||
}
|
||||
|
||||
public void setColors(int normalColor, int pressedColor)
|
||||
{
|
||||
this.normalColor = normalColor;
|
||||
this.pressedColor = pressedColor;
|
||||
}
|
||||
|
||||
private double getMovementRadius(float x, float y)
|
||||
@@ -119,15 +69,15 @@ public class AnalogStick extends View
|
||||
return x > 0 ? x : -x;
|
||||
}
|
||||
|
||||
return Math.sqrt(x * x + y * y);
|
||||
return Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||
{
|
||||
radius_complete = getPercent(getCorrectWidth() / 2, 95);
|
||||
radius_dead_zone = getPercent(getCorrectWidth() / 2, 20);
|
||||
radius_analog_stick = getPercent(getCorrectWidth() / 2, 30);
|
||||
radius_complete = getPercent(getCorrectWidth() / 2, 95);
|
||||
radius_dead_zone = getPercent(getCorrectWidth() / 2, 20);
|
||||
radius_analog_stick = getPercent(getCorrectWidth() / 2, 30);
|
||||
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
}
|
||||
@@ -135,29 +85,29 @@ public class AnalogStick extends View
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(getPercent(getCorrectWidth() / 2, 2));
|
||||
|
||||
// draw outer circle
|
||||
if (!viewPressed || click_state == _CLICK_STATE.SINGLE)
|
||||
{
|
||||
paint.setColor(normalColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.setColor(pressedColor);
|
||||
}
|
||||
// draw outer circle
|
||||
if (!viewPressed || click_state == _CLICK_STATE.SINGLE)
|
||||
{
|
||||
paint.setColor(normalColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.setColor(pressedColor);
|
||||
}
|
||||
|
||||
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint);
|
||||
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint);
|
||||
|
||||
paint.setColor(normalColor);
|
||||
paint.setColor(normalColor);
|
||||
|
||||
// draw dead zone
|
||||
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint);
|
||||
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint);
|
||||
|
||||
// draw stick depending on state (no movement, moved, active(out of dead zone))
|
||||
if (analogStickActive)
|
||||
@@ -209,11 +159,11 @@ public class AnalogStick extends View
|
||||
{
|
||||
if (way_x > 0)
|
||||
{
|
||||
angle = Math.PI * 3/2;
|
||||
angle = Math.PI * 3 / 2;
|
||||
}
|
||||
else if (way_x < 0)
|
||||
{
|
||||
angle = Math.PI * 1/2;
|
||||
angle = Math.PI * 1 / 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -221,30 +171,31 @@ public class AnalogStick extends View
|
||||
if (way_x > 0)
|
||||
{
|
||||
if (way_y < 0)
|
||||
{ // first quadrant
|
||||
angle = 3 * Math.PI / 2 + Math.atan((double)(-way_y / way_x));
|
||||
{ // first quadrant
|
||||
angle =
|
||||
3 * Math.PI / 2 + Math.atan((double) (-way_y / way_x));
|
||||
}
|
||||
else
|
||||
{ // second quadrant
|
||||
angle = Math.PI + Math.atan((double)(way_x / way_y));
|
||||
{ // second quadrant
|
||||
angle = Math.PI + Math.atan((double) (way_x / way_y));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (way_y > 0)
|
||||
{ // third quadrant
|
||||
angle = Math.PI / 2 + Math.atan((double)(way_y / -way_x));
|
||||
{ // third quadrant
|
||||
angle = Math.PI / 2 + Math.atan((double) (way_y / -way_x));
|
||||
}
|
||||
else
|
||||
{ // fourth quadrant
|
||||
{ // fourth quadrant
|
||||
angle = 0 + Math.atan((double) (-way_x / -way_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_DBG("angle: " + angle + " way y: "+ way_y + " way x: " + way_x);
|
||||
_DBG("angle: " + angle + " way y: " + way_y + " way x: " + way_x);
|
||||
|
||||
return angle;
|
||||
return angle;
|
||||
}
|
||||
|
||||
private void moveActionCallback(float x, float y)
|
||||
@@ -258,50 +209,49 @@ public class AnalogStick extends View
|
||||
}
|
||||
}
|
||||
|
||||
private void clickActionCallback()
|
||||
{
|
||||
_DBG("click");
|
||||
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void doubleClickActionCallback()
|
||||
{
|
||||
_DBG("double click");
|
||||
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onDoubleClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void revokeActionCallback()
|
||||
{
|
||||
_DBG("revoke");
|
||||
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onRevoke();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updatePosition(float x, float y)
|
||||
private void clickActionCallback()
|
||||
{
|
||||
float way_x = -(getWidth() / 2 - x);
|
||||
float way_y = -(getHeight() / 2 - y);
|
||||
_DBG("click");
|
||||
|
||||
float movement_x = 0;
|
||||
float movement_y = 0;
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
double movement_radius = getMovementRadius(way_x, way_y);
|
||||
double movement_angle = getAngle(way_x, way_y);
|
||||
private void doubleClickActionCallback()
|
||||
{
|
||||
_DBG("double click");
|
||||
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onDoubleClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void revokeActionCallback()
|
||||
{
|
||||
_DBG("revoke");
|
||||
|
||||
// notify listeners
|
||||
for (AnalogStickListener listener : listeners)
|
||||
{
|
||||
listener.onRevoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePosition(float x, float y)
|
||||
{
|
||||
float way_x = -(getWidth() / 2 - x);
|
||||
float way_y = -(getHeight() / 2 - y);
|
||||
|
||||
float movement_x = 0;
|
||||
float movement_y = 0;
|
||||
|
||||
double movement_radius = getMovementRadius(way_x, way_y);
|
||||
double movement_angle = getAngle(way_x, way_y);
|
||||
|
||||
// chop radius if out of outer circle
|
||||
if (movement_radius > (radius_complete - radius_analog_stick))
|
||||
@@ -309,8 +259,10 @@ public class AnalogStick extends View
|
||||
movement_radius = radius_complete - radius_analog_stick;
|
||||
}
|
||||
|
||||
float correlated_y = (float)(Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
|
||||
float correlated_x = (float)(Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
|
||||
float correlated_y =
|
||||
(float) (Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
|
||||
float correlated_x =
|
||||
(float) (Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
|
||||
|
||||
float complete = (radius_complete - radius_analog_stick);
|
||||
|
||||
@@ -336,71 +288,69 @@ public class AnalogStick extends View
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
|
||||
// get masked (not specific to a pointer) action
|
||||
int action = event.getActionMasked();
|
||||
_CLICK_STATE lastClickState = click_state;
|
||||
boolean wasPressed = analogStickActive;
|
||||
int action = event.getActionMasked();
|
||||
_CLICK_STATE lastClickState = click_state;
|
||||
boolean wasPressed = analogStickActive;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
viewPressed = true;
|
||||
// check for double click
|
||||
if (lastClickState == _CLICK_STATE.SINGLE && timeLastClick + timeoutDoubleClick > System.currentTimeMillis())
|
||||
{
|
||||
click_state = _CLICK_STATE.DOUBLE;
|
||||
{
|
||||
viewPressed = true;
|
||||
// check for double click
|
||||
if (lastClickState == _CLICK_STATE.SINGLE && timeLastClick + timeoutDoubleClick > System.currentTimeMillis())
|
||||
{
|
||||
click_state = _CLICK_STATE.DOUBLE;
|
||||
|
||||
doubleClickActionCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
click_state = _CLICK_STATE.SINGLE;
|
||||
doubleClickActionCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
click_state = _CLICK_STATE.SINGLE;
|
||||
|
||||
clickActionCallback();
|
||||
}
|
||||
clickActionCallback();
|
||||
}
|
||||
|
||||
timeLastClick = System.currentTimeMillis();
|
||||
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
if (analogStickActive || timeLastClick + timeoutDoubleClick < System.currentTimeMillis())
|
||||
{
|
||||
analogStickActive = true;
|
||||
}
|
||||
timeLastClick = System.currentTimeMillis();
|
||||
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
analogStickActive = false;
|
||||
viewPressed = false;
|
||||
if (analogStickActive || timeLastClick + timeoutDoubleClick < System.currentTimeMillis())
|
||||
{
|
||||
analogStickActive = true;
|
||||
}
|
||||
|
||||
revokeActionCallback();
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
analogStickActive = false;
|
||||
viewPressed = false;
|
||||
|
||||
revokeActionCallback();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no longer pressed reset movement
|
||||
if (analogStickActive)
|
||||
{ // when is pressed calculate new positions (will trigger movement if necessary)
|
||||
{ // when is pressed calculate new positions (will trigger movement if necessary)
|
||||
updatePosition(event.getX(), event.getY());
|
||||
}
|
||||
else
|
||||
{ // no longer pressed reset movement
|
||||
if (wasPressed)
|
||||
{
|
||||
moveActionCallback(0, 0);
|
||||
}
|
||||
else if (wasPressed)
|
||||
{
|
||||
moveActionCallback(0, 0);
|
||||
}
|
||||
|
||||
// to get view refreshed
|
||||
@@ -408,4 +358,28 @@ public class AnalogStick extends View
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum _STICK_STATE
|
||||
{
|
||||
NO_MOVEMENT,
|
||||
MOVED
|
||||
}
|
||||
|
||||
|
||||
private enum _CLICK_STATE
|
||||
{
|
||||
SINGLE,
|
||||
DOUBLE
|
||||
}
|
||||
|
||||
public interface AnalogStickListener
|
||||
{
|
||||
void onMovement(float x, float y);
|
||||
|
||||
void onClick();
|
||||
|
||||
void onRevoke();
|
||||
|
||||
void onDoubleClick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -16,214 +15,181 @@ import java.util.TimerTask;
|
||||
/**
|
||||
* Created by Karim on 24.01.2015.
|
||||
*/
|
||||
public class DigitalButton extends View
|
||||
public class DigitalButton extends VirtualControllerElement
|
||||
{
|
||||
private class TimerLongClickTimerTask extends TimerTask
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
onLongClickCallback();
|
||||
}
|
||||
}
|
||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
List<DigitalButtonListener> listeners = new ArrayList<DigitalButtonListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
boolean clicked;
|
||||
private String text = "";
|
||||
private int icon = -1;
|
||||
private long timerLongClickTimeout = 3000;
|
||||
private Timer timerLongClick = null;
|
||||
private TimerLongClickTimerTask longClickTimerTask = null;
|
||||
|
||||
private int normalColor = 0xF0888888;
|
||||
private int pressedColor = 0xF00000FF;
|
||||
private String text = "";
|
||||
private int icon = -1;
|
||||
public DigitalButton(Context context)
|
||||
{
|
||||
super(context);
|
||||
clicked = false;
|
||||
}
|
||||
|
||||
private long timerLongClickTimeout = 3000;
|
||||
private Timer timerLongClick = null;
|
||||
private TimerLongClickTimerTask longClickTimerTask = null;
|
||||
public void addDigitalButtonListener(DigitalButtonListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
onTouchListener = listener;
|
||||
}
|
||||
|
||||
public interface DigitalButtonListener
|
||||
{
|
||||
void onClick();
|
||||
void onLongClick();
|
||||
void onRelease();
|
||||
}
|
||||
public void setText(String text)
|
||||
{
|
||||
this.text = text;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void addDigitalButtonListener(DigitalButtonListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
public void setIcon(int id)
|
||||
{
|
||||
this.icon = id;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setColors(int normalColor, int pressedColor)
|
||||
{
|
||||
this.normalColor = normalColor;
|
||||
this.pressedColor = pressedColor;
|
||||
}
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
onTouchListener = listener;
|
||||
}
|
||||
Paint paint = new Paint();
|
||||
|
||||
private static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("DigitalButton: " + text);
|
||||
}
|
||||
}
|
||||
paint.setTextSize(getPercent(getCorrectWidth(), 50));
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
paint.setStrokeWidth(3);
|
||||
|
||||
List<DigitalButtonListener> listeners = new ArrayList<DigitalButtonListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
paint.setColor(clicked ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
1, 1,
|
||||
getWidth() - 1, getHeight() - 1,
|
||||
paint
|
||||
);
|
||||
|
||||
boolean clicked;
|
||||
if (icon != -1)
|
||||
{
|
||||
Drawable d = getResources().getDrawable(icon);
|
||||
d.setBounds(5, 5, getWidth() - 5, getHeight() - 5);
|
||||
d.draw(canvas);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText(text,
|
||||
getPercent(getWidth(), 50), getPercent(getHeight(), 73),
|
||||
paint);
|
||||
}
|
||||
|
||||
public DigitalButton(Context context)
|
||||
{
|
||||
super(context);
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
clicked = false;
|
||||
}
|
||||
private void onClickCallback()
|
||||
{
|
||||
_DBG("clicked");
|
||||
|
||||
public void setText(String text)
|
||||
{
|
||||
this.text = text;
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onClick();
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
timerLongClick = new Timer();
|
||||
longClickTimerTask = new TimerLongClickTimerTask();
|
||||
|
||||
public void setIcon(int id)
|
||||
{
|
||||
this.icon = id;
|
||||
timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
private void onLongClickCallback()
|
||||
{
|
||||
_DBG("long click");
|
||||
|
||||
private float getPercent(float value, float percent)
|
||||
{
|
||||
return value / 100 * percent;
|
||||
}
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onLongClick();
|
||||
}
|
||||
}
|
||||
|
||||
private int getCorrectWidth()
|
||||
{
|
||||
return getWidth() > getHeight() ? getHeight() : getWidth();
|
||||
}
|
||||
private void onReleaseCallback()
|
||||
{
|
||||
_DBG("released");
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onRelease();
|
||||
}
|
||||
|
||||
Paint paint = new Paint();
|
||||
timerLongClick.cancel();
|
||||
longClickTimerTask.cancel();
|
||||
}
|
||||
|
||||
paint.setTextSize(getPercent(getCorrectWidth(), 50));
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
paint.setStrokeWidth(3);
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
/*
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
*/
|
||||
// get masked (not specific to a pointer) action
|
||||
int action = event.getActionMasked();
|
||||
|
||||
paint.setColor(clicked ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
1, 1,
|
||||
getWidth() - 1, getHeight() - 1,
|
||||
paint
|
||||
);
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
clicked = true;
|
||||
onClickCallback();
|
||||
|
||||
if (icon != -1)
|
||||
{
|
||||
Drawable d = getResources().getDrawable(icon);
|
||||
d.setBounds(5, 5, getWidth() - 5, getHeight() - 5);
|
||||
d.draw(canvas);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText(text,
|
||||
getPercent(getWidth(), 50), getPercent(getHeight(), 73),
|
||||
paint);
|
||||
}
|
||||
invalidate();
|
||||
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
clicked = false;
|
||||
onReleaseCallback();
|
||||
|
||||
private void onClickCallback()
|
||||
{
|
||||
_DBG("clicked");
|
||||
invalidate();
|
||||
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onClick();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
timerLongClick = new Timer();
|
||||
longClickTimerTask = new TimerLongClickTimerTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
|
||||
}
|
||||
public interface DigitalButtonListener
|
||||
{
|
||||
void onClick();
|
||||
|
||||
private void onLongClickCallback()
|
||||
{
|
||||
_DBG("long click");
|
||||
void onLongClick();
|
||||
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onLongClick();
|
||||
}
|
||||
}
|
||||
void onRelease();
|
||||
}
|
||||
|
||||
private void onReleaseCallback()
|
||||
{
|
||||
_DBG("released");
|
||||
|
||||
// notify listeners
|
||||
for (DigitalButtonListener listener : listeners)
|
||||
{
|
||||
listener.onRelease();
|
||||
}
|
||||
|
||||
timerLongClick.cancel();
|
||||
longClickTimerTask.cancel();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
/*
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
*/
|
||||
// get masked (not specific to a pointer) action
|
||||
int action = event.getActionMasked();
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
clicked = true;
|
||||
onClickCallback();
|
||||
|
||||
invalidate();
|
||||
|
||||
return true;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
clicked = false;
|
||||
onReleaseCallback();
|
||||
|
||||
invalidate();
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private class TimerLongClickTimerTask extends TimerTask
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
onLongClickCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -13,273 +12,244 @@ import java.util.List;
|
||||
/**
|
||||
* Created by Karim Mreisi on 23.01.2015.
|
||||
*/
|
||||
public class DigitalPad extends View
|
||||
public class DigitalPad extends VirtualControllerElement
|
||||
{
|
||||
public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0;
|
||||
public final static int DIGITAL_PAD_DIRECTION_LEFT = 1;
|
||||
public final static int DIGITAL_PAD_DIRECTION_UP = 2;
|
||||
public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4;
|
||||
public final static int DIGITAL_PAD_DIRECTION_DOWN = 8;
|
||||
public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0;
|
||||
int direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION;
|
||||
public final static int DIGITAL_PAD_DIRECTION_LEFT = 1;
|
||||
public final static int DIGITAL_PAD_DIRECTION_UP = 2;
|
||||
public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4;
|
||||
public final static int DIGITAL_PAD_DIRECTION_DOWN = 8;
|
||||
List<DigitalPadListener> listeners = new ArrayList<DigitalPadListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
|
||||
private int normalColor = 0xF0888888;
|
||||
private int pressedColor = 0xF00000FF;
|
||||
public DigitalPad(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
public void addDigitalPadListener(DigitalPadListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public interface DigitalPadListener
|
||||
{
|
||||
void onDirectionChange(int direction);
|
||||
}
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
onTouchListener = listener;
|
||||
}
|
||||
|
||||
public void addDigitalPadListener (DigitalPadListener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
|
||||
public void setOnTouchListener(OnTouchListener listener)
|
||||
{
|
||||
onTouchListener = listener;
|
||||
}
|
||||
Paint paint = new Paint();
|
||||
|
||||
private static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("DigitalPad: " + text);
|
||||
}
|
||||
}
|
||||
paint.setTextSize(getPercent(getCorrectWidth(), 20));
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
paint.setStrokeWidth(3);
|
||||
|
||||
List<DigitalPadListener> listeners = new ArrayList<DigitalPadListener>();
|
||||
OnTouchListener onTouchListener = null;
|
||||
if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION)
|
||||
{
|
||||
// draw no direction rect
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setColor(normalColor);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 36), getPercent(getHeight(), 36),
|
||||
getPercent(getWidth(), 63), getPercent(getHeight(), 63),
|
||||
paint
|
||||
);
|
||||
}
|
||||
|
||||
int direction;
|
||||
// draw left rect
|
||||
paint.setColor(
|
||||
(direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("LF",
|
||||
getPercent(getWidth(), 16.5f), getPercent(getHeight(), 56),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
0, getPercent(getHeight(), 33),
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
|
||||
public DigitalPad(Context context)
|
||||
{
|
||||
super(context);
|
||||
// draw left up line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_UP) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
0, getPercent(getWidth(), 33),
|
||||
getPercent(getWidth(), 33), 0,
|
||||
paint
|
||||
);
|
||||
|
||||
direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION;
|
||||
}
|
||||
// draw up rect
|
||||
paint.setColor(
|
||||
(direction & DIGITAL_PAD_DIRECTION_UP) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("UP",
|
||||
getPercent(getWidth(), 49.5f), getPercent(getHeight(), 23),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 33), 0,
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 33),
|
||||
paint
|
||||
);
|
||||
|
||||
private float getPercent(float value, float percent)
|
||||
{
|
||||
return value / 100 * percent;
|
||||
}
|
||||
// draw up right line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_UP) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 66), 0,
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 33),
|
||||
paint
|
||||
);
|
||||
|
||||
private int getCorrectWidth()
|
||||
{
|
||||
return getWidth() > getHeight() ? getHeight() : getWidth();
|
||||
}
|
||||
// draw right rect
|
||||
paint.setColor(
|
||||
(direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("RI",
|
||||
getPercent(getWidth(), 82.5f), getPercent(getHeight(), 56),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 33),
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
|
||||
public void setColors(int normalColor, int pressedColor)
|
||||
{
|
||||
this.normalColor = normalColor;
|
||||
this.pressedColor = pressedColor;
|
||||
}
|
||||
// draw right down line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_DOWN) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 66),
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 100),
|
||||
paint
|
||||
);
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
// set transparent background
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
// draw down rect
|
||||
paint.setColor(
|
||||
(direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("DW",
|
||||
getPercent(getWidth(), 49.5f), getPercent(getHeight(), 89),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 66),
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 100),
|
||||
paint
|
||||
);
|
||||
|
||||
Paint paint = new Paint();
|
||||
// draw down left line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_LEFT) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 100),
|
||||
getPercent(getWidth(), 0), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
|
||||
paint.setTextSize(getPercent(getCorrectWidth(), 20));
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
paint.setStrokeWidth(3);
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION)
|
||||
{
|
||||
// draw no direction rect
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setColor(normalColor);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 36), getPercent(getHeight(), 36),
|
||||
getPercent(getWidth(), 63), getPercent(getHeight(), 63),
|
||||
paint
|
||||
);
|
||||
}
|
||||
private void newDirectionCallback(int direction)
|
||||
{
|
||||
_DBG("direction: " + direction);
|
||||
|
||||
// draw left rect
|
||||
paint.setColor((direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("LF",
|
||||
getPercent(getWidth(), 16.5f), getPercent(getHeight(), 56),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
0, getPercent(getHeight(), 33),
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
// notify listeners
|
||||
for (DigitalPadListener listener : listeners)
|
||||
{
|
||||
listener.onDirectionChange(direction);
|
||||
}
|
||||
}
|
||||
|
||||
// draw left up line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_UP) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
0, getPercent(getWidth(), 33),
|
||||
getPercent(getWidth(), 33), 0,
|
||||
paint
|
||||
);
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
|
||||
// draw up rect
|
||||
paint.setColor((direction & DIGITAL_PAD_DIRECTION_UP) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("UP",
|
||||
getPercent(getWidth(), 49.5f), getPercent(getHeight(), 23),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 33), 0,
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 33),
|
||||
paint
|
||||
);
|
||||
// get masked (not specific to a pointer) action
|
||||
int action = event.getActionMasked();
|
||||
|
||||
// draw up right line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_UP) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 66), 0,
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 33),
|
||||
paint
|
||||
);
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
direction = 0;
|
||||
|
||||
// draw right rect
|
||||
paint.setColor((direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("RI",
|
||||
getPercent(getWidth(), 82.5f), getPercent(getHeight(), 56),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 33),
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
if (event.getX() < getPercent(getWidth(), 33))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_LEFT;
|
||||
}
|
||||
|
||||
// draw right down line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_DOWN) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 100), getPercent(getHeight(), 66),
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 100),
|
||||
paint
|
||||
);
|
||||
if (event.getX() > getPercent(getWidth(), 66))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_RIGHT;
|
||||
}
|
||||
|
||||
// draw down rect
|
||||
paint.setColor((direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 ? pressedColor : normalColor);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
canvas.drawText("DW",
|
||||
getPercent(getWidth(), 49.5f), getPercent(getHeight(), 89),
|
||||
paint);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawRect(
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 66),
|
||||
getPercent(getWidth(), 66), getPercent(getHeight(), 100),
|
||||
paint
|
||||
);
|
||||
if (event.getY() > getPercent(getHeight(), 66))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_DOWN;
|
||||
}
|
||||
|
||||
// draw down left line
|
||||
paint.setColor((
|
||||
(direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 &&
|
||||
(direction & DIGITAL_PAD_DIRECTION_LEFT) > 0
|
||||
) ? pressedColor : normalColor
|
||||
);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(
|
||||
getPercent(getWidth(), 33), getPercent(getHeight(), 100),
|
||||
getPercent(getWidth(), 0), getPercent(getHeight(), 66),
|
||||
paint
|
||||
);
|
||||
if (event.getY() < getPercent(getHeight(), 33))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_UP;
|
||||
}
|
||||
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
newDirectionCallback(direction);
|
||||
|
||||
private void newDirectionCallback(int direction)
|
||||
{
|
||||
_DBG("direction: " + direction);
|
||||
invalidate();
|
||||
|
||||
// notify listeners
|
||||
for (DigitalPadListener listener : listeners)
|
||||
{
|
||||
listener.onDirectionChange(direction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
direction = 0;
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
if (onTouchListener != null)
|
||||
{
|
||||
return onTouchListener.onTouch(this, event);
|
||||
}
|
||||
newDirectionCallback(direction);
|
||||
|
||||
// get masked (not specific to a pointer) action
|
||||
int action = event.getActionMasked();
|
||||
invalidate();
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
{
|
||||
direction = 0;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getX() < getPercent(getWidth(), 33))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_LEFT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.getX() > getPercent(getWidth(), 66))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_RIGHT;
|
||||
}
|
||||
|
||||
if (event.getY() > getPercent(getHeight(), 66))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_DOWN;
|
||||
}
|
||||
|
||||
if (event.getY() < getPercent(getHeight(), 33))
|
||||
{
|
||||
direction |= DIGITAL_PAD_DIRECTION_UP;
|
||||
}
|
||||
|
||||
newDirectionCallback(direction);
|
||||
|
||||
invalidate();
|
||||
|
||||
return true;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
{
|
||||
direction = 0;
|
||||
|
||||
newDirectionCallback(direction);
|
||||
|
||||
invalidate();
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public interface DigitalPadListener
|
||||
{
|
||||
void onDirectionChange(int direction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,9 @@ package com.limelight.binding.input.virtual_controller;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.limelight.R;
|
||||
import com.limelight.nvstream.NvConnection;
|
||||
@@ -19,183 +15,63 @@ import com.limelight.nvstream.input.ControllerPacket;
|
||||
*/
|
||||
public class VirtualController
|
||||
{
|
||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
NvConnection connection = null;
|
||||
private Context context = null;
|
||||
private short inputMap = 0x0000;
|
||||
private byte leftTrigger = 0x00;
|
||||
private byte rightTrigger = 0x00;
|
||||
private short rightStickX = 0x0000;
|
||||
private short rightStickY = 0x0000;
|
||||
private short leftStickX = 0x0000;
|
||||
private short leftStickY = 0x0000;
|
||||
|
||||
private static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("VirtualController: " + text);
|
||||
}
|
||||
}
|
||||
private FrameLayout frame_layout = null;
|
||||
private RelativeLayout relative_layout = null;
|
||||
|
||||
private short inputMap = 0x0000;
|
||||
private byte leftTrigger = 0x00;
|
||||
private byte rightTrigger = 0x00;
|
||||
private short rightStickX = 0x0000;
|
||||
private short rightStickY = 0x0000;
|
||||
private short leftStickX = 0x0000;
|
||||
private short leftStickY = 0x0000;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonStart = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonSelect = null;
|
||||
|
||||
private FrameLayout frame_layout = null;
|
||||
private RelativeLayout relative_layout = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsDPad = null;
|
||||
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonStart = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonSelect = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonA = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonB = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonX = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonY = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonLT = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonRT = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonLB = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonRB = null;
|
||||
|
||||
private RelativeLayout.LayoutParams layoutParamsDPad = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsStick = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsStick2 = null;
|
||||
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonA = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonB = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonX = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonY = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonLT = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonRT = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonLB = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonRB = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null;
|
||||
|
||||
private RelativeLayout.LayoutParams layoutParamsStick = null;
|
||||
private RelativeLayout.LayoutParams layoutParamsStick2 = null;
|
||||
private DigitalButton buttonStart = null;
|
||||
private DigitalButton buttonSelect = null;
|
||||
|
||||
private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null;
|
||||
private DigitalPad digitalPad = null;
|
||||
|
||||
private DigitalButton buttonStart = null;
|
||||
private DigitalButton buttonSelect = null;
|
||||
private DigitalButton buttonA = null;
|
||||
private DigitalButton buttonB = null;
|
||||
private DigitalButton buttonX = null;
|
||||
private DigitalButton buttonY = null;
|
||||
private DigitalButton buttonLT = null;
|
||||
private DigitalButton buttonRT = null;
|
||||
private DigitalButton buttonLB = null;
|
||||
private DigitalButton buttonRB = null;
|
||||
|
||||
private DigitalPad digitalPad = null;
|
||||
private AnalogStick stick = null;
|
||||
private AnalogStick stick2 = null;
|
||||
|
||||
private DigitalButton buttonA = null;
|
||||
private DigitalButton buttonB = null;
|
||||
private DigitalButton buttonX = null;
|
||||
private DigitalButton buttonY = null;
|
||||
private DigitalButton buttonLT = null;
|
||||
private DigitalButton buttonRT = null;
|
||||
private DigitalButton buttonLB = null;
|
||||
private DigitalButton buttonRB = null;
|
||||
|
||||
private AnalogStick stick = null;
|
||||
private AnalogStick stick2 = null;
|
||||
|
||||
private DigitalButton buttonConfigure = null;
|
||||
|
||||
NvConnection connection = null;
|
||||
|
||||
private int getPercentageV(int percent)
|
||||
{
|
||||
return (int)(((float)frame_layout.getHeight() / (float)100) * (float)percent);
|
||||
}
|
||||
|
||||
private int getPercentageH(int percent)
|
||||
{
|
||||
return (int)(((float)frame_layout.getWidth() / (float)100) * (float)percent);
|
||||
}
|
||||
|
||||
private void setPercentilePosition(RelativeLayout.LayoutParams parm, float pos_x, float pos_y)
|
||||
{
|
||||
parm.setMargins(
|
||||
(int)(((float)frame_layout.getWidth() / (float)100 * pos_x) - ((float)parm.width / (float)2)),
|
||||
(int)(((float)frame_layout.getHeight() / (float)100 * pos_y) - ((float)parm.height / (float)2)),
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
void refreshLayout()
|
||||
{
|
||||
relative_layout.removeAllViews();
|
||||
|
||||
layoutParamsDPad = new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30));
|
||||
|
||||
layoutParamsStick = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
|
||||
layoutParamsStick2 = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
|
||||
|
||||
layoutParamsButtonA = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonX = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonY = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonLT = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonRT = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
layoutParamsButtonLB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonRB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
layoutParamsButtonStart = new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
|
||||
layoutParamsButtonSelect = new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
|
||||
|
||||
layoutParamsButtonConfigure = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
setPercentilePosition(layoutParamsDPad, 10, 35);
|
||||
|
||||
setPercentilePosition(layoutParamsStick, 22, 78);
|
||||
setPercentilePosition(layoutParamsStick2, 78, 78);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonA, 85, 52);
|
||||
setPercentilePosition(layoutParamsButtonB, 92, 47);
|
||||
setPercentilePosition(layoutParamsButtonX, 85, 40);
|
||||
setPercentilePosition(layoutParamsButtonY, 92, 35);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonLT, 95, 68);
|
||||
setPercentilePosition(layoutParamsButtonRT, 95, 80);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonLB, 85, 28);
|
||||
setPercentilePosition(layoutParamsButtonRB, 92, 23);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonSelect, 43, 94);
|
||||
setPercentilePosition(layoutParamsButtonStart, 57, 94);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonConfigure, 93, 7);
|
||||
|
||||
relative_layout.addView(digitalPad, layoutParamsDPad);
|
||||
|
||||
relative_layout.addView(stick, layoutParamsStick);
|
||||
relative_layout.addView(stick2, layoutParamsStick2);
|
||||
|
||||
relative_layout.addView(buttonA, layoutParamsButtonA);
|
||||
relative_layout.addView(buttonB, layoutParamsButtonB);
|
||||
relative_layout.addView(buttonX, layoutParamsButtonX);
|
||||
relative_layout.addView(buttonY, layoutParamsButtonY);
|
||||
relative_layout.addView(buttonLT, layoutParamsButtonLT);
|
||||
relative_layout.addView(buttonRT, layoutParamsButtonRT);
|
||||
relative_layout.addView(buttonLB, layoutParamsButtonLB);
|
||||
relative_layout.addView(buttonRB, layoutParamsButtonRB);
|
||||
|
||||
relative_layout.addView(buttonSelect, layoutParamsButtonSelect);
|
||||
relative_layout.addView(buttonStart, layoutParamsButtonStart);
|
||||
|
||||
relative_layout.addView(buttonConfigure, layoutParamsButtonConfigure);
|
||||
}
|
||||
|
||||
private DigitalButton createDigitalButton(String text, final int key, Context context)
|
||||
{
|
||||
DigitalButton button = new DigitalButton(context);
|
||||
button.setText(text);
|
||||
button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener() {
|
||||
@Override
|
||||
public void onClick() {
|
||||
inputMap |= key;
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease() {
|
||||
inputMap &= ~key;
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
private DigitalButton buttonConfigure = null;
|
||||
|
||||
public VirtualController(final NvConnection conn, FrameLayout layout, final Context context)
|
||||
{
|
||||
this.connection = conn;
|
||||
frame_layout = layout;
|
||||
this.connection = conn;
|
||||
this.frame_layout = layout;
|
||||
this.context = context;
|
||||
|
||||
relative_layout = new RelativeLayout(context);
|
||||
|
||||
@@ -210,113 +86,113 @@ public class VirtualController
|
||||
|
||||
frame_layout.addView(relative_layout);
|
||||
|
||||
digitalPad = new DigitalPad(context);
|
||||
digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener()
|
||||
{
|
||||
@Override
|
||||
public void onDirectionChange(int direction)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION)
|
||||
{
|
||||
inputMap &= ~ControllerPacket.LEFT_FLAG;
|
||||
inputMap &= ~ControllerPacket.RIGHT_FLAG;
|
||||
inputMap &= ~ControllerPacket.UP_FLAG;
|
||||
inputMap &= ~ControllerPacket.DOWN_FLAG;
|
||||
digitalPad = new DigitalPad(context);
|
||||
digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener()
|
||||
{
|
||||
@Override
|
||||
public void onDirectionChange(int direction)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION)
|
||||
{
|
||||
inputMap &= ~ControllerPacket.LEFT_FLAG;
|
||||
inputMap &= ~ControllerPacket.RIGHT_FLAG;
|
||||
inputMap &= ~ControllerPacket.UP_FLAG;
|
||||
inputMap &= ~ControllerPacket.DOWN_FLAG;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.LEFT_FLAG;
|
||||
}
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.LEFT_FLAG;
|
||||
}
|
||||
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.RIGHT_FLAG;
|
||||
}
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.RIGHT_FLAG;
|
||||
}
|
||||
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.UP_FLAG;
|
||||
}
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.UP_FLAG;
|
||||
}
|
||||
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.DOWN_FLAG;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0)
|
||||
{
|
||||
inputMap |= ControllerPacket.DOWN_FLAG;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
buttonX = createDigitalButton("X", ControllerPacket.X_FLAG ,context);
|
||||
buttonY = createDigitalButton("Y", ControllerPacket.Y_FLAG ,context);
|
||||
buttonA = createDigitalButton("A", ControllerPacket.A_FLAG ,context);
|
||||
buttonB = createDigitalButton("B", ControllerPacket.B_FLAG ,context);
|
||||
buttonX = createDigitalButton("X", ControllerPacket.X_FLAG, context);
|
||||
buttonY = createDigitalButton("Y", ControllerPacket.Y_FLAG, context);
|
||||
buttonA = createDigitalButton("A", ControllerPacket.A_FLAG, context);
|
||||
buttonB = createDigitalButton("B", ControllerPacket.B_FLAG, context);
|
||||
|
||||
buttonLT = new DigitalButton(context);
|
||||
buttonLT.setText("LT");
|
||||
buttonLT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
leftTrigger = (byte) (1 * 0xFF);
|
||||
buttonLT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
leftTrigger = (byte) (1 * 0xFF);
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
leftTrigger = (byte) (0 * 0xFF);
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
leftTrigger = (byte) (0 * 0xFF);
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
buttonRT = new DigitalButton(context);
|
||||
buttonRT.setText("RT");
|
||||
buttonRT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
rightTrigger = (byte) (0xFF);
|
||||
buttonRT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
rightTrigger = (byte) (0xFF);
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
rightTrigger = (byte) (0);
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
rightTrigger = (byte) (0);
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
buttonLB = createDigitalButton("LB", ControllerPacket.LB_FLAG ,context);
|
||||
buttonRB = createDigitalButton("RB", ControllerPacket.RB_FLAG ,context);
|
||||
buttonLB = createDigitalButton("LB", ControllerPacket.LB_FLAG, context);
|
||||
buttonRB = createDigitalButton("RB", ControllerPacket.RB_FLAG, context);
|
||||
|
||||
stick = new AnalogStick(context);
|
||||
stick = new AnalogStick(context);
|
||||
|
||||
stick.addAnalogStickListener(new AnalogStick.AnalogStickListener()
|
||||
{
|
||||
@@ -326,30 +202,30 @@ public class VirtualController
|
||||
leftStickX = (short) (x * 0x7FFE);
|
||||
leftStickY = (short) (y * 0x7FFE);
|
||||
|
||||
_DBG("LEFT STICK MOVEMENT X: "+ leftStickX + " Y: " + leftStickY);
|
||||
_DBG("LEFT STICK MOVEMENT X: " + leftStickX + " Y: " + leftStickY);
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoubleClick()
|
||||
{
|
||||
inputMap |= ControllerPacket.LS_CLK_FLAG;
|
||||
@Override
|
||||
public void onDoubleClick()
|
||||
{
|
||||
inputMap |= ControllerPacket.LS_CLK_FLAG;
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevoke()
|
||||
{
|
||||
inputMap &= ~ControllerPacket.LS_CLK_FLAG;
|
||||
@Override
|
||||
public void onRevoke()
|
||||
{
|
||||
inputMap &= ~ControllerPacket.LS_CLK_FLAG;
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
stick2 = new AnalogStick(context);
|
||||
@@ -361,83 +237,229 @@ public class VirtualController
|
||||
rightStickX = (short) (x * 0x7FFE);
|
||||
rightStickY = (short) (y * 0x7FFE);
|
||||
|
||||
_DBG("RIGHT STICK MOVEMENT X: "+ rightStickX + " Y: " + rightStickY);
|
||||
_DBG("RIGHT STICK MOVEMENT X: " + rightStickX + " Y: " + rightStickY);
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoubleClick()
|
||||
{
|
||||
inputMap |= ControllerPacket.RS_CLK_FLAG;
|
||||
@Override
|
||||
public void onDoubleClick()
|
||||
{
|
||||
inputMap |= ControllerPacket.RS_CLK_FLAG;
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevoke()
|
||||
{
|
||||
inputMap &= ~ControllerPacket.RS_CLK_FLAG;
|
||||
@Override
|
||||
public void onRevoke()
|
||||
{
|
||||
inputMap &= ~ControllerPacket.RS_CLK_FLAG;
|
||||
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
buttonStart = createDigitalButton("START", ControllerPacket.PLAY_FLAG, context);
|
||||
buttonSelect = createDigitalButton("SELECT", ControllerPacket.SPECIAL_BUTTON_FLAG, context);
|
||||
buttonStart = createDigitalButton("START", ControllerPacket.PLAY_FLAG, context);
|
||||
buttonSelect =
|
||||
createDigitalButton("SELECT", ControllerPacket.SPECIAL_BUTTON_FLAG, context);
|
||||
|
||||
buttonConfigure = new DigitalButton(context);
|
||||
buttonConfigure.setIcon(R.drawable.settings);
|
||||
buttonConfigure.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick() {
|
||||
buttonConfigure = new DigitalButton(context);
|
||||
buttonConfigure.setIcon(R.drawable.settings);
|
||||
buttonConfigure.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
Intent virtualControllerConfiguration = new Intent(context,VirtualControllerSettings.class);
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
openSettingsDialog();
|
||||
}
|
||||
|
||||
virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
|
||||
context.startActivity(virtualControllerConfiguration);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
refreshLayout();
|
||||
}
|
||||
|
||||
private static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("VirtualController: " + text);
|
||||
}
|
||||
}
|
||||
|
||||
private int getPercentageV(int percent)
|
||||
{
|
||||
return (int) (((float) frame_layout.getHeight() / (float) 100) * (float) percent);
|
||||
}
|
||||
|
||||
private int getPercentageH(int percent)
|
||||
{
|
||||
return (int) (((float) frame_layout.getWidth() / (float) 100) * (float) percent);
|
||||
}
|
||||
|
||||
private void setPercentilePosition(RelativeLayout.LayoutParams parm, float pos_x, float pos_y)
|
||||
{
|
||||
parm.setMargins(
|
||||
(int) (((float) frame_layout.getWidth() / (float) 100 * pos_x) - ((float) parm.width / (float) 2)),
|
||||
(int) (((float) frame_layout.getHeight() / (float) 100 * pos_y) - ((float) parm.height / (float) 2)),
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public void openSettingsDialog()
|
||||
{
|
||||
Intent virtualControllerConfiguration =
|
||||
new Intent(context, VirtualControllerSettings.class);
|
||||
virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
context.startActivity(virtualControllerConfiguration);
|
||||
|
||||
}
|
||||
|
||||
void refreshLayout()
|
||||
{
|
||||
relative_layout.removeAllViews();
|
||||
|
||||
layoutParamsDPad =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30));
|
||||
|
||||
layoutParamsStick =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
|
||||
layoutParamsStick2 =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
|
||||
|
||||
layoutParamsButtonA =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonB =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonX =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonY =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonLT =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonRT =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
layoutParamsButtonLB =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
layoutParamsButtonRB =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
layoutParamsButtonStart =
|
||||
new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
|
||||
layoutParamsButtonSelect =
|
||||
new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
|
||||
|
||||
layoutParamsButtonConfigure =
|
||||
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
|
||||
|
||||
setPercentilePosition(layoutParamsDPad, 10, 35);
|
||||
|
||||
setPercentilePosition(layoutParamsStick, 22, 78);
|
||||
setPercentilePosition(layoutParamsStick2, 78, 78);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonA, 85, 52);
|
||||
setPercentilePosition(layoutParamsButtonB, 92, 47);
|
||||
setPercentilePosition(layoutParamsButtonX, 85, 40);
|
||||
setPercentilePosition(layoutParamsButtonY, 92, 35);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonLT, 95, 68);
|
||||
setPercentilePosition(layoutParamsButtonRT, 95, 80);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonLB, 85, 28);
|
||||
setPercentilePosition(layoutParamsButtonRB, 92, 23);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonSelect, 43, 94);
|
||||
setPercentilePosition(layoutParamsButtonStart, 57, 94);
|
||||
|
||||
setPercentilePosition(layoutParamsButtonConfigure, 93, 7);
|
||||
|
||||
relative_layout.addView(digitalPad, layoutParamsDPad);
|
||||
|
||||
relative_layout.addView(stick, layoutParamsStick);
|
||||
relative_layout.addView(stick2, layoutParamsStick2);
|
||||
|
||||
relative_layout.addView(buttonA, layoutParamsButtonA);
|
||||
relative_layout.addView(buttonB, layoutParamsButtonB);
|
||||
relative_layout.addView(buttonX, layoutParamsButtonX);
|
||||
relative_layout.addView(buttonY, layoutParamsButtonY);
|
||||
relative_layout.addView(buttonLT, layoutParamsButtonLT);
|
||||
relative_layout.addView(buttonRT, layoutParamsButtonRT);
|
||||
relative_layout.addView(buttonLB, layoutParamsButtonLB);
|
||||
relative_layout.addView(buttonRB, layoutParamsButtonRB);
|
||||
|
||||
relative_layout.addView(buttonSelect, layoutParamsButtonSelect);
|
||||
relative_layout.addView(buttonStart, layoutParamsButtonStart);
|
||||
|
||||
relative_layout.addView(buttonConfigure, layoutParamsButtonConfigure);
|
||||
}
|
||||
|
||||
private DigitalButton createDigitalButton(String text, final int key, Context context)
|
||||
{
|
||||
DigitalButton button = new DigitalButton(context);
|
||||
button.setText(text);
|
||||
button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick()
|
||||
{
|
||||
inputMap |= key;
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease()
|
||||
{
|
||||
inputMap &= ~key;
|
||||
sendControllerInputPacket();
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private void sendControllerInputPacket()
|
||||
{
|
||||
try {
|
||||
_DBG("INPUT_MAP + " + inputMap);
|
||||
_DBG("LEFT_TRIGGER " + leftTrigger);
|
||||
_DBG("RIGHT_TRIGGER " + rightTrigger);
|
||||
_DBG("LEFT STICK X: " + leftStickX + " Y: " + leftStickY);
|
||||
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
|
||||
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
|
||||
try
|
||||
{
|
||||
_DBG("INPUT_MAP + " + inputMap);
|
||||
_DBG("LEFT_TRIGGER " + leftTrigger);
|
||||
_DBG("RIGHT_TRIGGER " + rightTrigger);
|
||||
_DBG("LEFT STICK X: " + leftStickX + " Y: " + leftStickY);
|
||||
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
|
||||
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
connection.sendControllerInput(inputMap, leftTrigger, rightTrigger,
|
||||
leftStickX, leftStickY, rightStickX, rightStickY);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (connection != null)
|
||||
{
|
||||
connection.sendControllerInput(inputMap, leftTrigger, rightTrigger,
|
||||
leftStickX, leftStickY, rightStickX, rightStickY);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.limelight.binding.input.virtual_controller;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -16,29 +14,30 @@ import com.limelight.R;
|
||||
*/
|
||||
public class VirtualControllerConfiguration extends Activity
|
||||
{
|
||||
VirtualController virtualController;
|
||||
VirtualController virtualController;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// We don't want a title bar
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
// We don't want a title bar
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
// Full-screen and don't let the display go off
|
||||
getWindow().addFlags(
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN |
|
||||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
// Full-screen and don't let the display go off
|
||||
getWindow().addFlags(
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN |
|
||||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
// Inflate the content
|
||||
setContentView(R.layout.activity_configure_virtual_controller);
|
||||
// Inflate the content
|
||||
setContentView(R.layout.activity_configure_virtual_controller);
|
||||
|
||||
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout);
|
||||
FrameLayout frameLayout =
|
||||
(FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout);
|
||||
|
||||
// start with configuration constructor
|
||||
virtualController = new VirtualController(null, frameLayout, this);
|
||||
// start with configuration constructor
|
||||
virtualController = new VirtualController(null, frameLayout, this);
|
||||
|
||||
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.limelight.binding.input.virtual_controller;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Karim on 27.01.2015.
|
||||
*/
|
||||
public abstract class VirtualControllerElement extends View
|
||||
{
|
||||
protected static boolean _PRINT_DEBUG_INFORMATION = false;
|
||||
protected int normalColor = 0xF0888888;
|
||||
protected int pressedColor = 0xF00000FF;
|
||||
|
||||
protected VirtualControllerElement(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
protected static final void _DBG(String text)
|
||||
{
|
||||
if (_PRINT_DEBUG_INFORMATION)
|
||||
{
|
||||
System.out.println("DigitalButton: " + text);
|
||||
}
|
||||
}
|
||||
|
||||
public void setColors(int normalColor, int pressedColor)
|
||||
{
|
||||
this.normalColor = normalColor;
|
||||
this.pressedColor = pressedColor;
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected final float getPercent(float value, float percent)
|
||||
{
|
||||
return value / 100 * percent;
|
||||
}
|
||||
|
||||
protected final int getCorrectWidth()
|
||||
{
|
||||
return getWidth() > getHeight() ? getHeight() : getWidth();
|
||||
}
|
||||
}
|
||||
@@ -2,46 +2,28 @@ package com.limelight.binding.input.virtual_controller;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.limelight.R;
|
||||
|
||||
import org.apache.http.util.VersionInfo;
|
||||
|
||||
/**
|
||||
* Created by Karim on 26.01.2015.
|
||||
*/
|
||||
public class VirtualControllerSettings extends Activity
|
||||
{
|
||||
private static VirtualController controller = null;
|
||||
private static View view = null;
|
||||
private VirtualController controller = null;
|
||||
|
||||
static void setController(VirtualController value)
|
||||
{
|
||||
controller = value;
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
// We don't want a title bar
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
static void setView(View value)
|
||||
{
|
||||
view = value;
|
||||
}
|
||||
// Inflate the content
|
||||
setContentView(R.layout.activity_virtual_controller_settings);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
// We don't want a title bar
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
// Inflate the content
|
||||
setContentView(R.layout.activity_virtual_controller_settings);
|
||||
|
||||
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +251,11 @@ public class ComputerManagerService extends Service {
|
||||
((!details.name.isEmpty() && !tuple.computer.name.isEmpty()) &&
|
||||
tuple.computer.name.equals(details.name))) {
|
||||
|
||||
// Update details anyway in case this machine has been re-added by IP
|
||||
// after not being reachable by our existing information
|
||||
tuple.computer.localIp = details.localIp;
|
||||
tuple.computer.remoteIp = details.remoteIp;
|
||||
|
||||
// Start a polling thread if polling is active
|
||||
if (pollingActive && tuple.thread == null) {
|
||||
tuple.thread = createPollingThread(details);
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
package com.limelight.grid;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.koushikdutta.async.future.FutureCallback;
|
||||
import com.koushikdutta.ion.ImageViewBitmapInfo;
|
||||
import com.koushikdutta.ion.Ion;
|
||||
import com.koushikdutta.ion.bitmap.BitmapInfo;
|
||||
import com.limelight.AppView;
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.R;
|
||||
import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.nvstream.http.LimelightCryptoProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyManagementException;
|
||||
@@ -32,14 +46,15 @@ import java.security.cert.X509Certificate;
|
||||
|
||||
public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
||||
|
||||
private boolean listMode;
|
||||
private InetAddress address;
|
||||
private String uniqueId;
|
||||
private LimelightCryptoProvider cryptoProvider;
|
||||
private SSLContext sslContext;
|
||||
private final HashMap<ImageView, Future> pendingRequests = new HashMap<ImageView, Future>();
|
||||
|
||||
public AppGridAdapter(Context context, InetAddress address, String uniqueId) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
super(context, R.layout.app_grid_item, R.drawable.image_loading);
|
||||
public AppGridAdapter(Context context, boolean listMode, InetAddress address, String uniqueId) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
super(context, listMode ? R.layout.simple_row : R.layout.app_grid_item, R.drawable.image_loading);
|
||||
|
||||
this.address = address;
|
||||
this.uniqueId = uniqueId;
|
||||
@@ -107,7 +122,9 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
||||
}
|
||||
|
||||
for (Future f : tempMap.values()) {
|
||||
f.cancel(true);
|
||||
if (!f.isCancelled() && !f.isDone()) {
|
||||
f.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (pendingRequests) {
|
||||
@@ -118,28 +135,92 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap checkBitmapCache(String addrStr, int appId) {
|
||||
File addrFolder = new File(context.getCacheDir(), addrStr);
|
||||
if (addrFolder.isDirectory()) {
|
||||
File bitmapFile = new File(addrFolder, appId+".png");
|
||||
if (bitmapFile.exists()) {
|
||||
InputStream fileIn = null;
|
||||
try {
|
||||
fileIn = new BufferedInputStream(new FileInputStream(bitmapFile));
|
||||
Bitmap bm = BitmapFactory.decodeStream(fileIn);
|
||||
if (bm == null) {
|
||||
// The image seems corrupt
|
||||
bitmapFile.delete();
|
||||
}
|
||||
|
||||
return bm;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
bitmapFile.delete();
|
||||
} finally {
|
||||
if (fileIn != null) {
|
||||
try {
|
||||
fileIn.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Handle pruning of bitmap cache
|
||||
private void populateBitmapCache(String addrStr, int appId, Bitmap bitmap) {
|
||||
File addrFolder = new File(context.getCacheDir(), addrStr);
|
||||
addrFolder.mkdirs();
|
||||
|
||||
File bitmapFile = new File(addrFolder, appId+".png");
|
||||
try {
|
||||
// PNG ignores quality setting
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(bitmapFile));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean populateImageView(final ImageView imgView, AppView.AppObject obj) {
|
||||
public boolean populateImageView(final ImageView imgView, final AppView.AppObject obj) {
|
||||
|
||||
// Set SSL contexts correctly to allow us to authenticate
|
||||
Ion.getDefault(imgView.getContext()).getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustAllCerts);
|
||||
Ion.getDefault(imgView.getContext()).getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext);
|
||||
|
||||
// Set off the deferred image load
|
||||
// Check the on-disk cache
|
||||
Bitmap cachedBitmap = checkBitmapCache(address.getHostAddress(), obj.app.getAppId());
|
||||
if (cachedBitmap != null) {
|
||||
// Cache hit; we're done
|
||||
LimeLog.info("Image cache hit for ("+address.getHostAddress()+", "+obj.app.getAppId()+")");
|
||||
imgView.setImageBitmap(cachedBitmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Kick off the deferred image load
|
||||
synchronized (pendingRequests) {
|
||||
Future f = Ion.with(imgView)
|
||||
Future<ImageViewBitmapInfo> f = Ion.with(imgView)
|
||||
.placeholder(defaultImageRes)
|
||||
.error(defaultImageRes)
|
||||
.load("https://" + address.getHostAddress() + ":47984/appasset?uniqueid=" + uniqueId + "&appid=" +
|
||||
obj.app.getAppId() + "&AssetType=2&AssetIdx=0")
|
||||
.setCallback(new FutureCallback<ImageView>() {
|
||||
@Override
|
||||
public void onCompleted(Exception e, ImageView result) {
|
||||
synchronized (pendingRequests) {
|
||||
pendingRequests.remove(imgView);
|
||||
}
|
||||
}
|
||||
});
|
||||
.withBitmapInfo()
|
||||
.setCallback(
|
||||
new FutureCallback<ImageViewBitmapInfo>() {
|
||||
@Override
|
||||
public void onCompleted(Exception e, ImageViewBitmapInfo result) {
|
||||
synchronized (pendingRequests) {
|
||||
pendingRequests.remove(imgView);
|
||||
}
|
||||
|
||||
// Populate the cache if we got an image back
|
||||
if (result != null &&
|
||||
result.getBitmapInfo() != null &&
|
||||
result.getBitmapInfo().bitmap != null) {
|
||||
populateBitmapCache(address.getHostAddress(), obj.app.getAppId(),
|
||||
result.getBitmapInfo().bitmap);
|
||||
}
|
||||
}
|
||||
});
|
||||
pendingRequests.put(imgView, f);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,17 +60,21 @@ public abstract class GenericGridAdapter<T> extends BaseAdapter {
|
||||
ImageView overlayView = (ImageView) convertView.findViewById(R.id.grid_overlay);
|
||||
TextView txtView = (TextView) convertView.findViewById(R.id.grid_text);
|
||||
|
||||
if (!populateImageView(imgView, itemList.get(i))) {
|
||||
imgView.setImageResource(defaultImageRes);
|
||||
if (imgView != null) {
|
||||
if (!populateImageView(imgView, itemList.get(i))) {
|
||||
imgView.setImageResource(defaultImageRes);
|
||||
}
|
||||
}
|
||||
if (!populateTextView(txtView, itemList.get(i))) {
|
||||
txtView.setText(itemList.get(i).toString());
|
||||
}
|
||||
if (!populateOverlayView(overlayView, itemList.get(i))) {
|
||||
overlayView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
else {
|
||||
overlayView.setVisibility(View.VISIBLE);
|
||||
if (overlayView != null) {
|
||||
if (!populateOverlayView(overlayView, itemList.get(i))) {
|
||||
overlayView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
else {
|
||||
overlayView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
return convertView;
|
||||
|
||||
@@ -8,14 +8,27 @@ import com.limelight.PcView;
|
||||
import com.limelight.R;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class PcGridAdapter extends GenericGridAdapter<PcView.ComputerObject> {
|
||||
|
||||
public PcGridAdapter(Context context) {
|
||||
super(context, R.layout.pc_grid_item, R.drawable.computer);
|
||||
public PcGridAdapter(Context context, boolean listMode) {
|
||||
super(context, listMode ? R.layout.simple_row : R.layout.pc_grid_item, R.drawable.computer);
|
||||
}
|
||||
|
||||
public void addComputer(PcView.ComputerObject computer) {
|
||||
itemList.add(computer);
|
||||
sortList();
|
||||
}
|
||||
|
||||
private void sortList() {
|
||||
Collections.sort(itemList, new Comparator<PcView.ComputerObject>() {
|
||||
@Override
|
||||
public int compare(PcView.ComputerObject lhs, PcView.ComputerObject rhs) {
|
||||
return lhs.details.name.compareTo(rhs.details.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean removeComputer(PcView.ComputerObject computer) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.limelight.preferences;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
@@ -15,8 +16,10 @@ import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.Preference;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
@@ -132,6 +135,13 @@ public class AddComputerManually extends Activity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String locale = PreferenceConfiguration.readPreferences(this).language;
|
||||
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
|
||||
Configuration config = new Configuration(getResources().getConfiguration());
|
||||
config.locale = new Locale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_add_computer_manually);
|
||||
|
||||
UiHelper.notifyNewRootView(this);
|
||||
|
||||
@@ -13,6 +13,8 @@ public class PreferenceConfiguration {
|
||||
private static final String DISABLE_TOASTS_PREF_STRING = "checkbox_disable_warnings";
|
||||
private static final String HOST_AUDIO_PREF_STRING = "checkbox_host_audio";
|
||||
private static final String DEADZONE_PREF_STRING = "seekbar_deadzone";
|
||||
private static final String LANGUAGE_PREF_STRING = "list_languages";
|
||||
private static final String LIST_MODE_PREF_STRING = "checkbox_list_mode";
|
||||
|
||||
private static final String VIRTUAL_CONTROLLER_ENABLE = "virtual_controller_checkbox_enable";
|
||||
private static final Boolean VIRTUAL_CONTROLLER_ENABLE_DEFAULT = true;
|
||||
@@ -30,6 +32,8 @@ public class PreferenceConfiguration {
|
||||
private static final boolean DEFAULT_DISABLE_TOASTS = false;
|
||||
private static final boolean DEFAULT_HOST_AUDIO = false;
|
||||
private static final int DEFAULT_DEADZONE = 15;
|
||||
public static final String DEFAULT_LANGUAGE = "default";
|
||||
private static final boolean DEFAULT_LIST_MODE = false;
|
||||
|
||||
public static final int FORCE_HARDWARE_DECODER = -1;
|
||||
public static final int AUTOSELECT_DECODER = 0;
|
||||
@@ -40,6 +44,8 @@ public class PreferenceConfiguration {
|
||||
public int decoder;
|
||||
public int deadzonePercentage;
|
||||
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
|
||||
public String language;
|
||||
public boolean listMode;
|
||||
|
||||
public boolean virtualController_enable;
|
||||
|
||||
@@ -140,11 +146,14 @@ public class PreferenceConfiguration {
|
||||
|
||||
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
|
||||
|
||||
config.language = prefs.getString(LANGUAGE_PREF_STRING, DEFAULT_LANGUAGE);
|
||||
|
||||
// Checkbox preferences
|
||||
config.disableWarnings = prefs.getBoolean(DISABLE_TOASTS_PREF_STRING, DEFAULT_DISABLE_TOASTS);
|
||||
config.enableSops = prefs.getBoolean(SOPS_PREF_STRING, DEFAULT_SOPS);
|
||||
config.stretchVideo = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH);
|
||||
config.playHostAudio = prefs.getBoolean(HOST_AUDIO_PREF_STRING, DEFAULT_HOST_AUDIO);
|
||||
config.listMode = prefs.getBoolean(LIST_MODE_PREF_STRING, DEFAULT_LIST_MODE);
|
||||
|
||||
config.virtualController_enable = prefs.getBoolean(VIRTUAL_CONTROLLER_ENABLE, VIRTUAL_CONTROLLER_ENABLE_DEFAULT);
|
||||
|
||||
|
||||
@@ -2,22 +2,33 @@ package com.limelight.preferences;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.app.Activity;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.limelight.PcView;
|
||||
import com.limelight.R;
|
||||
import com.limelight.binding.input.virtual_controller.VirtualController;
|
||||
import com.limelight.binding.input.virtual_controller.VirtualControllerConfiguration;
|
||||
import com.limelight.utils.UiHelper;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class StreamSettings extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String locale = PreferenceConfiguration.readPreferences(this).language;
|
||||
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
|
||||
Configuration config = new Configuration(getResources().getConfiguration());
|
||||
config.locale = new Locale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_stream_settings);
|
||||
getFragmentManager().beginTransaction().replace(
|
||||
R.id.stream_settings, new SettingsFragment()
|
||||
@@ -26,6 +37,16 @@ public class StreamSettings extends Activity {
|
||||
UiHelper.notifyNewRootView(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
finish();
|
||||
|
||||
// Restart the PC view to apply UI changes
|
||||
Intent intent = new Intent(this, PcView.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent, null);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
35
app/src/main/java/com/limelight/ui/AdapterFragment.java
Normal file
35
app/src/main/java/com/limelight/ui/AdapterFragment.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.limelight.ui;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
|
||||
import com.limelight.R;
|
||||
|
||||
public class AdapterFragment extends Fragment {
|
||||
private AdapterFragmentCallbacks callbacks;
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
callbacks = (AdapterFragmentCallbacks) activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(callbacks.getAdapterFragmentLayoutId(), container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
callbacks.receiveAbsListView((AbsListView) getView().findViewById(R.id.fragmentView));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.limelight.ui;
|
||||
|
||||
import android.widget.AbsListView;
|
||||
|
||||
public interface AdapterFragmentCallbacks {
|
||||
public int getAdapterFragmentLayoutId();
|
||||
public void receiveAbsListView(AbsListView gridView);
|
||||
}
|
||||
5
app/src/main/java/com/limelight/ui/GameGestures.java
Normal file
5
app/src/main/java/com/limelight/ui/GameGestures.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.limelight.ui;
|
||||
|
||||
public interface GameGestures {
|
||||
public void showKeyboard();
|
||||
}
|
||||
7
app/src/main/res/drawable/list_view_unselected.xml
Normal file
7
app/src/main/res/drawable/list_view_unselected.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
|
||||
<stroke android:width="1dip" android:color="#ffffff"/>
|
||||
|
||||
</shape>
|
||||
@@ -33,12 +33,10 @@
|
||||
android:text="@string/searching_pc"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<GridView
|
||||
android:id="@+id/pcGridView"
|
||||
<FrameLayout
|
||||
android:id="@+id/pcFragmentContainer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="160dp"
|
||||
android:gravity="center"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentTop="true"
|
||||
|
||||
@@ -33,12 +33,10 @@
|
||||
android:text="@string/searching_pc"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<GridView
|
||||
android:id="@+id/pcGridView"
|
||||
<FrameLayout
|
||||
android:id="@+id/pcFragmentContainer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="160dp"
|
||||
android:gravity="center"
|
||||
android:layout_toLeftOf="@+id/manuallyAddPc"
|
||||
android:layout_toStartOf="@+id/manuallyAddPc"
|
||||
|
||||
@@ -8,21 +8,17 @@
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context=".AppView" >
|
||||
|
||||
<GridView
|
||||
android:id="@+id/appGridView"
|
||||
<FrameLayout
|
||||
android:id="@+id/appFragmentContainer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="160dp"
|
||||
android:stretchMode="spacingWidth"
|
||||
android:gravity="center"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_below="@+id/appListText">
|
||||
</GridView>
|
||||
android:layout_below="@+id/appListText"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/appListText"
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
android:text="Color 1"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
android:text="Color 2"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_width="200dp"
|
||||
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
|
||||
13
app/src/main/res/layout/app_grid_view.xml
Normal file
13
app/src/main/res/layout/app_grid_view.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<GridView
|
||||
android:id="@+id/fragmentView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="160dp"
|
||||
android:stretchMode="spacingWidth"
|
||||
android:gravity="center"/>
|
||||
</LinearLayout>
|
||||
17
app/src/main/res/layout/list_view.xml
Normal file
17
app/src/main/res/layout/list_view.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/fragmentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/list_view_unselected"
|
||||
android:fastScrollEnabled="true"
|
||||
android:longClickable="false"
|
||||
android:stackFromBottom="false" >
|
||||
|
||||
</ListView>
|
||||
|
||||
</LinearLayout>
|
||||
12
app/src/main/res/layout/pc_grid_view.xml
Normal file
12
app/src/main/res/layout/pc_grid_view.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<GridView
|
||||
android:id="@+id/fragmentView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="160dp"
|
||||
android:gravity="center"/>
|
||||
</LinearLayout>
|
||||
15
app/src/main/res/layout/simple_row.xml
Normal file
15
app/src/main/res/layout/simple_row.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:padding="10dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grid_text"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="false"
|
||||
android:textSize="16sp" >
|
||||
</TextView>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -94,11 +94,17 @@
|
||||
<string name="title_seekbar_deadzone">Aggiusta deadzone degli stick analogici</string>
|
||||
<string name="suffix_seekbar_deadzone">%</string>
|
||||
|
||||
<string name="category_ui_settings">UI Settings</string>
|
||||
<string name="title_language_list">Lingua</string>
|
||||
<string name="summary_language_list">Lingua da usare in Limelight</string>
|
||||
<string name="title_checkbox_list_mode">Use lists instead of grids</string>
|
||||
<string name="summary_checkbox_list_mode">Display apps and PCs in lists instead of grids</string>
|
||||
|
||||
<string name="category_host_settings">Impostazioni Host</string>
|
||||
<string name="title_checkbox_enable_sops">Ottimizza le impostazioni dei giochi</string>
|
||||
<string name="summary_checkbox_enable_sops">Permetti a GFE di modificare le impostazioni dei giochi per uno streaming ottimale</string>
|
||||
<string name="title_checkbox_host_audio">Riproduci audio sul PC</string>
|
||||
<string name="summary_checkbox_host_audio">Riproduci l\'audio sul computer e su questo dispositivo. Richiede GFE 2.1.2+</string>
|
||||
<string name="summary_checkbox_host_audio">Riproduci l\'audio sul computer e su questo dispositivo</string>
|
||||
|
||||
<string name="category_advanced_settings">Impostazioni Avanzate</string>
|
||||
<string name="title_decoder_list">Cambia decoder</string>
|
||||
|
||||
@@ -13,6 +13,17 @@
|
||||
<item>1080p60</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="language_names" translatable="false">
|
||||
<item>Default</item>
|
||||
<item>English</item>
|
||||
<item>Italiano</item>
|
||||
</string-array>
|
||||
<string-array name="language_values" translatable="false">
|
||||
<item>default</item>
|
||||
<item>en</item>
|
||||
<item>it</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="decoder_names">
|
||||
<item>Auto-select Decoder</item>
|
||||
<item>Force Software Decoding</item>
|
||||
|
||||
@@ -94,11 +94,17 @@
|
||||
<string name="title_seekbar_deadzone">Adjust analog stick deadzone</string>
|
||||
<string name="suffix_seekbar_deadzone">%</string>
|
||||
|
||||
<string name="category_ui_settings">UI Settings</string>
|
||||
<string name="title_language_list">Language</string>
|
||||
<string name="summary_language_list">Language to use for Limelight</string>
|
||||
<string name="title_checkbox_list_mode">Use lists instead of grids</string>
|
||||
<string name="summary_checkbox_list_mode">Display apps and PCs in lists instead of grids</string>
|
||||
|
||||
<string name="category_host_settings">Host Settings</string>
|
||||
<string name="title_checkbox_enable_sops">Optimize game settings</string>
|
||||
<string name="summary_checkbox_enable_sops">Allow GFE to modify game settings for optimal streaming</string>
|
||||
<string name="title_checkbox_host_audio">Play audio on PC</string>
|
||||
<string name="summary_checkbox_host_audio">Play audio from the computer and this device. Requires GFE 2.1.2+</string>
|
||||
<string name="summary_checkbox_host_audio">Play audio from the computer and this device</string>
|
||||
|
||||
<string name="category_advanced_settings">Advanced Settings</string>
|
||||
<string name="title_decoder_list">Change decoder</string>
|
||||
|
||||
@@ -46,6 +46,20 @@
|
||||
android:summary="@string/summary_checkbox_host_audio"
|
||||
android:defaultValue="false" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/category_ui_settings">
|
||||
<ListPreference
|
||||
android:key="list_languages"
|
||||
android:title="@string/title_language_list"
|
||||
android:entries="@array/language_names"
|
||||
android:entryValues="@array/language_values"
|
||||
android:summary="@string/summary_language_list"
|
||||
android:defaultValue="default" />
|
||||
<CheckBoxPreference
|
||||
android:key="checkbox_list_mode"
|
||||
android:title="@string/title_checkbox_list_mode"
|
||||
android:summary="@string/summary_checkbox_list_mode"
|
||||
android:defaultValue="false" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/category_advanced_settings">
|
||||
<ListPreference
|
||||
android:key="list_decoders"
|
||||
@@ -66,4 +80,4 @@
|
||||
android:summary="tbd"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
||||
Reference in New Issue
Block a user