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 package com.android.launcher3.util;
17 
18 import static android.view.View.MeasureSpec.EXACTLY;
19 import static android.view.View.MeasureSpec.makeMeasureSpec;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ResolveInfo;
25 import android.graphics.Point;
26 import android.view.View;
27 import android.view.WindowManager;
28 
29 import com.android.launcher3.Launcher;
30 
31 import org.robolectric.Robolectric;
32 import org.robolectric.RuntimeEnvironment;
33 import org.robolectric.android.controller.ActivityController;
34 import org.robolectric.shadows.ShadowLooper;
35 import org.robolectric.util.ReflectionHelpers;
36 
37 import java.util.List;
38 
39 /**
40  * Utility class to help manage Launcher UI and related objects for test.
41  */
42 public class LauncherUIHelper {
43 
44     /**
45      * Returns the class name for the Launcher activity as defined in the manifest
46      */
getLauncherClassName()47     public static String getLauncherClassName() {
48         Context context = RuntimeEnvironment.application;
49         Intent homeIntent = new Intent(Intent.ACTION_MAIN)
50                 .addCategory(Intent.CATEGORY_HOME)
51                 .setPackage(context.getPackageName())
52                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
53 
54         List<ResolveInfo> launchers = context.getPackageManager()
55                 .queryIntentActivities(homeIntent, 0);
56         if (launchers.size() != 1) {
57             return null;
58         }
59         return launchers.get(0).activityInfo.name;
60     }
61 
62     /**
63      * Returns an activity controller for Launcher activity defined in the manifest
64      */
buildLauncher()65     public static <T extends Launcher> ActivityController<T> buildLauncher() {
66         try {
67             Class<T> tClass = (Class<T>) Class.forName(getLauncherClassName());
68             return Robolectric.buildActivity(tClass);
69         } catch (Exception e) {
70             throw new RuntimeException(e);
71         }
72     }
73 
74     /**
75      * Creates and binds a Launcher activity defined in the manifest.
76      * Note that the model must be bound before calling this
77      */
buildAndBindLauncher()78     public static <T extends Launcher> T buildAndBindLauncher() {
79         ActivityController<T> controller = buildLauncher();
80 
81         T launcher = controller.setup().get();
82         doLayout(launcher);
83         ViewOnDrawExecutor executor = ReflectionHelpers.getField(launcher, "mPendingExecutor");
84         if (executor != null) {
85             executor.runAllTasks();
86         }
87         return launcher;
88     }
89 
90     /**
91      * Performs a measure and layout pass for the given activity
92      */
doLayout(Activity activity)93     public static void doLayout(Activity activity) {
94         Point size = new Point();
95         RuntimeEnvironment.application.getSystemService(WindowManager.class)
96                 .getDefaultDisplay().getSize(size);
97         View view = activity.getWindow().getDecorView();
98         view.measure(makeMeasureSpec(size.x, EXACTLY), makeMeasureSpec(size.y, EXACTLY));
99         view.layout(0, 0, size.x, size.y);
100         ShadowLooper.idleMainLooper();
101     }
102 }
103