DroidFish: Added function to receive chess positions from other programs using intent ACTION_GET_CONTENT of type "application/x-chess-fen".

This commit is contained in:
Peter Osterlund 2013-03-02 11:58:48 +00:00
parent c16424aa9c
commit 6a1186dca5
4 changed files with 185 additions and 47 deletions

View File

@ -37,6 +37,7 @@ you are not actively using the program.\
<string name="load_game">Load game from PGN file</string>
<string name="load_scid_game">Load game from Scid file</string>
<string name="save_game">Save game to PGN file</string>
<string name="get_fen">Retrieve Position</string>
<string name="truncate_gametree">Truncate Game Tree</string>
<string name="move_var_up">Move Variation Up</string>
<string name="move_var_down">Move Variation Down</string>

View File

@ -19,15 +19,14 @@
package org.petero.droidfish;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -75,8 +74,10 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Typeface;
@ -1159,6 +1160,7 @@ public class DroidFish extends Activity implements GUIInterface {
static private final int RESULT_SELECT_SCID = 3;
static private final int RESULT_OI_PGN_SAVE = 4;
static private final int RESULT_OI_PGN_LOAD = 5;
static private final int RESULT_GET_FEN = 6;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@ -1289,6 +1291,39 @@ public class DroidFish extends Activity implements GUIInterface {
}
}
break;
case RESULT_GET_FEN:
if (resultCode == RESULT_OK) {
String fen = data.getStringExtra(Intent.EXTRA_TEXT);
if (fen == null) {
String pathName = getFilePathFromUri(data.getData());
if (pathName != null) {
InputStream is = null;
try {
is = new FileInputStream(pathName);
fen = Util.readFromStream(is);
} catch (FileNotFoundException e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
} finally {
if (is != null)
try { is.close(); } catch (IOException e) {}
}
}
}
if (fen != null) {
try {
ctrl.setFENOrPGN(fen);
} catch (ChessParseError e) {
// If FEN corresponds to illegal chess position, go into edit board mode.
try {
TextIO.readFEN(fen);
} catch (ChessParseError e2) {
if (e2.pos != null)
startEditBoard(fen);
}
}
}
}
break;
}
}
@ -1302,7 +1337,7 @@ public class DroidFish extends Activity implements GUIInterface {
ctrl.setGameMode(gameMode);
}
private static String getFilePathFromUri(Uri uri) {
public static String getFilePathFromUri(Uri uri) {
if (uri == null)
return null;
return uri.getPath();
@ -1713,6 +1748,7 @@ public class DroidFish extends Activity implements GUIInterface {
final int LOAD_GAME = 4;
final int SAVE_GAME = 5;
final int LOAD_SCID_GAME = 6;
final int GET_FEN = 7;
List<CharSequence> lst = new ArrayList<CharSequence>();
List<Integer> actions = new ArrayList<Integer>();
@ -1725,6 +1761,9 @@ public class DroidFish extends Activity implements GUIInterface {
if (hasScidProvider()) {
lst.add(getString(R.string.load_scid_game)); actions.add(LOAD_SCID_GAME);
}
if (hasFenProvider(getPackageManager())) {
lst.add(getString(R.string.get_fen)); actions.add(GET_FEN);
}
final List<Integer> finalActions = actions;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.tools_menu);
@ -1769,6 +1808,9 @@ public class DroidFish extends Activity implements GUIInterface {
case SAVE_GAME:
selectPgnFile(true);
break;
case GET_FEN:
getFen();
break;
}
}
});
@ -1823,22 +1865,11 @@ public class DroidFish extends Activity implements GUIInterface {
String title = getString(R.string.app_name);
WebView wv = new WebView(this);
builder.setView(wv);
String data = "";
try {
InputStream is = getResources().openRawResource(R.raw.about);
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append('\n');
}
br.close();
data = sb.toString();
} catch (UnsupportedEncodingException e1) {
} catch (IOException e) {
}
String data = Util.readFromStream(is);
if (data == null)
data = "";
try { is.close(); } catch (IOException e1) {}
wv.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);
try {
PackageInfo pi = getPackageManager().getPackageInfo("org.petero.droidfish", 0);
@ -2823,6 +2854,23 @@ public class DroidFish extends Activity implements GUIInterface {
}
}
public final static boolean hasFenProvider(PackageManager manager) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("application/x-chess-fen");
List<ResolveInfo> resolvers = manager.queryIntentActivities(i, 0);
return (resolvers != null) && (resolvers.size() > 0);
}
private final void getFen() {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("application/x-chess-fen");
try {
startActivityForResult(i, RESULT_GET_FEN);
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
final static int FT_NONE = 0;
final static int FT_PGN = 1;
final static int FT_SCID = 2;

View File

@ -5,6 +5,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import org.petero.droidfish.gamelogic.Piece;
@ -52,7 +53,28 @@ public final class Util {
return ret.toArray(new String[ret.size()]);
}
/** Represent materiel difference as two unicode strings. */
/** Read all data from an input stream. Return null if IO error. */
public static String readFromStream(InputStream is) {
InputStreamReader isr;
try {
isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append('\n');
}
br.close();
return sb.toString();
} catch (UnsupportedEncodingException e) {
return null;
} catch (IOException e) {
return null;
}
}
/** Represent material difference as two unicode strings. */
public final static class MaterialDiff {
public CharSequence white;
public CharSequence black;

View File

@ -18,9 +18,15 @@
package org.petero.droidfish.activities;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.petero.droidfish.ChessBoard;
import org.petero.droidfish.DroidFish;
import org.petero.droidfish.R;
import org.petero.droidfish.ChessBoard.SquareDecoration;
import org.petero.droidfish.Util;
@ -36,6 +42,7 @@ import org.petero.droidfish.gtb.Probe;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -364,31 +371,48 @@ public class EditBoard extends Activity {
protected Dialog onCreateDialog(int id) {
switch (id) {
case EDIT_DIALOG: {
final CharSequence[] items = {
getString(R.string.side_to_move),
getString(R.string.clear_board), getString(R.string.initial_position),
getString(R.string.castling_flags), getString(R.string.en_passant_file),
getString(R.string.move_counters),
getString(R.string.copy_position), getString(R.string.paste_position)
};
final int SIDE_TO_MOVE = 0;
final int CLEAR_BOARD = 1;
final int INITIAL_POS = 2;
final int CASTLING_FLAGS = 3;
final int EN_PASSANT_FILE = 4;
final int MOVE_COUNTERS = 5;
final int COPY_POSITION = 6;
final int PASTE_POSITION = 7;
final int GET_FEN = 8;
List<CharSequence> lst = new ArrayList<CharSequence>();
List<Integer> actions = new ArrayList<Integer>();
lst.add(getString(R.string.side_to_move)); actions.add(SIDE_TO_MOVE);
lst.add(getString(R.string.clear_board)); actions.add(CLEAR_BOARD);
lst.add(getString(R.string.initial_position)); actions.add(INITIAL_POS);
lst.add(getString(R.string.castling_flags)); actions.add(CASTLING_FLAGS);
lst.add(getString(R.string.en_passant_file)); actions.add(EN_PASSANT_FILE);
lst.add(getString(R.string.move_counters)); actions.add(MOVE_COUNTERS);
lst.add(getString(R.string.copy_position)); actions.add(COPY_POSITION);
lst.add(getString(R.string.paste_position)); actions.add(PASTE_POSITION);
if (DroidFish.hasFenProvider(getPackageManager())) {
lst.add(getString(R.string.get_fen)); actions.add(GET_FEN);
}
final List<Integer> finalActions = actions;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.edit_board);
builder.setItems(items, new DialogInterface.OnClickListener() {
builder.setItems(lst.toArray(new CharSequence[lst.size()]), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
switch (item) {
case 0: // Edit side to move
switch (finalActions.get(item)) {
case SIDE_TO_MOVE:
showDialog(SIDE_DIALOG);
setSelection(-1);
checkValidAndUpdateMaterialDiff();
break;
case 1: { // Clear board
case CLEAR_BOARD: {
Position pos = new Position();
cb.setPosition(pos);
setSelection(-1);
checkValidAndUpdateMaterialDiff();
break;
}
case 2: { // Set initial position
case INITIAL_POS: {
try {
Position pos = TextIO.readFEN(TextIO.startPosFEN);
cb.setPosition(pos);
@ -398,25 +422,25 @@ public class EditBoard extends Activity {
}
break;
}
case 3: // Edit castling flags
case CASTLING_FLAGS:
removeDialog(CASTLE_DIALOG);
showDialog(CASTLE_DIALOG);
setSelection(-1);
checkValidAndUpdateMaterialDiff();
break;
case 4: // Edit en passant file
case EN_PASSANT_FILE:
removeDialog(EP_DIALOG);
showDialog(EP_DIALOG);
setSelection(-1);
checkValidAndUpdateMaterialDiff();
break;
case 5: // Edit move counters
case MOVE_COUNTERS:
removeDialog(MOVCNT_DIALOG);
showDialog(MOVCNT_DIALOG);
setSelection(-1);
checkValidAndUpdateMaterialDiff();
break;
case 6: { // Copy position
case COPY_POSITION: {
setPosFields();
String fen = TextIO.toFEN(cb.pos) + "\n";
ClipboardManager clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
@ -424,23 +448,22 @@ public class EditBoard extends Activity {
setSelection(-1);
break;
}
case 7: { // Paste position
case PASTE_POSITION: {
ClipboardManager clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
if (clipboard.hasText()) {
String fen = clipboard.getText().toString();
try {
Position pos = TextIO.readFEN(fen);
cb.setPosition(pos);
} catch (ChessParseError e) {
if (e.pos != null)
cb.setPosition(e.pos);
Toast.makeText(getApplicationContext(), getParseErrString(e), Toast.LENGTH_SHORT).show();
}
setSelection(-1);
checkValidAndUpdateMaterialDiff();
setFEN(fen);
}
break;
}
case GET_FEN:
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("application/x-chess-fen");
try {
startActivityForResult(i, RESULT_GET_FEN);
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
});
@ -566,4 +589,48 @@ public class EditBoard extends Activity {
}
return null;
}
private final void setFEN(String fen) {
if (fen == null)
return;
try {
Position pos = TextIO.readFEN(fen);
cb.setPosition(pos);
} catch (ChessParseError e) {
if (e.pos != null)
cb.setPosition(e.pos);
Toast.makeText(getApplicationContext(), getParseErrString(e), Toast.LENGTH_SHORT).show();
}
setSelection(-1);
checkValidAndUpdateMaterialDiff();
}
static private final int RESULT_GET_FEN = 0;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case RESULT_GET_FEN:
if (resultCode == RESULT_OK) {
String fen = data.getStringExtra(Intent.EXTRA_TEXT);
if (fen == null) {
String pathName = DroidFish.getFilePathFromUri(data.getData());
if (pathName != null) {
InputStream is = null;
try {
is = new FileInputStream(pathName);
fen = Util.readFromStream(is);
} catch (FileNotFoundException e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
} finally {
if (is != null)
try { is.close(); } catch (IOException e) {}
}
}
}
setFEN(fen);
}
break;
}
}
}