什么是实现隐藏调试选项的最佳方法?

时间:2018-01-25 11:03:57

标签: java android

我正在我的公司部署一个应用程序来跟踪生产等。现在我想知道我应该如何实现一个隐藏的调试菜单。在我的C#程序中,我通常在主窗口的左下角制作一个2px乘2px隐藏按钮,但这对于Android触控应用来说似乎不切实际。如果出现问题,我需要有办法打开一个菜单,没有人知道如何打开它,也无法找到。我试过谷歌搜索,但我发现的是如何隐藏/禁用Android设置中的开发设置。

那么,如果不将其插入PC或必须转到单独的应用程序,这些问题的实用解决方案是什么?

4 个答案:

答案 0 :(得分:1)

我的建议:在点击一些屏幕元素N次之后,然后打开一个输入对话框并询问一个导致隐藏调试屏幕的秘密。您可以创建一个“关于”菜单,该菜单指向一个不太有用的屏幕,其中包含应用程序的名称和版本,并在该屏幕上的某些标签或图像上编写“魔术点击”。

答案 1 :(得分:1)

这是一个建议:听多点触控模式(只有添加/删除触摸的顺序,而不是位置)。 在Activity.dispatchTouchEvent中很容易做到 在不干扰UI的情况下,很难偶然触发。

一个简单的实现(对不起它在Kotlin中,但在Java中翻译应该相当容易):

class DebuggableActivity : Activity() {

    // This pattern means :
    // 1, 2, 3, 4 : touch with 4 fingers (adding one at a time)
    // 3, 2 : removes 2 any touches (again one at a time)
    // 3, 2 : add, then remove one touch
    val pattern = listOf(1, 2, 3, 4, 3, 2, 3, 2)

    // current number of touches
    val pointers = mutableSetOf<Int>()

    // current position in pattern
    var patternIndex = 0

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        when (ev.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                // new gesture, reset
                pointers.clear()
                patternIndex = 0
                pointers.add(ev.getPointerId(ev.actionIndex))
                checkPattern()
            }

            MotionEvent.ACTION_POINTER_DOWN -> {
                // new touch
                pointers.add(ev.getPointerId(ev.actionIndex))
                checkPattern()
            }

            MotionEvent.ACTION_POINTER_UP -> {
                // touch released
                pointers.remove(ev.getPointerId(ev.actionIndex))
                checkPattern()
            }
        }

        return super.dispatchTouchEvent(ev)
    }

    fun checkPattern() {
        if (pattern[patternIndex] == pointers.size) {
            // progressing

            patternIndex++

            if (patternIndex == pattern.size) {
                // triggered debug mode
                patternIndex = 0
                showDebugDialog()
            }
        } else {
            // failed, reset
            patternIndex = 0
        }
    }

    fun showDebugDialog() {
        AlertDialog.Builder(this)
        .setTitle("Debug mode")
        .setItems(arrayOf<String>("option 1", "option2", "option3"), { dialog, which ->
            Log.d(TAG, "Clicked on " + which)
        })
        .show()
    }

    ....

}

答案 2 :(得分:0)

@bwt的示例翻译成Java:

// Variables required
// Change pattern to indicate the sequence of touches required to activate
// the secret action.
private int[] pattern = {1, 2, 3, 4, 3, 2, 3, 2};
private HashSet pointers = new HashSet();
private int patternIndex = 0;

// We override dispatchTouchEvent and count the number of fingers down
// based on the values in pattern. See:
// https://stackoverflow.com/questions/48441348/whats-the-best-way-to-implement-hidden-debug-options
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    switch(ev.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            // new gesture, reset
            pointers.clear();
            patternIndex = 0;
            pointers.add(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
            checkPattern();
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            // new touch
            pointers.add(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
            checkPattern();
            break;
        case MotionEvent.ACTION_POINTER_UP:
            // touch released
            pointers.remove(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
            checkPattern();
    }
    return super.dispatchTouchEvent(ev);
}

private void checkPattern() {
    if (pattern[patternIndex] == pointers.size()) {
        // progressing
        patternIndex++;
        if (patternIndex == pattern.length) {
            // triggered, show debug screen
            patternIndex = 0;
            showDebugScreen();
        }
    } else {
        // reset
        patternIndex = 0;
    }
}

private void showDebugScreen() {
    // Open your diagnostic screen here.
}

一个有趣的增强功能是在showDebugScreen中检查文本小部件的值,如果没有特定值,则返回。这有助于减少用户通过敲打手机而偶然绊倒它的机会。

答案 3 :(得分:0)

受@bwt答案的启发,我更新了实现,使其具有基于手指数量的真实模式。

 // ---- DEBUG ----

// The number in the pattern means the number of fingers touching on the current activity.
private val pattern = listOf(1, 2, 3, 2, 1)

// current position in pattern
private var patternIndex = 0

private var shouldReadPointerCount = true
private var pointerCount = 0

override fun dispatchTouchEvent(event: MotionEvent): Boolean {
    val action: Int = event.action and MotionEvent.ACTION_MASK

    if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
        pointerCount = 0
        shouldReadPointerCount = true
    } else if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP) {
        if (shouldReadPointerCount) {
            pointerCount = event.pointerCount
            shouldReadPointerCount = false
        }
        if (event.pointerCount == pointerCount) {
            Log.i(TAG, pointerCount.toString())
            checkPattern(pointerCount)
        }
    }

    return super.dispatchTouchEvent(event)
}

private fun checkPattern(count: Int) {
    if (pattern[patternIndex] == count) {
        patternIndex++

        if (patternIndex == pattern.size) {
            patternIndex = 0
            showDebugDialog()
        }
    } else {
        patternIndex = 0
    }
}