1 /* 2 * Copyright (C) 2016 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.car; 18 19 import android.content.Context; 20 import android.hardware.display.DisplayManager; 21 import android.os.PowerManager; 22 import android.os.PowerManager.WakeLock; 23 import android.os.SystemClock; 24 import android.util.Log; 25 import android.view.Display; 26 27 /** 28 * Interface to abstract all system interaction. 29 */ 30 public abstract class SystemInterface { setDisplayState(boolean on)31 public abstract void setDisplayState(boolean on); releaseAllWakeLocks()32 public abstract void releaseAllWakeLocks(); shutdown()33 public abstract void shutdown(); enterDeepSleep(int wakeupTimeSec)34 public abstract void enterDeepSleep(int wakeupTimeSec); switchToPartialWakeLock()35 public abstract void switchToPartialWakeLock(); switchToFullWakeLock()36 public abstract void switchToFullWakeLock(); startDisplayStateMonitoring(CarPowerManagementService service)37 public abstract void startDisplayStateMonitoring(CarPowerManagementService service); stopDisplayStateMonitoring()38 public abstract void stopDisplayStateMonitoring(); isSystemSupportingDeepSleep()39 public abstract boolean isSystemSupportingDeepSleep(); isWakeupCausedByTimer()40 public abstract boolean isWakeupCausedByTimer(); 41 42 getDefault(Context context)43 public static SystemInterface getDefault(Context context) { 44 return new SystemInterfaceImpl(context); 45 } 46 47 private static class SystemInterfaceImpl extends SystemInterface { 48 private final PowerManager mPowerManager; 49 private final DisplayManager mDisplayManager; 50 private final WakeLock mFullWakeLock; 51 private final WakeLock mPartialWakeLock; 52 private final DisplayStateListener mDisplayListener; 53 private CarPowerManagementService mService; 54 private boolean mDisplayStateSet; 55 SystemInterfaceImpl(Context context)56 private SystemInterfaceImpl(Context context) { 57 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 58 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 59 mFullWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, 60 CarLog.TAG_POWER); 61 mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 62 CarLog.TAG_POWER); 63 mDisplayListener = new DisplayStateListener(); 64 } 65 66 @Override startDisplayStateMonitoring(CarPowerManagementService service)67 public void startDisplayStateMonitoring(CarPowerManagementService service) { 68 synchronized (this) { 69 mService = service; 70 mDisplayStateSet = isMainDisplayOn(); 71 } 72 mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); 73 } 74 75 @Override stopDisplayStateMonitoring()76 public void stopDisplayStateMonitoring() { 77 mDisplayManager.unregisterDisplayListener(mDisplayListener); 78 } 79 80 @Override setDisplayState(boolean on)81 public void setDisplayState(boolean on) { 82 synchronized (this) { 83 mDisplayStateSet = on; 84 } 85 if (on) { 86 switchToFullWakeLock(); 87 Log.i(CarLog.TAG_POWER, "on display"); 88 mPowerManager.wakeUp(SystemClock.uptimeMillis()); 89 } else { 90 switchToPartialWakeLock(); 91 Log.i(CarLog.TAG_POWER, "off display"); 92 mPowerManager.goToSleep(SystemClock.uptimeMillis()); 93 } 94 } 95 isMainDisplayOn()96 private boolean isMainDisplayOn() { 97 Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 98 return disp.getState() == Display.STATE_ON; 99 } 100 101 @Override shutdown()102 public void shutdown() { 103 mPowerManager.shutdown(false /* no confirm*/, null, true /* true */); 104 } 105 106 @Override enterDeepSleep(int wakeupTimeSec)107 public void enterDeepSleep(int wakeupTimeSec) { 108 //TODO set wake up time, bug: 32061842 109 mPowerManager.goToSleep(SystemClock.uptimeMillis(), 110 PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 111 PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); 112 } 113 114 @Override isSystemSupportingDeepSleep()115 public boolean isSystemSupportingDeepSleep() { 116 //TODO should return by checking some kernel suspend control sysfs, bug: 32061842 117 return false; 118 } 119 120 @Override switchToPartialWakeLock()121 public void switchToPartialWakeLock() { 122 if (!mPartialWakeLock.isHeld()) { 123 mPartialWakeLock.acquire(); 124 } 125 if (mFullWakeLock.isHeld()) { 126 mFullWakeLock.release(); 127 } 128 } 129 130 @Override switchToFullWakeLock()131 public void switchToFullWakeLock() { 132 if (!mFullWakeLock.isHeld()) { 133 mFullWakeLock.acquire(); 134 } 135 if (mPartialWakeLock.isHeld()) { 136 mPartialWakeLock.release(); 137 } 138 } 139 140 @Override releaseAllWakeLocks()141 public void releaseAllWakeLocks() { 142 if (mPartialWakeLock.isHeld()) { 143 mPartialWakeLock.release(); 144 } 145 if (mFullWakeLock.isHeld()) { 146 mFullWakeLock.release(); 147 } 148 } 149 150 @Override isWakeupCausedByTimer()151 public boolean isWakeupCausedByTimer() { 152 //TODO bug: 32061842, check wake up reason and do necessary operation information should 153 // come from kernel. it can be either power on or wake up for maintenance 154 // power on will involve GPIO trigger from power controller 155 // its own wakeup will involve timer expiration. 156 return false; 157 } 158 handleMainDisplayChanged()159 private void handleMainDisplayChanged() { 160 boolean isOn = isMainDisplayOn(); 161 CarPowerManagementService service; 162 synchronized (this) { 163 if (mDisplayStateSet == isOn) { // same as what is set 164 return; 165 } 166 service = mService; 167 } 168 service.handleMainDisplayChanged(isOn); 169 } 170 171 private class DisplayStateListener implements DisplayManager.DisplayListener { 172 173 @Override onDisplayAdded(int displayId)174 public void onDisplayAdded(int displayId) { 175 //ignore 176 } 177 178 @Override onDisplayChanged(int displayId)179 public void onDisplayChanged(int displayId) { 180 if (displayId == Display.DEFAULT_DISPLAY) { 181 handleMainDisplayChanged(); 182 } 183 } 184 185 @Override onDisplayRemoved(int displayId)186 public void onDisplayRemoved(int displayId) { 187 //ignore 188 } 189 } 190 } 191 } 192