Java com.marlonjones.nimbus.WeatherWatchFaceService.WeatherWatchFaceEngine中没有可用的默认构造函数

Java com.marlonjones.nimbus.WeatherWatchFaceService.WeatherWatchFaceEngine中没有可用的默认构造函数,java,android,wear-os,watch-face-api,Java,Android,Wear Os,Watch Face Api,我看了好几个地方,包括这里,我发现答案没有帮助。我还查看了我正在使用的模板的代码,没有看到哪里出了问题,所以如果这似乎是一个糟糕的问题,我很抱歉。但我正在做一个表盘,我正试图从我的引擎WeatherWatchFaceEngine扩展它。但是当我这样做的时候,我得到了这个问题标题中的错误。我做错了什么 这是手表表面的代码: public class NimbusSplashAnalog extends WeatherWatchFaceService { /** * Update rate

我看了好几个地方,包括这里,我发现答案没有帮助。我还查看了我正在使用的模板的代码,没有看到哪里出了问题,所以如果这似乎是一个糟糕的问题,我很抱歉。但我正在做一个表盘,我正试图从我的引擎WeatherWatchFaceEngine扩展它。但是当我这样做的时候,我得到了这个问题标题中的错误。我做错了什么

这是手表表面的代码:

    public class NimbusSplashAnalog extends WeatherWatchFaceService {
/**
 * Update rate in milliseconds for interactive mode. We update once a second to advance the
 * second hand.
 */
private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);

/**
 * Handler message id for updating the time periodically in interactive mode.
 */
private static final int MSG_UPDATE_TIME = 0;

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

private class Engine extends WeatherWatchFaceEngine {
    Paint mBackgroundPaint;
    Paint mHandPaint;
    boolean mAmbient;
    Time mTime;

    final Handler mUpdateTimeHandler = new EngineHandler(this);

    final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mTime.clear(intent.getStringExtra("time-zone"));
            mTime.setToNow();
        }
    };
    boolean mRegisteredTimeZoneReceiver = false;

    /**
     * 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(NimbusSplashAnalog.this)
                .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build());

        Resources resources = NimbusSplashAnalog.this.getResources();

        mBackgroundPaint = new Paint();
        mBackgroundPaint.setColor(resources.getColor(R.color.analog_background));

        mHandPaint = new Paint();
        mHandPaint.setColor(resources.getColor(R.color.analog_hands));
        mHandPaint.setStrokeWidth(resources.getDimension(R.dimen.analog_hand_stroke));
        mHandPaint.setAntiAlias(true);
        mHandPaint.setStrokeCap(Paint.Cap.ROUND);

        mTime = new Time();
    }

    @Override
    public void onDestroy() {
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        super.onDestroy();
    }

    @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) {
                mHandPaint.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();
    }

    @Override
    public void onDraw(Canvas canvas, Rect bounds) {
        mTime.setToNow();

        int width = bounds.width();
        int height = bounds.height();

        // Draw the background.
        canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);

        // Find the center. Ignore the window insets so that, on round watches with a
        // "chin", the watch face is centered on the entire screen, not just the usable
        // portion.
        float centerX = width / 2f;
        float centerY = height / 2f;

        float secRot = mTime.second / 30f * (float) Math.PI;
        int minutes = mTime.minute;
        float minRot = minutes / 30f * (float) Math.PI;
        float hrRot = ((mTime.hour + (minutes / 60f)) / 6f) * (float) Math.PI;

        float secLength = centerX - 20;
        float minLength = centerX - 40;
        float hrLength = centerX - 80;

        if (!mAmbient) {
            float secX = (float) Math.sin(secRot) * secLength;
            float secY = (float) -Math.cos(secRot) * secLength;
            canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mHandPaint);
        }

        float minX = (float) Math.sin(minRot) * minLength;
        float minY = (float) -Math.cos(minRot) * minLength;
        canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mHandPaint);

        float hrX = (float) Math.sin(hrRot) * hrLength;
        float hrY = (float) -Math.cos(hrRot) * hrLength;
        canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHandPaint);
    }


    @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);
        NimbusSplashAnalog.this.registerReceiver(mTimeZoneReceiver, filter);
    }

    private void unregisterReceiver() {
        if (!mRegisteredTimeZoneReceiver) {
            return;
        }
        mRegisteredTimeZoneReceiver = false;
        NimbusSplashAnalog.this.unregisterReceiver(mTimeZoneReceiver);
    }

    /**
     * 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);
        }
    }
}

private static class EngineHandler extends Handler {
    private final WeakReference<NimbusSplashAnalog.Engine> mWeakReference;

    public EngineHandler(NimbusSplashAnalog.Engine reference) {
        mWeakReference = new WeakReference<>(reference);
    }

    @Override
    public void handleMessage(Message msg) {
        NimbusSplashAnalog.Engine engine = mWeakReference.get();
        if (engine != null) {
            switch (msg.what) {
                case MSG_UPDATE_TIME:
                    engine.handleUpdateTimeMessage();
                    break;
            }
        }
    }
}
公共类NimbusSplashAnalog扩展WeatherWatchFaceService{
/**
*交互式模式的更新速率(毫秒)。我们每秒更新一次以提高
*二手货。
*/
私有静态最终长交互更新速率=时间单位。秒。托米利斯(1);
/**
*用于在交互模式下定期更新时间的处理程序消息id。
*/
私有静态最终int MSG_UPDATE_TIME=0;
@凌驾
公共引擎onCreateEngine(){
返回新发动机();
}
私有类引擎扩展了WeatherWatchFaceEngine{
油漆;背景漆;
油漆和油漆;
布尔乳头;
时间mTime;
最终处理程序mUpdateTimeHandler=新引擎处理程序(此);
最终BroadcastReceiver mTimeZoneReceiver=新的BroadcastReceiver(){
@凌驾
公共void onReceive(上下文、意图){
mTime.clear(intent.getStringExtra(“时区”);
mTime.setToNow();
}
};
布尔值mRegisteredTimeZoneReceiver=false;
/**
*在环境模式下,显示器是否支持每种颜色的较少位。如果为true,则
*在环境模式下禁用抗锯齿。
*/
布尔MLOWBITA环境;
@凌驾
创建后的公共作废(表面持有人){
super.onCreate(持有者);
setWatchFaceStyle(新WatchFaceStyle.Builder(NimbusSplashAnalog.this)
.SetCardPeek模式(WatchFaceStyle.PEEK_模式_SHORT)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND\u VISIBILITY\u中断)
.setShowSystemUiTime(假)
.build());
Resources Resources=NimbusSplashAnalog.this.getResources();
mBackgroundPaint=新油漆();
setColor(参考资料.getColor(R.color.analog_background));
mHandPaint=新油漆();
mHandPaint.setColor(参考资料.getColor(R.color.analog_-hands));
mHandPaint.setStrokeWidth(参考资料.getDimension(R.dimen.analog_hand_stroke));
mHandPaint.setAntiAlias(真);
mHandPaint.setStrokeCap(油漆盖圆形);
mTime=新时间();
}
@凌驾
公共空间{
移除消息(消息更新时间);
super.ondestory();
}
@凌驾
已更改属性上的公共无效(捆绑属性){
super.onPropertiesChanged(属性);
mLowBitAmbient=properties.getBoolean(PROPERTY\u LOW\u BIT\u AMBIENT,false);
}
@凌驾
公共void onTimeTick(){
super.onTimeTick();
使无效();
}
@凌驾
AmbientMode上的公共无效已更改(AmbientMode上的布尔值){
super.onAmbientModeChanged(inAmbientMode);
如果(mAmbient!=环境模式){
mAmbient=inAmbientMode;
if(mLowBitAmbient){
mHandPaint.setAntiAlias(!inAmbientMode);
}
使无效();
}
//计时器是否应该运行取决于我们是否可见(以及
//无论我们是否处于环境模式),因此我们可能需要启动或停止计时器。
updateTimer();
}
@凌驾
公共无效onDraw(画布、矩形边界){
mTime.setToNow();
int width=bounds.width();
int height=bounds.height();
//画背景。
drawRect(0,0,canvas.getWidth(),canvas.getHeight(),mBackgroundPaint);
//找到中心。忽略窗口插图,以便在带有
//“下巴”,手表的正面位于整个屏幕的中心,而不仅仅是屏幕
//部分。
浮动中心X=宽度/2f;
浮动中心Y=高度/2f;
float secRot=mTime.second/30f*(float)Math.PI;
int minutes=mTime.minute;
float minRot=minutes/30f*(float)Math.PI;
float hrRot=((mTime.hour+(minutes/60f))/6f)*(float)Math.PI;
float secLength=centerX-20;
浮动最小长度=中心x-40;
浮动hrLength=centerX-80;
如果(!mAmbient){
float secX=(float)数学sin(secRot)*secLength;
浮点secY=(浮点)-数学cos(secRot)*secLength;
画布.抽绳(centerX、centerY、centerX+secX、centerY+secY、mHandPaint);
}
float minX=(float)Math.sin(minRot)*minLength;
float minY=(float)-Math.cos(minRot)*minLength;
画布.抽绳(centerX、centerY、centerX+minX、centerY+minY、mHandPaint);
float hrX=(float)数学sin(hrRot)*hrLength;
float hrY=(float)-Math.cos(hrRot)*hrLength;
画布.抽绳(centerX、centerY、centerX+hrX、centerY+hrY、mHandPaint);
}
@凌驾
公共无效onVisibilityChanged(布尔可见){
super.onVisibilityChanged(可见);
如果(可见){
registerReceiver();
//更新时区,以防它在我们不可见时发生变化。
清除(TimeZone.getDefault().getID());
mTime.setToNow();
}否则{
取消注册接收者();
}
//计时器是否应该运行取决于我们是否可见(以及
//无论我们是否处于环境模式),因此我们可能需要启动或停止计时器。
updateTimer();
}
私有无效注册表接收者(){
if(mRegisteredTimeZoneReceiver){
返回;
}
mRegisteredTimeZoneReceiver=true;
    public abstract class WeatherWatchFaceService extends CanvasWatchFaceService {
public class WeatherWatchFaceEngine extends CanvasWatchFaceService.Engine
        implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        DataApi.DataListener, NodeApi.NodeListener {

    protected static final int MSG_UPDATE_TIME = 0;
    protected long UPDATE_RATE_MS;
    protected static final long WEATHER_INFO_TIME_OUT = DateUtils.HOUR_IN_MILLIS * 6;
    protected final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //Time zone changed
            mWeatherInfoReceivedTime = 0;
            mTime.clear(intent.getStringExtra("time-zone"));
            mTime.setToNow();
        }
    };
    /**
     * Handler to update the time periodically in interactive mode.
     */
    protected final Handler mUpdateTimeHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MSG_UPDATE_TIME:
                    invalidate();

                    if (shouldUpdateTimerBeRunning()) {
                        long timeMs = System.currentTimeMillis();
                        long delayMs = UPDATE_RATE_MS - (timeMs % UPDATE_RATE_MS);
                        mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
                        requireWeatherInfo();
                    }
                    break;
            }
        }
    };
    protected int mTheme = 3;
    protected int mTimeUnit = ConverterUtil.TIME_UNIT_12;
    protected AssetManager mAsserts;
    protected Bitmap mWeatherConditionDrawable;
    protected GoogleApiClient mGoogleApiClient;
    protected Paint mBackgroundPaint;
    protected Paint mDatePaint;
    protected Paint mDateSuffixPaint;
    protected Paint mDebugInfoPaint;
    protected Paint mTemperatureBorderPaint;
    protected Paint mTemperaturePaint;
    protected Paint mTemperatureSuffixPaint;
    protected Paint mTimePaint;
    protected Resources mResources;
    protected String mWeatherCondition;
    protected String mWeatherConditionResourceName;
    protected Time mSunriseTime;
    protected Time mSunsetTime;
    protected Time mTime;
    protected boolean isRound;
    protected boolean mLowBitAmbient;
    protected boolean mRegisteredService = false;

    protected int mBackgroundColor;
    protected int mBackgroundDefaultColor;
    protected int mRequireInterval;
    protected int mTemperature = Integer.MAX_VALUE;
    protected int mTemperatureScale;
    protected long mWeatherInfoReceivedTime;
    protected long mWeatherInfoRequiredTime;
    private String mName;

    public WeatherWatchFaceEngine(String name) {
        mName = name;
        mGoogleApiClient = new GoogleApiClient.Builder(WeatherWatchFaceService.this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(Wearable.API)
                .build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        log("Connected: " + bundle);
        getConfig();

        Wearable.NodeApi.addListener(mGoogleApiClient, this);
        Wearable.DataApi.addListener(mGoogleApiClient, this);
        requireWeatherInfo();
    }

    @Override
    public void onConnectionSuspended(int i) {
        log("ConnectionSuspended: " + i);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (int i = 0; i < dataEvents.getCount(); i++) {
            DataEvent event = dataEvents.get(i);
            DataMap dataMap = DataMap.fromByteArray(event.getDataItem().getData());
            log("onDataChanged: " + dataMap);

            fetchConfig(dataMap);
        }
    }

    @Override
    public void onPeerConnected(Node node) {
        log("PeerConnected: " + node);
        requireWeatherInfo();
    }

    @Override
    public void onPeerDisconnected(Node node) {
        log("PeerDisconnected: " + node);
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        log("ConnectionFailed: " + connectionResult);

    }


    @Override
    public void onCreate(SurfaceHolder holder) {
        super.onCreate(holder);

        setWatchFaceStyle(new WatchFaceStyle.Builder(WeatherWatchFaceService.this)
                .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                .setAmbientPeekMode(WatchFaceStyle.AMBIENT_PEEK_MODE_HIDDEN)
                .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build());

        mResources = WeatherWatchFaceService.this.getResources();
        mAsserts = WeatherWatchFaceService.this.getAssets();

        mDebugInfoPaint = new Paint();
        mDebugInfoPaint.setColor(Color.parseColor("White"));
        mDebugInfoPaint.setTextSize(20);
        mDebugInfoPaint.setAntiAlias(true);

        mTime = new Time();
        mSunriseTime = new Time();
        mSunsetTime = new Time();

        mRequireInterval = mResources.getInteger(R.integer.weather_default_require_interval);
        mWeatherInfoRequiredTime = System.currentTimeMillis() - (DateUtils.SECOND_IN_MILLIS * 58);
        mGoogleApiClient.connect();
    }

    @Override
    public void onDestroy() {
        log("Destroy");
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        super.onDestroy();
    }

    @Override
    public void onInterruptionFilterChanged(int interruptionFilter) {
        super.onInterruptionFilterChanged(interruptionFilter);

        log("onInterruptionFilterChanged: " + interruptionFilter);
    }

    @Override
    public void onPropertiesChanged(Bundle properties) {
        super.onPropertiesChanged(properties);
        mLowBitAmbient = properties.getBoolean(WatchFaceService.PROPERTY_LOW_BIT_AMBIENT, false);

        log("onPropertiesChanged: LowBitAmbient=" + mLowBitAmbient);
    }

    @Override
    public void onTimeTick() {
        super.onTimeTick();
        log("TimeTick");
        invalidate();
        requireWeatherInfo();
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        super.onVisibilityChanged(visible);
        log("onVisibilityChanged: " + visible);

        if (visible) {
            mGoogleApiClient.connect();
            registerTimeZoneService();

            // Update time zone in case it changed while we weren't visible.
            mTime.clear(TimeZone.getDefault().getID());
            mTime.setToNow();
        } else {
            if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
                Wearable.DataApi.removeListener(mGoogleApiClient, this);
                Wearable.NodeApi.removeListener(mGoogleApiClient, this);
                mGoogleApiClient.disconnect();
            }

            unregisterTimeZoneService();
        }

        // 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();
    }

    protected Paint createTextPaint(int color, Typeface typeface) {
        Paint paint = new Paint();
        paint.setColor(color);
        if (typeface != null)
            paint.setTypeface(typeface);
        paint.setAntiAlias(true);
        return paint;
    }

    protected boolean shouldUpdateTimerBeRunning() {
        return isVisible() && !isInAmbientMode();
    }

    protected void fetchConfig(DataMap config) {
        if (config.containsKey(Consts.KEY_WEATHER_UPDATE_TIME)) {
            mWeatherInfoReceivedTime = config.getLong(Consts.KEY_WEATHER_UPDATE_TIME);
        }

        if (config.containsKey(Consts.KEY_WEATHER_CONDITION)) {
            String cond = config.getString(Consts.KEY_WEATHER_CONDITION);
            if (TextUtils.isEmpty(cond)) {
                mWeatherCondition = null;
            } else {
                mWeatherCondition = cond;
            }
        }

        if (config.containsKey(Consts.KEY_WEATHER_TEMPERATURE)) {
            mTemperature = config.getInt(Consts.KEY_WEATHER_TEMPERATURE);
            if (mTemperatureScale != ConverterUtil.FAHRENHEIT) {
                mTemperature = ConverterUtil.convertFahrenheitToCelsius(mTemperature);
            }
        }

        if (config.containsKey(Consts.KEY_WEATHER_SUNRISE)) {
            mSunriseTime.set(config.getLong(Consts.KEY_WEATHER_SUNRISE) * 1000);
            log("SunriseTime: " + mSunriseTime);
        }

        if (config.containsKey(Consts.KEY_WEATHER_SUNSET)) {
            mSunsetTime.set(config.getLong(Consts.KEY_WEATHER_SUNSET) * 1000);
            log("SunsetTime: " + mSunsetTime);
        }

        if (config.containsKey(Consts.KEY_CONFIG_TEMPERATURE_SCALE)) {
            int scale = config.getInt(Consts.KEY_CONFIG_TEMPERATURE_SCALE);

            if (scale != mTemperatureScale) {
                if (scale == ConverterUtil.FAHRENHEIT) {
                    mTemperature = ConverterUtil.convertCelsiusToFahrenheit(mTemperature);
                } else {
                    mTemperature = ConverterUtil.convertFahrenheitToCelsius(mTemperature);
                }
            }

            mTemperatureScale = scale;
        }

        if (config.containsKey(Consts.KEY_CONFIG_THEME)) {
            mTheme = config.getInt(Consts.KEY_CONFIG_THEME);
        }

        if (config.containsKey(Consts.KEY_CONFIG_TIME_UNIT)) {
            mTimeUnit = config.getInt(Consts.KEY_CONFIG_TIME_UNIT);
        }

        if (config.containsKey(Consts.KEY_CONFIG_REQUIRE_INTERVAL)) {
            mRequireInterval = config.getInt(Consts.KEY_CONFIG_REQUIRE_INTERVAL);
        }

        invalidate();
    }

    protected void getConfig() {
        log("Start getting Config");
        Wearable.NodeApi.getLocalNode(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
            @Override
            public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
                Uri uri = new Uri.Builder()
                        .scheme("wear")
                        .path(Consts.PATH_CONFIG + mName)
                        .authority(getLocalNodeResult.getNode().getId())
                        .build();

                getConfig(uri);

                uri = new Uri.Builder()
                        .scheme("wear")
                        .path(Consts.PATH_WEATHER_INFO)
                        .authority(getLocalNodeResult.getNode().getId())
                        .build();

                getConfig(uri);
            }
        });
    }

    protected void getConfig(Uri uri) {

        Wearable.DataApi.getDataItem(mGoogleApiClient, uri)
                .setResultCallback(
                        new ResultCallback<DataApi.DataItemResult>() {
                            @Override
                            public void onResult(DataApi.DataItemResult dataItemResult) {
                                log("Finish Config: " + dataItemResult.getStatus());
                                if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
                                    fetchConfig(DataMapItem.fromDataItem(dataItemResult.getDataItem()).getDataMap());
                                }
                            }
                        }
                );
    }

    protected void log(String message) {
        Log.d(WeatherWatchFaceService.this.getClass().getSimpleName(), message);
    }

    protected void registerTimeZoneService() {
        //TimeZone
        if (mRegisteredService) {
            return;
        }

        mRegisteredService = true;

        // TimeZone
        IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
        WeatherWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
    }

    protected void requireWeatherInfo() {
        if (!mGoogleApiClient.isConnected())
            return;

        long timeMs = System.currentTimeMillis();

        // The weather info is still up to date.
        if ((timeMs - mWeatherInfoReceivedTime) <= mRequireInterval)
            return;

        // Try once in a min.
        if ((timeMs - mWeatherInfoRequiredTime) <= DateUtils.MINUTE_IN_MILLIS)
            return;

        mWeatherInfoRequiredTime = timeMs;
        Wearable.MessageApi.sendMessage(mGoogleApiClient, "", Consts.PATH_WEATHER_REQUIRE, null)
                .setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
                    @Override
                    public void onResult(MessageApi.SendMessageResult sendMessageResult) {
                        log("SendRequireMessage:" + sendMessageResult.getStatus());
                    }
                });
    }

    protected void unregisterTimeZoneService() {
        if (!mRegisteredService) {
            return;
        }
        mRegisteredService = false;

        //TimeZone
        WeatherWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
    }

    protected void updateTimer() {
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        if (shouldUpdateTimerBeRunning()) {
            mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
        }
    }
}