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.launcher3.ui;
18 
19 import android.app.Activity;
20 import android.app.Application;
21 import android.os.Bundle;
22 
23 import androidx.test.InstrumentationRegistry;
24 
25 import com.android.launcher3.tapl.TestHelpers;
26 
27 import java.util.WeakHashMap;
28 
29 public class ActivityLeakTracker implements Application.ActivityLifecycleCallbacks {
30     private final WeakHashMap<Activity, Boolean> mActivities = new WeakHashMap<>();
31 
32     private int mActivitiesCreated;
33 
ActivityLeakTracker()34     ActivityLeakTracker() {
35         if (!TestHelpers.isInLauncherProcess()) return;
36         final Application app =
37                 (Application) InstrumentationRegistry.getTargetContext().getApplicationContext();
38         app.registerActivityLifecycleCallbacks(this);
39     }
40 
getActivitiesCreated()41     public int getActivitiesCreated() {
42         return mActivitiesCreated;
43     }
44 
45     @Override
onActivityCreated(Activity activity, Bundle bundle)46     public void onActivityCreated(Activity activity, Bundle bundle) {
47         mActivities.put(activity, true);
48         ++mActivitiesCreated;
49     }
50 
51     @Override
onActivityStarted(Activity activity)52     public void onActivityStarted(Activity activity) {
53     }
54 
55     @Override
onActivityResumed(Activity activity)56     public void onActivityResumed(Activity activity) {
57     }
58 
59     @Override
onActivityPaused(Activity activity)60     public void onActivityPaused(Activity activity) {
61     }
62 
63     @Override
onActivityStopped(Activity activity)64     public void onActivityStopped(Activity activity) {
65     }
66 
67     @Override
onActivitySaveInstanceState(Activity activity, Bundle bundle)68     public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
69     }
70 
71     @Override
onActivityDestroyed(Activity activity)72     public void onActivityDestroyed(Activity activity) {
73     }
74 
noLeakedActivities()75     public boolean noLeakedActivities() {
76         int liveActivities = 0;
77         int destroyedActivities = 0;
78 
79         for (Activity activity : mActivities.keySet()) {
80             if (activity.isDestroyed()) {
81                 ++destroyedActivities;
82             } else {
83                 ++liveActivities;
84             }
85         }
86 
87         if (liveActivities > 2) return false;
88 
89         // It's OK to have 1 leaked activity if no active activities exist.
90         return liveActivities == 0 ? destroyedActivities <= 1 : destroyedActivities == 0;
91     }
92 }
93