1 /* 2 * Copyright (C) 2018 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.garagemode; 18 19 import android.app.job.JobScheduler; 20 import android.car.hardware.power.CarPowerManager; 21 import android.car.hardware.power.CarPowerManager.CarPowerStateListener; 22 import android.car.hardware.power.CarPowerManager.CarPowerStateListenerWithCompletion; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.os.Handler; 26 import android.os.Looper; 27 28 import com.android.car.CarLocalServices; 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.util.List; 32 import java.util.concurrent.CompletableFuture; 33 34 /** 35 * Main controller for GarageMode. It controls all the flows of GarageMode and defines the logic. 36 */ 37 public class Controller implements CarPowerStateListenerWithCompletion { 38 private static final Logger LOG = new Logger("Controller"); 39 40 @VisibleForTesting final WakeupPolicy mWakeupPolicy; 41 private final GarageMode mGarageMode; 42 private final Handler mHandler; 43 private final Context mContext; 44 private CarPowerManager mCarPowerManager; 45 Controller(Context context, Looper looper)46 public Controller(Context context, Looper looper) { 47 this(context, looper, null, null, null); 48 } 49 Controller( Context context, Looper looper, WakeupPolicy wakeupPolicy, Handler handler, GarageMode garageMode)50 public Controller( 51 Context context, 52 Looper looper, 53 WakeupPolicy wakeupPolicy, 54 Handler handler, 55 GarageMode garageMode) { 56 mContext = context; 57 mHandler = (handler == null ? new Handler(looper) : handler); 58 mWakeupPolicy = 59 (wakeupPolicy == null ? WakeupPolicy.initFromResources(context) : wakeupPolicy); 60 mGarageMode = (garageMode == null ? new GarageMode(this) : garageMode); 61 } 62 63 /** init */ init()64 public void init() { 65 mCarPowerManager = CarLocalServices.createCarPowerManager(mContext); 66 mCarPowerManager.setListenerWithCompletion(Controller.this); 67 } 68 69 /** release */ release()70 public void release() { 71 mCarPowerManager.clearListener(); 72 } 73 74 @Override onStateChanged(int state, CompletableFuture<Void> future)75 public void onStateChanged(int state, CompletableFuture<Void> future) { 76 switch (state) { 77 case CarPowerStateListener.SHUTDOWN_CANCELLED: 78 LOG.d("CPM state changed to SHUTDOWN_CANCELLED"); 79 handleShutdownCancelled(); 80 break; 81 case CarPowerStateListener.SHUTDOWN_ENTER: 82 LOG.d("CPM state changed to SHUTDOWN_ENTER"); 83 handleShutdownEnter(); 84 break; 85 case CarPowerStateListener.SHUTDOWN_PREPARE: 86 LOG.d("CPM state changed to SHUTDOWN_PREPARE"); 87 handleShutdownPrepare(future); 88 break; 89 case CarPowerStateListener.SUSPEND_ENTER: 90 LOG.d("CPM state changed to SUSPEND_ENTER"); 91 handleSuspendEnter(); 92 break; 93 case CarPowerStateListener.SUSPEND_EXIT: 94 LOG.d("CPM state changed to SUSPEND_EXIT"); 95 handleSuspendExit(); 96 break; 97 default: 98 } 99 } 100 101 /** 102 * @return boolean whether any jobs are currently in running that GarageMode cares about 103 */ isGarageModeActive()104 boolean isGarageModeActive() { 105 return mGarageMode.isGarageModeActive(); 106 } 107 108 /** 109 * @return Garage Mode's status, including what jobs it is waiting for 110 */ dump()111 List<String> dump() { 112 return mGarageMode.dump(); 113 } 114 115 /** 116 * Wrapper method to send a broadcast 117 * 118 * @param i intent that contains broadcast data 119 */ sendBroadcast(Intent i)120 void sendBroadcast(Intent i) { 121 LOG.d("Sending broadcast with action: " + i.getAction()); 122 mContext.sendBroadcast(i); 123 } 124 125 /** 126 * @return JobSchedulerService instance 127 */ getJobSchedulerService()128 JobScheduler getJobSchedulerService() { 129 return (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); 130 } 131 132 /** 133 * @return Handler instance used by controller 134 */ getHandler()135 Handler getHandler() { 136 return mHandler; 137 } 138 139 /** 140 * Initiates GarageMode flow which will set the system idleness to true and will start 141 * monitoring jobs which has idleness constraint enabled. 142 */ initiateGarageMode(CompletableFuture<Void> future)143 void initiateGarageMode(CompletableFuture<Void> future) { 144 mWakeupPolicy.incrementCounter(); 145 mGarageMode.enterGarageMode(future); 146 } 147 148 /** 149 * Resets GarageMode. 150 */ resetGarageMode()151 void resetGarageMode() { 152 mGarageMode.cancel(); 153 mWakeupPolicy.resetCounter(); 154 } 155 156 @VisibleForTesting finishGarageMode()157 void finishGarageMode() { 158 mGarageMode.finish(); 159 } 160 161 @VisibleForTesting setCarPowerManager(CarPowerManager cpm)162 void setCarPowerManager(CarPowerManager cpm) { 163 mCarPowerManager = cpm; 164 } 165 scheduleNextWakeup()166 void scheduleNextWakeup() { 167 if (mWakeupPolicy.getNextWakeUpInterval() <= 0) { 168 // Either there is no policy or nothing left to schedule 169 return; 170 } 171 int seconds = mWakeupPolicy.getNextWakeUpInterval(); 172 mCarPowerManager.scheduleNextWakeupTime(seconds); 173 } 174 handleSuspendExit()175 private void handleSuspendExit() { 176 resetGarageMode(); 177 } 178 handleSuspendEnter()179 private void handleSuspendEnter() { 180 resetGarageMode(); 181 } 182 handleShutdownEnter()183 private void handleShutdownEnter() { 184 resetGarageMode(); 185 } 186 handleShutdownPrepare(CompletableFuture<Void> future)187 private void handleShutdownPrepare(CompletableFuture<Void> future) { 188 initiateGarageMode(future); 189 } 190 handleShutdownCancelled()191 private void handleShutdownCancelled() { 192 resetGarageMode(); 193 } 194 } 195