info.tellmetime.DaydreamService.java Source code

Java tutorial

Introduction

Here is the source code for info.tellmetime.DaydreamService.java

Source

/*
 * Copyright (c) 2014 Samuel Jarosiski <samueljarosinski@gmail.com>
 *
 * This file is part of "Tell me time".
 * http://tellmetime.info
 *
 * "Tell me time" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "Tell me time" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Tell me time". If not, see <http://www.gnu.org/licenses/>.
 */

package info.tellmetime;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Handler;
import android.service.dreams.DreamService;
import android.support.v4.view.MotionEventCompat;
import android.util.Property;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.io.File;
import java.io.FileInputStream;
import java.util.Calendar;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class DaydreamService extends DreamService {

    private Handler mHandler = new Handler();

    private int mHighlightColor;

    private int mBacklightColor;

    private int mMinutesSize = 36;

    private int mShorterEdge;

    private float mDensity;

    private boolean isNightMode;

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();

        setInteractive(true);

        setFullscreen(true);

        setContentView(R.layout.daydream);

        LinearLayout mClock = (LinearLayout) findViewById(R.id.clock);

        SharedPreferences settings = getSharedPreferences("PREFS", Context.MODE_PRIVATE);
        mHighlightColor = settings.getInt(TellmetimeActivity.HIGHLIGHT, Color.WHITE);
        mBacklightColor = settings.getInt(TellmetimeActivity.BACKLIGHT,
                getResources().getColor(R.color.backlight_light));
        mMinutesSize = settings.getInt(TellmetimeActivity.MINUTES_SIZE, 36);
        isNightMode = settings.getBoolean(TellmetimeActivity.NIGHTMODE, false);

        setScreenBright(!isNightMode);
        findViewById(R.id.overlay).setBackgroundColor(
                getResources().getColor(isNightMode ? R.color.night_mode_overlay : android.R.color.transparent));

        RelativeLayout mSurface = (RelativeLayout) findViewById(R.id.surface);
        mSurface.setBackgroundColor(
                settings.getInt(TellmetimeActivity.BACKGROUND, getResources().getColor(R.color.background)));
        switch (settings.getInt(TellmetimeActivity.BACKGROUND_MODE, TellmetimeActivity.MODE_BACKGROUND_SOLID)) {
        case TellmetimeActivity.MODE_BACKGROUND_WALLPAPER:
            ((ImageView) findViewById(R.id.background_image))
                    .setImageDrawable(WallpaperManager.getInstance(this).getDrawable());
            break;

        case TellmetimeActivity.MODE_BACKGROUND_IMAGE:
            try {
                ((ImageView) findViewById(R.id.background_image)).setImageBitmap(BitmapFactory.decodeStream(
                        new FileInputStream(new File(getFilesDir(), TellmetimeActivity.IMAGE_FILE_NAME))));
            } catch (Exception ignored) {
                // Image is not set, set background color loaded from setting is visible.
            }

            break;
        }

        mShorterEdge = Math.min(getResources().getDisplayMetrics().widthPixels,
                getResources().getDisplayMetrics().heightPixels);
        mDensity = getResources().getDisplayMetrics().density;

        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
                FrameLayout.LayoutParams.WRAP_CONTENT);
        lp.addRule(RelativeLayout.CENTER_IN_PARENT);
        lp.width = mShorterEdge;
        mClock.setLayoutParams(lp);

        Typeface mTypeface = Typeface.createFromAsset(getAssets(), "Roboto-BoldCondensed.ttf");
        final float mItemSize = mShorterEdge / mClock.getChildCount();
        final int mRowMargin = (int) -(mItemSize / 2.2);

        for (int i = 0; i < mClock.getChildCount(); i++) {
            LinearLayout row = (LinearLayout) mClock.getChildAt(i);

            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) row.getLayoutParams();
            params.bottomMargin = mRowMargin;
            row.setLayoutParams(params);

            for (int j = 0; j < row.getChildCount(); j++) {
                TextView tv = (TextView) row.getChildAt(j);

                tv.setTypeface(mTypeface);
                tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mItemSize);
                tv.setTextColor(mBacklightColor);
                tv.setShadowLayer(mShorterEdge / 200 * mDensity, 0, 0, mBacklightColor);
            }
        }
        LinearLayout lastRow = (LinearLayout) mClock.getChildAt(mClock.getChildCount() - 1);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) lastRow.getLayoutParams();
        params.bottomMargin = 0;
        lastRow.setLayoutParams(params);

        TextView twenty = (TextView) findViewById(R.id.twenty);
        params = (LinearLayout.LayoutParams) twenty.getLayoutParams();
        params.leftMargin = 0;
        twenty.setLayoutParams(params);

        inflateMinutesIndicators();
    }

    @Override
    public void onDreamingStarted() {
        super.onDreamingStarted();

        scheduleTimer();
    }

    @Override
    public void onDreamingStopped() {
        super.onDreamingStopped();

        mHandler.removeCallbacks(timerTask);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        inflateMinutesIndicators();
        mClockAlgorithm.tickTock();
    }

    private final Runnable timerTask = new Runnable() {
        @Override
        public void run() {
            scheduleTimer();
        }
    };

    private void scheduleTimer() {
        mClockAlgorithm.tickTock();

        Calendar date = Calendar.getInstance();
        date.set(Calendar.MILLISECOND, 0);
        date.set(Calendar.SECOND, 0);
        date.add(Calendar.MINUTE, 1);

        mHandler.postDelayed(timerTask, date.getTimeInMillis() - System.currentTimeMillis());
    }

    Clock mClockAlgorithm = new Clock(true) {

        @Override
        protected void setColor(final String item, final boolean isHighlighting) {
            final int newColor = isHighlighting ? mHighlightColor : mBacklightColor;
            final TextView tv = (TextView) findViewById(getItem(item));

            final int shadowSize = Math
                    .min((isHighlighting ? mShorterEdge / 100 : mShorterEdge / 200) * (int) mDensity, 25);

            final Property<TextView, Integer> propertyHighlight = new Property<TextView, Integer>(int.class,
                    "textColor") {
                @Override
                public Integer get(TextView object) {
                    return object.getCurrentTextColor();
                }

                @Override
                public void set(TextView object, Integer value) {
                    object.setTextColor(value);
                    object.setShadowLayer(shadowSize, 0, 0, value);
                }
            };

            tv.setLayerType(View.LAYER_TYPE_HARDWARE, null);

            ObjectAnimator animator = ObjectAnimator.ofInt(tv, propertyHighlight, newColor);
            animator.setDuration(1500L);
            animator.setEvaluator(new ArgbEvaluator());
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    tv.setLayerType(View.LAYER_TYPE_NONE, null);
                }
            });
            animator.start();
        }

    };

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
            isNightMode = !isNightMode;

            findViewById(R.id.overlay).setBackgroundColor(getResources()
                    .getColor(isNightMode ? R.color.night_mode_overlay : android.R.color.transparent));

            setScreenBright(!isNightMode);

            return true;
        } else
            return super.dispatchTouchEvent(event);
    }

    private void inflateMinutesIndicators() {
        FrameLayout minutesLayout = (FrameLayout) findViewById(R.id.minutes_indicators);
        minutesLayout.removeAllViews();
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final boolean isLandscape = getResources()
                .getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
        inflater.inflate(isLandscape ? R.layout.minutes_land : R.layout.minutes_portrait, minutesLayout);
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                isLandscape ? FrameLayout.LayoutParams.MATCH_PARENT : FrameLayout.LayoutParams.WRAP_CONTENT);
        if (!isLandscape) {
            layoutParams.addRule(RelativeLayout.BELOW, R.id.clock);
            layoutParams.topMargin = (int) -TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mMinutesSize / 3,
                    getResources().getDisplayMetrics());
        }
        minutesLayout.setLayoutParams(layoutParams);

        Typeface mTypefaceBold = Typeface.createFromAsset(getAssets(), "Roboto-BoldCondensed.ttf");
        ViewGroup minutesDots = (ViewGroup) findViewById(R.id.minutes_dots);
        for (int i = 0; i < minutesDots.getChildCount(); i++) {
            TextView m = (TextView) minutesDots.getChildAt(i);

            m.setTypeface(mTypefaceBold);
            m.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mMinutesSize);
            m.setTextColor(mBacklightColor);
            m.setShadowLayer(mShorterEdge / 200 * mDensity, 0, 0, mBacklightColor);
        }
    }

}