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 
17 package com.android.deskclock;
18 
19 import android.app.AlarmManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.res.Configuration;
25 import android.database.ContentObserver;
26 import android.os.Handler;
27 import android.preference.PreferenceManager;
28 import android.provider.Settings;
29 import android.service.dreams.DreamService;
30 import android.util.Log;
31 import android.view.View;
32 import android.widget.TextClock;
33 
34 import com.android.deskclock.Utils.ScreensaverMoveSaverRunnable;
35 import com.android.deskclock.settings.ScreensaverSettingsActivity;
36 
37 public class Screensaver extends DreamService {
38 
39     public static final int ORIENTATION_CHANGE_DELAY_MS = 250;
40 
41     private static final boolean DEBUG = false;
42     private static final String TAG = "DeskClock/Screensaver";
43 
44     private View mContentView, mSaverView;
45     private View mAnalogClock, mDigitalClock;
46     private String mDateFormat;
47     private String mDateFormatForAccessibility;
48 
49     private final Handler mHandler = new Handler();
50 
51     private final ScreensaverMoveSaverRunnable mMoveSaverRunnable;
52 
53     /* Register ContentObserver to see alarm changes for pre-L */
54     private final ContentObserver mSettingsContentObserver = Utils.isPreL()
55         ? new ContentObserver(mHandler) {
56             @Override
57             public void onChange(boolean selfChange) {
58                 Utils.refreshAlarm(Screensaver.this, mContentView);
59             }
60         }
61         : null;
62 
63     // Thread that runs every midnight and refreshes the date.
64     private final Runnable mMidnightUpdater = new Runnable() {
65         @Override
66         public void run() {
67             Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
68             Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
69         }
70     };
71 
72     /**
73      * Receiver to handle time reference changes.
74      */
75     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
76         @Override
77         public void onReceive(Context context, Intent intent) {
78             final String action = intent.getAction();
79             if (DEBUG) Log.v(TAG, "Screensaver onReceive, action: " + action);
80 
81             if (action == null) {
82                 return;
83             }
84 
85             if (action.equals(Intent.ACTION_TIME_CHANGED)
86                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
87                 Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
88                 Utils.refreshAlarm(Screensaver.this, mContentView);
89                 Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
90             } else if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
91                 Utils.refreshAlarm(Screensaver.this, mContentView);
92             }
93         }
94     };
95 
Screensaver()96     public Screensaver() {
97         if (DEBUG) Log.d(TAG, "Screensaver allocated");
98         mMoveSaverRunnable = new ScreensaverMoveSaverRunnable(mHandler);
99     }
100 
101     @Override
onCreate()102     public void onCreate() {
103         if (DEBUG) Log.d(TAG, "Screensaver created");
104         super.onCreate();
105 
106         setTheme(R.style.ScreensaverActivityTheme);
107 
108         mDateFormat = getString(R.string.abbrev_wday_month_day_no_year);
109         mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year);
110     }
111 
112     @Override
onConfigurationChanged(Configuration newConfig)113     public void onConfigurationChanged(Configuration newConfig) {
114         if (DEBUG) Log.d(TAG, "Screensaver configuration changed");
115         super.onConfigurationChanged(newConfig);
116 
117         // Ignore the configuration change if no window exists.
118         if (getWindow() != null) {
119             mHandler.removeCallbacks(mMoveSaverRunnable);
120             layoutClockSaver();
121             mHandler.postDelayed(mMoveSaverRunnable, ORIENTATION_CHANGE_DELAY_MS);
122         }
123     }
124 
125     @Override
onAttachedToWindow()126     public void onAttachedToWindow() {
127         if (DEBUG) Log.d(TAG, "Screensaver attached to window");
128         super.onAttachedToWindow();
129 
130         // We want the screen saver to exit upon user interaction.
131         setInteractive(false);
132 
133         setFullscreen(true);
134 
135         layoutClockSaver();
136 
137         // Setup handlers for time reference changes and date updates.
138         final IntentFilter filter = new IntentFilter();
139         filter.addAction(Intent.ACTION_TIME_CHANGED);
140         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
141         registerReceiver(mIntentReceiver, filter);
142         Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
143 
144         if (Utils.isPreL()) {
145             getContentResolver().registerContentObserver(
146                 Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED),
147                 false,
148                 mSettingsContentObserver);
149         }
150 
151         mHandler.post(mMoveSaverRunnable);
152     }
153 
154     @Override
onDetachedFromWindow()155     public void onDetachedFromWindow() {
156         if (DEBUG) Log.d(TAG, "Screensaver detached from window");
157         super.onDetachedFromWindow();
158 
159         mHandler.removeCallbacks(mMoveSaverRunnable);
160 
161         if (Utils.isPreL()) {
162             getContentResolver().unregisterContentObserver(mSettingsContentObserver);
163         }
164 
165         // Tear down handlers for time reference changes and date updates.
166         Utils.cancelMidnightUpdater(mHandler, mMidnightUpdater);
167         unregisterReceiver(mIntentReceiver);
168     }
169 
setClockStyle()170     private void setClockStyle() {
171         Utils.setScreensaverClockStyle(mDigitalClock, mAnalogClock);
172         mSaverView = findViewById(R.id.main_clock);
173         boolean dimNightMode = Utils.getDefaultSharedPreferences(this)
174                 .getBoolean(ScreensaverSettingsActivity.KEY_NIGHT_MODE, false);
175         Utils.dimClockView(dimNightMode, mSaverView);
176         setScreenBright(!dimNightMode);
177     }
178 
layoutClockSaver()179     private void layoutClockSaver() {
180         setContentView(R.layout.desk_clock_saver);
181         mDigitalClock = findViewById(R.id.digital_clock);
182         mAnalogClock = findViewById(R.id.analog_clock);
183         setClockStyle();
184         Utils.setTimeFormat(this, (TextClock) mDigitalClock);
185 
186         mContentView = (View) mSaverView.getParent();
187         mSaverView.setAlpha(0);
188 
189         mMoveSaverRunnable.registerViews(mContentView, mSaverView);
190 
191         Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mContentView);
192         Utils.refreshAlarm(Screensaver.this, mContentView);
193     }
194 }
195