Skip to content

Commit

Permalink
Switch UI to use data binding and make actual phone work
Browse files Browse the repository at this point in the history
  • Loading branch information
efokschaner committed Jan 9, 2016
1 parent fdc2444 commit 3ab75d0
Show file tree
Hide file tree
Showing 11 changed files with 445 additions and 363 deletions.
10 changes: 9 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
apply plugin: 'com.android.application'
//apply plugin: 'com.android.databinding'

android {
compileSdkVersion 23
buildToolsVersion "19.1.0"
buildToolsVersion '23.0.2'

defaultConfig {
applicationId "efokschaner.infinityloopsolver"
Expand All @@ -16,6 +17,13 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
}
}
dataBinding {
enabled = true
}
}

Expand Down
Binary file modified app/src/main/assets/Empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static void sendBitmap(Bitmap bitmap) {
@Override
public void run() {
try {
URL url = new URL("http://10.0.2.2:8888/" + getNewTimestamp() + ".png");
URL url = new URL("http://efoks1ml1:8888/" + getNewTimestamp() + ".png");
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
Expand Down
508 changes: 263 additions & 245 deletions app/src/main/java/efokschaner/infinityloopsolver/ImageProcessor.java

Large diffs are not rendered by default.

54 changes: 30 additions & 24 deletions app/src/main/java/efokschaner/infinityloopsolver/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
package efokschaner.infinityloopsolver;

import android.databinding.DataBindingUtil;
import android.databinding.ObservableField;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.view.View;
import android.widget.Switch;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;

import efokschaner.infinityloopsolver.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();

Switch mEnabledSwitch;
public ObservableField<Solver> solver;

public View.OnClickListener onEnable = new View.OnClickListener() {
@Override
public void onClick(View v) {
solver.get().isEnabled.set(((Switch)v).isChecked());
}
};

public View.OnClickListener onRunOnce = new View.OnClickListener() {
@Override
public void onClick(View v) {
solver.get().runOnce();
}
};

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch(status) {
case LoaderCallbackInterface.SUCCESS:
Log.i(TAG, "OpenCV Manager Connected");
mEnabledSwitch.setEnabled(true);
((SolverApplication) getApplication()).createSolver();
break;
case LoaderCallbackInterface.INIT_FAILED:
Log.i(TAG,"Init Failed");
Expand All @@ -43,36 +61,24 @@ public void onManagerConnected(int status) {
}
};

@Override
protected void onResume() {
super.onResume();
//initialize OpenCV manager
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mLoaderCallback);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SolverApplication app = (SolverApplication) getApplication();
setContentView(R.layout.activity_main);
mEnabledSwitch = (Switch) findViewById(R.id.switch_solver_enabled);
mEnabledSwitch.setEnabled(false);
mEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
app.enableSolver();
} else {
app.disableSolver();
}
}
});
solver = app.solver;
//initialize OpenCV manager
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mLoaderCallback);
ActivityMainBinding m = DataBindingUtil.setContentView(this, R.layout.activity_main);
m.setModel(this);
}

@Override
protected void onDestroy() {
final SolverApplication app = (SolverApplication) getApplication();
app.disableSolver();
final Solver solver = app.solver.get();
if(solver != null) {
solver.isEnabled.set(false);
}
super.onDestroy();
}
}
108 changes: 61 additions & 47 deletions app/src/main/java/efokschaner/infinityloopsolver/Solver.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@


import android.app.UiAutomation;
import android.databinding.Observable;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableField;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
Expand All @@ -22,20 +24,42 @@ public class Solver {
private final UiAutomation mUiAutomation;
private final ImageProcessor mImageProcessor;
private Thread mSolverThread;
private boolean mNextRunIsOnce;

public final ObservableBoolean isEnabled = new ObservableBoolean(false);
public final ObservableField<String> lastError = new ObservableField<>();

private void startOrStopSolverThread() {
if(isEnabled.get() && isInfinityLoopReady(mUiAutomation.getWindows())) {
if(mSolverThread == null) {
mSolverThread = new Thread(getSolverFunc(mNextRunIsOnce));
mNextRunIsOnce = false;
mSolverThread.start();
}
} else {
stopSolver();
}
}

public void runOnce() {
mNextRunIsOnce = true;
isEnabled.set(true);
}

public Solver(UiAutomation uiAutomation, ImageProcessor imageProcessor) {
isEnabled.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
startOrStopSolverThread();
}
});
mImageProcessor = imageProcessor;
mUiAutomation = uiAutomation;
mUiAutomation.setOnAccessibilityEventListener(new UiAutomation.OnAccessibilityEventListener() {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if(isInfinityLoopReady(mUiAutomation, event)) {
if(mSolverThread == null) {
mSolverThread = new Thread(mRunnableSolver);
mSolverThread.start();
}
} else {
stopSolver();
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED) {
startOrStopSolverThread();
}
}
});
Expand All @@ -55,11 +79,6 @@ private void stopSolver() {
}
}

public void shutdown() {
mUiAutomation.setOnAccessibilityEventListener(null);
stopSolver();
}

private static final Runnable NOOP = new Runnable() { public void run() {} };

private static AccessibilityNodeInfo findInfinityLoopView(AccessibilityNodeInfo node) {
Expand All @@ -84,15 +103,6 @@ private static boolean isInfinityLoopReady(List<AccessibilityWindowInfo> windows
(findInfinityLoopView(windows.get(0).getRoot())) != null);
}

private static boolean isInfinityLoopReady(UiAutomation uiAutomation, AccessibilityEvent event) {
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED) {
final List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
return isInfinityLoopReady(windows);
} else {
return false;
}
}

/**
* Helper method injects a click event at a point on the active screen via the UiAutomation object.
* @param x the x position on the screen to inject the click event
Expand Down Expand Up @@ -129,23 +139,23 @@ private static void injectClickEvent(float x, float y, UiAutomation automation){
motionDown.recycle();
}

private Runnable mRunnableSolver = new Runnable() {
@Override
public void run() {
try {
mUiAutomation.waitForIdle(1000, 10000);
while(!Thread.interrupted()) {
// click to complete the level
Log.d(TAG, "Completing level");
injectClickEvent(20, 20, mUiAutomation);
Thread.sleep(3200);
Log.d(TAG, "Interpreting");
Bitmap b = mUiAutomation.takeScreenshot();
try{
final GameState gameStateFromImage = mImageProcessor.getGameStateFromImage(b);
if(gameStateFromImage != null) {
Log.d(TAG, "Solving");
try {
private Runnable getSolverFunc(final boolean runOnce) {
return new Runnable() {
@Override
public void run() {
try {
mUiAutomation.waitForIdle(1000, 10000);
while(!Thread.interrupted()) {
// click to complete the level
Log.d(TAG, "Completing level");
injectClickEvent(20, 20, mUiAutomation);
Thread.sleep(3200);
Log.d(TAG, "Interpreting");
Bitmap b = mUiAutomation.takeScreenshot();
try{
final GameState gameStateFromImage = mImageProcessor.getGameStateFromImage(b);
if(gameStateFromImage != null) {
Log.d(TAG, "Solving");
final List<ClickAction> actions = gameStateFromImage.getSolution();
if(!Thread.interrupted()) {
Log.d(TAG, "Acting");
Expand All @@ -154,17 +164,21 @@ public void run() {
}
Thread.sleep(1500);
}
} catch (GameState.UnsolvableError unsolvableError) {
unsolvableError.printStackTrace();
}
} finally {
b.recycle();
}
if(runOnce) {
break;
}
} finally {
b.recycle();
}
} catch (TimeoutException | InterruptedException | GameState.UnsolvableError e) {
e.printStackTrace();
lastError.set(Log.getStackTraceString(e));
} finally {
isEnabled.set(false);
}
} catch (TimeoutException | InterruptedException e) {
e.printStackTrace();
}
}
};
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,39 @@
import android.app.UiAutomation;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.databinding.Observable;
import android.databinding.ObservableField;

public class SolverApplication extends Application {
public final ObservableField<Solver> solver = new ObservableField<>();

private ImageProcessor mProcessor;
private UiAutomation mUiAutomation;

private ImageProcessor getImageProcessor() {
if (mProcessor == null) {
mProcessor = new ImageProcessor(getAssets());
}
return mProcessor;
}

private UiAutomation mUiAutomation;

public void setUiAutomation(UiAutomation mUiAutomation) {
this.mUiAutomation = mUiAutomation;
}

private Solver mSolver;

public void enableSolver() {
if(mSolver == null) {
mSolver = new Solver(mUiAutomation, getImageProcessor());
final PackageManager packageManager = SolverApplication.this.getPackageManager();
final Intent launchIntent = packageManager.getLaunchIntentForPackage("com.balysv.loop");
if(launchIntent != null) {
SolverApplication.this.startActivity(launchIntent);
public void createSolver() {
solver.set(new Solver(mUiAutomation, getImageProcessor()));
solver.get().isEnabled.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
if (solver.get().isEnabled.get()) {
final PackageManager packageManager = SolverApplication.this.getPackageManager();
final Intent launchIntent = packageManager.getLaunchIntentForPackage("com.balysv.loop");
if (launchIntent != null) {
SolverApplication.this.startActivity(launchIntent);
}
}
}
}
});
}

public void disableSolver() {
if(mSolver != null) {
mSolver.shutdown();
mSolver = null;
}
public void setUiAutomation(UiAutomation uiAutomation) {
mUiAutomation = uiAutomation;
}

}
Loading

0 comments on commit 3ab75d0

Please sign in to comment.