• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.graphics;
17 
18 import android.annotation.TargetApi;
19 import android.app.Activity;
20 import android.app.Application;
21 import android.app.Application.ActivityLifecycleCallbacks;
22 import android.content.Context;
23 import android.graphics.Canvas;
24 import android.os.Build.VERSION_CODES;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.util.Log;
28 import android.view.View;
29 import android.view.View.OnAttachStateChangeListener;
30 import android.view.ViewTreeObserver.OnDrawListener;
31 
32 import com.android.launcher3.Utilities;
33 import com.android.launcher3.icons.GraphicsUtils;
34 
35 /**
36  * Utility class to check bitmap creation during draw pass.
37  */
38 public class BitmapCreationCheck {
39 
40     private static final String TAG = "BitmapCreationCheck";
41 
42     public static final boolean ENABLED = false;
43 
44     /**
45      * Starts tracking bitmap creations during {@link View#draw(Canvas)} calls
46      */
startTracking(Context context)47     public static void startTracking(Context context) {
48         MyTracker tracker = new MyTracker();
49         ((Application) context.getApplicationContext()).registerActivityLifecycleCallbacks(tracker);
50         GraphicsUtils.sOnNewBitmapRunnable = tracker::onBitmapCreated;
51     }
52 
53     @TargetApi(VERSION_CODES.Q)
54     private static class MyTracker
55             implements ActivityLifecycleCallbacks, OnAttachStateChangeListener {
56 
57         private final ThreadLocal<Boolean> mCurrentThreadDrawing =
58                 ThreadLocal.withInitial(() -> false);
59 
60         @Override
onActivityCreated(Activity activity, Bundle bundle)61         public void onActivityCreated(Activity activity, Bundle bundle) {
62             activity.getWindow().getDecorView().addOnAttachStateChangeListener(this);
63         }
64 
65         @Override
onActivityStarted(Activity activity)66         public void onActivityStarted(Activity activity) { }
67 
68         @Override
onActivityResumed(Activity activity)69         public void onActivityResumed(Activity activity) { }
70 
71         @Override
onActivityPaused(Activity activity)72         public void onActivityPaused(Activity activity) { }
73 
74         @Override
onActivityStopped(Activity activity)75         public void onActivityStopped(Activity activity) { }
76 
77         @Override
onActivitySaveInstanceState(Activity activity, Bundle bundle)78         public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
79 
80         @Override
onActivityDestroyed(Activity activity)81         public void onActivityDestroyed(Activity activity) { }
82 
83         @Override
onViewAttachedToWindow(View view)84         public void onViewAttachedToWindow(View view) {
85             view.getViewTreeObserver().addOnDrawListener(new MyViewDrawListener(view.getHandler()));
86         }
87 
88         @Override
onViewDetachedFromWindow(View view)89         public void onViewDetachedFromWindow(View view) { }
90 
91         private class MyViewDrawListener implements OnDrawListener, Runnable {
92 
93             private final Handler mHandler;
94 
MyViewDrawListener(Handler handler)95             MyViewDrawListener(Handler handler) {
96                 mHandler = handler;
97             }
98 
99             @Override
onDraw()100             public void onDraw() {
101                 mCurrentThreadDrawing.set(true);
102                 Utilities.postAsyncCallback(mHandler, this);
103             }
104 
105             @Override
run()106             public void run() {
107                 mCurrentThreadDrawing.set(false);
108             }
109         }
110 
onBitmapCreated()111         private void onBitmapCreated() {
112             if (mCurrentThreadDrawing.get()) {
113                 Log.e(TAG, "Bitmap created during draw pass", new Exception());
114             }
115         }
116     }
117 
118 }
119