public class DebugDrawer {
    private static final DebugDrawer INSTANCE = new DebugDrawer(null);

    private DebugDrawer(Builder builder) {

    }

    /**
     * Open the drawer
     */
    public void openDrawer() {

    }

    /**
     * close the drawer
     */
    public void closeDrawer() {

    }

    /**
     * Get the current state of the drawer.
     * True if the drawer is currently open.
     *
     * @return
     */
    public boolean isDrawerOpen() {
        return false;
    }

    /**
     * Enable or disable interaction with all drawers.
     */
    public void setDrawerLockMode(int lockMode) {

    }

    /**
     * Calls modules {@link DebugModule#onResume()} method
     */
    void onResume() {

    }

    /**
     * Calls modules {@link DebugModule#onPause()} method
     */
    void onPause() {

    }

    /**
     * Starts all modules and calls their {@link DebugModule#onStart()} method
     */
    void onStart() {

    }

    /**
     * Removes all modules and calls their {@link DebugModule#onStop()} method
     */
    void onStop() {

    }

    public static class Builder {

        /**
         * Pass the activity you use the drawer in ;)
         * This is required if you want to set any values by resource
         */
        public Builder(Activity activity) {

        }

        /**
         * Pass the rootView of the Drawer which will be used to inflate the DrawerLayout in
         */
        public Builder rootView(ViewGroup rootView) {
            return this;
        }

        /**
         * Pass the rootView as resource of the Drawer which will be used to inflate the
         * DrawerLayout in
         */
        public Builder rootView(int rootViewRes) {
            return this;
        }

        /**
         * Set the gravity for the drawer. START, LEFT | RIGHT, END
         */
        public Builder gravity(int gravity) {
            return this;
        }

        /**
         * Set the Drawer width with a pixel value
         */
        public Builder widthPx(int drawerWidthPx) {
            return this;
        }

        /**
         * Set the Drawer width with a dp value
         */
        public Builder widthDp(int drawerWidthDp) {
            return this;
        }

        /**
         * Set the Drawer width with a dimension resource
         */
        public Builder widthRes(int drawerWidthRes) {
            return this;
        }

        /**
         * Set the background color for the Slider.
         * This is the view containing the list.
         */
        public Builder backgroundColor(int sliderBackgroundColor) {
            return this;
        }

        /**
         * Set the background color for the Slider from a Resource.
         * This is the view containing the list.
         */
        public Builder backgroundColorRes(@IntegerRes int sliderBackgroundColorRes) {
            return this;
        }


        /**
         * Set the background drawable for the Slider.
         * This is the view containing the list.
         */
        public Builder backgroundDrawable(Drawable sliderBackgroundDrawable) {
            return this;
        }


        /**
         * Set the background drawable for the Slider from a Resource.
         * This is the view containing the list.
         */
        public Builder backgroundDrawableRes(@DrawableRes int sliderBackgroundDrawableRes) {
            return this;
        }

        public Builder setDrawerListener(DrawerLayout.DrawerListener onDrawerListener) {
            return this;
        }

        public Builder withTheme(@StyleRes int themeRes) {
            return this;
        }

        /**
         * Add a initial DrawerItem or a DrawerItem Array  for the Drawer
         */
        public Builder modules(DebugModule... drawerItems) {
            return this;
        }

        /**
         * Build and add the Drawer to your activity
         *
         * @return
         */
        public DebugDrawer build() {
            return DebugDrawer.INSTANCE;
        }
    }
} public class ActionsModule implements DebugModule {
    private final List<Action> actions = new ArrayList<>();
    private final String title;

    public ActionsModule(String title, Action... actions) {
        this.title = title;
        if (actions != null) {
            this.actions.addAll(Arrays.asList(actions));
        }
    }

    public ActionsModule(Action... actions) {
        this("Actions", actions);
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final LinearLayout view = (LinearLayout) inflater.inflate(R.layout.dd_debug_drawer_module_actions, parent, false);
        final TextView titleView = view.findViewById(R.id.dd_actions_title);
        titleView.setText(title);

        if (actions.isEmpty()) {
            final TextView noActionsLabel = new TextView(parent.getContext());
            noActionsLabel.setTextColor(parent.getResources().getColor(android.R.color.white));
            noActionsLabel.setText("No actions added");
            view.addView(noActionsLabel);
        } else {
            for (Action action : actions) {
                view.addView(action.getView(inflater, view));
            }
        }

        return view;
    }

    @Override
    public void onOpened() {
        for (Action action : actions) {
            action.onOpened();
        }
    }

    @Override
    public void onClosed() {
        for (Action action : actions) {
            action.onClosed();
        }
    }

    @Override
    public void onResume() {
        for (Action action : actions) {
            action.onResume();
        }
    }

    @Override
    public void onPause() {
        for (Action action : actions) {
            action.onPause();
        }
    }

    @Override
    public void onStart() {
        for (Action action : actions) {
            action.onStart();
        }
    }

    @Override
    public void onStop() {
        for (Action action : actions) {
            action.onStop();
        }
    }
} public class ButtonAction implements Action {

    private final String name;
    private final Listener listener;

    public ButtonAction(String name, Listener listener) {
        this.name = name;
        this.listener = listener;
    }

    @Override
    public View getView(@NonNull final LayoutInflater inflater, @NonNull final LinearLayout parent) {
        final Button button = (Button) inflater.inflate(R.layout.dd_debug_drawer_module_actions_button, parent, false);
        button.setText(name);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onClick();
                }
            }
        });

        return button;
    }

    @Override
    public void onOpened() {
        /* no-op */
    }

    @Override
    public void onClosed() {
        /* no-op */
    }

    @Override
    public void onResume() {

    }

    @Override
    public void onPause() {

    }

    @Override
    public void onStart() {
        /* no-op */
    }

    @Override
    public void onStop() {
        /* no-op */
    }

    public interface Listener {
        void onClick();
    }
} public class SpinnerAction<T> implements Action {

    public interface OnItemSelectedListener<T> {
        void onItemSelected(T value);
    }

    private final static int SPINNER_DEFAULT_POSITION = 0;

    private final List<String> titles;
    private final List<T> values;
    private final OnItemSelectedListener<T> listener;

    private int selectedPosition = SPINNER_DEFAULT_POSITION;

    public SpinnerAction(List<T> values, OnItemSelectedListener<T> listener) {
        this(getTitles(values), values, listener, SPINNER_DEFAULT_POSITION);
    }

    public SpinnerAction(List<T> values, OnItemSelectedListener<T> listener, int initialSelectedPosition) {
        this(getTitles(values), values, listener, initialSelectedPosition);
    }

    public SpinnerAction(List<String> titles, List<T> values, OnItemSelectedListener<T> listener, int initialSelectedPosition) {
        this.values = values;
        this.titles = titles;
        this.listener = listener;
        if (initialSelectedPosition >= 0 && initialSelectedPosition < values.size()) {
            this.selectedPosition = initialSelectedPosition;
        } else {
            throw new IllegalStateException("initial selected position is out of bounds");
        }
    }

    @Override
    public View getView(@NonNull final LayoutInflater inflater, @NonNull final LinearLayout parent) {
        final Context context = parent.getContext();
        final Spinner spinner = (Spinner) inflater.inflate(R.layout.dd_debug_drawer_module_actions_spinner, parent, false);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (listener != null && position != selectedPosition) {
                    listener.onItemSelected(values.get(position));
                }
                selectedPosition = position;
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

        final ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.dd_debug_drawer_module_actions_spinner_item, titles);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

        if (!values.isEmpty()) {
            spinner.setSelection(selectedPosition);
        }

        return spinner;
    }

    @Override
    public void onOpened() {

    }

    @Override
    public void onClosed() {

    }

    @Override
    public void onResume() {

    }

    @Override
    public void onPause() {

    }

    @Override
    public void onStart() {

    }

    @Override
    public void onStop() {

    }

    private static <T> List<String> getTitles(List<T> values) {
        final List<String> titles = new ArrayList<>(values.size());
        for (T value : values) {
            titles.add(value.toString());
        }
        return titles;
    }
} public class SwitchAction implements Action {

    private final String name;
    private final Listener listener;
    private final boolean shouldEmitFirstValue;

    private WeakReference<Context> contextRef;

    private Switch switchButton;

    public SwitchAction(String name, @Nullable Listener listener) {
        this.name = name;
        this.listener = listener;
        this.shouldEmitFirstValue = false;
    }

    public SwitchAction(String name, @Nullable Listener listener, boolean shouldEmitFirstValue) {
        this.name = name;
        this.listener = listener;
        this.shouldEmitFirstValue = shouldEmitFirstValue;
    }

    @Override
    public View getView(@NonNull final LayoutInflater inflater, @NonNull final LinearLayout parent) {
        final Context context = parent.getContext();

        if (contextRef == null) {
            contextRef = new WeakReference<>(context);
        }

        View viewGroup = inflater.inflate(R.layout.dd_debug_drawer_module_actions_switch, parent, false);

        final TextView textView = viewGroup.findViewById(R.id.action_switch_name);
        textView.setText(name);

        switchButton = viewGroup.findViewById(R.id.action_switch_switch);
        switchButton.setOnCheckedChangeListener(switchListener);

        return viewGroup;
    }

    @Override
    public void onOpened() {
        /* no-op */
    }

    @Override
    public void onClosed() {
        /* no-op */
    }

    @Override
    public void onResume() {

    }

    @Override
    public void onPause() {

    }

    @Override
    public void onStart() {
        final boolean isChecked = readValue();

        switchButton.setOnCheckedChangeListener(null);
        switchButton.setChecked(isChecked);
        switchButton.setOnCheckedChangeListener(switchListener);

        if (shouldEmitFirstValue && listener != null) {
            listener.onCheckedChanged(isChecked);
        }
    }

    @Override
    public void onStop() {
        /* no-op */
    }

    private CompoundButton.OnCheckedChangeListener switchListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (listener != null) {
                listener.onCheckedChanged(isChecked);
            }
            writeValue(isChecked);
        }
    };

    public boolean isChecked() {
        return readValue();
    }

    public void setChecked(boolean checked) {
        switchButton.setChecked(checked);
    }

    private boolean readValue() {
        return getPreferences().getBoolean(name, false);
    }

    private void writeValue(boolean b) {
        getPreferences().edit().putBoolean(name, b).apply();
    }

    private SharedPreferences getPreferences() {
        return contextRef.get().getSharedPreferences(name, Context.MODE_PRIVATE);
    }

    public interface Listener {
        void onCheckedChanged(boolean value);
    }
} public class BuildModule extends DebugModuleAdapter {

    private WeakReference<Context> context;

    private TextView codeLabel;
    private TextView nameLabel;
    private TextView packageLabel;

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {

        if (context == null) {
            context = new WeakReference<>(parent.getContext());
        }

        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_build, parent, false);
        view.setClickable(false);
        view.setEnabled(false);

        codeLabel = view.findViewById(R.id.dd_debug_build_code);
        nameLabel = view.findViewById(R.id.dd_debug_build_name);
        packageLabel = view.findViewById(R.id.dd_debug_build_package);

        refresh();

        return view;
    }

    @Override
    public void onOpened() {
        refresh();
    }

    private void refresh() {
        try {
            final Context context = this.context.get();
            if (context != null) {
                final PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
                codeLabel.setText(String.valueOf(info.versionCode));
                nameLabel.setText(info.versionName);
                packageLabel.setText(info.packageName);
            }
        } catch (PackageManager.NameNotFoundException e) {
        }
    }
} public class DeviceModule extends DebugModuleAdapter {

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_device, parent, false);
        view.setClickable(false);
        view.setEnabled(false);

        final TextView deviceMakeLabel = view.findViewById(R.id.dd_debug_device_make);
        final TextView deviceModelLabel = view.findViewById(R.id.dd_debug_device_model);
        final TextView deviceResolutionLabel = view.findViewById(R.id.dd_debug_device_resolution);
        final TextView deviceDensityLabel = view.findViewById(R.id.dd_debug_device_density);
        final TextView deviceReleaseLabel = view.findViewById(R.id.dd_debug_device_release);
        final TextView deviceApiLabel = view.findViewById(R.id.dd_debug_device_api);

        final DisplayMetrics displayMetrics = parent.getContext().getResources().getDisplayMetrics();
        final String densityBucket = getDensityString(displayMetrics);
        final String deviceMake = truncateAt(Build.MANUFACTURER, 20);
        final String deviceModel = truncateAt(Build.MODEL, 20);
        final String deviceResolution = displayMetrics.heightPixels + "x" + displayMetrics.widthPixels;
        final String deviceDensity = displayMetrics.densityDpi + "dpi (" + densityBucket + ")";
        final String deviceRelease = Build.VERSION.RELEASE;
        final String deviceApi = String.valueOf(Build.VERSION.SDK_INT);

        deviceModelLabel.setText(deviceModel);
        deviceMakeLabel.setText(deviceMake);
        deviceResolutionLabel.setText(deviceResolution);
        deviceDensityLabel.setText(deviceDensity);
        deviceApiLabel.setText(deviceApi);
        deviceReleaseLabel.setText(deviceRelease);

        return view;
    }

    private static String truncateAt(String string, int length) {
        return string.length() > length ? string.substring(0, length) : string;
    }

    private static String getDensityString(DisplayMetrics displayMetrics) {
        switch (displayMetrics.densityDpi) {
            case DisplayMetrics.DENSITY_LOW:
                return "ldpi";
            case DisplayMetrics.DENSITY_MEDIUM:
                return "mdpi";
            case DisplayMetrics.DENSITY_HIGH:
                return "hdpi";
            case DisplayMetrics.DENSITY_XHIGH:
                return "xhdpi";
            case DisplayMetrics.DENSITY_XXHIGH:
                return "xxhdpi";
            case DisplayMetrics.DENSITY_XXXHIGH:
                return "xxxhdpi";
            case DisplayMetrics.DENSITY_TV:
                return "tvdpi";
            default:
                return String.valueOf(displayMetrics.densityDpi);
        }
    }
} public class NetworkModule extends DebugModuleAdapter {

    private NetworkController networkController;

    private Switch wifi;
    private Switch mobile;
    private Switch bluetooth;

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final Context context = parent.getContext().getApplicationContext();
        final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_network, parent, false);

        wifi = view.findViewById(R.id.dd_debug_network_wifi);
        mobile = view.findViewById(R.id.dd_debug_network_mobile);
        // In JellyBean 4.2, mobile network settings are only accessible from system apps
        final boolean mobileToggleAvailable = Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1;
        mobile.setVisibility(mobileToggleAvailable ? View.VISIBLE : View.GONE);
        view.findViewById(R.id.dd_debug_network_mobile_label).setVisibility(mobileToggleAvailable ? View.VISIBLE : View.GONE);
        bluetooth = view.findViewById(R.id.dd_debug_network_bluetooth);

        networkController = NetworkController.newInstance(context);

        wifi.setChecked(wifiManager.isWifiEnabled());
        wifi.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton button, boolean isChecked) {
                wifiManager.setWifiEnabled(isChecked);
            }
        });

        mobile.setChecked(isMobileNetworkEnabled(connectivityManager));
        mobile.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton button, boolean isChecked) {
                setMobileNetworkEnabled(connectivityManager, isChecked);
            }
        });

        if (bluetoothAdapter != null) {
            bluetooth.setChecked(hasBluetoothPermission(context) && bluetoothAdapter.isEnabled());
            bluetooth.setOnCheckedChangeListener(
                new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton button, boolean isChecked) {
                        if (isChecked) {
                            bluetoothAdapter.enable();
                        } else {
                            bluetoothAdapter.disable();
                        }
                    }
                });
        } else {
            bluetooth.setEnabled(false);
        }

        return view;
    }

    @Override
    public void onStop() {
        networkController.setOnNetworkChangedListener(null);
        networkController.unregisterReceiver();
    }

    @Override
    public void onStart() {
        networkController.setOnNetworkChangedListener(onNetworkChangedListener);
        networkController.registerReceiver();
    }

    /**
     * True if mobile network enabled
     */
    private boolean isMobileNetworkEnabled(ConnectivityManager connectivityManager) {
        final NetworkInfo info = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        return (info != null && info.isConnected());
    }

    /**
     * http://stackoverflow.com/questions/11555366/enable-disable-data-connection-in-android-programmatically
     * Try to enabled/disable mobile network state using reflection.
     * Returns true if succeeded
     *
     * @param enabled
     */
    private boolean setMobileNetworkEnabled(ConnectivityManager connectivityManager, boolean enabled) {
        try {
            final Class conmanClass = Class.forName(connectivityManager.getClass().getName());
            final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
            iConnectivityManagerField.setAccessible(true);
            final Object iConnectivityManager = iConnectivityManagerField.get(connectivityManager);
            final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
            final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
            setMobileDataEnabledMethod.setAccessible(true);
            setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
            return true;
        } catch (ClassNotFoundException e) {
        } catch (InvocationTargetException e) {
        } catch (NoSuchMethodException e) {
        } catch (IllegalAccessException e) {
        } catch (NoSuchFieldException e) {
        }
        return false;
    }

    private boolean hasBluetoothPermission(Context context) {
        return context.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED;
    }

    private NetworkController.OnNetworkChangedListener onNetworkChangedListener = new NetworkController.OnNetworkChangedListener() {
        @Override
        public void onChanged(NetworkController.NetworkChangeEvent event) {
            if (wifi != null) {
                wifi.setChecked(event.wifiState == NetworkInfo.State.CONNECTED
                    || event.wifiState == NetworkInfo.State.CONNECTING);
            }
            if (mobile != null) {
                mobile.setChecked(event.mobileState == NetworkInfo.State.CONNECTED
                    || event.mobileState == NetworkInfo.State.CONNECTING);
            }
            if (bluetooth != null) {
                bluetooth.setChecked(event.bluetoothState == NetworkController.BluetoothState.ON
                    || event.bluetoothState == NetworkController.BluetoothState.TURNING_ON);
            }
        }
    };
} public class SettingsModule extends DebugModuleAdapter implements View.OnClickListener {

    private LinearLayout developer;
    private LinearLayout battery;
    private LinearLayout settings;
    private LinearLayout info;
    private LinearLayout uninstall;
    private LinearLayout location;

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_settings, parent, false);
        view.setClickable(false);
        view.setEnabled(false);

        developer = view.findViewById(R.id.dd_debug_settings_developer);
        battery = view.findViewById(R.id.dd_debug_settings_batery);
        settings = view.findViewById(R.id.dd_debug_settings_settings);
        info = view.findViewById(R.id.dd_debug_settings_info);
        uninstall = view.findViewById(R.id.dd_debug_settings_delete);
        location = view.findViewById(R.id.dd_debug_location_settings);

        developer.setOnClickListener(this);
        battery.setOnClickListener(this);
        settings.setOnClickListener(this);
        info.setOnClickListener(this);
        uninstall.setOnClickListener(this);
        location.setOnClickListener(this);
        return view;
    }

    @Override
    public void onClick(View v) {
        final Context context = v.getContext();
        if (v == developer) {
            // open dev settings
            Intent devIntent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
            devIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(devIntent, 0);
            if (resolveInfo != null) {
                context.startActivity(devIntent);
            } else {
                Toast.makeText(context, "Developer settings not available on device", Toast.LENGTH_SHORT).show();
            }
        } else if (v == battery) {
            // try to find an app to handle battery settings
            Intent batteryIntent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
            batteryIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(batteryIntent, 0);
            if (resolveInfo != null) {
                context.startActivity(batteryIntent);
            } else {
                Toast.makeText(context, "No app found to handle power usage intent", Toast.LENGTH_SHORT).show();
            }
        } else if (v == settings) {
            // open android settings
            Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
            settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(settingsIntent);
        } else if (v == info) {
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setData(Uri.parse("package:" + context.getPackageName()));
            context.startActivity(intent);
        } else if (v == uninstall) {
            // open dialog to uninstall app
            Uri packageURI = Uri.parse("package:" + context.getPackageName());
            Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
            context.startActivity(uninstallIntent);
        } else if (v == location) {
            Intent locationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            locationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(locationIntent);
        }
    }
} public class FpsModule extends DebugModuleAdapter {

    private static final boolean HAS_TAKT;

    static {
        boolean hasDependency;

        try {
            Class.forName("jp.wasabeef.takt.Takt");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_TAKT = hasDependency;
    }

    private final Takt.Program program;

    private boolean isChecked;

    public FpsModule(@NonNull Takt.Program program) {
        if (!HAS_TAKT) {
            throw new RuntimeException("Takt dependency is not found");
        }

        this.program = program;
    }

    @Override
    @NonNull
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_item_fps, parent, false);
        final Switch showSwitch = (Switch) view.findViewById(R.id.dd_debug_fps);
        showSwitch.setOnCheckedChangeListener(
            new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton button, boolean isChecked) {
                    FpsModule.this.isChecked = isChecked;
                    if (isChecked) {
                        program.play();
                    } else {
                        program.stop();
                    }
                }
            });
        return view;
    }

    @Override
    public void onResume() {
        if (isChecked) {
            program.play();
        }
    }

    @Override
    public void onPause() {
        if (isChecked) {
            program.stop();
        }
    }
} public class GlideModule extends DebugModuleAdapter {

    private static final boolean HAS_GLIDE;

    static {
        boolean hasDependency;

        try {
            Class.forName("com.bumptech.glide.Glide");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_GLIDE = hasDependency;
    }

    @NonNull
    private final Glide glide;
    @NonNull
    private final MemoryCache memoryCache;

    private TextView poolSizeLabel;
    private TextView memCacheCurrentLabel;
    private TextView memCacheMaxLabel;
    private Button memCacheClearButton;
    private Button diskCacheClearButton;

    public GlideModule(@NonNull Glide glide) {
        if (!HAS_GLIDE) {
            throw new RuntimeException("Glide dependency is not found");
        }

        this.glide = glide;

        try {
            final Class<?> glideClass = glide.getClass();
            final Field field = glideClass.getDeclaredField("memoryCache");
            field.setAccessible(true);
            this.memoryCache = (MemoryCache) field.get(glide);
        } catch (Throwable t) {
            throw new RuntimeException("Incompatible Glide version", t);
        }
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_item_glide, parent, false);

        poolSizeLabel = view.findViewById(R.id.dd_debug_glide_pool_size);
        memCacheCurrentLabel = view.findViewById(R.id.dd_debug_glide_memcache_current);
        memCacheMaxLabel = view.findViewById(R.id.dd_debug_glide_memcache_max);
        memCacheClearButton = view.findViewById(R.id.dd_button_clear_memcache);
        diskCacheClearButton = view.findViewById(R.id.dd_button_clear_diskcache);

        memCacheClearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                glide.clearMemory();
                refresh();
            }
        });

        diskCacheClearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // Needs to be called on a background thread
                        glide.clearDiskCache();
                    }
                }).start();
            }
        });
        refresh();
        return view;
    }

    @Override
    public void onOpened() {
        refresh();
    }

    @Override
    public void onResume() {
        refresh();
    }

    private void refresh() {
        final BitmapPool pool = glide.getBitmapPool();

        final String total = getSizeString(pool.getMaxSize());
        final String memCacheCurrent = getSizeString(memoryCache.getCurrentSize());
        final String memCacheMax = getSizeString(memoryCache.getMaxSize());

        poolSizeLabel.setText(total);
        memCacheCurrentLabel.setText(memCacheCurrent);
        memCacheMaxLabel.setText(memCacheMax);
    }

    private static String getSizeString(long bytes) {
        final String[] units = new String[]{"B", "KB", "MB", "GB"};
        int unit = 0;
        while (bytes >= 1024) {
            bytes /= 1024;
            unit += 1;
        }
        return bytes + units[unit];
    }
} public class LocationModule implements DebugModule {

    private static final boolean HAS_LOCATION;

    static {
        boolean hasDependency;

        try {
            Class.forName("com.google.android.gms.location.LocationRequest");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_LOCATION = hasDependency;
    }


    private final LocationRequest locationRequest;

    private WeakReference<Context> contextRef;

    private boolean hasPermission;

    @Nullable
    private LocationController locationController;

    private TextView latitude;

    private TextView longitude;

    private TextView accuracy;

    private TextView time;

    private TextView provider;

    private Location location;

    private boolean opened;

    public LocationModule() {
        this(true);
    }

    /**
     * @param locationRequestsAvailable defines if location should be updated every 10 seconds
     */
    public LocationModule(boolean locationRequestsAvailable) {
        this(HAS_LOCATION && locationRequestsAvailable ? new LocationRequest()
            .setInterval(TimeUnit.SECONDS.toMillis(10))
            .setFastestInterval(TimeUnit.SECONDS.toMillis(5))
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) : null);
    }

    public LocationModule(long interval, long fastestInterval) {
        this(HAS_LOCATION ? new LocationRequest()
            .setInterval(interval)
            .setFastestInterval(fastestInterval)
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) : null);
    }

    public LocationModule(LocationRequest locationRequest) {
        if (!HAS_LOCATION) {
            throw new RuntimeException("Google Play location dependency is not found");
        }
        this.locationRequest = locationRequest;
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        if (contextRef == null) {
            contextRef = new WeakReference<>(parent.getContext());
        }

        final Context context = contextRef.get();

        checkPermission();
        final GoogleApiAvailability api = GoogleApiAvailability.getInstance();
        final boolean available = api.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
        if (available && hasPermission) {
            locationController = LocationController.newInstance(context);
            if (locationRequest != null) {
                locationController.setLocationRequest(locationRequest);
            }
        }

        if (locationController != null && hasPermission) {
            final View view = inflater.inflate(R.layout.dd_debug_drawer_module_location, parent, false);
            latitude = (TextView) view.findViewById(R.id.dd_debug_location_latitude);
            longitude = (TextView) view.findViewById(R.id.dd_debug_location_longitude);
            accuracy = (TextView) view.findViewById(R.id.dd_debug_location_accuracy);
            time = (TextView) view.findViewById(R.id.dd_debug_location_time);
            provider = (TextView) view.findViewById(R.id.dd_debug_location_provider);
            view.findViewById(R.id.dd_debug_location_map).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        openMaps(context);
                    }
                });
            locationController.setLocationListener(new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    if (opened) {
                        updateLocation(location);
                    }
                }
            });
            updateLastLocation();
            return view;
        } else if (!hasPermission) {
            final TextView errorText = new TextView(context);
            errorText.setTextAppearance(context, R.style.Widget_DebugDrawer_Base_Header);
            errorText.setText(R.string.dd_debug_drawer_location_no_permission);
            return errorText;
        } else {
            final TextView errorText = new TextView(context);
            errorText.setTextAppearance(context, R.style.Widget_DebugDrawer_Base_Header);
            errorText.setText(R.string.dd_debug_drawer_location_google_play_unavailable);
            return errorText;
        }
    }

    @Override
    public void onOpened() {
        updateLastLocation();
        opened = true;
    }

    @Override
    public void onClosed() {
        opened = false;
    }

    @Override
    public void onResume() {
        updateLastLocation();
        opened = true;
    }

    @Override
    public void onPause() {
        opened = false;
    }

    private void updateLastLocation() {
        if (locationController != null) {
            final Location lastLocation = locationController.getLastLocation();
            updateLocation(lastLocation);
        }
    }

    private void updateLocation(Location location) {
        if (location != null) {
            this.location = location;
            latitude.setText(String.valueOf(location.getLatitude()));
            longitude.setText(String.valueOf(location.getLongitude()));
            accuracy.setText(String.valueOf(location.getAccuracy()) + "m");

            final Date date = new Date(location.getTime());
            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            time.setText(sdf.format(date));
            provider.setText(location.getProvider());
        } else {
            latitude.setText(R.string.dd_debug_drawer_location_empty);
            longitude.setText(R.string.dd_debug_drawer_location_empty);
            accuracy.setText(R.string.dd_debug_drawer_location_empty);
            time.setText(R.string.dd_debug_drawer_location_empty);
            provider.setText(R.string.dd_debug_drawer_location_no_provider);
        }
    }

    @Override
    public void onStart() {
        if (locationController != null) {
            checkPermission();
            locationController.startLocationUpdates();
        }
    }

    @Override
    public void onStop() {
        if (locationController != null) {
            locationController.stopLocationUpdates();
        }
    }

    private void openMaps(Context context) {
        try {
            if (location != null) {
                final String uri = "geo:" + location.getLatitude() + "," + location.getLongitude();
                final Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri));
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            } else {
                Toast.makeText(context, R.string.dd_debug_drawer_location_not_found, Toast.LENGTH_SHORT).show();
            }
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, R.string.dd_debug_drawer_location_map_not_found, Toast.LENGTH_SHORT).show();
        }
    }

    private void checkPermission() {
        final Context context = contextRef.get();
        if (context != null) {
            hasPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED;
        }
    }
} public class LogsModule extends DebugModuleAdapter {

    private static final boolean HAS_LYNX;
    private static final boolean HAS_CHUCK;

    static {
        boolean hasDependencyLynx;
        boolean hasDependencyChuck;

        try {
            Class.forName("com.github.pedrovgs.lynx.LynxActivity");
            hasDependencyLynx = true;
        } catch (ClassNotFoundException e) {
            hasDependencyLynx = false;
        }

        try {
            Class.forName("com.readystatesoftware.chuck.Chuck");
            hasDependencyChuck = true;
        } catch (ClassNotFoundException e) {
            hasDependencyChuck = false;
        }

        HAS_LYNX = hasDependencyLynx;
        HAS_CHUCK = hasDependencyChuck;
    }

    private final LynxConfig lynxConfig;

    public LogsModule() {
        this(null);
    }

    public LogsModule(@Nullable LynxConfig lynxConfig) {
        this.lynxConfig = lynxConfig;
    }

    public static Interceptor chuckInterceptor(Context context) {
        if (!HAS_CHUCK) {
            throw new RuntimeException("Chuck dependency is not found");
        }
        return new ChuckInterceptor(context).showNotification(false);
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_module_logs, parent, false);
        view.findViewById(R.id.dd_module_logs_logcat).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!HAS_LYNX) {
                    throw new RuntimeException("Lynx dependency is not found");
                } else {
                    if (lynxConfig != null) {
                        view.getContext().startActivity(LynxActivity.getIntent(view.getContext(), lynxConfig));
                    } else {
                        view.getContext().startActivity(LynxActivity.getIntent(view.getContext()));
                    }
                }
            }
        });

        view.findViewById(R.id.dd_module_logs_chuck).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!HAS_CHUCK) {
                    throw new RuntimeException("Chuck dependency is not found");
                } else {
                    view.getContext().startActivity(Chuck.getLaunchIntent(view.getContext()));
                }
            }
        });

        return view;
    }
} public class NetworkQualityModule extends DebugModuleAdapter {

    private static final boolean HAS_OKHTTP3;

    static {
        boolean hasDependency;

        try {
            Class.forName("okhttp3.OkHttpClient");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_OKHTTP3 = hasDependency;
    }

    public static Interceptor interceptor(Context context) {
        if (!HAS_OKHTTP3) {
            throw new RuntimeException("OkHttp3 dependency is not found");
        }
        return new NetworkQualityInterceptor(new NetworkQualityConfig(context));
    }

    private static final List<Integer> DELAY_VALUES = Arrays.asList(0, 500, 1000, 2000, 3000, 5000, 10000);
    private static final List<Integer> ERROR_VALUES = Arrays.asList(0, 3, 10, 25, 50, 100);

    private final NetworkQualityConfig networkQualityConfig;

    private Switch enabledSwitch;
    private SeekBar delaySeekBar;
    private SeekBar errorSeekBar;

    public NetworkQualityModule(@NonNull Context context) {
        if (!HAS_OKHTTP3) {
            throw new RuntimeException("OkHttp3 dependency is not found");
        }
        this.networkQualityConfig = new NetworkQualityConfig(context);
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_module_network, parent, false);
        enabledSwitch = view.findViewById(R.id.dd_module_networkquality_enabled);
        enabledSwitch.setSaveEnabled(false);
        enabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                networkQualityConfig.networkEnabled(isChecked);
                delaySeekBar.setEnabled(isChecked);
                errorSeekBar.setEnabled(isChecked);
            }
        });

        final TextView delayIndicator = view.findViewById(R.id.debug_network_delay_indicator);
        delaySeekBar = view.findViewById(R.id.debug_network_delay);
        delaySeekBar.setSaveEnabled(false);
        delaySeekBar.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                delaySeekBar.getParent().requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        delaySeekBar.setMax(DELAY_VALUES.size() - 1);
        delaySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                int delay = DELAY_VALUES.get(progress);
                networkQualityConfig.delayMs(delay);
                delayIndicator.setText(delay(delay));
                setThemeColor(delayIndicator, progress == 0 ? android.R.attr.textColorSecondary : R.attr.colorAccent);

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        final TextView errorIndicator = view.findViewById(R.id.debug_network_error_indicator);
        errorSeekBar = view.findViewById(R.id.debug_network_error);
        errorSeekBar.setSaveEnabled(false);
        errorSeekBar.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                errorSeekBar.getParent().requestDisallowInterceptTouchEvent(true);
                return false;
            }
        });
        errorSeekBar.setMax(ERROR_VALUES.size() - 1);
        errorSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                int errorPercentage = ERROR_VALUES.get(progress);
                networkQualityConfig.errorPercentage(errorPercentage);
                errorIndicator.setText(errorPercentage + "%");

                setThemeColor(errorIndicator, progress == 0 ? android.R.attr.textColorSecondary : R.attr.colorAccent);

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        enabledSwitch.setChecked(networkQualityConfig.networkEnabled());
        delaySeekBar.setProgress(DELAY_VALUES.indexOf(networkQualityConfig.delayMs()));
        errorSeekBar.setProgress(ERROR_VALUES.indexOf(networkQualityConfig.errorPercentage()));
    }

    private String delay(int delay) {
        final String text;
        if (delay == 0) {
            text = "0s";
        } else if (delay % 1000 == 0) {
            text = delay / 1000.0 + "s";
        } else {
            text = ((float) delay) / 1000.0 + "s";
        }
        return text;
    }

    private void setThemeColor(TextView textView, @AttrRes int colorAttr) {
        TypedValue typedValue = new TypedValue();

        TypedArray a = textView.getContext().obtainStyledAttributes(typedValue.data, new int[]{colorAttr});
        int color = a.getColor(0, 0);

        a.recycle();

        textView.setTextColor(color);
    }
} public class OkHttp3Module extends DebugModuleAdapter {

    private static final boolean HAS_OKHTTP3;

    static {
        boolean hasDependency;

        try {
            Class.forName("okhttp3.OkHttpClient");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_OKHTTP3 = hasDependency;
    }

    private final OkHttpClient client;

    private TextView okHttpCacheMaxSizeView;

    private TextView okHttpCacheWriteErrorView;

    private TextView okHttpCacheRequestCountView;

    private TextView okHttpCacheNetworkCountView;

    private TextView okHttpCacheHitCountView;

    public OkHttp3Module(@NonNull OkHttpClient client) {
        if (!HAS_OKHTTP3) {
            throw new RuntimeException("OkHttp3 dependency is not found");
        }
        this.client = client;
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_okhttp3, parent, false);

        okHttpCacheMaxSizeView = view.findViewById(R.id.dd_debug_okhttp_cache_max_size);
        okHttpCacheWriteErrorView = view.findViewById(R.id.dd_debug_okhttp_cache_write_error);
        okHttpCacheRequestCountView = view.findViewById(R.id.dd_debug_okhttp_cache_request_count);
        okHttpCacheNetworkCountView = view.findViewById(R.id.dd_debug_okhttp_cache_network_count);
        okHttpCacheHitCountView = view.findViewById(R.id.dd_debug_okhttp_cache_hit_count);

        okHttpCacheMaxSizeView.setText(sizeString(maxSize()));

        view.findViewById(R.id.dd_debug_okhttp_cache_clear).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                clearCache();
            }
        });

        refresh();
        return view;
    }

    private void refresh() {
        final int writeTotal = writeSuccessCount() + writeAbortCount();
        final int percentage = (int) ((1f * writeAbortCount() / writeTotal) * 100);
        okHttpCacheWriteErrorView.setText(
            new StringBuilder().append(writeAbortCount())
                .append(" / ")
                .append(writeTotal)
                .append(" (")
                .append(percentage)
                .append("%)")
                .toString()
        );
        okHttpCacheRequestCountView.setText(String.valueOf(requestCount()));
        okHttpCacheNetworkCountView.setText(String.valueOf(networkCount()));
        okHttpCacheHitCountView.setText(String.valueOf(hitCount()));
    }

    @Override
    public void onOpened() {
        refresh();
    }

    private void clearCache() {
        try {
            client.cache().evictAll();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private long maxSize() {
        return client.cache().maxSize();
    }

    private int writeSuccessCount() {
        return client.cache().writeSuccessCount();
    }

    private int writeAbortCount() {
        return client.cache().writeAbortCount();
    }

    private int requestCount() {
        return client.cache().requestCount();
    }

    private int networkCount() {
        return client.cache().networkCount();
    }

    private int hitCount() {
        return client.cache().hitCount();
    }

    private static String sizeString(long bytes) {
        final String[] units = new String[]{"B", "KB", "MB", "GB"};
        int unit = 0;
        while (bytes >= 1024) {
            bytes /= 1024;
            unit += 1;
        }
        return bytes + units[unit];
    }
} public class ScalpelModule extends DebugModuleAdapter {

    private static final boolean HAS_SCALPEL;

    static {
        boolean hasDependency;

        try {
            Class.forName("com.jakewharton.scalpel.ScalpelFrameLayout");
            hasDependency = true;
        } catch (ClassNotFoundException e) {
            hasDependency = false;
        }

        HAS_SCALPEL = hasDependency;
    }

    private final Context context;
    private ViewGroup rootView;

    public ScalpelModule(@NonNull Activity activity) {
        if (!HAS_SCALPEL) {
            throw new RuntimeException("Scalpel dependency is not found");
        }
        context = activity;
        rootView = (ViewGroup) activity.findViewById(android.R.id.content);
    }

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {

        final ViewGroup contentView = (ViewGroup) rootView.getChildAt(0);
        final ViewGroup scrimInsets = (ViewGroup) contentView.getChildAt(0);
        final View contentRelativeView = scrimInsets.getChildAt(0);

        scrimInsets.removeView(contentRelativeView);

        final ScalpelFrameLayout scalpelFrameLayout = new ScalpelFrameLayout(context);
        scalpelFrameLayout.setLayoutParams(new LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT));
        scrimInsets.addView(scalpelFrameLayout);
        scalpelFrameLayout.addView(contentRelativeView);

        final View view = inflater.inflate(R.layout.dd_debug_drawer_item_scalpel, parent, false);
        final Switch debugEnableScalpel = view.findViewById(R.id.dd_debug_enable_scalpel);
        debugEnableScalpel.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                scalpelFrameLayout.setLayerInteractionEnabled(isChecked);
            }
        });
        final Switch debugDisableGraphics = view.findViewById(R.id.dd_debug_disable_graphics);
        debugDisableGraphics.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                scalpelFrameLayout.setDrawViews(!isChecked);
            }
        });
        final Switch debugShowIds = view.findViewById(R.id.dd_debug_show_ids);
        debugShowIds.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                scalpelFrameLayout.setDrawIds(isChecked);
            }
        });

        return view;
    }
} public class TimberModule extends DebugModuleAdapter {

    @NonNull
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @NonNull final ViewGroup parent) {
        final View view = inflater.inflate(R.layout.dd_debug_drawer_module_log, parent, false);

        view.findViewById(R.id.dd_button_log).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new LogDialog(parent.getContext()).show();
            }
        });

        return view;
    }
}
import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.palaima.debugdrawer.DebugDrawer;
import io.palaima.debugdrawer.actions.ActionsModule;
import io.palaima.debugdrawer.actions.ButtonAction;
import io.palaima.debugdrawer.actions.SpinnerAction;
import io.palaima.debugdrawer.actions.SwitchAction;
import io.palaima.debugdrawer.commons.BuildModule;
import io.palaima.debugdrawer.commons.DeviceModule;
import io.palaima.debugdrawer.commons.NetworkModule;
import io.palaima.debugdrawer.commons.SettingsModule;
import io.palaima.debugdrawer.fps.FpsModule;
import io.palaima.debugdrawer.glide.GlideModule;
import io.palaima.debugdrawer.location.LocationModule;
import io.palaima.debugdrawer.logs.LogsModule;
import io.palaima.debugdrawer.network.quality.NetworkQualityModule;
import io.palaima.debugdrawer.okhttp3.OkHttp3Module;
import io.palaima.debugdrawer.scalpel.ScalpelModule;
import io.palaima.debugdrawer.timber.TimberModule;
import jp.wasabeef.takt.Takt;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import timber.log.Timber;
package io.palaima.debugdrawer.app;





public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;

    private OkHttpClient okHttpClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        okHttpClient = createOkHttpClientBuilder(this.getApplication()).build();

        setupToolBar();

        SwitchAction switchAction = new SwitchAction("Test switch", new SwitchAction.Listener() {