1 /*
2  * Copyright (C) 2019 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 package com.android.launcher3.testing;
17 
18 import static android.graphics.Bitmap.Config.ARGB_8888;
19 
20 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
21 
22 import android.content.Context;
23 import android.graphics.Bitmap;
24 import android.graphics.Color;
25 import android.os.Bundle;
26 import android.os.Debug;
27 
28 import com.android.launcher3.DeviceProfile;
29 import com.android.launcher3.InvariantDeviceProfile;
30 import com.android.launcher3.Launcher;
31 import com.android.launcher3.LauncherAppState;
32 import com.android.launcher3.LauncherModel;
33 import com.android.launcher3.LauncherState;
34 import com.android.launcher3.R;
35 import com.android.launcher3.allapps.AllAppsStore;
36 import com.android.launcher3.util.ResourceBasedOverride;
37 
38 import java.util.LinkedList;
39 import java.util.concurrent.ExecutionException;
40 
41 public class TestInformationHandler implements ResourceBasedOverride {
42 
newInstance(Context context)43     public static TestInformationHandler newInstance(Context context) {
44         return Overrides.getObject(TestInformationHandler.class,
45                 context, R.string.test_information_handler_class);
46     }
47 
48     protected Context mContext;
49     protected DeviceProfile mDeviceProfile;
50     protected LauncherAppState mLauncherAppState;
51     protected Launcher mLauncher;
52     private static LinkedList mLeaks;
53 
init(Context context)54     public void init(Context context) {
55         mContext = context;
56         mDeviceProfile = InvariantDeviceProfile.INSTANCE.
57                 get(context).getDeviceProfile(context);
58         mLauncherAppState = LauncherAppState.getInstanceNoCreate();
59         mLauncher = mLauncherAppState != null ?
60                 (Launcher) mLauncherAppState.getModel().getCallback() : null;
61     }
62 
call(String method)63     public Bundle call(String method) {
64         final Bundle response = new Bundle();
65         switch (method) {
66             case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
67                 if (mLauncher == null) return null;
68 
69                 final float progress = LauncherState.OVERVIEW.getVerticalProgress(mLauncher)
70                         - LauncherState.ALL_APPS.getVerticalProgress(mLauncher);
71                 final float distance = mLauncher.getAllAppsController().getShiftRange() * progress;
72                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) distance);
73                 break;
74             }
75 
76             case TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT: {
77                 if (mLauncher == null) return null;
78 
79                 final float progress = LauncherState.NORMAL.getVerticalProgress(mLauncher)
80                         - LauncherState.ALL_APPS.getVerticalProgress(mLauncher);
81                 final float distance = mLauncher.getAllAppsController().getShiftRange() * progress;
82                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) distance);
83                 break;
84             }
85 
86             case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: {
87                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, isLauncherInitialized());
88                 break;
89             }
90 
91             case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
92                 TestProtocol.sDebugTracing = true;
93                 break;
94 
95             case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
96                 TestProtocol.sDebugTracing = false;
97                 break;
98 
99             case TestProtocol.REQUEST_FREEZE_APP_LIST:
100                 MAIN_EXECUTOR.execute(() ->
101                         mLauncher.getAppsView().getAppsStore().enableDeferUpdates(
102                                 AllAppsStore.DEFER_UPDATES_TEST));
103                 break;
104 
105             case TestProtocol.REQUEST_UNFREEZE_APP_LIST:
106                 MAIN_EXECUTOR.execute(() ->
107                         mLauncher.getAppsView().getAppsStore().disableDeferUpdates(
108                                 AllAppsStore.DEFER_UPDATES_TEST));
109                 break;
110 
111             case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
112                 try {
113                     final int deferUpdatesFlags = MAIN_EXECUTOR.submit(() ->
114                             mLauncher.getAppsView().getAppsStore().getDeferUpdatesFlags()).get();
115                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
116                             deferUpdatesFlags);
117                 } catch (ExecutionException e) {
118                     throw new RuntimeException(e);
119                 } catch (InterruptedException e) {
120                     throw new RuntimeException(e);
121                 }
122                 break;
123             }
124 
125             case TestProtocol.REQUEST_TOTAL_PSS_KB: {
126                 Debug.MemoryInfo mem = new Debug.MemoryInfo();
127                 Debug.getMemoryInfo(mem);
128                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
129                 break;
130             }
131 
132             case TestProtocol.REQUEST_JAVA_LEAK: {
133                 if (mLeaks == null) mLeaks = new LinkedList();
134 
135                 // Allocate and dirty the memory.
136                 final int leakSize = 1024 * 1024;
137                 final byte[] bytes = new byte[leakSize];
138                 for (int i = 0; i < leakSize; i += 239) {
139                     bytes[i] = (byte) (i % 256);
140                 }
141                 mLeaks.add(bytes);
142                 break;
143             }
144 
145             case TestProtocol.REQUEST_NATIVE_LEAK: {
146                 if (mLeaks == null) mLeaks = new LinkedList();
147 
148                 // Allocate and dirty a bitmap.
149                 final Bitmap bitmap = Bitmap.createBitmap(512, 512, ARGB_8888);
150                 bitmap.eraseColor(Color.RED);
151                 mLeaks.add(bitmap);
152                 break;
153             }
154 
155             case TestProtocol.REQUEST_ICON_HEIGHT: {
156                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
157                         mDeviceProfile.allAppsCellHeightPx);
158                 break;
159             }
160         }
161         return response;
162     }
163 
isLauncherInitialized()164     protected boolean isLauncherInitialized() {
165         final LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
166         return model.getCallback() == null || model.isModelLoaded();
167     }
168 }
169 
170