That fuck shit the fascists are using
at master 101 lines 3.4 kB view raw
1package org.tm.archive.util; 2 3import android.app.Application; 4import android.content.Context; 5import android.view.Choreographer; 6import android.view.Display; 7 8import androidx.annotation.NonNull; 9 10import org.signal.core.util.logging.Log; 11 12import java.util.Locale; 13import java.util.concurrent.TimeUnit; 14 15/** 16 * Tracks the frame rate of the app and logs when things are bad. 17 * 18 * In general, whenever alterations are made here, the author should be very cautious to do as 19 * little work as possible, because we don't want the tracker itself to impact the frame rate. 20 */ 21public class FrameRateTracker { 22 23 private static final String TAG = Log.tag(FrameRateTracker.class); 24 25 private static final int MAX_CONSECUTIVE_FRAME_LOGS = 10; 26 27 private final Application context; 28 29 private double refreshRate; 30 private long idealTimePerFrameNanos; 31 private long badFrameThresholdNanos; 32 33 private long lastFrameTimeNanos; 34 35 private long consecutiveFrameWarnings; 36 37 public FrameRateTracker(@NonNull Application application) { 38 this.context = application; 39 40 updateRefreshRate(); 41 } 42 43 public void start() { 44 Log.d(TAG, String.format(Locale.ENGLISH, "Beginning frame rate tracking. Screen refresh rate: %.2f hz, or %.2f ms per frame.", refreshRate, idealTimePerFrameNanos / (float) 1_000_000)); 45 46 lastFrameTimeNanos = System.nanoTime(); 47 48 Choreographer.getInstance().postFrameCallback(calculator); 49 } 50 51 public void stop() { 52 Choreographer.getInstance().removeFrameCallback(calculator); 53 } 54 55 /** 56 * The natural screen refresh rate, in hertz. May not always return the same value if a display 57 * has a dynamic refresh rate. 58 */ 59 public static float getDisplayRefreshRate(@NonNull Context context) { 60 Display display = ServiceUtil.getWindowManager(context).getDefaultDisplay(); 61 return display.getRefreshRate(); 62 } 63 64 /** 65 * Displays with dynamic refresh rates may change their reported refresh rate over time. 66 */ 67 private void updateRefreshRate() { 68 double newRefreshRate = getDisplayRefreshRate(context); 69 70 if (this.refreshRate != newRefreshRate) { 71 if (this.refreshRate > 0) { 72 Log.d(TAG, String.format(Locale.ENGLISH, "Refresh rate changed from %.2f hz to %.2f hz", refreshRate, newRefreshRate)); 73 } 74 75 this.refreshRate = getDisplayRefreshRate(context); 76 this.idealTimePerFrameNanos = (long) (TimeUnit.SECONDS.toNanos(1) / refreshRate); 77 this.badFrameThresholdNanos = idealTimePerFrameNanos * (int) (refreshRate / 4); 78 } 79 } 80 81 private final Choreographer.FrameCallback calculator = new Choreographer.FrameCallback() { 82 @Override 83 public void doFrame(long frameTimeNanos) { 84 long elapsedNanos = frameTimeNanos - lastFrameTimeNanos; 85 double fps = TimeUnit.SECONDS.toNanos(1) / (double) elapsedNanos; 86 87 if (elapsedNanos > badFrameThresholdNanos) { 88 if (consecutiveFrameWarnings < MAX_CONSECUTIVE_FRAME_LOGS) { 89 long droppedFrames = elapsedNanos / idealTimePerFrameNanos; 90 Log.w(TAG, String.format(Locale.ENGLISH, "Bad frame! Took %d ms (%d dropped frames, or %.2f FPS)", TimeUnit.NANOSECONDS.toMillis(elapsedNanos), droppedFrames, fps)); 91 consecutiveFrameWarnings++; 92 } 93 } else { 94 consecutiveFrameWarnings = 0; 95 } 96 97 lastFrameTimeNanos = frameTimeNanos; 98 Choreographer.getInstance().postFrameCallback(this); 99 } 100 }; 101}