Android 3.0中有隐藏系统栏的方法吗?这是一台内部设备,我正在管理导航。

32

在Android 2.3及以下版本,您可以使应用程序全屏,然后通过仅返回false onKeyDown()来“劫持”菜单/后退/搜索按钮...并将应用程序注册为默认的主屏幕启动器应用程序,这样就没有退出应用程序的方式。

在Android 3.0(Honeycomb)中,导航按钮(系统栏)始终存在,我想隐藏它。是否可能?

顺便说一下,我不会在Android Market上发布此应用程序。这是一个内部应用程序,专门为将要在内部使用的设备而设计的。我需要保护设备安全。


2
我很喜欢你加上FYI,以防有人指责你劫持Android设备的行为。 :) - Codemonkey
1
是的,我必须这样做,否则我知道答案会变成什么样子。 - velazcod
Duplicate https://dev59.com/DlbUa4cB1Zd3GeqPCddL - Gu1234
不一定,而且无论如何,要看问题被提出的日期有什么不同。 - velazcod
如果你认为这是重复的,那么你误解了问题。 - Fuzzy
这是非常古老的内容,但在寻找如何隐藏导航栏时总是会出现,因此我包括了来自4.4的内容。 https://developer.android.com/training/system-ui/immersive.html - Dominic Cerisano
11个回答

31

由于公共API无法实现此操作,我找到了一种非常“hack-ish”的方法来实现它,需要使用rooted设备。

更新:正如用户864555所指出的,这是另一种解决方案

$ adb remount
$ adb shell mv /system/app/SystemUI.odex /system/app/SystemUI.odexold
$ adb shell mv /system/app/SystemUI.apk /system/app/SystemUI.apkold
$ adb reboot

那段代码禁用了实际上是菜单栏的应用程序SystemUI。通过这种修改,您还将获得该系统栏的空间。但请确保有返回按钮或其他东西可供退出。

那也很好用。请投票支持他的答案。我会尽力使此答案保持更新。


更新: 这里有第三种方法。一种通过编程或使用命令行执行它的方式。 在此处找到:http://android.serverbox.ch/?p=306

此方法需要root访问权限,但您无需更改LCD密度,与原始密度相同,并且可以在不必每次重新启动的情况下轻松快速地获取UI导航栏。

这篇博客文章还展示了如何在Android应用程序中实现它,请记住它需要root权限,除非您的应用程序运行在信息亭或自己的设备上,否则不要在已发布在Android市场或任何公共场合的应用程序上实施此方法。

停止/删除/禁用系统栏(在发出此命令之前需要su):

$ service call activity 79 s16 com.android.systemui

要恢复系统栏,只需执行以下命令:

$ am startservice -n com.android.systemui/.SystemUIService

就这么简单。希望ICS尽快发布并附带源代码,这样任何人都可以为我们的Kiosk平板建立Android。


我在我的build.prop文件中找不到ro.sf.lcd_density=240(Acer Iconia A500平板电脑使用Samsung Galaxy 10.1 Rom进行root)。对于第二种方法,也找不到SystemUI.odex(honeycomb)。只需将SystemUI.apk重命名即可,看起来它正在工作,谢谢。 - Indrek Kõue
只要你的构建是deodexed,并且在你的端上也是这种情况,那就可以正常工作。你可能还想恢复并检查此应用程序:https://market.android.com/details?id=com.tlalexander.tabletbarhider(不是我的,但它使用了我上面发布的最后一种方法)。 - velazcod
服务调用和文件名更改使得在三星Fame手机上无法接收电话。 - sherif

11

在 Android 3.0 上,您无法隐藏系统栏。


2
这有点糟糕,连电子游戏或电影也不行吗? - Nathan Schwermann
4
您可以将系统栏置于“暗光模式”,使所有按钮和通知都变暗/隐藏。之前您可以进入全屏模式,因为设备必须具有硬件主页按钮,但现在不再是这种情况。用户必须始终能够按 HOME 键。 - Romain Guy
我知道这一点,但“灯光关闭”只会使按钮暂时不可见,而不是禁用它们。是的,用户必须始终能够点击主页,但仅此而已。我通过声明自己的私有应用程序为默认主屏幕启动器并劫持主屏幕来解决了这个问题。这基本上是从开发人员那里夺走控制权。我使用Android设备将它们提供给员工,并在其上运行内部私有应用程序,但我需要避免他们使用其他任何东西,以前我可以,现在我不能这样做。 - velazcod
13
你意识到即使在手机上,用户也可以通过安全模式重启(开机期间按住Home键),禁用所有第三方应用程序(包括你的应用程序),运行标准应用程序/卸载第三方应用程序吗?Android旨在确保用户始终掌控其设备。 - Romain Guy
把我算作另一个对Honeycomb的这个特性感到非常失望的开发者。我们的应用面向2-8岁的儿童,必须提供一种阻止导航按钮退出到正常Android环境的方法 - 这是为了防止孩子意外运行其他应用程序、删除项目或以其他方式搞乱设备。(我们给父母恢复控制设备的方法)。"灯光熄灭"模式不足以满足需求。我希望Android团队能够给开发者提供我们需要解决他们没有考虑到的用例的工具,并相信我们会做正确的事情。 - mportuesisf
显示剩余4条评论

7
如果您可以访问系统文件,您可以这样做(我的设备已经解锁和获取了root权限,所以我不确定您需要什么,我没有尝试过在出厂状态的xoom上进行操作):
adb shell
cd /system/app/
mv SystemUI.odex SystemUI.odexold
mv SystemUI.apk SystemUI.apkold
exit
adb reboot

那段代码禁用了实际菜单栏的应用程序SystemUI。通过这种修改,您还将获得该系统栏的空间,但请确保您的应用程序具有返回按钮或其他退出功能。
编辑:
如果您遇到只读文件的问题,则需要将 /system 目录挂载为可读写模式。要这样做,请在 adb shell 中使用此命令(来源:http://forum.xda-developers.com/showthread.php?t=1159495&page=5)。
mount -o remount,rw /dev/block/stl6 /system

您可以使用以下命令将其重新挂载为只读:

mount -o remount,ro [文件系统路径]

mount -o remount,ro /dev/block/stl6 /system

编辑:

这些方法允许在需要时正常显示软键盘。


很好,我认为这可能是一个更好的解决方案,在我看来。谢谢。 - velazcod
是的,它非常适合用于展示模式,我认为你无法使用它来制作恶意程序。所以它非常好。 - darkzangel
同意。嘿,在adb shell之前,您可以执行adb remount,然后您就不需要手动挂载-rw了,它也是设备无关的 ;) - velazcod

1

这里是与我之前回答相关的代码。它会自动隐藏状态栏,并在完成后再次显示出来。重要提示:为了再次显示它,代码必须重新启动system_server,这需要一些时间来重新启动,而在此期间,您将看到蜂窝引导动画。目前这是我找到的唯一方法来再次显示状态栏。重新启动SystemUI不足以解决问题。因此,在重新启动system_server时,它将关闭您的应用程序。

此代码需要已安装超级用户的rooted操作系统。

package com.projects;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TableLayout.LayoutParams;

// http://www.stealthcopter.com/blog/2010/01/android-requesting-root-access-in-your-app/
public class FullScreenTestActivity extends Activity implements Button.OnClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try
        {
            Process p;
            p = Runtime.getRuntime().exec("su"); 

            // Attempt to write a file to a root-only
            DataOutputStream os = new DataOutputStream(p.getOutputStream());
            os.writeBytes("mount -o remount,rw /dev/block/stl6 /system\n");
            os.writeBytes("mv /system/app/SystemUI.odex /system/app/SystemUI_Old.odex\n");
            os.writeBytes("mv /system/app/SystemUI.apk /system/app/SystemUI_Old.apk\n");
            os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");

            // Close the terminal
            os.writeBytes("exit\n");
            os.flush();
            p.waitFor();

            new AlertDialog.Builder(this)
                .setIconAttribute(android.R.attr.alertDialogIcon)
                .setMessage("Android Honeycomb StatusBar removed successfully!")
                .show();

            // Set action for exiting.
            Button cmdExit = new Button(this);
            cmdExit.setText("Exit");
            cmdExit.setOnClickListener(this);
            this.addContentView(cmdExit, new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
        }
        catch (Exception e)
        {
            ShowErrorGlobal(e);
        }
    }

    public void onClick(View v) {
        try
        {
            Process p;
            p = Runtime.getRuntime().exec("su"); 

            // Attempt to write a file to a root-only
            DataOutputStream os = new DataOutputStream(p.getOutputStream());
            os.writeBytes("mount -o remount,rw /dev/block/stl6 /system\n");
            os.writeBytes("mv /system/app/SystemUI_Old.odex /system/app/SystemUI.odex\n");
            os.writeBytes("mv /system/app/SystemUI_Old.apk /system/app/SystemUI.apk\n");
            os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");
            String systemServerPID = GetSystemServerPID();
            if (systemServerPID != null)
                os.writeBytes("kill " + systemServerPID + "\n");
            // else ... manual reboot is required if systemServerPID fail.

            // Close the terminal
            os.writeBytes("exit\n");
            os.flush();
            p.waitFor();
        }
        catch (Exception e)
        {
            ShowErrorGlobal(e);
        }
    }

    public String GetSystemServerPID()
    {
        try
        {
            Process p = Runtime.getRuntime().exec("ps -n system_server"); 
            p.waitFor();

            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            reader.readLine(); // Skip header.
            return reader.readLine().substring(10, 16).trim();
        }
        catch (Exception e)
        {
            return null;
        }
    }

    protected void ShowErrorGlobal(Exception e)
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream stream = new PrintStream( baos );
        e.printStackTrace(stream);
        stream.flush();

        new AlertDialog.Builder(this)
            .setIconAttribute(android.R.attr.alertDialogIcon)
            .setTitle("Epic fail")
            .setMessage("Error: " + new String( baos.toByteArray() ))
            .show();
    }
}

系统服务器还有什么其他功能?禁用它会产生什么后果? - Pandalover

0

虽然这并没有回答关于“锁定”屏幕的问题,但您可以使用setSystemUiVisibility API(API级别11)在没有root权限的情况下隐藏状态栏。

以下是一些伪代码:

public MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstance) {
        //...
        final View mainView = findViewById(R.id.you_main_view_id);
        mainView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);

        //Register a listener for when the status bar is shown/hidden:
        final Context context = getApplicationContext();
        mainView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener () {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility == View.SYSTEM_UI_FLAG_VISIBLE)) {
                    //Do stuff here...pause the video/game?
                } else {
                    //Do other stuff here..resume the video/game?
                }
            }
        });
    }
}

这将隐藏状态栏,直到用户点击屏幕下沿,此时状态栏将被显示(几秒钟后它将再次被隐藏)。

请确保在您的清单中指定了targetSdkVersion="11"或更高版本。


0

应用程序HideBar可用于隐藏Android平板电脑(HC,ICS,JB)上的系统栏。它包含一个可选的展示模式,可用于完全锁定平板电脑,以及其他选项,如隐藏返回按钮。它是GPL软件。如果需要大量安装此应用程序,请联系开发人员(即我,在应用程序网站上查看电子邮件)。


您的链接说它隐藏了状态栏。但是OP问的是系统栏。 - user316117
@user316117 你说得对。应该是系统栏(systembar)。我会更新网站,将状态栏(statusbar)改为系统栏(systembar)。程序的最新版本已经进行了更正。 - ppareit

0

0

对于其他遇到这个问题的人:

如果您在AndroidManifest.xml文件中没有正确设置android:targetSdkVersion,那么setSystemUiVisibility将无效(与其他高级API不同,它们无论是否正确设置了targetSDKVersion都可以正常工作)。

我不小心将我的targetSdkVersion保留在8。将其提升到16立即使setSystemUIVisiblity产生了预期的效果。


0

如果您在设备上拥有 root 访问权限,是可以做到的。

通过终止 StatusBar 的进程并重新调用它,这段代码可以隐藏和显示 StatusBar。

package com.example.statusbar;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends Activity {

    String commandToExecute;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        commandToExecute = "/system/xbin/su";
        executeShellCommand(commandToExecute);

        Button btHideStatusBar = (Button) findViewById(R.id.buttonHide);
        Button btShowStatusBar = (Button) findViewById(R.id.buttonShow);


        btHideStatusBar.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                commandToExecute = "/system/xbin/su -c /system/bin/service call activity 42 s16 com.android.systemui";
                executeShellCommand(commandToExecute);

            }
        });

    btShowStatusBar.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {

            commandToExecute = "/system/xbin/su -c /system/bin/am startservice -n com.android.systemui/.SystemUIService";
            executeShellCommand(commandToExecute);

        }
    });

    }

    private boolean executeShellCommand(String command) {
        try {

            Runtime.getRuntime().exec(command);

            return true;
        } catch (Exception e) {
            return false;

        }
    }


}

-1

android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen

或者

mainView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE)

不,任务栏仍然存在,但使用三个灰点代替经典图标。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接