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