我正在我的公司部署一个应用程序来跟踪生产等。现在我想知道我应该如何实现一个隐藏的调试菜单。在我的C#程序中,我通常在主窗口的左下角制作一个2px乘2px隐藏按钮,但这对于Android触控应用来说似乎不切实际。如果出现问题,我需要有办法打开一个菜单,没有人知道如何打开它,也无法找到。我试过谷歌搜索,但我发现的是如何隐藏/禁用Android设置中的开发设置。
那么,如果不将其插入PC或必须转到单独的应用程序,这些问题的实用解决方案是什么?
答案 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
}
}