Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a4ceb79 authored by ramindani's avatar ramindani Committed by Ram Indani
Browse files

Add support to render app on multiple displays

BUG: 241152647

Test: Manual Testing
Change-Id: I912f164b99c34e9b04d73cf37d0a97a19a1afc40
parent 07b5ffb2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    compileSdkVersion 33
    buildToolsVersion '28.0.3'

    defaultConfig {
        applicationId "com.prefabulated.touchlatency"
        minSdkVersion 28
        targetSdkVersion 28
        targetSdkVersion 33
        versionCode 1
        versionName "1.0"
    }
+8 −2
Original line number Diff line number Diff line
@@ -20,16 +20,22 @@
    <application android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:theme="@style/AppTheme">
         android:theme="@style/AppTheme"
        android:resizeableActivity="true" >
        <activity android:name=".TouchLatencyActivity"
             android:label="@string/app_name"
             android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <activity android:name=".TouchLatencyActivityPresentation"
            android:label="@string/app_name"
            android:parentActivityName=".TouchLatencyActivity"
            android:exported="true">
        </activity>
    </application>

</manifest>
+65 −206
Original line number Diff line number Diff line
@@ -17,218 +17,40 @@
package com.prefabulated.touchlatency;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.app.ActivityOptions;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.Display.Mode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import java.math.RoundingMode;
import java.text.DecimalFormat;

class TouchLatencyView extends View implements View.OnTouchListener {
    private static final String LOG_TAG = "TouchLatency";
    private static final int BACKGROUND_COLOR = 0xFF400080;
    private static final int INNER_RADIUS = 70;
    private static final int BALL_DIAMETER = 200;
    private static final int SEC_TO_NANOS = 1000000000;
    private static final float FPS_UPDATE_THRESHOLD = 20;
    private static final long BALL_VELOCITY = 420;

    public TouchLatencyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Trace.beginSection("TouchLatencyView constructor");
        setOnTouchListener(this);
        setWillNotDraw(false);
        mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBluePaint.setColor(0xFF0000FF);
        mBluePaint.setStyle(Paint.Style.FILL);
        mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mGreenPaint.setColor(0xFF00FF00);
        mGreenPaint.setStyle(Paint.Style.FILL);
        mYellowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mYellowPaint.setColor(0xFFFFFF00);
        mYellowPaint.setStyle(Paint.Style.FILL);
        mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mRedPaint.setColor(0xFFFF0000);
        mRedPaint.setStyle(Paint.Style.FILL);
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setColor(0xFFFFFFFF);
        mTextPaint.setTextSize(100);
        mTextPaint.setTextAlign(Align.RIGHT);

        mTouching = false;

        mLastDrawNano = 0;
        mFps = 0;
        mLastFpsUpdate = 0;
        mFrameCount = 0;

        mDf = new DecimalFormat("fps: #.##");
        mDf.setRoundingMode(RoundingMode.HALF_UP);

        Trace.endSection();
    }

public class TouchLatencyActivity extends Activity {
    private Mode mDisplayModes[];
    private int mCurrentModeIndex;
    private DisplayManager mDisplayManager;
    private final DisplayManager.DisplayListener mDisplayListener =
            new DisplayManager.DisplayListener() {
        @Override
    public boolean onTouch(View view, MotionEvent event) {
        Trace.beginSection("TouchLatencyView onTouch");
        int action = event.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
            mTouching = true;
            invalidate();

            mTouchX = event.getX();
            mTouchY = event.getY();
        } else if (action == MotionEvent.ACTION_UP) {
            mTouching = false;
            invalidate();
        }
        Trace.endSection();
        return true;
    }

    private void drawTouch(Canvas canvas) {
        Trace.beginSection("TouchLatencyView drawTouch");

        try {
            if (!mTouching) {
                Log.d(LOG_TAG, "Filling background");
                canvas.drawColor(BACKGROUND_COLOR);
                return;
            }

            float deltaX = (mTouchX - mLastDrawnX);
            float deltaY = (mTouchY - mLastDrawnY);
            float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;

            mLastDrawnX = mTouchX;
            mLastDrawnY = mTouchY;

            canvas.drawColor(BACKGROUND_COLOR);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
        } finally {
            Trace.endSection();
        }
    }

    private Paint getBallColor() {
        if (mFps > 75)
            return mGreenPaint;
        else if (mFps > 45)
            return mYellowPaint;
        else
            return mRedPaint;
    }

    private void drawBall(Canvas canvas) {
        Trace.beginSection("TouchLatencyView drawBall");
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        float fps = 0f;

        long t = System.nanoTime();
        long tDiff = t - mLastDrawNano;
        mLastDrawNano = t;
        mFrameCount++;

        if (tDiff < SEC_TO_NANOS) {
            fps = 1f * SEC_TO_NANOS / tDiff;
        }

        long fDiff = t - mLastFpsUpdate;
        if (Math.abs(mFps - fps) > FPS_UPDATE_THRESHOLD) {
            mFps = fps;
            mLastFpsUpdate = t;
            mFrameCount = 0;
        } else if (fDiff > SEC_TO_NANOS) {
            mFps = 1f * mFrameCount * SEC_TO_NANOS / fDiff;
            mLastFpsUpdate = t;
            mFrameCount = 0;
        }

        final long pos = t * BALL_VELOCITY / SEC_TO_NANOS;
        final long xMax = width - BALL_DIAMETER;
        final long yMax = height - BALL_DIAMETER;
        long xOffset = pos % xMax;
        long yOffset = pos % yMax;

        float left, right, top, bottom;

        if (((pos / xMax) & 1) == 0) {
            left = xMax - xOffset;
        } else {
            left = xOffset;
        }
        right = left + BALL_DIAMETER;

        if (((pos / yMax) & 1) == 0) {
            top = yMax - yOffset;
        } else {
            top = yOffset;
        }
        bottom = top + BALL_DIAMETER;

        // Draw the ball
        canvas.drawColor(BACKGROUND_COLOR);
        canvas.drawOval(left, top, right, bottom, getBallColor());
        canvas.drawText(mDf.format(mFps), width, 100, mTextPaint);

        invalidate();
        Trace.endSection();
        public void onDisplayAdded(int i) {
            invalidateOptionsMenu();
        }

        @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Trace.beginSection("TouchLatencyView onDraw");
        if (mMode == 0) {
            drawTouch(canvas);
        } else {
            drawBall(canvas);
        }
        Trace.endSection();
    }

    public void changeMode(MenuItem item) {
        Trace.beginSection("TouchLatencyView changeMode");
        final int NUM_MODES = 2;
        final String modes[] = {"Touch", "Ball"};
        mMode = (mMode + 1) % NUM_MODES;
        invalidate();
        item.setTitle(modes[mMode]);
        Trace.endSection();
        public void onDisplayRemoved(int i) {
            invalidateOptionsMenu();
        }

    private final Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint, mTextPaint;
    private int mMode;

    private boolean mTouching;
    private float mTouchX, mTouchY;
    private float mLastDrawnX, mLastDrawnY;

    private long mLastDrawNano, mLastFpsUpdate, mFrameCount;
    private float mFps;
    private DecimalFormat mDf;
        @Override
        public void onDisplayChanged(int i) {
            invalidateOptionsMenu();
        }

public class TouchLatencyActivity extends Activity {
    private Mode mDisplayModes[];
    private int mCurrentModeIndex;
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -236,9 +58,9 @@ public class TouchLatencyActivity extends Activity {

        Trace.beginSection("TouchLatencyActivity onCreate");
        setContentView(R.layout.activity_touch_latency);

        mTouchView = findViewById(R.id.canvasView);

        configureDisplayListener();
        WindowManager wm = getWindowManager();
        Display display = wm.getDefaultDisplay();
        mDisplayModes = display.getSupportedModes();
@@ -250,11 +72,9 @@ public class TouchLatencyActivity extends Activity {
                break;
            }
        }

        Trace.endSection();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu");
@@ -265,17 +85,26 @@ public class TouchLatencyActivity extends Activity {
            Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
            updateDisplayMode(menuItem, currentMode);
        }
        updateMultiDisplayMenu(menu.findItem(R.id.multi_display));
        Trace.endSection();
        return true;
    }


    private void updateDisplayMode(MenuItem menuItem, Mode displayMode) {
        int fps = (int) displayMode.getRefreshRate();
        menuItem.setTitle(fps + "hz");
        menuItem.setVisible(true);
    }

    private void updateMultiDisplayMenu(MenuItem item) {
        item.setVisible(mDisplayManager.getDisplays().length > 1);
    }

    private void configureDisplayListener() {
        mDisplayManager = getSystemService(DisplayManager.class);
        mDisplayManager.registerDisplayListener(mDisplayListener, new Handler());
    }

    public void changeDisplayMode(MenuItem item) {
        Window w = getWindow();
        WindowManager.LayoutParams params = w.getAttributes();
@@ -299,6 +128,19 @@ public class TouchLatencyActivity extends Activity {
        mCurrentModeIndex = modeIndex;
    }

    private void changeMultipleDisplays() {
        Intent intent = new Intent(this, TouchLatencyActivityPresentation.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
        ActivityOptions options = ActivityOptions.makeBasic();
        for (int i = 1; i < mDisplayManager.getDisplays().length; ++i) {
            // We assume the first display is already displaying the TouchLatencyActivity
            int displayId = mDisplayManager.getDisplays()[i].getDisplayId();
            options.setLaunchDisplayId(displayId);
            intent.putExtra(TouchLatencyActivityPresentation.DISPLAY_ID, displayId);
            startActivity(intent, options.toBundle());
        }
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
@@ -309,15 +151,32 @@ public class TouchLatencyActivity extends Activity {
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
        switch (id) {
            case R.id.action_settings: {
                mTouchView.changeMode(item);
        } else if (id == R.id.display_mode) {
                break;
            }
            case R.id.display_mode: {
                changeDisplayMode(item);
                break;
            }
            case R.id.multi_display: {
                changeMultipleDisplays();
                break;
            }
        }

        Trace.endSection();
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mDisplayManager != null) {
            mDisplayManager.unregisterDisplayListener(mDisplayListener);
        }
    }

    private TouchLatencyView mTouchView;
}
+128 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.prefabulated.touchlatency;

import android.app.Activity;
import android.os.Bundle;
import android.os.Trace;
import android.view.Display;
import android.view.Display.Mode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;

public class TouchLatencyActivityPresentation extends Activity {
    public static final String DISPLAY_ID = "DISPLAY_ID";
    private Mode[] mDisplayModes;
    private int mCurrentModeIndex;
    private int mDisplayId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getIntent().hasExtra(DISPLAY_ID)) {
            mDisplayId = (int) getIntent().getExtras().get(DISPLAY_ID);
        }
        Trace.beginSection(
                "TouchLatencyActivityPresentation::DisplayId::" + mDisplayId + " onCreate");
        setContentView(R.layout.activity_touch_latency);

        mTouchView = findViewById(R.id.canvasView);

        WindowManager wm = getWindowManager();
        Display display = wm.getDefaultDisplay();
        mDisplayModes = display.getSupportedModes();
        Mode currentMode = getWindowManager().getDefaultDisplay().getMode();

        for (int i = 0; i < mDisplayModes.length; i++) {
            if (currentMode.getModeId() == mDisplayModes[i].getModeId()) {
                mCurrentModeIndex = i;
                break;
            }
        }
        Trace.endSection();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Trace.beginSection(
                "TouchLatencyActivityPresentation::DisplayId:: "
                        + mDisplayId + "  onCreateOptionsMenu");
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
        if (mDisplayModes.length > 1) {
            MenuItem menuItem = menu.findItem(R.id.display_mode);
            Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
            updateDisplayMode(menuItem, currentMode);
        }
        Trace.endSection();
        return true;
    }

    private void updateDisplayMode(MenuItem menuItem, Mode displayMode) {
        int fps = (int) displayMode.getRefreshRate();
        menuItem.setTitle(fps + "hz");
        menuItem.setVisible(true);
    }

    public void changeDisplayMode(MenuItem item) {
        Window w = getWindow();
        WindowManager.LayoutParams params = w.getAttributes();

        int modeIndex = (mCurrentModeIndex + 1) % mDisplayModes.length;
        params.preferredDisplayModeId = mDisplayModes[modeIndex].getModeId();
        w.setAttributes(params);

        updateDisplayMode(item, mDisplayModes[modeIndex]);
        mCurrentModeIndex = modeIndex;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Trace.beginSection(
                "TouchLatencyActivityPresentation::DisplayId::"
                        + mDisplayId + "  onOptionsItemSelected");
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        switch (id) {
            case R.id.action_settings: {
                mTouchView.changeMode(item);
                break;
            }
            case R.id.display_mode: {
                changeDisplayMode(item);
                break;
            }
        }

        Trace.endSection();
        return super.onOptionsItemSelected(item);
    }

    private TouchLatencyView mTouchView;
}
+219 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.prefabulated.touchlatency;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;

import java.math.RoundingMode;
import java.text.DecimalFormat;

class TouchLatencyView extends View implements View.OnTouchListener {
    private static final String LOG_TAG = "TouchLatency";
    private static final int BACKGROUND_COLOR = 0xFF400080;
    private static final int INNER_RADIUS = 70;
    private static final int BALL_DIAMETER = 200;
    private static final int SEC_TO_NANOS = 1000000000;
    private static final float FPS_UPDATE_THRESHOLD = 20;
    private static final long BALL_VELOCITY = 420;

    public TouchLatencyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Trace.beginSection("TouchLatencyView constructor");
        setOnTouchListener(this);
        setWillNotDraw(false);
        mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBluePaint.setColor(0xFF0000FF);
        mBluePaint.setStyle(Paint.Style.FILL);
        mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mGreenPaint.setColor(0xFF00FF00);
        mGreenPaint.setStyle(Paint.Style.FILL);
        mYellowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mYellowPaint.setColor(0xFFFFFF00);
        mYellowPaint.setStyle(Paint.Style.FILL);
        mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mRedPaint.setColor(0xFFFF0000);
        mRedPaint.setStyle(Paint.Style.FILL);
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setColor(0xFFFFFFFF);
        mTextPaint.setTextSize(100);
        mTextPaint.setTextAlign(Paint.Align.RIGHT);

        mTouching = false;

        mLastDrawNano = 0;
        mFps = 0;
        mLastFpsUpdate = 0;
        mFrameCount = 0;

        mDf = new DecimalFormat("fps: #.##");
        mDf.setRoundingMode(RoundingMode.HALF_UP);

        Trace.endSection();
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        Trace.beginSection("TouchLatencyView onTouch");
        int action = event.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
            mTouching = true;
            invalidate();

            mTouchX = event.getX();
            mTouchY = event.getY();
        } else if (action == MotionEvent.ACTION_UP) {
            mTouching = false;
            invalidate();
        }
        Trace.endSection();
        return true;
    }

    private void drawTouch(Canvas canvas) {
        Trace.beginSection("TouchLatencyView drawTouch");

        try {
            if (!mTouching) {
                Log.d(LOG_TAG, "Filling background");
                canvas.drawColor(BACKGROUND_COLOR);
                return;
            }

            float deltaX = (mTouchX - mLastDrawnX);
            float deltaY = (mTouchY - mLastDrawnY);
            float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;

            mLastDrawnX = mTouchX;
            mLastDrawnY = mTouchY;

            canvas.drawColor(BACKGROUND_COLOR);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
        } finally {
            Trace.endSection();
        }
    }

    private Paint getBallColor() {
        if (mFps > 75) {
            return mGreenPaint;
        } else if (mFps > 45) {
            return mYellowPaint;
        } else
            return mRedPaint;
    }

    private void drawBall(Canvas canvas) {
        Trace.beginSection("TouchLatencyView drawBall");
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        float fps = 0f;

        long t = System.nanoTime();
        long tDiff = t - mLastDrawNano;
        mLastDrawNano = t;
        mFrameCount++;

        if (tDiff < SEC_TO_NANOS) {
            fps = 1f * SEC_TO_NANOS / tDiff;
        }

        long fDiff = t - mLastFpsUpdate;
        if (Math.abs(mFps - fps) > FPS_UPDATE_THRESHOLD) {
            mFps = fps;
            mLastFpsUpdate = t;
            mFrameCount = 0;
        } else if (fDiff > SEC_TO_NANOS) {
            mFps = 1f * mFrameCount * SEC_TO_NANOS / fDiff;
            mLastFpsUpdate = t;
            mFrameCount = 0;
        }

        final long pos = t * BALL_VELOCITY / SEC_TO_NANOS;
        final long xMax = width - BALL_DIAMETER;
        final long yMax = height - BALL_DIAMETER;
        long xOffset = pos % xMax;
        long yOffset = pos % yMax;

        float left, right, top, bottom;

        if (((pos / xMax) & 1) == 0) {
            left = xMax - xOffset;
        } else {
            left = xOffset;
        }
        right = left + BALL_DIAMETER;

        if (((pos / yMax) & 1) == 0) {
            top = yMax - yOffset;
        } else {
            top = yOffset;
        }
        bottom = top + BALL_DIAMETER;

        // Draw the ball
        canvas.drawColor(BACKGROUND_COLOR);
        canvas.drawOval(left, top, right, bottom, getBallColor());
        canvas.drawText(mDf.format(mFps), width, 100, mTextPaint);

        invalidate();
        Trace.endSection();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Trace.beginSection("TouchLatencyView onDraw");
        if (mMode == 0) {
            drawTouch(canvas);
        } else {
            drawBall(canvas);
        }
        Trace.endSection();
    }

    public void changeMode(MenuItem item) {
        Trace.beginSection("TouchLatencyView changeMode");
        final int NUM_MODES = 2;
        final String modes[] = {"Touch", "Ball"};
        mMode = (mMode + 1) % NUM_MODES;
        invalidate();
        item.setTitle(modes[mMode]);
        Trace.endSection();
    }

    private final Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint, mTextPaint;
    private int mMode;

    private boolean mTouching;
    private float mTouchX, mTouchY;
    private float mLastDrawnX, mLastDrawnY;

    private long mLastDrawNano, mLastFpsUpdate, mFrameCount;
    private float mFps;
    private DecimalFormat mDf;
}
Loading