Skip to content

Manabu-GT/DebugOverlay-Android

Repository files navigation

DebugOverlay-Android

Android Arsenal Maven Central API 16+ License

DebugOverlay is an Android library that allows developers to easily add custom overlay window/view for debugging purpose.

You can use it to show some performance related metrics such as cpu, memory, and fps. Or you can show logcat messages within your app for light debugging.

This library is fully customizable in terms of what you can show on the overlay. If you want to show something other than what's being provided, please go ahead and create your own overlay module!

DebugOverlay Simple Demo

Requirements

API Level 16 (Android 4.1) and above.

Setup

The library is pushed to Maven Central as an AAR, so you just need to add the followings to your build.gradle file:

dependencies {
  debugCompile 'com.ms-square:debugoverlay:1.1.3'
  releaseCompile 'com.ms-square:debugoverlay-no-op:1.1.3'
  testCompile 'com.ms-square:debugoverlay-no-op:1.1.3'
}

Please note that com.ms-square:debugoverlay:1.1.3 will add android.permission.SYSTEM_ALERT_WINDOW to your app. Threfore, you should avoid to use that dependency for your release build.

FYI, the following table describes the total number of method/field references in this library's release aar. This data is acquired by using Dexcount Gradle Plugin.

library methods fields
com.ms-square:debugoverlay:1.1.3 566 252
com.ms-square:debugoverlay-no-op:1.1.3 141 37

Due to the extensibility of this library, no-op version unfortunately has more than a few methods. If you want to eliminate such method count in your release build, consider having separate Application class only for your debug build which uses this library and just specify debugCompile 'com.ms-square:debugoverlay:1.1.3' in the dependencies section of build.gradle.

Usage

Simple

In your Application class:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    DebugOverlay.with(this).install();
    // Normal app init code...
  }
}

It will show a debug overlay on system layer with the follwing three default modules just like the gif animation image displayed on this README.

w/ Configurations

DebugOverlay Screen Capture

new DebugOverlay.Builder(this)
        .modules(new CpuUsageModule(),
                new MemInfoModule(this),
                new FpsModule(),
                new LogcatModule())
        .position(Position.BOTTOM_START)
        .bgColor(Color.parseColor("#60000000"))
        .textColor(Color.MAGENTA)
        .textSize(14f)
        .textAlpha(.8f)
        .allowSystemLayer(true)
        .notification(true, MainActivity.class.getName())
        .build()
        .install();
  • modules - [list or as variable length arguments]

List of OverlayModules to install

  • position - [Position]

Enum which specifies where to show the overlay. Default is BOTTOM_START.

  • bgColor - [color]

Color used for the background of the overlay. Default is 25% Black.

  • textColor - [color]

Color used for text on the overlay. Default is White.

  • textSize - [float]

Size in sp used for text on the overlay. Default is 12sp.

  • textAlpha - [float]

Alpha value used for text on the overlay. Default is 1f(fully opaque).

  • allowSystemLayer - [boolean]

If true, it adds the overlay window on Android's system window layer; in Android 7.1.1 and after, it will ask you for the overlay permission by taking you to the Android's settings screen when you first set up. If set to false, it will automatically add the overlay on each application window. In most cases, you want to set this to true. Default is true.

  • notification - [boolean, string(optional)]

applicable only when allowSystemLayer is set to true

When set to true, it will show notification which allows you to show/hide the overlay window. Default is true. You can optionally supply string which must be your activity's class name. It will be used to create PendingIntent to start the activity when the notification is tapped.

Provided Modules

CpuUsageModule

default

Collects total and app cpu usage % by reading /proc/stat and /proc/[myPid]/stat respectively.

Note: CpuUsageModule will be no-op on Android O and above. Please see this issue for why.

MemInfoModule

default

Collects device's current available memory, app's total PSS, and app's total private dirty info. Display unit is in Megabyte.

Refer to Investigating Your RAM Usage for more info about PSS and private dirty RAM.

If low memory situation is detected by reading lowMemory, texts will be automatically displayed in RED.

FpsModule

default

Measures FPS using Choreographer.

LogcatModule

optional

Collects logcat messages generated by your own app even on non-rooted devices.

CpuFreqModule

optional

Collects each cpu core's current and max frequency by reading /sys/devices/system/cpu/cpu[num]/cpufreq/scaling_cur_freq and /sys/devices/system/cpu/cpu[num]/cpufreq/cpuinfo_max_freq respectively.

Note: CpuFreqModule will be no-op on Android O and above. Please see this issue for why.

Extension Modules (available separately)

TimberModule

optional

An extension module which shows Timber logs for debugging.

For details, please check out debugoverlay-ext-timber.

NetStatsModule

optional

An extension module which shows the total network usage of the application. The stats include all network interfaces, and both TCP and UDP usage.

For details, please check out debugoverlay-ext-netstats.

Customization

Filtering and coloring scheme of logcat view

Filtering

implement the follwing IF method

boolean shouldFilterOut(LogcatLine.Priority priority, @NonNull String tag)

Coloring

implement the follwing IF method

@ColorInt
int getTextColor(LogcatLine.Priority priority, @NonNull String tag)

Example:

// filtering with LogcatLineFilter.SimpleLogcatLineFilter
// it filters out VERBOSE logs because DEBUG is minimum priority required
module = new LogcatModule(LogcatModule.DEFAULT_MAX_LINES,
                new LogcatLineFilter.SimpleLogcatLineFilter(LogcatLine.Priority.DEBUG));

// filtering with your own line filter
module = new LogcatModule(LogcatModule.DEFAULT_MAX_LINES, your_line_filter);

// coloring
module = new LogcatModule(LogcatModule.DEFAULT_MAX_LINES, your_color_scheme);

// both
module = new LogcatModule(LogcatModule.DEFAULT_MAX_LINES, your_line_filter, your_color_scheme);

Using custom overlay view for provided modules

For any modules provided, you can pass your own implementation of ViewModule to use your custom view entirely to display the module data.

Example:

// here, MyCpuViewModule must implement ViewModule interface
module = new CpuUsageModule(new MyCpuViewModule());

For CpuUsage, CpuFreq, MemInfo, and Fps modules, you can pass your own layout resource id as long as it contains TextView as a direct child with id set to debugoverlay_overlay_text which is already defined in this library. This allows you to style the TextView used within those modules very easily without fully implementing new ViewModule by yourself.

Adding your own overlay module

As an example, let's add a new overlay module in the sample project which displays a list of IP addresses on your device. It can be quite useful if you have any server-type service running within your app.

For any type of module you want to add, you need to implement the following three types of components. (In most cases, the real work will be done in DataModule.)

  • OverlayModule - composed of DataModule and ViewModule
  • DataModule - responsible for getting data and notifying its observers
  • ViewModule - responsible for creating an overlay view and updating it with the latest data

Since this is a very simple overlay module which is going to display just one line of text using TextView, you can just use the provided SimpleViewModule as ViewModule.

DataModule is where the hardwork is done to get some meaningful data to show. In this case, it will look like the following. For its full implementation, please take a look at IPAddressDataModule.

public class IPAddressDataModule extends BaseDataModule<String> {
    ....
    @Override
    public void start() {
        context.registerReceiver(receiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        ipAddresses = getV4IPAddressesString();
        notifyObservers();
    }

    @Override
    public void stop() {
        context.unregisterReceiver(receiver);
    }

    @Override
    protected String getLatestData() {
        return ipAddresses;
    }
    ....
}

We're almost done. Now just subclass OverlayModule and create IPAddressModule class using the IPAddressDataModule as its data module.

public class IPAddressModule extends OverlayModule<String> {

    public IPAddressModule(@NonNull Context context) {
        super(new IPAddressDataModule(context), new SimpleViewModule(R.layout.view_overlay_ip));
    }
}

Since a new custom module called IPAddressModule is created, let's actually show it on the overlay.

// inside Application's onCreate()
new DebugOverlay.Builder(this)
        .modules(new CpuFreqModule(),
                 new CpuUsageModule(),
                 new MemInfoModule(this),
                 new FpsModule(),
                 new IPAddressModule(this))
                .build()
                .install();

Now, the overlay successfully shows the newly added custom module at the bottom.

DebugOverlay Screen Capture

Thanks for reading!

License

Copyright 2017 Manabu Shimobe

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.