void postDelay(Runnable r, long delayMS);
void cancelPost(Runnable r);
}
- private TimerProvider mT;
+ private final TimerProvider mT;
public CtFwSGameState (TimerProvider t) {
mT = t;
// Informative messages handling
public class Msg {
- public long when;
- public String msg;
+ public final long when;
+ public final String msg;
Msg(long when, String msg) {
this.when = when;
this.msg = msg;
}
}
- private List<Msg> msgs = new ArrayList<>();
+ private final List<Msg> msgs = new ArrayList<>();
private long lastMsgTimestamp;
public void onNewMessage(String str) {
mCgs = cgs;
}
- IMqttMessageListener onConfig = new IMqttMessageListener() {
+ final IMqttMessageListener onConfig = new IMqttMessageListener() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String tm = message.toString().trim();
}
};
- IMqttMessageListener onEnd = new IMqttMessageListener() {
+ final IMqttMessageListener onEnd = new IMqttMessageListener() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d("CtFwS", "Message(End): " + message);
}
};
- IMqttMessageListener onFlags = new IMqttMessageListener() {
+ final IMqttMessageListener onFlags = new IMqttMessageListener() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String tm = message.toString().trim();
}
};
- IMqttMessageListener onMessage = new IMqttMessageListener() {
+ final IMqttMessageListener onMessage = new IMqttMessageListener() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String str = message.toString();
}
};
- IMqttMessageListener onPlayerMessage = new IMqttMessageListener() {
+ final IMqttMessageListener onPlayerMessage = new IMqttMessageListener() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String str = message.toString();
package com.acmetensortoys.ctfwstimer;
import android.app.Activity;
-import android.os.Handler;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.Log;
// TODO nwf is bad at UI design; someone who isn't him should improve this
class CtFwSDisplayLocal implements CtFwSGameState.Observer {
final private Activity mAct;
- public String gameStateLabelText;
+ String gameStateLabelText;
CtFwSDisplayLocal(Activity a) {
mAct = a;
gameStateLabelText = mAct.getResources().getString(R.string.header_gamestate0);
}
- private Runnable mProber;
-
@Override
public void onCtFwSConfigure(final CtFwSGameState gs) {
int gameix = gs.getGameIx();
}
// Otherwise, it's game on!
+ // Upper line text
{
final TextView tv_jb = (TextView) (mAct.findViewById(R.id.tv_jailbreak));
tv_jb.post(new Runnable() {
}
}
});
+ }
+ // Upper progress bar and chronometer
+ // TODO: Older devices cannot count down in Chronometer, so will see only zeros, I
+ // think. This should be fixed by making those devices count up (and still rendering
+ // the progress bar rotated for decreasing, one assumes).
+ {
final ProgressBar pb_jb = (ProgressBar) (mAct.findViewById(R.id.pb_jailbreak));
pb_jb.post(new Runnable() {
@Override
}
});
}
+
+ // Lower progress bar and chronometer
if (now.round > 0) {
final ProgressBar pb_gp = (ProgressBar) (mAct.findViewById(R.id.pb_gameProgress));
pb_gp.post(new Runnable() {
ch_gp.post(new Runnable() {
@Override
public void run() {
+ ch_gp.setOnChronometerTickListener(null);
ch_gp.stop();
ch_gp.setVisibility(INVISIBLE);
}
tv_flags.post(new Runnable() {
@Override
public void run() {
- tv_flags.setText(
- String.format(mAct.getResources().getString(R.string.ctfws_flags), gs.flagsTotal));
+ tv_flags.setText(mAct.getResources()
+ .getQuantityString(R.plurals.ctfws_flags,gs.flagsTotal,gs.flagsTotal));
}
});
}
ch.post(new Runnable() {
@Override
public void run() {
+ ch.setOnChronometerTickListener(null);
ch.stop();
ch.setVisibility(View.INVISIBLE);
}
import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.Button;
public class DefaultableEditTextPreference extends EditTextPreference {
// GAH! Our parent Preference has this as a private field. Grrr Android!
// TODO surely this belongs somewhere else
private static final String defserver = "tcp://ctfws-mqtt.ietfng.org:1883";
- private MainActivityBuildHooks mabh = new MainActivityBuildHooksImpl();
+ private final MainActivityBuildHooks mabh = new MainActivityBuildHooksImpl();
private MainService.LocalBinder mSrvBinder; // set once connection completed
- private MainService.Observer mSrvObs = new MainService.Observer() {
+ private final MainService.Observer mSrvObs = new MainService.Observer() {
@Override
public void onMqttServerChanged(MainService.LocalBinder b, final String sURL) {
mTvSU.post(new Runnable() {
mCdl = new CtFwSDisplayLocal(this);
}
- private ServiceConnection ctfwssc = new ServiceConnection() {
+ private final ServiceConnection ctfwssc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSrvBinder = (MainService.LocalBinder) service;
}
// Kick the mqtt layer on a click on the status stuff
- public void onclick_connmeta(View v) {
+ public void onclick_connmeta(@SuppressWarnings("UnusedParameters") View v) {
mSrvBinder.connect(true);
}
package com.acmetensortoys.ctfwstimer;
-import com.acmetensortoys.ctfwstimer.lib.CtFwSGameState;
-
// The MainActivity expects a "MainActivityBuildHooksImpl" class that ascribes to this interface
// per build flavor. This will be used when, for example, we kick on Google Play for Wear
// interaction and want to push messages out to the wearable data network.
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
public class MainService extends Service {
mHandler.removeCallbacks(r);
}
});
- private CtFwSCallbacksMQTT mCtfwscbs = new CtFwSCallbacksMQTT(mCgs);
+ private final CtFwSCallbacksMQTT mCtfwscbs = new CtFwSCallbacksMQTT(mCgs);
+ @SuppressWarnings({"FieldCanBeLocal", "unused"})
private MainServiceNotification mMsn; // set in onCreate
public MainService() { }
CtFwSGameState getGameState() {
return mCgs;
}
- MqttServerEvent getServerState() {
- return mMSE;
- }
// It should not be necessary to call this except at the beginning or to force a reconnect;
// most everything else you might want in a connect method is handled by the
synchronized(this) { mObsvs.remove(o); }
}
}
- private LocalBinder mBinder = new LocalBinder();
+ private final LocalBinder mBinder = new LocalBinder();
@Override
public IBinder onBind(Intent intent) {
class MainServiceNotification {
final private MainService mService;
- private NotificationCompat.Builder userNoteBuilder;
+ private final NotificationCompat.Builder userNoteBuilder;
MainServiceNotification(MainService ms, CtFwSGameState game){
mService = ms;
});
}
- private long[] VIBRATE_PATTERN_NOW = {0, 100, 100, 300, 100, 300, 100, 300}; // 'J' = .---
- private long[] VIBRATE_PATTERN_FLAG = {0, 100, 100, 100, 100, 300, 100, 100}; // 'F' = ..-.
- private long[] VIBRATE_PATTERN_MSG = {0, 300, 100, 300}; // 'M' = --
+ private final long[] VIBRATE_PATTERN_NOW = {0, 100, 100, 300, 100, 300, 100, 300}; // 'J' = .---
+ private final long[] VIBRATE_PATTERN_FLAG = {0, 100, 100, 100, 100, 300, 100, 100}; // 'F' = ..-.
+ private final long[] VIBRATE_PATTERN_MSG = {0, 300, 100, 300}; // 'M' = --
private void vibrate(long[] pattern) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mService.getBaseContext());
android:layout_height="wrap_content"
app:srcCompat="@drawable/shield1"
android:id="@+id/about_image"
- android:layout_above="@+id/about_text" />
+ android:layout_above="@+id/about_text"
+ android:contentDescription="@string/about_imagealt"/>
<WebView
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mqtt_uri_label"
- android:gravity="right" />
+ android:gravity="end" />
<TextView
android:layout_width="wrap_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mqtt_state_label"
- android:gravity="right" />
+ android:gravity="end" />
<TextView
android:layout_width="wrap_content"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <plurals name="ctfws_flags">
+ <item quantity="one">%1$d Flag:</item>
+ <item quantity="other">%1$d Flags:</item>
+ </plurals>
+</resources>
\ No newline at end of file
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">CMUKGB CtFwS Timer</string>
<string name="ctfws_gameend">Game\nEnd</string>
<string name="ctfws_gamestart">Game\nStart</string>
<string name="ctfws_jailbreak">Jailbreak\n%1$d of %2$d</string>
- <string name="ctfws_flags">%1$d Flags:</string>
<string name="dialog_reset">Default</string>
<string name="header_gamestate0">Game State:</string>
- <string name="header_gamestateN">Game %1$d State:</string>
+ <string name="header_gamestateN" tools:ignore="PluralsCandidate">Game %1$d State:</string>
<string name="header_gametimeela">Game\nTime\nElapsed</string>
<string name="header_messages">Messages:</string>
<string name="notify_afoot">The game\'s afoot!</string>
- <string name="notify_flags">Flag captured! Red:%1$d Yellow:%2$d</string>
+ <string name="notify_flags" tools:ignore="PluralsCandidate">Flag captured! Red:%1$d Yellow:%2$d</string>
<string name="notify_gameend">Game ending soon</string>
<string name="notify_gamestart">Setup phase</string>
<string name="notify_jailbreak">Jailbreak %1$d of %2$d</string>
<string name="string_null"><<null>></string>
+ <string name="about_imagealt">The CMUKGB Shield Logo</string>
<string name="about_text"><![CDATA[
<center>
<a href="http://www.cmukgb.org/activities/ctfws.php">Capture The Flag With Stuff Rules</a>
apply plugin: 'com.android.application'
android {
- compileSdkVersion 24
+ compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.acmetensortoys.ctfwstimer"