package com.totsp.crossword; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.content.ContextCompat; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.totsp.crossword.io.IO; import com.totsp.crossword.puz.MovementStrategy; import com.totsp.crossword.puz.Playboard; import com.totsp.crossword.puz.Playboard.Clue; import com.totsp.crossword.puz.Playboard.Position; import com.totsp.crossword.puz.Playboard.Word; import com.totsp.crossword.puz.Puzzle; import com.totsp.crossword.shortyz.R; import com.totsp.crossword.shortyz.ShortyzApplication; import com.totsp.crossword.view.PlayboardRenderer; import com.totsp.crossword.view.ScrollingImageView; import com.totsp.crossword.view.ScrollingImageView.ClickListener; import com.totsp.crossword.view.ScrollingImageView.Point; import com.totsp.crossword.view.ScrollingImageView.ScaleListener; import com.totsp.crossword.view.SeparatedListAdapter; import java.io.File; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import static com.totsp.crossword.shortyz.ShortyzApplication.BOARD; import static com.totsp.crossword.shortyz.ShortyzApplication.RENDERER; public class PlayActivity extends ShortyzActivity { private static final Logger LOG = Logger.getLogger("com.totsp.crossword"); private static final int INFO_DIALOG = 0; private static final int REVEAL_PUZZLE_DIALOG = 2; static final String ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; @SuppressWarnings("rawtypes") private AdapterView across; @SuppressWarnings("rawtypes") private AdapterView down; private AlertDialog revealPuzzleDialog; private ListView allClues; private ClueListAdapter acrossAdapter; private ClueListAdapter downAdapter; private SeparatedListAdapter allCluesAdapter; private Configuration configuration; private Dialog dialog; private File baseFile; private Handler handler = new Handler(); private ImaginaryTimer timer; private KeyboardView keyboardView = null; private MovementStrategy movement = null; private Puzzle puz; private ScrollingImageView boardView; private TextView clue; private boolean fitToScreen; private boolean runTimer = false; private Runnable updateTimeTask = new Runnable() { public void run() { if (timer != null) { getWindow().setTitle(timer.time()); //noinspection deprecation getWindow().setFeatureInt(Window.FEATURE_PROGRESS, puz.getPercentComplete() * 100); } if (runTimer) { handler.postDelayed(this, 1000); } } }; private boolean showCount = false; private boolean showErrors = false; private boolean useNativeKeyboard = false; private long lastKey; private long lastTap = 0; private long resumedOn; private int screenWidthInInches; private Runnable fitToScreenTask = new Runnable() { @Override public void run() { fitToScreen(); } }; @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); this.configuration = newConfig; if (this.prefs.getBoolean("forceKeyboard", false) || (this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) || (this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_UNDEFINED)) { if (this.useNativeKeyboard) { keyboardView.setVisibility(View.GONE); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_NOT_ALWAYS); } else { this.keyboardView.setVisibility(View.VISIBLE); } } else { this.keyboardView.setVisibility(View.GONE); } this.runTimer = prefs.getBoolean("runTimer", false); if (runTimer) { this.handler.post(this.updateTimeTask); } metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); this.screenWidthInInches = (metrics.widthPixels > metrics.heightPixels ? metrics.widthPixels : metrics.heightPixels) / Math.round(160 * metrics.density); LOG.info("Configuration Changed "+this.screenWidthInInches+" "); if(this.screenWidthInInches >= 7){ this.handler.post(this.fitToScreenTask); } } DisplayMetrics metrics; /** * Called when the activity is first created. */ @SuppressWarnings({"rawtypes", "unchecked"}) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); this.screenWidthInInches = (metrics.widthPixels > metrics.heightPixels ? metrics.widthPixels : metrics.heightPixels) / Math.round(160 * metrics.density); this.configuration = getBaseContext().getResources().getConfiguration(); try { if (!prefs.getBoolean("showTimer", false)) { if (ShortyzApplication.isLandscape(metrics)) { if (ShortyzApplication.isMiniTabletish(metrics)) { utils.hideWindowTitle(this); } } else if (android.os.Build.VERSION.SDK_INT < 11) { utils.hideWindowTitle(this); } } else { supportRequestWindowFeature(Window.FEATURE_PROGRESS); } } catch (Exception e) { e.printStackTrace(); } utils.holographic(this); utils.finishOnHomeButton(this); this.showErrors = this.prefs.getBoolean("showErrors", false); setDefaultKeyMode(Activity.DEFAULT_KEYS_DISABLE); MovementStrategy movement = this.getMovementStrategy(); if (prefs.getBoolean("fullScreen", false)) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } View.OnKeyListener onKeyListener = new View.OnKeyListener() { @Override public boolean onKey(View view, int i, KeyEvent keyEvent) { return keyEvent.getAction() == KeyEvent.ACTION_UP && PlayActivity.this.onKeyUp(i, keyEvent); } }; try { Uri u = this.getIntent().getData(); if (u != null) { if (u.getScheme().equals("file")) { baseFile = new File(u.getPath()); puz = IO.load(baseFile); } } if (puz == null) { throw new IOException(); } BOARD = new Playboard(puz, movement, prefs.getBoolean("preserveCorrectLettersInShowErrors", false)); RENDERER = new PlayboardRenderer(BOARD, metrics.densityDpi, metrics.widthPixels, !prefs.getBoolean("supressHints", false), ContextCompat.getColor(this, R.color.boxColor), ContextCompat.getColor(this, R.color.blankColor), ContextCompat.getColor(this, R.color.errorColor)); float scale = prefs.getFloat("scale", 1.0F); if (scale > RENDERER.getDeviceMaxScale()) { scale = RENDERER.getDeviceMaxScale(); } else if (scale < RENDERER.getDeviceMinScale()) { scale = RENDERER.getDeviceMinScale(); } else if (Float.isNaN(scale)) { scale = 1F; } prefs.edit().putFloat("scale", scale).apply(); RENDERER.setScale(scale); BOARD.setSkipCompletedLetters(this.prefs.getBoolean("skipFilled", false)); if (puz.getPercentComplete() != 100) { this.timer = new ImaginaryTimer(puz.getTime()); this.timer.start(); this.runTimer = prefs.getBoolean("showTimer", false); if (runTimer) { this.handler.post(this.updateTimeTask); } } setContentView(R.layout.play); int keyboardType = "CONDENSED_ARROWS".equals(prefs.getString( "keyboardType", "")) ? R.xml.keyboard_dpad : R.xml.keyboard; Keyboard keyboard = new Keyboard(this, keyboardType); keyboardView = (KeyboardView) this.findViewById(R.id.playKeyboard); keyboardView.setKeyboard(keyboard); this.useNativeKeyboard = "NATIVE".equals(prefs.getString( "keyboardType", "")); if (this.useNativeKeyboard) { keyboardView.setVisibility(View.GONE); } keyboardView.setOnKeyListener(onKeyListener); keyboardView .setOnKeyboardActionListener(new OnKeyboardActionListener() { private long lastSwipe = 0; public void onKey(int primaryCode, int[] keyCodes) { long eventTime = System.currentTimeMillis(); if (keyboardView.getVisibility() == View.GONE || (eventTime - lastSwipe) < 500) { return; } KeyEvent event = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, primaryCode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); PlayActivity.this.onKeyUp(primaryCode, event); } public void onPress(int primaryCode) { } public void onRelease(int primaryCode) { } public void onText(CharSequence text) { // TODO Auto-generated method stub } public void swipeDown() { long eventTime = System.currentTimeMillis(); lastSwipe = eventTime; KeyEvent event = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); PlayActivity.this.onKeyUp( KeyEvent.KEYCODE_DPAD_DOWN, event); } public void swipeLeft() { long eventTime = System.currentTimeMillis(); lastSwipe = eventTime; KeyEvent event = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); PlayActivity.this.onKeyUp( KeyEvent.KEYCODE_DPAD_LEFT, event); } public void swipeRight() { long eventTime = System.currentTimeMillis(); lastSwipe = eventTime; KeyEvent event = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); PlayActivity.this.onKeyUp( KeyEvent.KEYCODE_DPAD_RIGHT, event); } public void swipeUp() { long eventTime = System.currentTimeMillis(); lastSwipe = eventTime; KeyEvent event = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); PlayActivity.this.onKeyUp(KeyEvent.KEYCODE_DPAD_UP, event); } }); this.clue = (TextView) this.findViewById(R.id.clueLine); if (clue != null && clue.getVisibility() != View.GONE) { clue.setVisibility(View.GONE); View custom = utils.onActionBarCustom(this, R.layout.clue_line_only); if (custom != null) { clue = (TextView) custom.findViewById(R.id.clueLine); } } if(this.clue != null) { this.clue.setClickable(true); this.clue.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { Intent i = new Intent(PlayActivity.this, ClueListActivity.class); i.setData(Uri.fromFile(baseFile)); PlayActivity.this.startActivityForResult(i, 0); } }); } boardView = (ScrollingImageView) this.findViewById(R.id.board); this.boardView.setCurrentScale(scale); this.boardView.setFocusable(true); //this.boardView.setOnKeyListener(onKeyListener); this.registerForContextMenu(boardView); boardView.setContextMenuListener(new ClickListener() { public void onContextMenu(final Point e) { handler.post(new Runnable() { public void run() { try { Position p = RENDERER.findBox(e); Word w = BOARD.setHighlightLetter(p); RENDERER.draw(w); PlayActivity.this.openContextMenu(boardView); } catch (Exception ex) { ex.printStackTrace(); } } }); } public void onTap(Point e) { try { if (prefs.getBoolean("doubleTap", false) && ((System.currentTimeMillis() - lastTap) < 300)) { if (fitToScreen) { RENDERER.setScale(prefs.getFloat("scale", 1F)); boardView.setCurrentScale(1F); BOARD.setHighlightLetter(RENDERER.findBox(e)); render(); } else { int w = boardView.getWidth(); int h = boardView.getHeight(); float scale = RENDERER.fitTo((w < h) ? w : h); boardView.setCurrentScale(scale); render(true); boardView.scrollTo(0, 0); } fitToScreen = !fitToScreen; } else { Position p = RENDERER.findBox(e); Word old = BOARD.setHighlightLetter(p); PlayActivity.this.render(old); } lastTap = System.currentTimeMillis(); } catch (Exception ex) { ex.printStackTrace(); } } }); } catch (IOException e) { System.err.println(this.getIntent().getData()); e.printStackTrace(); String filename = null; try { filename = this.baseFile.getName(); } catch (Exception ee) { e.printStackTrace(); } Toast t = Toast .makeText( this, "Unable to read file" + (filename != null ? (" \n" + filename) : "") , Toast.LENGTH_SHORT); t.show(); this.finish(); return; } revealPuzzleDialog = new AlertDialog.Builder(this).create(); revealPuzzleDialog.setTitle("Reveal Entire Puzzle"); revealPuzzleDialog.setMessage("Are you sure?"); revealPuzzleDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { BOARD.revealPuzzle(); render(); } }); revealPuzzleDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); this.boardView.setFocusable(true); this.boardView.setScaleListener(new ScaleListener() { TimerTask t; Timer renderTimer = new Timer(); public void onScale(float newScale, final Point center) { //fitToScreen = false; if (t != null) { t.cancel(); } renderTimer.purge(); t = new TimerTask() { @Override public void run() { handler.post(new Runnable() { public void run() { int w = boardView.getImageView().getWidth(); int h = boardView.getImageView().getHeight(); float scale = RENDERER.fitTo((w < h) ? w : h); prefs.edit() .putFloat("scale", scale) .apply(); BOARD.setHighlightLetter(RENDERER .findBox(center)); render(true); } }); } }; renderTimer.schedule(t, 500); lastTap = System.currentTimeMillis(); } }); if (puz.isUpdatable()) { this.showErrors = false; } if (BOARD.isShowErrors() != this.showErrors) { BOARD.toggleShowErrors(); } this.render(true); this.across = (AdapterView) this.findViewById(R.id.acrossList); this.down = (AdapterView) this.findViewById(R.id.downList); boolean isGal = false; if ((this.across == null) && (this.down == null)) { this.across = (AdapterView) this.findViewById(R.id.acrossListGal); this.down = (AdapterView) this.findViewById(R.id.downListGal); isGal = true; } if ((across != null) && (down != null)) { across.setAdapter(this.acrossAdapter = new ClueListAdapter(this, BOARD.getAcrossClues(), true)); down.setAdapter(this.downAdapter = new ClueListAdapter(this, BOARD .getDownClues(), false)); if (!isGal) { across.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { arg0.setSelected(true); BOARD.jumpTo(arg2, true); render(); } }); } across.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (!BOARD.isAcross() || (BOARD.getCurrentClueIndex() != arg2)) { BOARD.jumpTo(arg2, true); render(); } } public void onNothingSelected(AdapterView<?> view) { } }); if (!isGal) { down.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, final int arg2, long arg3) { BOARD.jumpTo(arg2, false); render(); } }); } down.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (BOARD.isAcross() || (BOARD.getCurrentClueIndex() != arg2)) { BOARD.jumpTo(arg2, false); render(); } } public void onNothingSelected(AdapterView<?> arg0) { } }); down.scrollTo(0, 0); across.scrollTo(0, 0); down.setOnKeyListener(onKeyListener); across.setOnKeyListener(onKeyListener); down.setFocusable(false); across.setFocusable(false); } this.allClues = (ListView) this.findViewById(R.id.allClues); if (this.allClues != null) { this.allCluesAdapter = new SeparatedListAdapter(this); this.allCluesAdapter.addSection( "Across", this.acrossAdapter = new ClueListAdapter(this, BOARD .getAcrossClues(), true)); this.allCluesAdapter.addSection( "Down", this.downAdapter = new ClueListAdapter(this, BOARD .getDownClues(), false)); allClues.setAdapter(this.allCluesAdapter); allClues.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int clickIndex, long arg3) { boolean across = clickIndex <= BOARD.getAcrossClues().length + 1; int index = clickIndex - 1; if (index > BOARD.getAcrossClues().length) { index = index - BOARD.getAcrossClues().length - 1; } arg0.setSelected(true); BOARD.jumpTo(index, across); render(); } }); allClues.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int clickIndex, long arg3) { boolean across = clickIndex <= BOARD.getAcrossClues().length + 1; int index = clickIndex - 1; if (index > BOARD.getAcrossClues().length) { index = index - BOARD.getAcrossClues().length - 1; } if (!BOARD.isAcross() == across && BOARD.getCurrentClueIndex() != index) { arg0.setSelected(true); BOARD.jumpTo(index, across); render(); } } public void onNothingSelected(AdapterView<?> view) { } }); } if (!prefs.getBoolean("showTimer", false)) { if (ShortyzApplication.isLandscape(metrics)) { if (ShortyzApplication.isMiniTabletish(metrics) && allClues != null) { utils.hideActionBar(this); } } } this.setClueSize(prefs.getInt("clueSize", 12)); setTitle(neverNull(puz.getTitle()) + " - " + neverNull(puz.getAuthor()) + " - " + neverNull(puz.getCopyright())); this.showCount = prefs.getBoolean("showCount", false); if (this.prefs.getBoolean("fitToScreen", false) || (android.os.Build.VERSION.SDK_INT > 11 && ShortyzApplication.isLandscape(metrics)) && (ShortyzApplication.isTabletish(metrics) || ShortyzApplication.isMiniTabletish(metrics))) { this.handler.postDelayed(new Runnable() { public void run() { boardView.scrollTo(0, 0); int v = (boardView.getWidth() < boardView.getHeight()) ? boardView .getWidth() : boardView.getHeight(); if (v == 0) { handler.postDelayed(this, 100); } float newScale = RENDERER.fitTo(v); boardView.setCurrentScale(newScale); prefs.edit().putFloat("scale", newScale).apply(); render(); } }, 100); } } private static String neverNull(String val) { return val == null ? "" : val.trim(); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { // System.out.println("CCM " + view); // if (view == boardView) { // Menu clueSize = menu.addSubMenu("Clue Text Size"); // clueSize.add("Small"); // clueSize.add("Medium"); // clueSize.add("Large"); // // menu.add("Zoom In"); // // if (RENDERER.getScale() < RENDERER.getDeviceMaxScale()) // menu.add("Zoom In Max"); // // menu.add("Zoom Out"); // menu.add("Fit to Screen"); // menu.add("Zoom Reset"); // } } @Override public boolean onCreateOptionsMenu(Menu menu) { if (puz != null && !puz.isUpdatable()) { MenuItem showItem = menu.add( this.showErrors ? "Hide Errors" : "Show Errors").setIcon( android.R.drawable.ic_menu_view); if (ShortyzApplication.isTabletish(metrics)) { utils.onActionBarWithText(showItem); } SubMenu reveal = menu.addSubMenu("Reveal").setIcon( android.R.drawable.ic_menu_view); reveal.add(createSpannableForMenu("Letter")).setTitleCondensed("Letter"); reveal.add(createSpannableForMenu("Word")).setTitleCondensed("Word"); reveal.add(createSpannableForMenu("Errors")).setTitleCondensed("Errors"); reveal.add(createSpannableForMenu("Puzzle")).setTitleCondensed("Puzzle"); if (ShortyzApplication.isTabletish(metrics)) { utils.onActionBarWithText(reveal); } } else { menu.add("Show Errors").setEnabled(false) .setIcon(android.R.drawable.ic_menu_view); menu.add("Reveal").setIcon(android.R.drawable.ic_menu_view) .setEnabled(false); } menu.add("Clues").setIcon(android.R.drawable.ic_menu_agenda); Menu clueSize = menu.addSubMenu("Clue Text Size"); clueSize.add(createSpannableForMenu("Small")).setTitleCondensed("Small"); clueSize.add(createSpannableForMenu("Medium")).setTitleCondensed("Medium"); clueSize.add(createSpannableForMenu("Large")).setTitleCondensed("Large"); Menu zoom = menu.addSubMenu("Zoom"); zoom.add(createSpannableForMenu("Zoom In")).setTitleCondensed("Zoom In"); if (RENDERER.getScale() < RENDERER.getDeviceMaxScale()) zoom.add(createSpannableForMenu("Zoom In Max")).setTitleCondensed("Zoom In Max"); zoom.add(createSpannableForMenu("Zoom Out")).setTitleCondensed("Zoom Out"); zoom.add(createSpannableForMenu("Fit to Screen")).setTitleCondensed("Fit to Screen"); zoom.add(createSpannableForMenu("Zoom Reset")).setTitleCondensed("Zoom Reset"); menu.add("Info").setIcon(android.R.drawable.ic_menu_info_details); menu.add("Help").setIcon(android.R.drawable.ic_menu_help); menu.add("Settings").setIcon(android.R.drawable.ic_menu_preferences); return true; } private SpannableString createSpannableForMenu(String value){ SpannableString s = new SpannableString(value); s.setSpan(new ForegroundColorSpan(ContextCompat.getColor(this, R.color.textColorPrimary)), 0, s.length(), 0); return s; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return keyCode == KeyEvent.KEYCODE_ENTER; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { Word previous; if ((System.currentTimeMillis() - this.resumedOn) < 500) { return true; } switch (keyCode) { case KeyEvent.KEYCODE_SEARCH: System.out.println("Next clue."); BOARD.setMovementStrategy(MovementStrategy.MOVE_NEXT_CLUE); previous = BOARD.nextWord(); BOARD.setMovementStrategy(this.getMovementStrategy()); this.render(previous); return true; case KeyEvent.KEYCODE_BACK: this.finish(); return true; case KeyEvent.KEYCODE_MENU: return false; case KeyEvent.KEYCODE_DPAD_DOWN: if ((System.currentTimeMillis() - lastKey) > 50) { previous = BOARD.moveDown(); this.render(previous); } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_DPAD_UP: if ((System.currentTimeMillis() - lastKey) > 50) { previous = BOARD.moveUp(); this.render(previous); } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if ((System.currentTimeMillis() - lastKey) > 50) { previous = BOARD.moveLeft(); this.render(previous); } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if ((System.currentTimeMillis() - lastKey) > 50) { previous = BOARD.moveRight(); this.render(previous); } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_DPAD_CENTER: previous = BOARD.toggleDirection(); this.render(previous); return true; case KeyEvent.KEYCODE_SPACE: if ((System.currentTimeMillis() - lastKey) > 150) { if (prefs.getBoolean("spaceChangesDirection", true)) { previous = BOARD.toggleDirection(); this.render(previous); } else { previous = BOARD.playLetter(' '); this.render(previous); } } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_ENTER: if ((System.currentTimeMillis() - lastKey) > 150) { if (prefs.getBoolean("enterChangesDirection", true)) { previous = BOARD.toggleDirection(); this.render(previous); } else { previous = BOARD.nextWord(); this.render(previous); } } lastKey = System.currentTimeMillis(); return true; case KeyEvent.KEYCODE_DEL: if ((System.currentTimeMillis() - lastKey) > 150) { previous = BOARD.deleteLetter(); this.render(previous); } lastKey = System.currentTimeMillis(); return true; } char c = Character .toUpperCase(((this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) || this.useNativeKeyboard) ? event .getDisplayLabel() : ((char) keyCode)); if (ALPHA.indexOf(c) != -1) { previous = BOARD.playLetter(c); this.render(previous); return true; } return super.onKeyUp(keyCode, event); } @Override public boolean onContextItemSelected(MenuItem item) { return onOptionsItemSelected(item); } @SuppressWarnings("deprecation") @Override public boolean onOptionsItemSelected(MenuItem item) { System.out.println(item.getTitle()); if (item.getTitle() == null) { finish(); return true; } if (item.getTitle().toString().equals("Letter")) { BOARD.revealLetter(); this.render(); return true; } else if (item.getTitle().toString().equals("Word")) { BOARD.revealWord(); this.render(); return true; } else if (item.getTitle().toString().equals("Errors")) { BOARD.revealErrors(); this.render(); return true; } else if (item.getTitle().toString().equals("Puzzle")) { this.showDialog(REVEAL_PUZZLE_DIALOG); return true; } else if (item.getTitle().toString().equals("Show Errors") || item.getTitle().toString().equals("Hide Errors")) { BOARD.toggleShowErrors(); item.setTitle(BOARD.isShowErrors() ? "Hide Errors" : "Show Errors"); this.prefs.edit().putBoolean("showErrors", BOARD.isShowErrors()) .apply(); this.render(); return true; } else if (item.getTitle().toString().equals("Settings")) { Intent i = new Intent(this, PreferencesActivity.class); this.startActivity(i); return true; } else if (item.getTitle().toString().equals("Zoom In")) { this.boardView.scrollTo(0, 0); float newScale = RENDERER.zoomIn(); this.prefs.edit().putFloat("scale", newScale).apply(); this.fitToScreen = false; boardView.setCurrentScale(newScale); this.render(); return true; } else if (item.getTitle().toString().equals("Zoom In Max")) { this.boardView.scrollTo(0, 0); float newScale = RENDERER.zoomInMax(); this.prefs.edit().putFloat("scale", newScale).apply(); this.fitToScreen = false; boardView.setCurrentScale(newScale); this.render(); return true; } else if (item.getTitle().toString().equals("Zoom Out")) { this.boardView.scrollTo(0, 0); float newScale = RENDERER.zoomOut(); this.prefs.edit().putFloat("scale", newScale).apply(); this.fitToScreen = false; boardView.setCurrentScale(newScale); this.render(); return true; } else if (item.getTitle().toString().equals("Fit to Screen")) { fitToScreen(); return true; } else if (item.getTitle().toString().equals("Zoom Reset")) { float newScale = RENDERER.zoomReset(); boardView.setCurrentScale(newScale); this.prefs.edit().putFloat("scale", newScale).apply(); this.render(); this.boardView.scrollTo(0, 0); return true; } else if (item.getTitle().toString().equals("Info")) { if (dialog != null) { TextView view = (TextView) dialog .findViewById(R.id.puzzle_info_time); if (timer != null) { this.timer.stop(); view.setText("Elapsed Time: " + this.timer.time()); this.timer.start(); } else { view.setText("Elapsed Time: " + new ImaginaryTimer(puz.getTime()).time()); } } this.showDialog(INFO_DIALOG); return true; } else if (item.getTitle().toString().equals("Clues")) { Intent i = new Intent(PlayActivity.this, ClueListActivity.class); i.setData(Uri.fromFile(baseFile)); PlayActivity.this.startActivityForResult(i, 0); return true; } else if (item.getTitle().toString().equals("Help")) { Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("file:///android_asset/playscreen.html"), this, HTMLActivity.class); this.startActivity(i); } else if (item.getTitle().toString().equals("Small")) { this.setClueSize(12); } else if (item.getTitle().toString().equals("Medium")) { this.setClueSize(14); } else if (item.getTitle().toString().equals("Large")) { this.setClueSize(16); } return false; } private void fitToScreen() { this.boardView.scrollTo(0, 0); int v = (this.boardView.getWidth() < this.boardView.getHeight()) ? this.boardView .getWidth() : this.boardView.getHeight(); float newScale = RENDERER.fitTo(v); this.prefs.edit().putFloat("scale", newScale).apply(); boardView.setCurrentScale(newScale); this.render(); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { this.render(); } protected Dialog onCreateDialog(int id) { switch (id) { case INFO_DIALOG: // This is weird. I don't know why a rotate resets the dialog. // Whatevs. return createInfoDialog(); case REVEAL_PUZZLE_DIALOG: return revealPuzzleDialog; default: return null; } } @Override protected void onPause() { try { if ((puz != null) && (baseFile != null)) { if ((puz.getPercentComplete() != 100) && (this.timer != null)) { this.timer.stop(); puz.setTime(timer.getElapsed()); this.timer = null; } IO.save(puz, baseFile); } } catch (IOException ioe) { LOG.log(Level.SEVERE, null, ioe); } this.timer = null; if ((this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) || (this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_UNDEFINED)) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(clue.getWindowToken(), 0); } super.onPause(); } @Override protected void onRestart() { super.onRestart(); if (this.timer != null) { this.timer.start(); } } @Override protected void onResume() { super.onResume(); this.resumedOn = System.currentTimeMillis(); BOARD.setSkipCompletedLetters(this.prefs .getBoolean("skipFilled", false)); BOARD.setMovementStrategy(this.getMovementStrategy()); int keyboardType = "CONDENSED_ARROWS".equals(prefs.getString( "keyboardType", "")) ? R.xml.keyboard_dpad : R.xml.keyboard; final Keyboard keyboard = new Keyboard(this, keyboardType); keyboardView = (KeyboardView) this.findViewById(R.id.playKeyboard); keyboardView.setKeyboard(keyboard); this.useNativeKeyboard = "NATIVE".equals(prefs.getString( "keyboardType", "")); if (this.useNativeKeyboard) { keyboardView.setVisibility(View.GONE); } handler.post(new Runnable() { @Override public void run() { keyboardView.invalidate(); keyboardView.invalidateAllKeys(); } }); this.showCount = prefs.getBoolean("showCount", false); this.onConfigurationChanged(this.configuration); if (puz.getPercentComplete() != 100) { timer = new ImaginaryTimer(this.puz.getTime()); timer.start(); } this.runTimer = prefs.getBoolean("showTimer", false); if (runTimer) { this.handler.post(this.updateTimeTask); } render(); } @Override protected void onStop() { super.onStop(); if (this.timer != null) { this.timer.stop(); } } private void setClueSize(int dps) { this.clue.setTextSize(TypedValue.COMPLEX_UNIT_SP, dps); if ((acrossAdapter != null) && (downAdapter != null)) { acrossAdapter.textSize = dps; acrossAdapter.notifyDataSetInvalidated(); downAdapter.textSize = dps; downAdapter.notifyDataSetInvalidated(); } if (prefs.getInt("clueSize", 12) != dps) { this.prefs.edit().putInt("clueSize", dps).apply(); } } private MovementStrategy getMovementStrategy() { if (movement != null) { return movement; } else { String stratName = this.prefs.getString("movementStrategy", "MOVE_NEXT_ON_AXIS"); switch (stratName) { case "MOVE_NEXT_ON_AXIS": movement = MovementStrategy.MOVE_NEXT_ON_AXIS; break; case "STOP_ON_END": movement = MovementStrategy.STOP_ON_END; break; case "MOVE_NEXT_CLUE": movement = MovementStrategy.MOVE_NEXT_CLUE; break; case "MOVE_PARALLEL_WORD": movement = MovementStrategy.MOVE_PARALLEL_WORD; break; } return movement; } } private Dialog createInfoDialog() { if (dialog == null) { dialog = new Dialog(this); } dialog.setTitle("Puzzle Info"); dialog.setContentView(R.layout.puzzle_info_dialog); TextView view = (TextView) dialog.findViewById(R.id.puzzle_info_title); view.setText(this.puz.getTitle()); view = (TextView) dialog.findViewById(R.id.puzzle_info_author); view.setText(this.puz.getAuthor()); view = (TextView) dialog.findViewById(R.id.puzzle_info_copyright); view.setText(this.puz.getCopyright()); view = (TextView) dialog.findViewById(R.id.puzzle_info_time); if (timer != null) { this.timer.stop(); view.setText("Elapsed Time: " + this.timer.time()); this.timer.start(); } else { view.setText("Elapsed Time: " + new ImaginaryTimer(puz.getTime()).time()); } ProgressBar progress = (ProgressBar) dialog .findViewById(R.id.puzzle_info_progress); progress.setProgress(this.puz.getPercentComplete()); return dialog; } private void render() { render(null); } private void render(boolean rescale) { this.render(null, rescale); } private void render(Word previous) { this.render(previous, true); } private void render(Word previous, boolean rescale) { if (this.prefs.getBoolean("forceKeyboard", false) || (this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) || (this.configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_UNDEFINED)) { if (this.useNativeKeyboard) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); } else { this.keyboardView.setVisibility(View.VISIBLE); } } else { this.keyboardView.setVisibility(View.GONE); } Clue c = BOARD.getClue(); BOARD.toggleDirection(); BOARD.toggleDirection(); if (c.hint == null) { BOARD.toggleDirection(); c = BOARD.getClue(); } this.boardView.setBitmap(RENDERER.draw(previous), rescale); this.boardView.requestFocus(); /* * If we jumped to a new word, ensure the first letter is visible. * Otherwise, insure that the current letter is visible. Only necessary * if the cursor is currently off screen. */ if (rescale && this.prefs.getBoolean("ensureVisible", true)) { Point topLeft; Point bottomRight; Point cursorTopLeft; Point cursorBottomRight; cursorTopLeft = RENDERER.findPointTopLeft(BOARD .getHighlightLetter()); cursorBottomRight = RENDERER.findPointBottomRight(BOARD .getHighlightLetter()); if ((previous != null) && previous.equals(BOARD.getCurrentWord())) { topLeft = cursorTopLeft; bottomRight = cursorBottomRight; } else { topLeft = RENDERER .findPointTopLeft(BOARD.getCurrentWordStart()); bottomRight = RENDERER.findPointBottomRight(BOARD .getCurrentWordStart()); } int tlDistance = cursorTopLeft.distance(topLeft); int brDistance = cursorBottomRight.distance(bottomRight); if (!this.boardView.isVisible(topLeft) && (tlDistance < brDistance)) { this.boardView.ensureVisible(topLeft); } if (!this.boardView.isVisible(bottomRight) && (brDistance < tlDistance)) { this.boardView.ensureVisible(bottomRight); } // ensure the cursor is always on the screen. this.boardView.ensureVisible(cursorBottomRight); this.boardView.ensureVisible(cursorTopLeft); } this.clue .setText("(" + (BOARD.isAcross() ? "across" : "down") + ") " + c.number + ". " + c.hint + (this.showCount ? (" [" + BOARD.getCurrentWord().length + "]") : "")); if (this.allClues != null) { if (BOARD.isAcross()) { ClueListAdapter cla = (ClueListAdapter) this.allCluesAdapter.sections .get(0); cla.setActiveDirection(BOARD.isAcross()); cla.setHighlightClue(c); this.allCluesAdapter.notifyDataSetChanged(); this.allClues.setSelectionFromTop(cla.indexOf(c) + 1, (this.allClues.getHeight() / 2) - 50); } else { ClueListAdapter cla = (ClueListAdapter) this.allCluesAdapter.sections .get(1); cla.setActiveDirection(!BOARD.isAcross()); cla.setHighlightClue(c); this.allCluesAdapter.notifyDataSetChanged(); this.allClues.setSelectionFromTop( cla.indexOf(c) + BOARD.getAcrossClues().length + 2, (this.allClues.getHeight() / 2) - 50); } } if (this.down != null) { this.downAdapter.setHighlightClue(c); this.downAdapter.setActiveDirection(!BOARD.isAcross()); this.downAdapter.notifyDataSetChanged(); if (!BOARD.isAcross() && !c.equals(this.down.getSelectedItem())) { if (this.down instanceof ListView) { ((ListView) this.down).setSelectionFromTop( this.downAdapter.indexOf(c), (down.getHeight() / 2) - 50); } else { // Gallery this.down.setSelection(this.downAdapter.indexOf(c)); } } } if (this.across != null) { this.acrossAdapter.setHighlightClue(c); this.acrossAdapter.setActiveDirection(BOARD.isAcross()); this.acrossAdapter.notifyDataSetChanged(); if (BOARD.isAcross() && !c.equals(this.across.getSelectedItem())) { if (across instanceof ListView) { ((ListView) this.across).setSelectionFromTop( this.acrossAdapter.indexOf(c), (across.getHeight() / 2) - 50); } else { // Gallery view this.across.setSelection(this.acrossAdapter.indexOf(c)); } } } if ((puz.getPercentComplete() == 100) && (timer != null)) { timer.stop(); puz.setTime(timer.getElapsed()); this.timer = null; Intent i = new Intent(PlayActivity.this, PuzzleFinishedActivity.class); this.startActivity(i); } this.boardView.requestFocus(); } }