I'm trying to add an AlarmManager to update a watch face on half minute intervals. This is for a ternary clock. This is my first time programming with Java or android studio.
I'm following a guide at https://developer.android.com/training/wearables/apps/always-on.html
The guide says to "declare the alarm manager and the pending intent in the onCreate() method of your activity"
Should I use
@Override
public Engine onCreateEngine() {
return new Engine();
}
or
@Override
public Engine onCreateEngine() {
return new Engine();
}
or should I start a new method or declare it elsewhere?
Currently I'm using
private class Engine extends CanvasWatchFaceService.Engine {
final Handler mUpdateTimeHandler = new EngineHandler(this);
for most of my initialization.
This is my code without the alarm manager. The issue is that it must update during half minutes, because as balanced ternary the time should be to the nearest minute.
public class ternary extends CanvasWatchFaceService {
private static final Typeface NORMAL_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
private static final int MSG_UPDATE_TIME = 0;
@Override
public Engine onCreateEngine() {
return new Engine();
}
private static class EngineHandler extends Handler {
private final WeakReference<ternary.Engine> mWeakReference;
public EngineHandler(ternary.Engine reference) {
mWeakReference = new WeakReference<>(reference);
}
@Override
public void handleMessage(Message msg) {
ternary.Engine engine = mWeakReference.get();
if (engine != null) {
switch (msg.what) {
case MSG_UPDATE_TIME:
engine.handleUpdateTimeMessage();
break;
}
}
}
}
private class Engine extends CanvasWatchFaceService.Engine {
final Handler mUpdateTimeHandler = new EngineHandler(this);
boolean mRegisteredTimeZoneReceiver = false;
Paint mBackgroundPaint;
Paint mTextPaint;
boolean mAmbient;
Time mTime;
final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mTime.clear(intent.getStringExtra("time-zone"));
mTime.setToNow();
}
};
int mTapCount;
float mXOffset;
float mYOffset;
// adjust text size
float textRatio = (float)1; // 2/3;
// make adjusted offset for hours
float hrsIndent;
float hrsIndentAdjust = textRatio * 55;
// vertical offset for multiple lines
float ySpacer = textRatio * 65;
// first run.
boolean yesFirstRun = true;
// flag for seconds
boolean yesSecs;
// prior state of yesSecs
boolean wasSecs = true;
// flag for conservation mode (no seconds in ambient)
boolean yesConcerve = false;
// flag for allowing seconds
boolean allowSecs = true;
// for execution control
boolean openGate = false;
// counter for next draw
int c = 0;
// counter for time loops
int k;
boolean drawNow = true;
// strings for draw
String hrs = "";
String mns = "";
String sks = "";
// register for milliseconds
long millis = 0;
// float for calculating trits from time.
float tim = 0;
// ints for minute and hour offsets.
int minInt = 0;
int hourInt = 0;
// lists for time to trit for loop conversions.
int [] trits3 = {9, 3, 1};
int [] trits4 = {27, 9, 3, 1};
// absolute count for trouble shooting
// long x = 0;
/**
* Whether the display supports fewer bits for each color in ambient mode. When true, we
* disable anti-aliasing in ambient mode.
*/
boolean mLowBitAmbient;
@Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
setWatchFaceStyle(new WatchFaceStyle.Builder(ternary.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.setAcceptsTapEvents(true)
.build());
Resources resources = ternary.this.getResources();
// shift y offset up
mYOffset = -30 + resources.getDimension(R.dimen.digital_y_offset);
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(resources.getColor(R.color.background));
mTextPaint = new Paint();
mTextPaint = createTextPaint(resources.getColor(R.color.digital_text));
mTime = new Time();
}
@Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
private Paint createTextPaint(int textColor) {
Paint paint = new Paint();
paint.setColor(textColor);
paint.setTypeface(NORMAL_TYPEFACE);
paint.setAntiAlias(true);
return paint;
}
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
registerReceiver();
// Update time zone in case it changed while we weren't visible.
mTime.clear(TimeZone.getDefault().getID());
mTime.setToNow();
} else {
unregisterReceiver();
}
// Whether the timer should be running depends on whether we're visible (as well as
// whether we're in ambient mode), so we may need to start or stop the timer.
updateTimer();
}
private void registerReceiver() {
if (mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
ternary.this.registerReceiver(mTimeZoneReceiver, filter);
}
private void unregisterReceiver() {
if (!mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = false;
ternary.this.unregisterReceiver(mTimeZoneReceiver);
}
@Override
public void onApplyWindowInsets(WindowInsets insets) {
super.onApplyWindowInsets(insets);
// Load resources that have alternate values for round watches.
Resources resources = ternary.this.getResources();
boolean isRound = insets.isRound();
// shift offset 75 to the right
mXOffset = 75 + resources.getDimension(isRound
? R.dimen.digital_x_offset_round : R.dimen.digital_x_offset);
float textSize = resources.getDimension(isRound
? R.dimen.digital_text_size_round : R.dimen.digital_text_size);
// adjust hrs Indent to MXOffset
hrsIndent = hrsIndentAdjust + mXOffset;
// adjust size to textRatio
mTextPaint.setTextSize(textSize * textRatio );
}
@Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
}
@Override
public void onTimeTick() {
super.onTimeTick();
invalidate();
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (mAmbient != inAmbientMode) {
mAmbient = inAmbientMode;
if (mLowBitAmbient) {
mTextPaint.setAntiAlias(!inAmbientMode);
}
invalidate();
}
// Whether the timer should be running depends on whether we're visible (as well as
// whether we're in ambient mode), so we may need to start or stop the timer.
updateTimer();
}
/**
* Captures tap event (and tap type) and toggles the background color if the user finishes
* a tap.
*/
@Override
public void onTapCommand(int tapType, int x, int y, long eventTime) {
Resources resources = ternary.this.getResources();
switch (tapType) {
case TAP_TYPE_TOUCH:
// The user has started touching the screen.
break;
case TAP_TYPE_TOUCH_CANCEL:
// The user has started a different gesture or otherwise cancelled the tap.
break;
case TAP_TYPE_TAP:
// The user has completed the tap gesture.
mTapCount++;
mBackgroundPaint.setColor(resources.getColor(mTapCount % 2 == 0 ?
R.color.background : R.color.background2));
break;
}
invalidate();
}
@Override
public void onDraw(Canvas canvas, Rect bounds) {
// Greebo counter
// x += 1;
// seconds handling
wasSecs = yesSecs;
yesSecs = allowSecs && !isInAmbientMode();
// for clearing seconds
if (!yesSecs && wasSecs) { sks = ""; }
// Draw at mid second
if (c == 0 && yesSecs) {
drawNow = true;
} else {
c = 0;
// mid minute
if (mTime.second == 30 || isInAmbientMode()) {
drawNow = true;
} else {
// mid hour
if (mTime.second == 0) {
if (mTime.minute == 30) {
drawNow = true;
} else {
// mid night
if (mTime.minute == 0) {
if (mTime.hour == 0) {
drawNow = true;
}
}
}
}
}
}
if (drawNow) {
drawNow = false;
mTime.setToNow();
millis = System.currentTimeMillis() % 1000;
// mid seconds
if (yesSecs) { if (millis > 499) { c = 1; } }
tim = (float)((mTime.minute * 60 + mTime.second) * 1000 + millis)/ 3600000;
// hours past noon
tim += mTime.hour - 12;
// find hrs 9s, 3s, 1s.
openGate = false;
if (yesFirstRun || mTime.minute == 30){ openGate = true; }
else { openGate = mTime.second == 0 && mTime.minute == 0 && mTime.hour == 0;}
if (openGate) {
hrs = "";
hourInt = 0;
// i is for item.
for (int i : trits3) {
if (tim > ((float) i / 2)) {
tim -= i;
hourInt -= i;
hrs = hrs + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
hourInt += i;
hrs = hrs + "¬";
} else {
hrs = hrs + "0";
}
}
// add space
if (i > 1) {hrs += " "; }
}
} else { tim += hourInt; }
// minutes 27s, 9s, 3s, 1s
openGate = false;
if (yesFirstRun || mTime.second == 30 || isInAmbientMode()) {openGate = true; }
else { openGate = mTime.second == 0 && (mTime.minute == 30
|| (mTime.minute == 0 && mTime.hour == 0));}
if (openGate) {
mns = "";
tim *= 60;
minInt = 0;
// i is for item.
for (int i : trits4) {
if (tim > ((float) i / 2)) {
tim -= i;
if (yesSecs) {minInt -= i;}
mns = mns + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
if (yesSecs) {minInt += i;}
mns = mns + "¬";
} else {
mns = mns + "0";
}
}
// add space
if (i > 1) {mns += " "; }
}
} else { if (yesSecs) { tim += minInt; tim *= 60; } }
// seconds 27s, 9s, 3s, 1s
if (yesSecs) {
sks = "";
tim *= 60;
for (int i : trits4) {
if (tim > ((float) i / 2)) {
tim -= i;
sks = sks + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
sks = sks + "¬";
} else {
sks = sks + "0";
}
}
// add space
if (i > 1) {sks += " "; }
}
}
}
// Draw the background.
if (isInAmbientMode()) {
canvas.drawColor(Color.BLACK);
} else {
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
}
// draw hours
canvas.drawText(hrs, hrsIndent, mYOffset - ySpacer, mTextPaint);
// draw minutes
canvas.drawText(mns, mXOffset, mYOffset, mTextPaint);
// draw or clear seconds
if (yesSecs || wasSecs) {canvas.drawText(sks, mXOffset, mYOffset + ySpacer , mTextPaint);}
// show count and millis for greebo reduction.
// canvas.drawText(String.format("%1$03d,%2$02d,%3$d", x % 1000, millis / 10, 0), mXOffset, mYOffset + 100, mTextPaint);
//canvas.drawText(String.format("%$02d:%2$02d:%3$02d", mTime.hour, mTime.minute,
// mTime.second), mXOffset, mYOffset + 100, mTextPaint);
}
/**
* Starts the {@link #mUpdateTimeHandler} timer if it should be running and isn't currently
* or stops it if it shouldn't be running but currently is.
*/
private void updateTimer() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
/**
* Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer should
* only run when we're visible and in interactive mode.
*/
private boolean shouldTimerBeRunning() {
return isVisible() && !isInAmbientMode();
}
/**
* Handle updating the time periodically in interactive mode.
*/
private void handleUpdateTimeMessage() {
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs = INTERACTIVE_UPDATE_RATE_MS
- (timeMs % INTERACTIVE_UPDATE_RATE_MS);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
}
}
}
The "onCreate()" method seems to correlate with:
public class ternary extends CanvasWatchFaceService
Your declaration should be as follows:
public class ternary extends CanvasWatchFaceService {
private AlarmManager mAmbientStateAlarmManager;
private PendingIntent mAmbientStatePendingIntent;
And be sure to import android.app.AlarmManager and android.app.PendingIntent .