android4.0屏蔽导航按钮的方法

最近做个ANDROID项目,需要屏蔽平板底层的导航按钮,难点是APP里不仅有自己写的activity,还有调用别的APP(GSF)里的activity里,不是很好实现,先将已有的不完善的解决方法写出来。

所有的实现都在NEXSU 7上测试的,别的机子没测过,不保证有用。

下面介绍的第五种方法是现在最好的解决方法。通过反射机制获取隐藏服务StatusBarService,调用它的disable()方法来屏蔽导航按钮。


一. 自己写的activity屏蔽导航按钮


1. 获取到界面上的一个view

2. 调用API

 view.setSystemUiVisibility (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)

3. 不过Google认为导航按钮太重要了,当你点击屏幕的时候,导航按钮会再次显示出来。

我尝试的监听导航按钮显示事件,当收到显示事件后,再次调用上面的API来隐藏,不过这样显示有问题,屏幕有抖动。

  view.setOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener);
 View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener 
           = new View.OnSystemUiVisibilityChangeListener() {
		@Override
                public void onSystemUiVisibilityChange(int vis) {
                   if ((vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) { //当前状态是显示,隐藏它
                       view.setSystemUiVisibility (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
                    }
                }

4. 由于目前还没有好的解决上面的问题,我就不去掉导航按钮整个一栏,而是仅仅去掉导航按钮

int INVISBLE = 0x00400000|0x00200000|0x01000000|0x00010000;//这几个整数参数API是不开放的
//INVISBLE = View.STATUS_BAR_DISABLE_EXPAND | View.STATUS_BAR_DISABLE_RECENT|View.STATUS_BAR_DISABLE_BACK|View.STATUS_BAR_DISABLE_HOME
view.setSystemUiVisibility(INVISBLE);


运行效果图如下,最下面的导航栏已经没有导航按钮了,只有一个圈圈,无法触控。




二. 调用第三方APK里的activity


由于需要GOOGLE的登录界面,我就调用了GSF提供的登录activity,方法如下:

Intent localIntent = new Intent(com.google.android.accounts.AccountIntro);
localIntent.putExtra("firstRun", true);
localIntent.putExtra("allowSkip", true);
startActivityForResult(localIntent, requestCode);

但是当登录界面弹出对话框时,导航按钮都显示出来了,这个是客户接受不了的,要我必须改掉,目前还没有解决掉(已经解决)。问题界面如下


目前想出来的方法是将下面导航栏都去掉,有三种方法,当必须都已经ROOT了。

两种方法屏蔽掉导航按钮,不需要ROOT。


第一种:

修改system/build.prop 添加系统属性 qemu.hw.mainkeys=1,重启。

缺点: 需要重启,所以就没有采用。

第二种:

删除system/app/SystemUI.apk ,这个就是用来显示系统导航栏的APK,但在需要的时候,将APK在放到app目录下,启动服务就行了。

在APK开始运行的时候,将SystemUI.apk移动另一个地方,当APK运行结束的时候,在将SystemUI.apk移回原位,启动SystemUIService服务。

源码如下:

    protected static void moveSystemUIapkFile(boolean move) {  
        try {  
            File systemUIapkFile = new File("/system/app/SystemUI.apk");
            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");  
            if (move && systemUIapkFile.exists()) {  
                os.writeBytes("mv /system/app/SystemUI.apk /system/SystemUI.apk\n");  
            } 
            if (!move && !systemUIapkFile.exists()){  
                os.writeBytes("mv /system/SystemUI.apk /system/app/SystemUI.apk\n");
                os.writeBytes("LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService");
            }  
            os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");  
   
            // Close the terminal  
            os.writeBytes("exit\n");  
            os.flush();  
            p.waitFor();  
        } catch (Exception e) {  
             Log.e(TAG,"moveSystemUIapkFile",e);
        }  
    }
先在开始的时候调用 
moveSystemUIapkFile(true);
再在结束的时候调用

moveSystemUIapkFile(false);
缺点: 当将SystemUI.apk移走时,平板会重启,重启后也就没有了导航栏。需要重启,也没有采用。


第三钟:

将系统进程com.android.systemui杀掉,不过系统会自动将它重启,那就循环的KILL。

实验下来循环时间在300MS左右是最好的,时间长了,屏幕就会由抖动现象。

首先将 killall 和 usleep 这两个命令程序拷贝到asserts目录下,源码和命令程序在这里下载

一部分源码如下:

package com.dstvmobile.walkatouch.setupwizard;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Map;

import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.util.Log;


public enum Device {

    INSTANCE;

    private static String TAG = Device.class.getSimpleName();

    private boolean mHasRootBeenChecked = false;
    private boolean mIsDeviceRooted = false;

    private boolean mHasBeenInitialized = false;
    private Context mAppContext = null;

    private boolean mSystembarVisible = true;

    static public void initialize(Context appContext) {
        if (INSTANCE.mHasBeenInitialized == true) {
            Log.e(TAG, "Initializing already initialized class " + TAG);
        }
        INSTANCE.mHasBeenInitialized = true;
        INSTANCE.mAppContext = appContext;
        AddKillAll(appContext, "killall");
        AddKillAll(appContext, "usleep");
       // moveSystemUIapkFile(true);      
    }

    public static void AddKillAll(Context appContext, String commandFileName) {
		File killAllFile = new File("/system/xbin/"+commandFileName);
		if (!killAllFile.exists()) {
			AssetManager assetManager = appContext.getAssets();
			InputStream inputStream = null;
			String commandFilePath = null;
			try {
				inputStream = assetManager.open(commandFileName);
				commandFilePath = appContext.getApplicationContext().getFilesDir()
						.getAbsolutePath() + File.separator + commandFileName;
				saveToFile(commandFilePath, inputStream);
			} catch (IOException e) {
				Log.e("tag", e.toString());
			}
			try {
				Process p;
				p = Runtime.getRuntime().exec("su");
				DataOutputStream os = new DataOutputStream(p.getOutputStream());
				os.writeBytes("mount -o remount,rw /dev/block/stl6 /system\n");
				os.writeBytes("cd system/xbin\n");
				os.writeBytes("cat " + commandFilePath + " > " + commandFileName + "\n");
				os.writeBytes("chmod 755 " + commandFileName + "\n");
				os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");
				os.writeBytes("exit\n");
				os.flush();
				p.waitFor();
			} catch (Exception e) {
				Log.e(TAG, e.toString());
			}
		}
	}

    static public Device getInstance() {
        INSTANCE.checkInitialized();
        return INSTANCE;
    }

    private void checkInitialized() {
        if (mHasBeenInitialized == false)
            throw new IllegalStateException("Singleton class " + TAG
                    + " is not yet initialized");
    }

    public boolean isRooted() {

        checkInitialized();


        if (mHasRootBeenChecked) {
            return mIsDeviceRooted;
        }

        try {
            File file = new File("/system/app/Superuser.apk");
            if (file.exists()) {
                mHasRootBeenChecked = true;
                mIsDeviceRooted = true;
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            ArrayList<String> envlist = new ArrayList<String>();
            Map<String, String> env = System.getenv();
            for (String envName : env.keySet()) {
                envlist.add(envName + "=" + env.get(envName));
            }
            String[] envp = (String[]) envlist.toArray(new String[0]);
            Process proc = Runtime.getRuntime()
                    .exec(new String[] { "which", "su" }, envp);
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    proc.getInputStream()));
            if (in.readLine() != null) {
                mHasRootBeenChecked = true;
                mIsDeviceRooted = true;
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        mHasRootBeenChecked = true;
        mIsDeviceRooted = false;
        return false;

    }

    public enum AndroidVersion {
        HC, ICS, JB, UNKNOWN
    };

    public AndroidVersion getAndroidVersion() {
        checkInitialized();
        int sdk = android.os.Build.VERSION.SDK_INT;
        if (11 <= sdk && sdk <= 13) {
            return AndroidVersion.HC;
        } else if (14 <= sdk && sdk <= 15) {
            return AndroidVersion.ICS;
        } else if (16 == sdk) {
            return AndroidVersion.JB;
        } else {
            return AndroidVersion.UNKNOWN;
        }
    }
    
    protected static void moveSystemUIapkFile(boolean move) {  
        try {  
        	File systemUIapkFile = new File("/system/app/SystemUI.apk");
            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");  
            if (move && systemUIapkFile.exists()) {  
                os.writeBytes("cp /system/app/SystemUI.apk /system/SystemUI.apk\n");  
            } 
            if (!move && !systemUIapkFile.exists()){  
                os.writeBytes("cp /system/SystemUI.apk /system/app/SystemUI.apk\n");  
            }  
            os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");  
            
            // Close the terminal  
            os.writeBytes("exit\n");  
            os.flush();  
            p.waitFor(); 
            if(!move){
            	
            }
        } catch (Exception e) {  
             Log.e(TAG,"moveSystemUIapkFile",e);
        }  
    }
    public void showSystembar(boolean makeVisible) {
        checkInitialized();
        try {
            ArrayList<String> envlist = new ArrayList<String>();
            Map<String, String> env = System.getenv();
            for (String envName : env.keySet()) {
                envlist.add(envName + "=" + env.get(envName));
            }
            String[] envp = (String[]) envlist.toArray(new String[0]);
            if (makeVisible) {
                String command;
                Device dev = Device.getInstance();
                if (dev.getAndroidVersion() == AndroidVersion.HC) {
                    command = "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
                } else {
                    command = ""
                    		+"rm /sdcard/hidebar-lock\n"
                            + "sleep 5\n"
                            + "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
                }
                Runtime.getRuntime().exec(new String[] { "su", "-c", command }, envp);
                mSystembarVisible = true;
            } else {
                String command;
                Device dev = Device.getInstance();
                if (dev.getAndroidVersion() == AndroidVersion.HC) {
                    command = "LD_LIBRARY_PATH=/vendor/lib:/system/lib service call activity 79 s16 com.android.systemui";
                } else {
                    command = "touch /sdcard/hidebar-lock\n"
                            + "while [ -f /sdcard/hidebar-lock ]\n"
                            + "do\n"
                            + "killall com.android.systemui\n"                                                   
                            + "usleep 300000\n"
                            + "done\n"
                            + "LD_LIBRARY_PATH=/vendor/lib:/system/lib am startservice -n com.android.systemui/.SystemUIService";
                }
                Runtime.getRuntime().exec(new String[] { "su", "-c", command }, envp);
                mSystembarVisible = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean isSystembarVisible() {
        checkInitialized();
        return mSystembarVisible;
    }

    public void sendBackEvent() {
        try {
            ArrayList<String> envlist = new ArrayList<String>();
            Map<String, String> env = System.getenv();
            for (String envName : env.keySet()) {
                envlist.add(envName + "=" + env.get(envName));
            }
            String[] envp = (String[]) envlist.toArray(new String[0]);
            Runtime.getRuntime().exec(
                    new String[] { "su", "-c",
                            "LD_LIBRARY_PATH=/vendor/lib:/system/lib input keyevent 4" },
                    envp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void saveToFile(String filePath, InputStream in){
		FileOutputStream fos = null;
		BufferedInputStream bis = null;
		int BUFFER_SIZE = 1024;
		byte[] buf = new byte[BUFFER_SIZE];
		int size = 0;
		bis = new BufferedInputStream(in);
		try {
			fos = new FileOutputStream(filePath);
			while ((size = bis.read(buf)) != -1)
				fos.write(buf, 0, size);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
				if (bis != null) {
					bis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

在需要隐藏时候调度

Device.initialize(this);
Device.getInstance().showSystembar(false);

在需要去消隐藏的时候调用

Device.getInstance().showSystembar(true);

效果界面:



目前在研究如何屏蔽第三方APK界面的三个导航按钮,而不是去掉整个导航栏。

刚发现了屏蔽三个导航按钮的方案。

第四种:

使用StatusBarManager类,不过这个类是隐藏的,必须在源码下编译,使用SDK编译的肯定是找不到类。

import android.app.StatusBarManager;
mStatusBarManager = (StatusBarManager)this.getSystemService(Context.STATUS_BAR_SERVICE);
在需要隐藏的时候调用:
mStatusBarManager.disable(StatusBarManager.DISABLE_HOME
        			|StatusBarManager.DISABLE_BACK|StatusBarManager.DISABLE_RECENT);
在需要显示的时候调度:

mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);

第五种:

对于第四种方法,SDK编译下也可以实现,使用JAVA的反射机制,获取隐藏接口。

这个方法在我的另一篇文章里已经介绍过了,来实现关机功能 http://blog.csdn.net/kobeyxyx/article/details/9112641

   private void statusBarDisable(boolean disable) {  
    	
        try {
          int DISABLE_NAVIGATION  = 0x00200000 | 0x00400000 | 0x01000000;
            //int DISABLE_NAVIGATION =  View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_BACK | View.STATUS_BAR_DISABLE_RECENT;
          int DISABLE_NONE = 0x00000000;
          //获得ServiceManager类
          Class<?> ServiceManager = Class
             .forName("android.os.ServiceManager");
          
          //获得ServiceManager的getService方法
          Method getService = ServiceManager.getMethod("getService", java.lang.String.class);
          
          //调用getService获取RemoteService
          Object oRemoteService = getService.invoke(null,"statusbar");
          
          //获得IStatusBarService.Stub类
          Class<?> cStub = Class
             .forName("com.android.internal.statusbar.IStatusBarService$Stub");
          //获得asInterface方法
          Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);
          //调用asInterface方法获取IStatusBarService对象
          Object oIStatusBarService = asInterface.invoke(null, oRemoteService);
          //获得disable()方法
          Method disableMethod = oIStatusBarService.getClass().getMethod("disable",int.class,IBinder.class,String.class);
          //调用disable()方法
          if(disable){
             disableMethod.invoke(oIStatusBarService,DISABLE_NAVIGATION,new Binder(),this.getPackageName());   
          }else{
             disableMethod.invoke(oIStatusBarService,DISABLE_NONE,new Binder(),this.getPackageName());   
          } 	       
        }catch (Exception e) {	         
     	   Log.e(TAG, e.toString(), e);	        
        }
     }


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值