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