1 /*
2  * Copyright (C) 2021 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 android.cts.statsdatom.sizecompatrestartbutton;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.cts.statsdatom.lib.AtomTestUtils;
22 import android.cts.statsdatom.lib.ConfigUtils;
23 import android.cts.statsdatom.lib.DeviceUtils;
24 import android.cts.statsdatom.lib.ReportUtils;
25 
26 import com.android.os.AtomsProto;
27 import com.android.os.AtomsProto.SizeCompatRestartButtonEventReported;
28 import com.android.os.AtomsProto.SizeCompatRestartButtonEventReported.Event;
29 import com.android.os.StatsLog;
30 import com.android.tradefed.build.IBuildInfo;
31 import com.android.tradefed.device.ITestDevice;
32 import com.android.tradefed.log.LogUtil.CLog;
33 import com.android.tradefed.testtype.DeviceTestCase;
34 import com.android.tradefed.testtype.IBuildReceiver;
35 import com.android.tradefed.util.Pair;
36 import com.android.tradefed.util.RunUtil;
37 
38 import java.util.List;
39 
40 /**
41  * This test is for making sure that Size Compat Restart Button appearances and clicks log the
42  * desired atoms.
43  *
44  *  <p>Build/Install/Run:
45  *  atest CtsStatsdAtomHostTestCases:SizeCompatRestartButtonStatsTests
46  */
47 // TODO(b/197223993): add test for clicked event
48 public class SizeCompatRestartButtonStatsTests extends DeviceTestCase implements IBuildReceiver {
49 
50     private static final String NON_RESIZEABLE_PORTRAIT_ACTIVITY =
51             "StatsdCtsNonResizeablePortraitActivity";
52     private static final String CMD_GET_STAY_ON = "settings get global stay_on_while_plugged_in";
53     private static final String CMD_PUT_STAY_ON_TEMPLATE =
54             "settings put global stay_on_while_plugged_in %d";
55     private static final int ENABLE_STAY_ON_CODE = 7;
56     private static final String CMD_RESET_DEVICE_STATE = "cmd device_state state reset";
57     private static final String CMD_PUT_DEVICE_STATE_TEMPLATE = "cmd device_state state %d";
58     private static final String CMD_GET_CURRENT_DEVICE_STATE = "cmd device_state print-state";
59     private static final int DEVICE_STATE_CLOSED = 0;
60     private static final int DEVICE_STATE_OPENED = 2;
61 
62     private IBuildInfo mCtsBuild;
63     private long mOriginalStayOnSetting;
64     private int mOriginalDeviceState;
65 
66     @Override
setUp()67     protected void setUp() throws Exception {
68         super.setUp();
69         assertThat(mCtsBuild).isNotNull();
70         mOriginalStayOnSetting = Long.parseLong(
71                 getDevice().executeShellCommand(CMD_GET_STAY_ON).trim());
72         mOriginalDeviceState = Integer.parseInt(
73                 getDevice().executeShellCommand(CMD_GET_CURRENT_DEVICE_STATE).trim());
74         getDevice().executeShellCommand(
75                 String.format(CMD_PUT_STAY_ON_TEMPLATE, ENABLE_STAY_ON_CODE));
76         getDevice().executeShellCommand(
77                 String.format(CMD_PUT_DEVICE_STATE_TEMPLATE, DEVICE_STATE_CLOSED));
78         ConfigUtils.removeConfig(getDevice());
79         ReportUtils.clearReports(getDevice());
80         DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild);
81         DeviceUtils.turnScreenOn(getDevice());
82         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
83         ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
84                 AtomsProto.Atom.SIZE_COMPAT_RESTART_BUTTON_EVENT_REPORTED_FIELD_NUMBER,
85                 /*uidInAttributionChain=*/ false);
86     }
87 
88     @Override
tearDown()89     protected void tearDown() throws Exception {
90         getDevice().executeShellCommand(
91                 String.format(CMD_PUT_STAY_ON_TEMPLATE, mOriginalStayOnSetting));
92         getDevice().executeShellCommand(
93                 String.format(CMD_PUT_DEVICE_STATE_TEMPLATE, mOriginalDeviceState));
94         getDevice().executeShellCommand(CMD_RESET_DEVICE_STATE);
95         ConfigUtils.removeConfig(getDevice());
96         ReportUtils.clearReports(getDevice());
97         DeviceUtils.uninstallStatsdTestApp(getDevice());
98         super.tearDown();
99     }
100 
101     @Override
setBuild(IBuildInfo buildInfo)102     public void setBuild(IBuildInfo buildInfo) {
103         mCtsBuild = buildInfo;
104     }
105 
testSizeCompatRestartButtonAppearedButNotClicked()106     public void testSizeCompatRestartButtonAppearedButNotClicked() throws Exception {
107         if (!isFoldableStateAvailable(DEVICE_STATE_OPENED)
108                 || !isFoldableStateAvailable(DEVICE_STATE_CLOSED)) {
109             CLog.i("Device doesn't support OPENED or CLOSED device states.");
110             return;
111         }
112 
113         Pair<Integer, Integer> displaySizeClosed = getDisplayRealSize(getDevice());
114         if (displaySizeClosed == null) {
115             CLog.i("Could not determine display size while CLOSED.");
116             return;
117         }
118         try (AutoCloseable a = DeviceUtils.withActivity(getDevice(),
119                 DeviceUtils.STATSD_ATOM_TEST_PKG, NON_RESIZEABLE_PORTRAIT_ACTIVITY, "action",
120                 "action.sleep_top")) {
121             // Wait before unfolding to make sure app is opened.
122             RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
123             getDevice().executeShellCommand(
124                     String.format(CMD_PUT_DEVICE_STATE_TEMPLATE, DEVICE_STATE_OPENED));
125             RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
126         }
127 
128         Pair<Integer, Integer> displaySizeOpened = getDisplayRealSize(getDevice());
129         if (displaySizeOpened == null) {
130             CLog.i("Could not determine display size while OPENED.");
131             return;
132         }
133         if (displaySizeClosed.equals(displaySizeOpened)) {
134             CLog.i("Display size has not changed.");
135             return;
136         }
137         // Wait to make sure metric event is reported.
138         RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG);
139         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
140         assertThat(data.size()).isEqualTo(1);
141 
142         SizeCompatRestartButtonEventReported atom =
143                 data.get(0).getAtom().getSizeCompatRestartButtonEventReported();
144         assertThat(atom.getUid()).isEqualTo(DeviceUtils.getStatsdTestAppUid(getDevice()));
145         assertThat(atom.getEvent()).isEqualTo(Event.APPEARED);
146     }
147 
isFoldableStateAvailable(int state)148     private boolean isFoldableStateAvailable(int state) throws Exception {
149         return getDevice().getFoldableStates().stream().anyMatch(
150                 foldableState -> foldableState.getIdentifier() == state);
151     }
152 
153     /**
154      * Returns the physical size of the current display used.
155      */
getDisplayRealSize(ITestDevice device)156     private Pair<Integer, Integer> getDisplayRealSize(ITestDevice device) throws Exception {
157         final String physicalSize = "Physical size: ";
158         String str = device.executeShellCommand("wm size");
159         if (!str.isEmpty()) {
160             String[] lines = str.split(System.getProperty("line.separator"));
161             for (String s : lines) {
162                 if (s.contains(physicalSize)) {
163                     String substring = s.substring(physicalSize.length());
164                     if (!substring.isEmpty()) {
165                         return Pair.create(Integer.parseInt(substring.split("x")[0]),
166                                 Integer.parseInt(substring.split("x")[1]));
167                     }
168                 }
169             }
170         }
171         return null;
172     }
173 }
174