1 /*
2  * Copyright (C) 2020 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.cts.verifier.car;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.SharedPreferences;
22 import android.os.Bundle;
23 import android.provider.Settings;
24 import android.util.Log;
25 import android.view.View;
26 import android.widget.Button;
27 import android.widget.TextView;
28 
29 import com.android.cts.verifier.PassFailButtons;
30 import com.android.cts.verifier.R;
31 
32 import java.text.DateFormat;
33 
34 /**
35  * Tests that Garage Mode runs at the end of a drive
36  */
37 public final class GarageModeTestActivity extends PassFailButtons.Activity {
38     // Requirements from Android 11 Compatibility Definition
39     // 2.5.4. Performance and Power
40     // Automotive device implementations:
41     //
42     // [8.3/A-1-3] MUST support Garage Mode
43     // [8.3/A-1-4] SHOULD be in Garage Mode for at least 15 minutes unless:
44     //                 The battery is drained.
45     //                 No idle jobs are scheduled.
46     //                 The driver exits Garage Mode.
47     //
48     // I understand that Google intends to require that Garage Mode is occasionally
49     // allowed to run at least 30 seconds. This code tests for that minimum time.
50 
51     private static final String TAG = GarageModeTestActivity.class.getSimpleName();
52 
53     // The recommendation is for Garage Mode to run for 15 minutes. To allow
54     // for some variation, run the test for 14 minutes and verify that it
55     // ran at least 13 minutes.
56     private static final int NUM_SECONDS_DURATION = 14 * 60;
57     private static final long RECOMMENDED_DURATION_MS = (NUM_SECONDS_DURATION - 60) * 1000L;
58 
59     // The hard requirement is for Garage Mode to run for 30 seconds. Fail if
60     // the test doesn't run at least this long.
61     private static final long REQUIRED_DURATION_MS = 30 * 1000L;
62 
63     // Once a test is started, Garage Mode is expected to start within 10 minutes. If it doesn't,
64     // the test is marked as fail.
65     private static final long MAX_WAIT_UNTIL_GARAGE_MODE = 10 * 60 * 1000L;
66 
67     private TextView mStatusText;
68 
69     @Override
onCreate(Bundle savedInstanceState)70     protected void onCreate(Bundle savedInstanceState) {
71         super.onCreate(savedInstanceState);
72         View view = getLayoutInflater().inflate(R.layout.garage_test_main, null);
73         setContentView(view);
74 
75         setInfoResources(R.string.car_garage_mode_test, R.string.car_garage_mode_test_desc, -1);
76         setPassFailButtonClickListeners();
77         getPassButton().setEnabled(false);
78         mStatusText = findViewById(R.id.car_garage_mode_results);
79 
80         // Garage Mode Monitor
81         Button monitorButton = (Button) view.findViewById(R.id.launch_garage_monitor);
82         monitorButton.setOnClickListener((buttonView) -> {
83             Context context = GarageModeTestActivity.this;
84             SharedPreferences prefs = context.getSharedPreferences(
85                     GarageModeChecker.PREFS_FILE_NAME, Context.MODE_PRIVATE);
86             long now = System.currentTimeMillis();
87             SharedPreferences.Editor editor = prefs.edit();
88             editor.putLong(GarageModeChecker.PREFS_INITIATION, now);
89             editor.putLong(GarageModeChecker.PREFS_GARAGE_MODE_START, 0);
90             editor.putLong(GarageModeChecker.PREFS_GARAGE_MODE_END, 0);
91             editor.putLong(GarageModeChecker.PREFS_TERMINATION, 0);
92             editor.putBoolean(GarageModeChecker.PREFS_HAD_CONNECTIVITY, false);
93             editor.putLong(GarageModeChecker.PREFS_START_BOOT_COUNT,
94                     GarageModeChecker.getBootCount(context));
95             editor.commit();
96 
97             GarageModeChecker.scheduleAnIdleJob(context, NUM_SECONDS_DURATION);
98             verifyStatus();
99             Log.v(TAG, "Scheduled GarageModeChecker to run when idle");
100         });
101 
102         // Wifi settings
103         Button wifiButton = view.findViewById(R.id.car_wifi_settings);
104         wifiButton.setOnClickListener(
105                 v -> startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS)));
106     }
107 
108     @Override
onResume()109     protected void onResume() {
110         super.onResume();
111         verifyStatus();
112     }
113 
114     @Override
onWindowFocusChanged(boolean hasWindowFocus)115     public void onWindowFocusChanged(boolean hasWindowFocus) {
116         super.onWindowFocusChanged(hasWindowFocus);
117         if (hasWindowFocus) {
118             verifyStatus();
119         }
120     }
121 
verifyStatus()122     private void verifyStatus() {
123         Context context = GarageModeTestActivity.this;
124         SharedPreferences prefs = context.getSharedPreferences(
125                 GarageModeChecker.PREFS_FILE_NAME, Context.MODE_PRIVATE);
126         String resultsString;
127         DateFormat dateTime = DateFormat.getDateTimeInstance();
128 
129         long now = System.currentTimeMillis();
130         long initiateTime = prefs.getLong(GarageModeChecker.PREFS_INITIATION, 0);
131         long garageModeStart = prefs.getLong(GarageModeChecker.PREFS_GARAGE_MODE_START, 0);
132         long garageModeEnd = prefs.getLong(GarageModeChecker.PREFS_GARAGE_MODE_END, 0);
133         long termination = prefs.getLong(GarageModeChecker.PREFS_TERMINATION, 0);
134         long jobUpdate = prefs.getLong(GarageModeChecker.PREFS_JOB_UPDATE, 0);
135         boolean hadConnectivity = prefs.getBoolean(GarageModeChecker.PREFS_HAD_CONNECTIVITY, false);
136         long startBootCount = prefs.getLong(GarageModeChecker.PREFS_START_BOOT_COUNT, 0);
137         long currentBootCount = GarageModeChecker.getBootCount(context);
138 
139         boolean testPassed = false;
140         if (initiateTime == 0) {
141             resultsString = "No results are available.\n\n"
142                     + "Perform the indicated steps to run the test.";
143         } else if (garageModeStart == 0) {
144             if (now < initiateTime + MAX_WAIT_UNTIL_GARAGE_MODE) {
145                 resultsString = String.format("Waitng for Garage Mode to start.\n\n"
146                                 + "%s -- Test was enabled",
147                         dateTime.format(initiateTime));
148             } else {
149                 resultsString = String.format("Test failed.\n"
150                                 + "Garage Mode did not run.\n\n"
151                                 + "%s -- Test was enabled",
152                         dateTime.format(initiateTime));
153             }
154         } else if (garageModeEnd > (garageModeStart + RECOMMENDED_DURATION_MS)) {
155             testPassed = hadConnectivity;
156             resultsString = String.format("Test %s.\n"
157                             + "Garage Mode ran as required and for the recommended time.\n"
158                             + "Connectivity was %savailable.\n\n"
159                             + "%s -- Test was enabled\n"
160                             + "%s -- Garage mode started\n"
161                             + "%s -- Garage mode completed",
162                     (testPassed ? "Passed" : "Failed"),
163                     (hadConnectivity ? "" : "not "),
164                     dateTime.format(initiateTime), dateTime.format(garageModeStart),
165                     dateTime.format(garageModeEnd));
166         } else if (termination > (garageModeStart + REQUIRED_DURATION_MS)) {
167             testPassed = hadConnectivity;
168             resultsString = String.format("Test %s.\n"
169                             + "Garage Mode ran as required, "
170                             + "but for less time than is recommended.\n"
171                             + "  The CDD recommends that Garage Mode runs for 15 minutes.\n"
172                             + "Connectivity was %savailable.\n\n"
173                             + "%s -- Test was enabled\n"
174                             + "%s -- Garage mode started\n"
175                             + "%s -- Garage mode was terminated",
176                     (testPassed ? "Passed" : "Failed"),
177                     (hadConnectivity ? "" : "not "),
178                     dateTime.format(initiateTime), dateTime.format(garageModeStart),
179                     dateTime.format(termination));
180         } else if (termination > 0) {
181             resultsString = String.format("Test Failed.\n"
182                             + "Garage Mode ran, but for less than the required time.\n"
183                             + "  The minimum requirement is that Garage Mode runs for 30 seconds.\n"
184                             + "  The CDD recommends that Garage Mode runs for 15 minutes.\n"
185                             + "Connectivity was %savailable.\n\n"
186                             + "%s -- Test was enabled\n"
187                             + "%s -- Garage mode started\n"
188                             + "%s -- Garage mode was terminated",
189                     (hadConnectivity ? "" : "not "),
190                     dateTime.format(initiateTime), dateTime.format(garageModeStart),
191                     dateTime.format(termination));
192         }  else if ((garageModeStart > 0 && garageModeEnd == 0)
193                                         && (currentBootCount - startBootCount > 0)) {
194             resultsString = "Test failed.\n\n"
195                     + "Garage Mode started, but system restarted before it completed.\n\n"
196                     + dateTime.format(initiateTime) + " -- Test was enabled\n"
197                     + dateTime.format(garageModeStart) + " -- Garage mode started";
198         } else if (now < jobUpdate + GarageModeChecker.MS_PER_ITERATION * 2) {
199             resultsString = "Garage Mode started and test is running.\n\n"
200                     + dateTime.format(initiateTime) + " -- Test was enabled\n"
201                     + dateTime.format(garageModeStart) + " -- Garage mode started\n"
202                     + dateTime.format(jobUpdate) + " -- Last job updated";
203         } else {
204             resultsString = "Test failed.\n\n"
205                     + "Garage Mode started, but terminated unexpectedly.\n\n"
206                     + dateTime.format(initiateTime) + " -- Test was enabled\n"
207                     + dateTime.format(garageModeStart) + " -- Garage mode started";
208         }
209         mStatusText.setText(resultsString);
210         getPassButton().setEnabled(testPassed);
211     }
212 }
213