Java 在何处声明报警管理器以在环境模式下更新手表?

Java 在何处声明报警管理器以在环境模式下更新手表?,java,android-studio,alarmmanager,wear-os,watch-face-api,Java,Android Studio,Alarmmanager,Wear Os,Watch Face Api,我正在尝试添加AlarmManager,以每半分钟更新一次表面。 这是一个三元时钟。 这是我第一次用Java或android studio编程 我在跟随一位导游 该指南要求“在活动的onCreate()方法中声明报警管理器和挂起的意图” 我应该用吗 @Override public Engine onCreateEngine() { return new Engine(); } 或 或者我应该启动一个新方法还是在别处声明它 目前我正在使用 private class Engine ex

我正在尝试添加AlarmManager,以每半分钟更新一次表面。 这是一个三元时钟。 这是我第一次用Java或android studio编程

我在跟随一位导游

该指南要求“在活动的onCreate()方法中声明报警管理器和挂起的意图”

我应该用吗

@Override
public Engine onCreateEngine() {
    return new Engine();
}

或者我应该启动一个新方法还是在别处声明它

目前我正在使用

private class Engine extends CanvasWatchFaceService.Engine {
    final Handler mUpdateTimeHandler = new EngineHandler(this);
在我初始化的大部分时间里

这是我没有报警管理器的代码。问题是它必须在半分钟内更新,因为时间应该是最接近的一分钟

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);
        }
    }
}
public类三元扩展CanvasWatchFaceService{
专用静态最终字体普通字体=
创建(Typeface.SANS_SERIF,Typeface.NORMAL);
私有静态最终int MSG_UPDATE_TIME=0;
@凌驾
公共引擎onCreateEngine(){
返回新发动机();
}
私有静态类EngineHandler扩展处理程序{
私人最终WeakReference mWeakReference;
公共发动机手柄(三元发动机参考){
mWeakReference=新的WeakReference(参考);
}
@凌驾
公共无效handleMessage(消息消息消息){
三元.Engine=mWeakReference.get();
如果(引擎!=null){
开关(msg.what){
案例消息更新时间:
engine.handleUpdateTimeMessage();
打破
}
}
}
}
私有类引擎扩展了CanvasWatchFaceService.Engine{
最终处理程序mUpdateTimeHandler=新引擎处理程序(此);
布尔值mRegisteredTimeZoneReceiver=false;
油漆;背景漆;
油漆;
布尔乳头;
时间mTime;
最终BroadcastReceiver mTimeZoneReceiver=新的BroadcastReceiver(){
@凌驾
公共void onReceive(上下文、意图){
mTime.clear(intent.getStringExtra(“时区”);
mTime.setToNow();
}
};
int mTapCount;
浮动偏移量;
浮动补偿;
//调整文本大小
浮点文本比率=(浮点)1;//2/3;
//按小时进行调整后的抵销
浮式水轮机;
浮动hrsIndentAdjust=textRatio*55;
//多行的垂直偏移
浮点ySpacer=textRatio*65;
//第一轮。
布尔值yesFirstRun=true;
//旗数秒
布尔yesSecs;
//先前的yesSecs状态
布尔值wasSecs=true;
//保存模式标志(环境中无秒)
布尔值yesConcerve=false;
//允许秒数的标志
布尔allowSecs=true;
//用于执行控制
布尔openGate=false;
//下次抽签的计数器
int c=0;
//时间循环计数器
int k;
布尔值drawNow=true;
//抽绳
字符串hrs=“”;
字符串mns=“”;
字符串sks=“”;
//注册毫秒数
长毫秒=0;
//用于实时计算Trit的浮点。
浮动时间=0;
//分钟和小时偏移的整数。
int minInt=0;
整数=0;
//循环转换的trit时间列表。
int[]trits3={9,3,1};
int[]trits4={27,9,3,1};
//故障排除的绝对计数
//长x=0;
/**
*在环境模式下,显示器是否支持每种颜色的较少位。如果为true,则
*在环境模式下禁用抗锯齿。
*/
布尔MLOWBITA环境;
@凌驾
创建后的公共作废(表面持有人){
super.onCreate(持有者);
setWatchFaceStyle(新的WatchFaceStyle.Builder(trialum.this)
.SetCardPeek模式(WatchFaceStyle.PEEK_模式_变量)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND\u VISIBILITY\u中断)
.setShowSystemUiTime(假)
.SetAcceptStatapEvents(真)
.build());
Resources=Trialum.this.getResources();
//y向上偏移
mYOffset=-30+resources.getDimen(R.dimen.dimen.digital\u y\u offset);
mBackgroundPaint=新油漆();
mBackgroundPaint.setColor(参考资料.getColor(R.color.background));
mTextPaint=新油漆();
mTextPaint=createTextPaint(resources.getColor(R.color.digital_text));
mTime=新时间();
}
@凌驾
公共空间{
移除消息(消息更新时间);
super.ondestory();
}
私有绘制createTextPaint(int textColor){
油漆=新油漆();
paint.setColor(textColor);
paint.setTypeface(普通字体);
paint.setAntiAlias(真);
返漆;
}
@凌驾
公共无效onVisibilityChanged(布尔可见){
super.onVisibilityChanged(可见);
如果(可见){
registerReceiver();
//更新时区,以防它在我们不可见时发生变化。
清除(TimeZone.getDefault().getID());
mTime.setToNow();
}否则{
取消注册接收者();
}
//计时器是否应该运行取决于我们是否可见(以及
//无论我们是否处于环境模式),因此我们可能需要启动或停止计时器。
updateTimer();
}
私有无效注册表接收者(){
if(mRegisteredTimeZoneReceiver){
返回;
}
mRegisteredTimeZoneReceiver=true;
IntentFilter筛选器=新的IntentFilter(Intent.ACTION\u时区\u已更改);
三元.this.registerReceiver(mTimeZoneReceiver,过滤器);
}
私有无效取消注册接收者(){
如果(!mRegisteredTimeZoneReceiver){
返回;
}
mRegisteredTimeZoneReceiver=false;
三元.this.unregisterereceiver(mTimeZoneReceiver);
}
@凌驾
应用窗口插图上的公共空白(窗口插图插图){
super.onapplyWindowInsetts(ins)
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);
        }
    }
}
public class ternary extends CanvasWatchFaceService {
    private AlarmManager mAmbientStateAlarmManager;
    private PendingIntent mAmbientStatePendingIntent;