Android Open Source - CalWatch Clock State






From Project

Back to project page CalWatch.

License

The source code is released under:

GNU General Public License

If you think the Android project CalWatch listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * CalWatch/*from www .ja v  a2s.c o  m*/
 * Copyright (C) 2014 by Dan Wallach
 * Home page: http://www.cs.rice.edu/~dwallach/calwatch/
 * Licensing: http://www.cs.rice.edu/~dwallach/calwatch/licensing.html
 */
package org.dwallach.calwatch;

import android.util.Log;

import org.dwallach.calwatch.WireEvent;
import org.dwallach.calwatch.WireUpdate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

public class ClockState extends Observable {
    private final static String TAG = "ClockState";

    public final static int FACE_TOOL = 0;
    public final static int FACE_NUMBERS = 1;
    public final static int FACE_LITE = 2;

    private int faceMode = Constants.DefaultWatchFace;
    private boolean showSeconds = Constants.DefaultShowSeconds;
    private boolean showDayDate = Constants.DefaultShowDayDate;
    private List<EventWrapper> eventList = null;
    private List<EventWrapper> visibleEventList = null;
    private int maxLevel = 0;

    private static ClockState singleton = null;

    private boolean wireInitialized = false;

    /**
     * Query whether or not a wire update has arrived yet. If the result is false,
     * *and* we're running on the watch, then we've only got default values. If we're
     * running on the phone, this data structure might be otherwise initialized, so
     * this getter might return false even when the data structure is loaded with events.
     * @return if a wire message has successfully initialized the clock state
     */
    public boolean getWireInitialized() {
        return wireInitialized;
    }


    // we don't want others constructing this
    private ClockState() { }

    // instead, they'll go through this
    public static ClockState getSingleton() {
        if(singleton == null)
            singleton = new ClockState();

        return singleton;
    }

    public void setFaceMode(int faceMode) {
        // warning: this might come in from another thread!
        this.faceMode = faceMode;

//        pingObservers();
    }

    public int getFaceMode() {
        return faceMode;
    }

    public void setShowSeconds(boolean showSeconds) {
        this.showSeconds = showSeconds;

//        pingObservers();
    }

    public boolean getShowSeconds() {
        return showSeconds;
    }

    public void setShowDayDate(boolean showDayDate) {
        this.showDayDate = showDayDate;

//        pingObservers();
    }

    public boolean getShowDayDate() {
        return showDayDate;
    }


    /**
     * Load the eventlist. This is meant to consume the output of the calendarFetcher,
     * which is in GMT time, *not* local time.
     * @param eventList list of events (GMT time)
     */
    public void setEventWrapperList(List<EventWrapper> eventList) {
        this.eventList = eventList;
        this.visibleEventList = null;
        pingObservers();
    }

    public void setWireEventList(List<WireEvent> wireEventList) {
        List<EventWrapper> results = new ArrayList<EventWrapper>();

        for (WireEvent wireEvent : wireEventList)
            results.add(new EventWrapper(wireEvent));

        setEventWrapperList(results);
        Log.v(TAG, "new calendar event list, " + results.size() + " entries");
    }

    /**
     * This fetches *every* event present in the ClockState (typically 24 hours worth),
     * and does it *without* clipping to the visible watchface. These will be in GMT time.
     */
    public List<WireEvent> getWireEventList() {
        List<WireEvent> output = new ArrayList<WireEvent>();

        if(eventList == null) return null;

        for(EventWrapper event: eventList)
            output.add(event.getWireEvent());

        return output;
    }

    private long lastClipTime = 0;

    private void computeVisibleEvents() {
//        if(eventList == null) {
//            Log.v(TAG, "no events to compute visibility over, going with empty list for now");
//        }

        // This is going to be called on every screen refresh, so it needs to be fast in the common case.
        // The current solution is to measure the time and try to figure out whether we've ticked onto
        // a new hour, which would mean that it's time to redo the visibility calculation. If new events
        // showed up for whatever other reason, then that would have nuked visibleEventList, so we'll
        // recompute that here as well.

//        Log.v(TAG, "starting event pool: " + eventList.size());

        int gmtOffset = TimeWrapper.getGmtOffset();

        long localClipTime = TimeWrapper.getLocalFloorHour();
        long clipStartMillis = localClipTime - gmtOffset; // convert from localtime back to GMT time for looking at events
        long clipEndMillis = clipStartMillis + 43200000;  // 12 hours later

        if(visibleEventList != null)
            EventLayout.sanityTest(visibleEventList, this.maxLevel, "Before clipping");

        // this used to compare to the GMT version (clipStartMillis), but this caused incorrect behavior
        // when the watch suddenly updated itself for a new timezone. Comparing to the *local* time
        // is the right answer.
        if(lastClipTime == localClipTime && visibleEventList != null)
            return; // we've already done it, and we've got a cache of the results

//        Log.v(TAG, "clipStart: " + TimeWrapper.formatGMTTime(clipStartMillis) + " (" + clipStartMillis +
//                "), clipEnd: " + TimeWrapper.formatGMTTime(clipEndMillis) + " (" + clipEndMillis + ")");

        lastClipTime = localClipTime;
        visibleEventList = new ArrayList<EventWrapper>();

        if(eventList != null) {
            Log.v(TAG, "clipping " + eventList.size() + " raw events to fit the screen");
            for (EventWrapper eventWrapper : eventList) {
                WireEvent e = eventWrapper.getWireEvent();

                long startTime = e.startTime;
                long endTime = e.endTime;

//                Log.v(TAG, "New event: startTime: " + TimeWrapper.formatGMTTime(startTime) +
//                        ", endTime: " + TimeWrapper.formatGMTTime(endTime));

                // clip the event to the screen
                if (startTime < clipStartMillis) startTime = clipStartMillis;
                if (endTime > clipEndMillis) endTime = clipEndMillis;


//                Log.v(TAG, "-- Clipped: startTime: " + TimeWrapper.formatGMTTime(startTime) +
//                        ", endTime: " + TimeWrapper.formatGMTTime(endTime));


                if (endTime < clipStartMillis || startTime > clipEndMillis)
                    continue; // this one is off-screen

                if(startTime == clipStartMillis && endTime == clipEndMillis)
                    continue; // this one covers the full 12-hour face of the watch; ignore for now
                // TODO if we ever do time-duration weighting of event thickness, then we can consider
                // bringing these back, as well as doing something more useful with all-day events,
                // which are similarly also ignored.

                visibleEventList.add((new EventWrapper(new WireEvent(startTime + gmtOffset, endTime + gmtOffset, e.displayColor))));
            }
        }

        // now, we run off and do screen layout
        if(eventList != null) {
            // first, try the fancy constraint solver
            if(EventLayoutUniform.go(visibleEventList)) {
                // yeah, we succeeded
                this.maxLevel = EventLayoutUniform.MAXLEVEL;
            } else {
                // something blew up with the Simplex solver, fall back to the cheesy, greedy algorithm
                Log.v(TAG, "falling back to older greedy method");
                this.maxLevel = EventLayout.go(visibleEventList);
            }
        } else
            this.maxLevel = 0;

        EventLayout.sanityTest(visibleEventList, this.maxLevel, "After new event layout");
        Log.v(TAG, "maxLevel for new events: " + this.maxLevel);
        Log.v(TAG, "number of new events: " + visibleEventList.size());

//        debugDump();
    }

    /**
     * This returns a list of *visible* events on the watchface, cropped to size, and adjusted to
     * the *local* timezone. If you want GMT events, which will not have been clipped, then use
     * getWireEventList().
     */
    public List<EventWrapper> getVisibleLocalEventList() {
        computeVisibleEvents(); // should be fast, since mostly it will detect that nothing has changed
        return visibleEventList;
    }

    /**
     * Load the ClockState with a protobuf containing a complete update
     * @param eventBytes a marshalled protobuf of type WireUpdate
     */
    public void setProtobuf(byte[] eventBytes) {
        WireUpdate wireUpdate = null;

        try {
            wireUpdate = WireUpdate.parseFrom(eventBytes);
            wireInitialized = true;
        } catch (IOException ioe) {
            Log.e(TAG, "parse failure on protobuf: nbytes(" + eventBytes.length + ")", ioe);
            return;
        } catch (Exception e) {
            if (eventBytes.length == 0)
                Log.e(TAG, "zero-length message received!");
            else
                Log.e(TAG, "some other weird failure on protobuf: nbytes(" + eventBytes.length + ")", e);
            return;
        }

        // note: we're no longer getting calendar events from the wire; we're just reading them locally
//            if (wireUpdate.newEvents)
//                setWireEventList(wireUpdate.events);

        setFaceMode(wireUpdate.faceMode);
        setShowSeconds(wireUpdate.showSecondHand);
        setShowDayDate(wireUpdate.showDayDate);

        pingObservers();

        Log.v(TAG, "event update complete");
    }

    /**
     * marshalls into a protobuf for transmission elsewhere
     * @return the protobuf
     */
    public byte[] getProtobuf() {
        // note: we're now *not* sending calendar events; just the UI state
        WireUpdate wireUpdate = new WireUpdate(getFaceMode(), getShowSeconds(), getShowDayDate());
        byte[] output = wireUpdate.toByteArray();

        return output;
    }

    public void pingObservers() {
        // this incantation will make observers elsewhere aware that there's new content
        setChanged();
        notifyObservers();
        clearChanged();
    }

    public int getMaxLevel() {
        return maxLevel;
    }

    private void debugDump() {
        Log.v(TAG, "All events in the DB:");
        for(EventWrapper e: eventList) {
            Log.v(TAG, "--> displayColor(" + Integer.toHexString(e.getWireEvent().displayColor) + "), minLevel(" + e.getMinLevel() + "), maxLevel(" + e.getMaxLevel() + "), startTime(" + e.getWireEvent().startTime + "), endTime(" + e.getWireEvent().endTime + ")");
        }

        Log.v(TAG, "Visible:");
        for(EventWrapper e: visibleEventList) {
            Log.v(TAG, "--> displayColor(" + Integer.toHexString(e.getWireEvent().displayColor) + "), minLevel(" + e.getMinLevel() + "), maxLevel(" + e.getMaxLevel() + "), startTime(" + e.getWireEvent().startTime + "), endTime(" + e.getWireEvent().endTime + ")");
        }
    }
}




Java Source Code List

EDU.Washington.grad.gjb.cassowary.CL.java
EDU.Washington.grad.gjb.cassowary.ClAbstractVariable.java
EDU.Washington.grad.gjb.cassowary.ClConstraint.java
EDU.Washington.grad.gjb.cassowary.ClDouble.java
EDU.Washington.grad.gjb.cassowary.ClDummyVariable.java
EDU.Washington.grad.gjb.cassowary.ClEditConstraint.java
EDU.Washington.grad.gjb.cassowary.ClEditInfo.java
EDU.Washington.grad.gjb.cassowary.ClEditOrStayConstraint.java
EDU.Washington.grad.gjb.cassowary.ClLinearConstraint.java
EDU.Washington.grad.gjb.cassowary.ClLinearEquation.java
EDU.Washington.grad.gjb.cassowary.ClLinearExpression.java
EDU.Washington.grad.gjb.cassowary.ClLinearInequality.java
EDU.Washington.grad.gjb.cassowary.ClObjectiveVariable.java
EDU.Washington.grad.gjb.cassowary.ClPoint.java
EDU.Washington.grad.gjb.cassowary.ClSimplexSolver.java
EDU.Washington.grad.gjb.cassowary.ClSlackVariable.java
EDU.Washington.grad.gjb.cassowary.ClStayConstraint.java
EDU.Washington.grad.gjb.cassowary.ClStrength.java
EDU.Washington.grad.gjb.cassowary.ClSymbolicWeight.java
EDU.Washington.grad.gjb.cassowary.ClTableau.java
EDU.Washington.grad.gjb.cassowary.ClTestColumns.java
EDU.Washington.grad.gjb.cassowary.ClTests.java
EDU.Washington.grad.gjb.cassowary.ClVariable.java
EDU.Washington.grad.gjb.cassowary.ExCLConstraintNotFound.java
EDU.Washington.grad.gjb.cassowary.ExCLError.java
EDU.Washington.grad.gjb.cassowary.ExCLInternalError.java
EDU.Washington.grad.gjb.cassowary.ExCLNonlinearExpression.java
EDU.Washington.grad.gjb.cassowary.ExCLNotEnoughStays.java
EDU.Washington.grad.gjb.cassowary.ExCLRequiredFailure.java
EDU.Washington.grad.gjb.cassowary.ExCLTooDifficult.java
EDU.Washington.grad.gjb.cassowary.Set.java
EDU.Washington.grad.gjb.cassowary.Timer.java
EDU.Washington.grad.gjb.cassowary.sym.java
EDU.Washington.grad.gjb.cassowary.testClLinearExpression.java
EDU.Washington.grad.gjb.cassowary.testClStrength.java
org.dwallach.calwatch.ApplicationTest.java
org.dwallach.calwatch.BatteryWrapper.java
org.dwallach.calwatch.CalWatchFaceService.java
org.dwallach.calwatch.CalendarFetcher.java
org.dwallach.calwatch.ClockFace.java
org.dwallach.calwatch.ClockState.java
org.dwallach.calwatch.Constants.java
org.dwallach.calwatch.EventLayoutTest.java
org.dwallach.calwatch.EventLayoutUniformTest.java
org.dwallach.calwatch.EventLayoutUniform.java
org.dwallach.calwatch.EventLayout.java
org.dwallach.calwatch.EventWrapper.java
org.dwallach.calwatch.MyViewAnim.java
org.dwallach.calwatch.PaintCan.java
org.dwallach.calwatch.PathCache.java
org.dwallach.calwatch.PhoneActivity.java
org.dwallach.calwatch.PreferencesHelper.java
org.dwallach.calwatch.TimeWrapper.java
org.dwallach.calwatch.VersionWrapper.java
org.dwallach.calwatch.WatchCalendarService.java
org.dwallach.calwatch.WearReceiverService.java
org.dwallach.calwatch.WearSender.java
org.dwallach.calwatch.WireEvent.java
org.dwallach.calwatch.WireUpdate.java
org.dwallach.calwatch.XWatchfaceReceiver.java