| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.car; |
| |
| import android.content.Context; |
| import android.hardware.display.DisplayManager; |
| import android.os.PowerManager; |
| import android.os.PowerManager.WakeLock; |
| import android.os.SystemClock; |
| import android.util.Log; |
| import android.view.Display; |
| |
| /** |
| * Interface to abstract all system interaction. |
| */ |
| public abstract class SystemInterface { |
| public abstract void setDisplayState(boolean on); |
| public abstract void releaseAllWakeLocks(); |
| public abstract void shutdown(); |
| public abstract void enterDeepSleep(int wakeupTimeSec); |
| public abstract void switchToPartialWakeLock(); |
| public abstract void switchToFullWakeLock(); |
| public abstract void startDisplayStateMonitoring(CarPowerManagementService service); |
| public abstract void stopDisplayStateMonitoring(); |
| public abstract boolean isSystemSupportingDeepSleep(); |
| public abstract boolean isWakeupCausedByTimer(); |
| |
| |
| public static SystemInterface getDefault(Context context) { |
| return new SystemInterfaceImpl(context); |
| } |
| |
| private static class SystemInterfaceImpl extends SystemInterface { |
| private final PowerManager mPowerManager; |
| private final DisplayManager mDisplayManager; |
| private final WakeLock mFullWakeLock; |
| private final WakeLock mPartialWakeLock; |
| private final DisplayStateListener mDisplayListener; |
| private CarPowerManagementService mService; |
| private boolean mDisplayStateSet; |
| |
| private SystemInterfaceImpl(Context context) { |
| mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); |
| mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); |
| mFullWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, |
| CarLog.TAG_POWER); |
| mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, |
| CarLog.TAG_POWER); |
| mDisplayListener = new DisplayStateListener(); |
| } |
| |
| @Override |
| public void startDisplayStateMonitoring(CarPowerManagementService service) { |
| synchronized (this) { |
| mService = service; |
| mDisplayStateSet = isMainDisplayOn(); |
| } |
| mDisplayManager.registerDisplayListener(mDisplayListener, service.getHandler()); |
| } |
| |
| @Override |
| public void stopDisplayStateMonitoring() { |
| mDisplayManager.unregisterDisplayListener(mDisplayListener); |
| } |
| |
| @Override |
| public void setDisplayState(boolean on) { |
| synchronized (this) { |
| mDisplayStateSet = on; |
| } |
| if (on) { |
| switchToFullWakeLock(); |
| Log.i(CarLog.TAG_POWER, "on display"); |
| mPowerManager.wakeUp(SystemClock.uptimeMillis()); |
| } else { |
| switchToPartialWakeLock(); |
| Log.i(CarLog.TAG_POWER, "off display"); |
| mPowerManager.goToSleep(SystemClock.uptimeMillis()); |
| } |
| } |
| |
| private boolean isMainDisplayOn() { |
| Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); |
| return disp.getState() == Display.STATE_ON; |
| } |
| |
| @Override |
| public void shutdown() { |
| mPowerManager.shutdown(false /* no confirm*/, null, true /* true */); |
| } |
| |
| @Override |
| public void enterDeepSleep(int wakeupTimeSec) { |
| //TODO set wake up time, bug: 32061842 |
| mPowerManager.goToSleep(SystemClock.uptimeMillis(), |
| PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, |
| PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); |
| } |
| |
| @Override |
| public boolean isSystemSupportingDeepSleep() { |
| //TODO should return by checking some kernel suspend control sysfs, bug: 32061842 |
| return false; |
| } |
| |
| @Override |
| public void switchToPartialWakeLock() { |
| if (!mPartialWakeLock.isHeld()) { |
| mPartialWakeLock.acquire(); |
| } |
| if (mFullWakeLock.isHeld()) { |
| mFullWakeLock.release(); |
| } |
| } |
| |
| @Override |
| public void switchToFullWakeLock() { |
| if (!mFullWakeLock.isHeld()) { |
| mFullWakeLock.acquire(); |
| } |
| if (mPartialWakeLock.isHeld()) { |
| mPartialWakeLock.release(); |
| } |
| } |
| |
| @Override |
| public void releaseAllWakeLocks() { |
| if (mPartialWakeLock.isHeld()) { |
| mPartialWakeLock.release(); |
| } |
| if (mFullWakeLock.isHeld()) { |
| mFullWakeLock.release(); |
| } |
| } |
| |
| @Override |
| public boolean isWakeupCausedByTimer() { |
| //TODO bug: 32061842, check wake up reason and do necessary operation information should |
| // come from kernel. it can be either power on or wake up for maintenance |
| // power on will involve GPIO trigger from power controller |
| // its own wakeup will involve timer expiration. |
| return false; |
| } |
| |
| private void handleMainDisplayChanged() { |
| boolean isOn = isMainDisplayOn(); |
| CarPowerManagementService service; |
| synchronized (this) { |
| if (mDisplayStateSet == isOn) { // same as what is set |
| return; |
| } |
| service = mService; |
| } |
| service.handleMainDisplayChanged(isOn); |
| } |
| |
| private class DisplayStateListener implements DisplayManager.DisplayListener { |
| |
| @Override |
| public void onDisplayAdded(int displayId) { |
| //ignore |
| } |
| |
| @Override |
| public void onDisplayChanged(int displayId) { |
| if (displayId == Display.DEFAULT_DISPLAY) { |
| handleMainDisplayChanged(); |
| } |
| } |
| |
| @Override |
| public void onDisplayRemoved(int displayId) { |
| //ignore |
| } |
| } |
| } |
| } |