Screensaver.java revision 90dc136d444ba29fe8db6b20872022b18f18dc94
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.deskclock;
18
19import android.animation.Animator;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.animation.TimeInterpolator;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.res.Configuration;
28import android.os.BatteryManager;
29import android.os.Handler;
30import android.service.dreams.Dream;
31import android.util.Log;
32import android.view.View;
33import android.view.WindowManager;
34import android.view.animation.AccelerateInterpolator;
35import android.view.animation.DecelerateInterpolator;
36
37public class Screensaver extends Dream {
38    static final boolean DEBUG = false;
39    static final String TAG = "DeskClock/Screensaver";
40
41    static int CLOCK_COLOR = 0xFF66AAFF;
42
43    static final long MOVE_DELAY = 60000; // DeskClock.SCREEN_SAVER_MOVE_DELAY;
44    static final long SLIDE_TIME = 10000;
45    static final long FADE_TIME = 1000;
46
47    static final boolean SLIDE = false;
48
49    private View mContentView, mSaverView;
50
51    private static TimeInterpolator mSlowStartWithBrakes =
52        new TimeInterpolator() {
53            public float getInterpolation(float x) {
54                return (float)(Math.cos((Math.pow(x,3) + 1) * Math.PI) / 2.0f) + 0.5f;
55            }
56        };
57
58    private Handler mHandler = new Handler();
59
60    private boolean mPlugged = false;
61    private final BroadcastReceiver mPowerIntentReceiver = new BroadcastReceiver() {
62        @Override
63        public void onReceive(Context context, Intent intent) {
64            final String action = intent.getAction();
65            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
66                // Only keep the screen on if we're plugged in.
67                boolean plugged = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
68                if (plugged != mPlugged) {
69                    if (DEBUG) Log.v(TAG, plugged ? "plugged in" : "unplugged");
70                    mPlugged = plugged;
71                    if (mPlugged) {
72                        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
73                    } else {
74                        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
75                    }
76                }
77            }
78        }
79    };
80
81    private final Runnable mMoveSaverRunnable = new Runnable() {
82        @Override
83        public void run() {
84            long delay = MOVE_DELAY;
85
86            if (DEBUG) Log.d(TAG,
87                    String.format("mContentView=(%d x %d) container=(%d x %d)",
88                        mContentView.getWidth(), mContentView.getHeight(),
89                        mSaverView.getWidth(), mSaverView.getHeight()
90                        ));
91            final float xrange = mContentView.getWidth() - mSaverView.getWidth();
92            final float yrange = mContentView.getHeight() - mSaverView.getHeight();
93
94            if (xrange == 0 && yrange == 0) {
95                delay = 500; // back in a split second
96            } else {
97                final int nextx = (int) (Math.random() * xrange);
98                final int nexty = (int) (Math.random() * yrange);
99
100                if (mSaverView.getAlpha() == 0f) {
101                    // jump right there
102                    mSaverView.setX(nextx);
103                    mSaverView.setY(nexty);
104                    ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f)
105                        .setDuration(FADE_TIME)
106                        .start();
107                } else {
108                    AnimatorSet s = new AnimatorSet();
109                    Animator xMove   = ObjectAnimator.ofFloat(mSaverView,
110                                         "x", mSaverView.getX(), nextx);
111                    Animator yMove   = ObjectAnimator.ofFloat(mSaverView,
112                                         "y", mSaverView.getY(), nexty);
113
114                    Animator xShrink = ObjectAnimator.ofFloat(mSaverView, "scaleX", 1f, 0.85f);
115                    Animator xGrow   = ObjectAnimator.ofFloat(mSaverView, "scaleX", 0.85f, 1f);
116
117                    Animator yShrink = ObjectAnimator.ofFloat(mSaverView, "scaleY", 1f, 0.85f);
118                    Animator yGrow   = ObjectAnimator.ofFloat(mSaverView, "scaleY", 0.85f, 1f);
119                    AnimatorSet shrink = new AnimatorSet(); shrink.play(xShrink).with(yShrink);
120                    AnimatorSet grow = new AnimatorSet(); grow.play(xGrow).with(yGrow);
121
122                    Animator fadeout = ObjectAnimator.ofFloat(mSaverView, "alpha", 1f, 0f);
123                    Animator fadein = ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f);
124
125
126                    if (SLIDE) {
127                        s.play(xMove).with(yMove);
128                        s.setDuration(SLIDE_TIME);
129
130                        s.play(shrink.setDuration(SLIDE_TIME/2));
131                        s.play(grow.setDuration(SLIDE_TIME/2)).after(shrink);
132                        s.setInterpolator(mSlowStartWithBrakes);
133                    } else {
134                        AccelerateInterpolator accel = new AccelerateInterpolator();
135                        DecelerateInterpolator decel = new DecelerateInterpolator();
136
137                        shrink.setDuration(FADE_TIME).setInterpolator(accel);
138                        fadeout.setDuration(FADE_TIME).setInterpolator(accel);
139                        grow.setDuration(FADE_TIME).setInterpolator(decel);
140                        fadein.setDuration(FADE_TIME).setInterpolator(decel);
141                        s.play(shrink);
142                        s.play(fadeout);
143                        s.play(xMove.setDuration(0)).after(FADE_TIME);
144                        s.play(yMove.setDuration(0)).after(FADE_TIME);
145                        s.play(fadein).after(FADE_TIME);
146                        s.play(grow).after(FADE_TIME);
147                    }
148                    s.start();
149                }
150
151                long now = System.currentTimeMillis();
152                long adjust = (now % 60000);
153                delay = delay
154                        + (MOVE_DELAY - adjust) // minute aligned
155                        - (SLIDE ? 0 : FADE_TIME) // start moving before the fade
156                        ;
157                if (DEBUG) Log.d(TAG,
158                        "will move again in " + delay + " now=" + now + " adjusted by " + adjust);
159            }
160
161            mHandler.removeCallbacks(this);
162            mHandler.postDelayed(this, delay);
163        }
164    };
165
166    public Screensaver() {
167        if (DEBUG) Log.d(TAG, "Screensaver allocated");
168    }
169
170    @Override
171    public void onCreate() {
172        if (DEBUG) Log.d(TAG, "Screensaver created");
173        super.onCreate();
174        setInteractive(false);
175    }
176
177    @Override
178    public void onStart() {
179        if (DEBUG) Log.d(TAG, "Screensaver started");
180        super.onStart();
181
182        CLOCK_COLOR = getResources().getColor(R.color.screen_saver_color);
183        layoutClockSaver();
184
185        final IntentFilter filter = new IntentFilter();
186        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
187        registerReceiver(mPowerIntentReceiver, filter);
188    }
189
190    @Override
191    public void onConfigurationChanged(Configuration newConfig) {
192        if (DEBUG) Log.d(TAG, "Screensaver configuration changed");
193        super.onConfigurationChanged(newConfig);
194        mHandler.removeCallbacks(mMoveSaverRunnable);
195        layoutClockSaver();
196        mHandler.post(mMoveSaverRunnable);
197    }
198
199    @Override
200    public void onAttachedToWindow() {
201        if (DEBUG) Log.d(TAG, "Screensaver attached to window");
202        super.onAttachedToWindow();
203
204        mHandler.post(mMoveSaverRunnable);
205    }
206
207    @Override
208    public void onDetachedFromWindow() {
209        if (DEBUG) Log.d(TAG, "Screensaver detached from window");
210        super.onDetachedFromWindow();
211
212        mHandler.removeCallbacks(mMoveSaverRunnable);
213    }
214
215    @Override
216    public void onDestroy() {
217        if (DEBUG) Log.d(TAG, "Screensaver destroyed");
218        super.onDestroy();
219
220        unregisterReceiver(mPowerIntentReceiver);
221    }
222
223    private void layoutClockSaver() {
224        setContentView(R.layout.desk_clock_saver);
225        mSaverView = findViewById(R.id.saver_view);
226        mContentView = (View) mSaverView.getParent();
227        mSaverView.setAlpha(0);
228
229        AndroidClockTextView timeDisplay = (AndroidClockTextView) findViewById(R.id.timeDisplay);
230        if (timeDisplay != null) {
231            timeDisplay.setTextColor(CLOCK_COLOR);
232            AndroidClockTextView amPm = (AndroidClockTextView)findViewById(R.id.am_pm);
233            if (amPm != null) amPm.setTextColor(CLOCK_COLOR);
234        }
235    }
236
237}
238