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 17 package com.android.systemui.keyguard; 18 19 import android.annotation.IntDef; 20 import android.app.IWallpaperManager; 21 import android.content.Context; 22 import android.content.res.Configuration; 23 import android.graphics.Point; 24 import android.os.Bundle; 25 import android.os.PowerManager; 26 import android.os.RemoteException; 27 import android.os.Trace; 28 import android.util.DisplayMetrics; 29 30 import androidx.annotation.Nullable; 31 32 import com.android.systemui.Dumpable; 33 import com.android.systemui.R; 34 import com.android.systemui.dagger.SysUISingleton; 35 import com.android.systemui.dump.DumpManager; 36 import com.android.systemui.util.time.SystemClock; 37 38 import java.io.PrintWriter; 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 42 import javax.inject.Inject; 43 44 /** 45 * Tracks the wakefulness lifecycle, including why we're waking or sleeping. 46 */ 47 @SysUISingleton 48 public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observer> implements 49 Dumpable { 50 51 @IntDef(prefix = { "WAKEFULNESS_" }, value = { 52 WAKEFULNESS_ASLEEP, 53 WAKEFULNESS_WAKING, 54 WAKEFULNESS_AWAKE, 55 WAKEFULNESS_GOING_TO_SLEEP, 56 }) 57 @Retention(RetentionPolicy.SOURCE) 58 public @interface Wakefulness {} 59 60 public static final int WAKEFULNESS_ASLEEP = 0; 61 public static final int WAKEFULNESS_WAKING = 1; 62 public static final int WAKEFULNESS_AWAKE = 2; 63 public static final int WAKEFULNESS_GOING_TO_SLEEP = 3; 64 65 private final Context mContext; 66 private final DisplayMetrics mDisplayMetrics; 67 private final SystemClock mSystemClock; 68 69 @Nullable 70 private final IWallpaperManager mWallpaperManagerService; 71 72 private int mWakefulness = WAKEFULNESS_AWAKE; 73 74 private @PowerManager.WakeReason int mLastWakeReason = PowerManager.WAKE_REASON_UNKNOWN; 75 76 public static final long UNKNOWN_LAST_WAKE_TIME = -1; 77 private long mLastWakeTime = UNKNOWN_LAST_WAKE_TIME; 78 79 @Nullable 80 private Point mLastWakeOriginLocation = null; 81 82 private @PowerManager.GoToSleepReason int mLastSleepReason = 83 PowerManager.GO_TO_SLEEP_REASON_MIN; 84 85 @Nullable 86 private Point mLastSleepOriginLocation = null; 87 88 @Inject WakefulnessLifecycle( Context context, @Nullable IWallpaperManager wallpaperManagerService, SystemClock systemClock, DumpManager dumpManager)89 public WakefulnessLifecycle( 90 Context context, 91 @Nullable IWallpaperManager wallpaperManagerService, 92 SystemClock systemClock, 93 DumpManager dumpManager) { 94 mContext = context; 95 mDisplayMetrics = context.getResources().getDisplayMetrics(); 96 mWallpaperManagerService = wallpaperManagerService; 97 mSystemClock = systemClock; 98 99 dumpManager.registerDumpable(getClass().getSimpleName(), this); 100 } 101 getWakefulness()102 public @Wakefulness int getWakefulness() { 103 return mWakefulness; 104 } 105 106 /** 107 * Returns the most recent reason the device woke up. This is one of PowerManager.WAKE_REASON_*. 108 */ getLastWakeReason()109 public @PowerManager.WakeReason int getLastWakeReason() { 110 return mLastWakeReason; 111 } 112 113 /** 114 * Returns the most recent time (in device uptimeMillis) the display woke up. 115 * Returns {@link UNKNOWN_LAST_WAKE_TIME} if there hasn't been a wakeup yet. 116 */ getLastWakeTime()117 public long getLastWakeTime() { 118 return mLastWakeTime; 119 } 120 121 /** 122 * Returns the most recent reason the device went to sleep up. This is one of 123 * PowerManager.GO_TO_SLEEP_REASON_*. 124 */ getLastSleepReason()125 public @PowerManager.GoToSleepReason int getLastSleepReason() { 126 return mLastSleepReason; 127 } 128 dispatchStartedWakingUp(@owerManager.WakeReason int pmWakeReason)129 public void dispatchStartedWakingUp(@PowerManager.WakeReason int pmWakeReason) { 130 if (getWakefulness() == WAKEFULNESS_WAKING) { 131 return; 132 } 133 setWakefulness(WAKEFULNESS_WAKING); 134 mLastWakeReason = pmWakeReason; 135 mLastWakeTime = mSystemClock.uptimeMillis(); 136 updateLastWakeOriginLocation(); 137 138 if (mWallpaperManagerService != null) { 139 try { 140 mWallpaperManagerService.notifyWakingUp( 141 mLastWakeOriginLocation.x, mLastWakeOriginLocation.y, new Bundle()); 142 } catch (RemoteException e) { 143 e.printStackTrace(); 144 } 145 } 146 147 dispatch(Observer::onStartedWakingUp); 148 } 149 dispatchFinishedWakingUp()150 public void dispatchFinishedWakingUp() { 151 if (getWakefulness() == WAKEFULNESS_AWAKE) { 152 return; 153 } 154 setWakefulness(WAKEFULNESS_AWAKE); 155 dispatch(Observer::onFinishedWakingUp); 156 dispatch(Observer::onPostFinishedWakingUp); 157 } 158 dispatchStartedGoingToSleep(@owerManager.GoToSleepReason int pmSleepReason)159 public void dispatchStartedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) { 160 if (getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP) { 161 return; 162 } 163 setWakefulness(WAKEFULNESS_GOING_TO_SLEEP); 164 mLastSleepReason = pmSleepReason; 165 updateLastSleepOriginLocation(); 166 167 if (mWallpaperManagerService != null) { 168 try { 169 mWallpaperManagerService.notifyGoingToSleep( 170 mLastSleepOriginLocation.x, mLastSleepOriginLocation.y, new Bundle()); 171 } catch (RemoteException e) { 172 e.printStackTrace(); 173 } 174 } 175 176 dispatch(Observer::onStartedGoingToSleep); 177 } 178 dispatchFinishedGoingToSleep()179 public void dispatchFinishedGoingToSleep() { 180 if (getWakefulness() == WAKEFULNESS_ASLEEP) { 181 return; 182 } 183 setWakefulness(WAKEFULNESS_ASLEEP); 184 dispatch(Observer::onFinishedGoingToSleep); 185 } 186 187 @Override dump(PrintWriter pw, String[] args)188 public void dump(PrintWriter pw, String[] args) { 189 pw.println("WakefulnessLifecycle:"); 190 pw.println(" mWakefulness=" + mWakefulness); 191 } 192 setWakefulness(@akefulness int wakefulness)193 private void setWakefulness(@Wakefulness int wakefulness) { 194 mWakefulness = wakefulness; 195 Trace.traceCounter(Trace.TRACE_TAG_APP, "wakefulness", wakefulness); 196 } 197 updateLastWakeOriginLocation()198 private void updateLastWakeOriginLocation() { 199 mLastWakeOriginLocation = null; 200 201 switch (mLastWakeReason) { 202 case PowerManager.WAKE_REASON_POWER_BUTTON: 203 mLastWakeOriginLocation = getPowerButtonOrigin(); 204 break; 205 default: 206 mLastWakeOriginLocation = getDefaultWakeSleepOrigin(); 207 break; 208 } 209 } 210 updateLastSleepOriginLocation()211 private void updateLastSleepOriginLocation() { 212 mLastSleepOriginLocation = null; 213 214 switch (mLastSleepReason) { 215 case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON: 216 mLastSleepOriginLocation = getPowerButtonOrigin(); 217 break; 218 default: 219 mLastSleepOriginLocation = getDefaultWakeSleepOrigin(); 220 break; 221 } 222 } 223 224 /** 225 * Returns the point on the screen closest to the physical power button. 226 */ getPowerButtonOrigin()227 private Point getPowerButtonOrigin() { 228 final boolean isPortrait = mContext.getResources().getConfiguration().orientation 229 == Configuration.ORIENTATION_PORTRAIT; 230 231 if (isPortrait) { 232 return new Point( 233 mDisplayMetrics.widthPixels, 234 mContext.getResources().getDimensionPixelSize( 235 R.dimen.physical_power_button_center_screen_location_y)); 236 } else { 237 return new Point( 238 mContext.getResources().getDimensionPixelSize( 239 R.dimen.physical_power_button_center_screen_location_y), 240 mDisplayMetrics.heightPixels); 241 } 242 } 243 244 /** 245 * Returns the point on the screen used as the default origin for wake/sleep events. This is the 246 * middle-bottom of the screen. 247 */ getDefaultWakeSleepOrigin()248 private Point getDefaultWakeSleepOrigin() { 249 return new Point(mDisplayMetrics.widthPixels / 2, mDisplayMetrics.heightPixels); 250 } 251 252 public interface Observer { onStartedWakingUp()253 default void onStartedWakingUp() {} onFinishedWakingUp()254 default void onFinishedWakingUp() {} 255 256 /** 257 * Called after the finished waking up call, ensuring it's after all the other listeners, 258 * reacting to {@link #onFinishedWakingUp()} 259 */ onPostFinishedWakingUp()260 default void onPostFinishedWakingUp() {} onStartedGoingToSleep()261 default void onStartedGoingToSleep() {} onFinishedGoingToSleep()262 default void onFinishedGoingToSleep() {} 263 } 264 } 265