Home | History | Annotate | Download | only in car
      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 {
     31     public abstract void setDisplayState(boolean on);
     32     public abstract void releaseAllWakeLocks();
     33     public abstract void shutdown();
     34     public abstract void enterDeepSleep(int wakeupTimeSec);
     35     public abstract void switchToPartialWakeLock();
     36     public abstract void switchToFullWakeLock();
     37     public abstract void startDisplayStateMonitoring(CarPowerManagementService service);
     38     public abstract void stopDisplayStateMonitoring();
     39     public abstract boolean isSystemSupportingDeepSleep();
     40     public abstract boolean isWakeupCausedByTimer();
     41 
     42 
     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 
     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
     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
     76         public void stopDisplayStateMonitoring() {
     77             mDisplayManager.unregisterDisplayListener(mDisplayListener);
     78         }
     79 
     80         @Override
     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 
     96         private boolean isMainDisplayOn() {
     97             Display disp = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
     98             return disp.getState() == Display.STATE_ON;
     99         }
    100 
    101         @Override
    102         public void shutdown() {
    103             mPowerManager.shutdown(false /* no confirm*/, null, true /* true */);
    104         }
    105 
    106         @Override
    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
    115         public boolean isSystemSupportingDeepSleep() {
    116             //TODO should return by checking some kernel suspend control sysfs, bug: 32061842
    117             return false;
    118         }
    119 
    120         @Override
    121         public void switchToPartialWakeLock() {
    122             if (!mPartialWakeLock.isHeld()) {
    123                 mPartialWakeLock.acquire();
    124             }
    125             if (mFullWakeLock.isHeld()) {
    126                 mFullWakeLock.release();
    127             }
    128         }
    129 
    130         @Override
    131         public void switchToFullWakeLock() {
    132             if (!mFullWakeLock.isHeld()) {
    133                 mFullWakeLock.acquire();
    134             }
    135             if (mPartialWakeLock.isHeld()) {
    136                 mPartialWakeLock.release();
    137             }
    138         }
    139 
    140         @Override
    141         public void releaseAllWakeLocks() {
    142             if (mPartialWakeLock.isHeld()) {
    143                 mPartialWakeLock.release();
    144             }
    145             if (mFullWakeLock.isHeld()) {
    146                 mFullWakeLock.release();
    147             }
    148         }
    149 
    150         @Override
    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 
    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
    174             public void onDisplayAdded(int displayId) {
    175                 //ignore
    176             }
    177 
    178             @Override
    179             public void onDisplayChanged(int displayId) {
    180                 if (displayId == Display.DEFAULT_DISPLAY) {
    181                     handleMainDisplayChanged();
    182                 }
    183             }
    184 
    185             @Override
    186             public void onDisplayRemoved(int displayId) {
    187                 //ignore
    188             }
    189         }
    190     }
    191 }
    192