• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.wallpaper.module;
17 
18 import android.content.BroadcastReceiver;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.PowerManager;
22 import android.os.PowerManager.WakeLock;
23 import android.util.Log;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.wallpaper.model.WallpaperMetadata;
28 import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
29 import com.android.wallpaper.module.WallpaperRefresher.RefreshListener;
30 import com.android.wallpaper.util.DiskBasedLogger;
31 
32 import java.util.Calendar;
33 
34 /**
35  * Performs daily logging operations when alarm is received.
36  */
37 public class DailyLoggingAlarmReceiver extends BroadcastReceiver {
38 
39     private static final String TAG = "DailyLoggingAlarm";
40 
41     /**
42      * Releases the provided WakeLock if and only if it's currently held as to avoid throwing a
43      * "WakeLock under-locked" RuntimeException.
44      */
releaseWakeLock(WakeLock wakeLock)45     private static void releaseWakeLock(WakeLock wakeLock) {
46         if (wakeLock.isHeld()) {
47             wakeLock.release();
48         }
49     }
50 
51     @Override
onReceive(Context context, Intent intent)52     public void onReceive(Context context, Intent intent) {
53         Context appContext = context.getApplicationContext();
54         Injector injector = InjectorProvider.getInjector();
55         UserEventLogger logger = injector.getUserEventLogger(appContext);
56         WallpaperPreferences preferences = injector.getPreferences(appContext);
57 
58         logger.logNumDailyWallpaperRotationsInLastWeek();
59         logger.logNumDailyWallpaperRotationsPreviousDay();
60         logger.logWallpaperPresentationMode();
61         logger.logSnapshot();
62 
63         preferences.setLastDailyLogTimestamp(System.currentTimeMillis());
64 
65         logDailyWallpaperRotationStatus(appContext);
66 
67         // Clear disk-based logs older than 7 days if they exist.
68         DiskBasedLogger.clearOldLogs(appContext);
69     }
70 
71     /**
72      * If daily wallpapers are currently in effect and were enabled more than 24 hours ago, then log
73      * the last-known rotation status as reported by the periodic background rotation components
74      * (BackdropAlarmReceiver and BackdropRotationTask), or if there wasn't any status update in the
75      * last 24 hours then log a "not attempted" status to the UserEventLogger.
76      */
logDailyWallpaperRotationStatus(Context appContext)77     private void logDailyWallpaperRotationStatus(Context appContext) {
78         // Acquire a partial wakelock because logging the daily rotation requires doing some work
79         // on another thread (via AsyncTask) after #onReceive returns, after which the kernel may
80         // power down and prevent our daily rotation log from being sent.
81         PowerManager powerManager = appContext.getSystemService(PowerManager.class);
82         final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
83         wakeLock.acquire(10000 /* timeout */);
84 
85         final Injector injector = InjectorProvider.getInjector();
86 
87         // First check if rotation is still in effect.
88         injector.getWallpaperRefresher(appContext).refresh(new RefreshListener() {
89             @Override
90             public void onRefreshed(WallpaperMetadata homeWallpaperMetadata,
91                     @Nullable WallpaperMetadata lockWallpaperMetadata,
92                     @PresentationMode int presentationMode) {
93                 // Don't log or do anything else if presentation mode is not rotating.
94                 if (presentationMode != WallpaperPreferences.PRESENTATION_MODE_ROTATING) {
95                     releaseWakeLock(wakeLock);
96                     return;
97                 }
98 
99                 WallpaperPreferences preferences = injector.getPreferences(appContext);
100 
101                 long dailyWallpaperEnabledTimestamp =
102                         preferences.getDailyWallpaperEnabledTimestamp();
103                 // Validate the daily wallpaper enabled timestamp.
104                 if (dailyWallpaperEnabledTimestamp < 0) {
105                     Log.e(TAG, "There's no valid daily wallpaper enabled timestamp");
106                     releaseWakeLock(wakeLock);
107                     return;
108                 }
109 
110                 Calendar midnightYesterday = Calendar.getInstance();
111                 midnightYesterday.add(Calendar.DAY_OF_MONTH, -1);
112                 midnightYesterday.set(Calendar.HOUR_OF_DAY, 0);
113                 midnightYesterday.set(Calendar.MINUTE, 0);
114 
115                 // Exclude rotations that were put into affect later than midnight yesterday
116                 // because the background task may not have had a chance to execute yet.
117                 if (dailyWallpaperEnabledTimestamp > midnightYesterday.getTimeInMillis()) {
118                     releaseWakeLock(wakeLock);
119                     return;
120                 }
121 
122                 try {
123                     long lastRotationStatusTimestamp =
124                             preferences.getDailyWallpaperLastRotationStatusTimestamp();
125 
126                     UserEventLogger logger = injector.getUserEventLogger(appContext);
127 
128                     // If a rotation status was reported more recently than midnight yesterday,
129                     // then log it. Otherwise, log a "not attempted" rotation status.
130                     if (lastRotationStatusTimestamp > midnightYesterday.getTimeInMillis()) {
131                         int lastDailyWallpaperRotationStatus =
132                                 preferences.getDailyWallpaperLastRotationStatus();
133 
134                         logger.logDailyWallpaperRotationStatus(lastDailyWallpaperRotationStatus);
135 
136                         // If the daily rotation status is "failed", increment the num days
137                         // failed in SharedPreferences and log it, otherwise reset the counter in
138                         // SharedPreferences to 0.
139                         if (UserEventLogger.ROTATION_STATUS_FAILED
140                                 == lastDailyWallpaperRotationStatus) {
141                             preferences.incrementNumDaysDailyRotationFailed();
142                             logger.logNumDaysDailyRotationFailed(
143                                     preferences.getNumDaysDailyRotationFailed());
144                         } else {
145                             preferences.resetNumDaysDailyRotationFailed();
146                         }
147 
148                         // If there was a valid rotation status reported since midnight
149                         // yesterday, then reset the counter for consecutive days of "not
150                         // attempted".
151                         preferences.resetNumDaysDailyRotationNotAttempted();
152                     } else {
153                         logger.logDailyWallpaperRotationStatus(
154                                 UserEventLogger.ROTATION_STATUS_NOT_ATTEMPTED);
155 
156                         // Increment and log the consecutive # days in a row that daily rotation
157                         // was not attempted.
158                         preferences.incrementNumDaysDailyRotationNotAttempted();
159                         logger.logNumDaysDailyRotationNotAttempted(
160                                 preferences.getNumDaysDailyRotationNotAttempted());
161 
162                         // Reset the disk-based counter for number of consecutive days daily
163                         // rotation failed because if rotation was not attempted but restarts
164                         // tomorrow after a boot and fails then, we want to report that as 1 day
165                         // of failure instead of 3 consecutive days.
166                         preferences.resetNumDaysDailyRotationFailed();
167                     }
168                 } finally {
169                     releaseWakeLock(wakeLock);
170                 }
171             }
172         });
173     }
174 }
175