1/*
2 * Copyright (C) 2012 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.app.AlarmManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.res.Configuration;
25import android.database.ContentObserver;
26import android.os.BatteryManager;
27import android.os.Build;
28import android.os.Handler;
29import android.provider.Settings;
30import android.support.v7.app.AppCompatActivity;
31import android.view.View;
32import android.view.Window;
33import android.view.WindowManager;
34import android.widget.TextClock;
35
36import com.android.deskclock.Utils.ScreensaverMoveSaverRunnable;
37
38public class ScreensaverActivity extends AppCompatActivity {
39    static final boolean DEBUG = false;
40    static final String TAG = "DeskClock/ScreensaverActivity";
41
42    // This value must match android:defaultValue of
43    // android:key="screensaver_clock_style" in dream_settings.xml
44    static final String DEFAULT_CLOCK_STYLE = "digital";
45
46    private static final boolean PRE_L_DEVICE =
47            Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
48
49    private View mContentView, mSaverView;
50    private View mAnalogClock, mDigitalClock;
51
52    private final Handler mHandler = new Handler();
53    private final ScreensaverMoveSaverRunnable mMoveSaverRunnable;
54    private String mDateFormat;
55    private String mDateFormatForAccessibility;
56    private String mClockStyle;
57    private boolean mPluggedIn = true;
58    private final int mFlags = (WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
59            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
60            | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
61            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
62
63    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
64        @Override
65        public void onReceive(Context context, Intent intent) {
66            LogUtils.v(TAG, "ScreensaverActivity onReceive, action: " + intent.getAction());
67
68            boolean changed = intent.getAction().equals(Intent.ACTION_TIME_CHANGED)
69                    || intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
70            if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
71                mPluggedIn = true;
72                setWakeLock();
73            } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
74                mPluggedIn = false;
75                setWakeLock();
76            } else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
77                finish();
78            }
79
80            if (changed) {
81                Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
82                Utils.refreshAlarm(ScreensaverActivity.this, mContentView);
83                Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
84            }
85
86            if (intent.getAction().equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
87                Utils.refreshAlarm(ScreensaverActivity.this, mContentView);
88            }
89        }
90    };
91
92    /* Register ContentObserver to see alarm changes for pre-L */
93    private final ContentObserver mSettingsContentObserver = PRE_L_DEVICE
94        ? new ContentObserver(mHandler) {
95            @Override
96            public void onChange(boolean selfChange) {
97                Utils.refreshAlarm(ScreensaverActivity.this, mContentView);
98            }
99        }
100        : null;
101
102    // Thread that runs every midnight and refreshes the date.
103    private final Runnable mMidnightUpdater = new Runnable() {
104        @Override
105        public void run() {
106            Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
107            Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
108        }
109    };
110
111    public ScreensaverActivity() {
112        LogUtils.d(TAG, "Screensaver allocated");
113        mMoveSaverRunnable = new ScreensaverMoveSaverRunnable(mHandler);
114    }
115
116    @Override
117    public void onStart() {
118        super.onStart();
119        IntentFilter filter = new IntentFilter();
120        filter.addAction(Intent.ACTION_POWER_CONNECTED);
121        filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
122        filter.addAction(Intent.ACTION_USER_PRESENT);
123        filter.addAction(Intent.ACTION_TIME_CHANGED);
124        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
125        registerReceiver(mIntentReceiver, filter);
126        if (PRE_L_DEVICE) {
127            getContentResolver().registerContentObserver(
128                Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED),
129                false,
130                mSettingsContentObserver);
131        }
132    }
133
134    @Override
135    public void onResume() {
136        super.onResume();
137        Intent chargingIntent =
138                registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
139        int plugged = chargingIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
140        mPluggedIn = plugged == BatteryManager.BATTERY_PLUGGED_AC
141                || plugged == BatteryManager.BATTERY_PLUGGED_USB
142                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
143
144        mDateFormat = getString(R.string.abbrev_wday_month_day_no_year);
145        mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year);
146
147        setWakeLock();
148        layoutClockSaver();
149        mHandler.post(mMoveSaverRunnable);
150
151        Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
152    }
153
154    @Override
155    public void onPause() {
156        mHandler.removeCallbacks(mMoveSaverRunnable);
157        Utils.cancelMidnightUpdater(mHandler, mMidnightUpdater);
158        super.onPause();
159    }
160
161    @Override
162    public void onStop() {
163        if (PRE_L_DEVICE) {
164            getContentResolver().unregisterContentObserver(mSettingsContentObserver);
165        }
166        unregisterReceiver(mIntentReceiver);
167        super.onStop();
168   }
169
170    @Override
171    public void onConfigurationChanged(Configuration newConfig) {
172        LogUtils.d(TAG, "Screensaver configuration changed");
173        super.onConfigurationChanged(newConfig);
174        mHandler.removeCallbacks(mMoveSaverRunnable);
175        layoutClockSaver();
176        mHandler.postDelayed(mMoveSaverRunnable, Screensaver.ORIENTATION_CHANGE_DELAY_MS);
177    }
178
179    @Override
180    public void onUserInteraction() {
181        // We want the screen saver to exit upon user interaction.
182        finish();
183    }
184
185    private void setWakeLock() {
186        Window win = getWindow();
187        WindowManager.LayoutParams winParams = win.getAttributes();
188        winParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
189        if (mPluggedIn)
190            winParams.flags |= mFlags;
191        else
192            winParams.flags &= (~mFlags);
193        win.setAttributes(winParams);
194    }
195
196    private void setClockStyle() {
197        Utils.setClockStyle(this, mDigitalClock, mAnalogClock,
198                SettingsActivity.KEY_CLOCK_STYLE);
199        mSaverView = findViewById(R.id.main_clock);
200        mClockStyle = (mSaverView == mDigitalClock ?
201                Utils.CLOCK_TYPE_DIGITAL : Utils.CLOCK_TYPE_ANALOG);
202        Utils.dimClockView(true, mSaverView);
203    }
204
205    private void layoutClockSaver() {
206        setContentView(R.layout.desk_clock_saver);
207        mDigitalClock = findViewById(R.id.digital_clock);
208        mAnalogClock = findViewById(R.id.analog_clock);
209        setClockStyle();
210        Utils.setTimeFormat(this, (TextClock) mDigitalClock,
211                getResources().getDimensionPixelSize(R.dimen.main_ampm_font_size));
212
213        mContentView = (View) mSaverView.getParent();
214        mContentView.forceLayout();
215        mSaverView.forceLayout();
216        mSaverView.setAlpha(0);
217
218        mMoveSaverRunnable.registerViews(mContentView, mSaverView);
219
220        mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
221                | View.SYSTEM_UI_FLAG_FULLSCREEN
222                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
223
224        Utils.updateDate(mDateFormat, mDateFormatForAccessibility,mContentView);
225        Utils.refreshAlarm(ScreensaverActivity.this, mContentView);
226    }
227
228}
229