导航栏的部分按键动态显示与隐藏

2种方式:
1.修改SystemUI Navigation部分中的aidl部分。
Navigation部分默认有3个虚拟按键:返回,HOME,菜单,例如需要隐藏最左边的返回按键。
首先,在IStatusBarService.aidl部分增加一个函数void updateNaviState(String s)。

//frameworks\base\core\java\com\android\internal\statusbar\IStatusBarService.aidl
interface IStatusBarService{
    void expandNotificationsPanel();
    void collapsePanels();
    void togglePanel();
    void disable(int what, IBinder token, String pkg);
    .....
    void updateNaviState(String s); 
}

然后,在IStatusBar.aidl中添加另一个函数updateNavibarState(String s)。

//frameworks\base\core\java\com\android\internal\statusbar\IStatusBar.aidl
oneway interface IStatusBar{
    void setIcon(String slot, in StatusBarIcon icon);
    void removeIcon(String slot);
    .....
    void updateNavibarState(String s)
}

然后,在CommandQueue类的Callbacks接口中添加函updateNavibarState。
CommandQueue继承自IStatusBar.Stub,IStatusBar.Stub是IStatusBar.aidl自动生成的java文件。在CommandQueue中定义了一个Callbacks接口,而IStatusBar接口中的定义都是通过Callbacks来调用的。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\systemui\statusbar\CommandQueue.java
public class CommandQueue extends IStatusBar.Stub {
    ..........
    public interface Callbacks {
        default void setIcon(String slot, StatusBarIcon icon) { }
        default void removeIcon(String slot) { }
        .......
        default void updateNavibarState(String s){ }
    }
    ..........
}

然后就是Callbacks 的使用,Callbacks 是在StatusBar 中使用的。StatusBar继承Callbacks后重写updateNavibarState。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\systemui\statusbar\phone\StatusBar.java
public class StatusBar extends SystemUI implements ...,CommandQueue.Callbacks{
   .......
  @Override
    public void updateNavibarState(String s) {
        getNavigationBarView().updateNaviSate(s);
    }
   .......

}

NavigationBarView返回的是NavigationBarView,需要在NavigationBarView中定义一个updateNaviSate(String s)函数。

首先,修改navigation_bar.xml文件。原文件如下所示:

//vendor\mediatek\proprietary\packages\xxx\xxx\res\layout\navigation_bar.xml


    


将NavigationBarInflaterView隐藏并自定义一个LinearLayout,用这个去实现隐藏部分按钮。由于NavigationBarInflaterView不容易更改因此直接隐藏通过自定义控件去实现该功能。



    
    
        

        


        
    

修改完后,再来定NavigationBarView中的内容。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\systemui\statusbar\phone\NavigationBarView.java
public class NavigationBarView extends FrameLayout implements PluginListener {
    .........
    private LinearLayout navigationBackground;
    private TextView leftNavTxtView;
    private TextView rightNavTxtView;
    private TextView midNavTxtView;
    .........
         public NavigationBarView(Context context, AttributeSet attrs) {
        .........
        navigationBackground = findViewById(R.id.navigation_background);
        leftNavTxtView = findViewById(R.id.navigation_menu);
        rightNavTxtView = findViewById(R.id.navigation_contact);
        midNavTxtView = findViewById(R.id.navigation_mid);
        .........     

        public void updateNaviSate(String s){
          leftNavTxtView.setText(s);
        }
    .........       
}

在StatusBarManager中新增一个函数,调用IStatusBarService中的updateNaviState(String s)。

//frameworks\base\core\java\android\app\StatusBarManager.java
@SystemService(Context.STATUS_BAR_SERVICE)
public class StatusBarManager {
    .....
    public void updateNaviState(String s) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.updateNaviState(s);
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    .....
}

在StatusBarManagerService 中增加对应的函数调用IStatusBar中的updateNavibarState

//frameworks\base\services\core\java\com\android\server\statusbar\StatusBarManagerService.java
public class StatusBarManagerService extends IStatusBarService.Stub {
    .....
    @Override
    public void updateNaviState(String s){
        if (mBar != null) {
            try {
                mBar.updateNavibarState(s);
            } catch (RemoteException ex) {
            }
        }
    }
    .....
}

最后使用就是在Activity 中定义updateNaviState函数。

//frameworks\base\core\java\android\app\Activity.java
public class Activity extends xxx{
    ..............
    public void updateNaviState(String s){
     getSystemService(StatusBarManager.class).updateNaviState(s);
    }
}

然后在需要使用的时候继承这个Activity 即可。

public class MainActivity extends Activity {
     ...........
     @Override
    protected void onResume() {
        super.onResume();
        updateNaviState("");
    }
     ...........
}

由于想隐藏最左边的控件,所以直接传了一个空的string。这里最好是在onResume中调用。
如果想隐藏整个导航栏,那么可以通过navigationBackground.setBackgroundColor设置为透明从而隐藏。
这一部分是通过获取service manage,调用service,并且增加对应回调函数去实现,不禁让我思考,到底什么是client,之前aidl的使用经历让我觉得需要有aidl文件并且调用service才算client,但是照目前来看,调用了service,可以算client(也就是说Activity 算client)。对于binder的实质,我始终没有弄清楚。

2.广播
广播的方式缺点是有延时,适用于没有界面的时候。
如果是使用广播的方式的话,StatusBar 中有一个mBaseBroadcastReceiver ,需要修改这一部分。

//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\systemui\statusbar\phone\StatusBar.java
public class StatusBar extends SystemUI implements ...,CommandQueue.Callbacks{
        public static final String ACTION_NAVI= "xxx.xxx.xxx.action.systemui.navi";
     ...........
    internalFilter.addAction(BANNER_ACTION_SETUP);
    internalFilter.addAction(ACTION_NAVI);
     ...........
    private final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver(){
       @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_USER_SWITCHED.equals(action)){
              ...........
            } 
              ...........
             else if (ACTION_NAVI.equals(intent.getAction())){
                 getNavigationBarView().updateNaviSate(  intent.getStringExtra("left"));
            }
       }
    }
     ...........
}

使用的话,发送广播即可。

String ACTION_NAVI= "xxx.xxx.xxx.action.systemui.navi";
Intent intent=new Intent(ACTION_NAVI);
intent.putExtra("left","");
sendBroadcast(intent);

参考链接:
Android系统服务(SystemService)简介
Android 状态栏, 标题栏, 导航栏,系统栏,应用栏的区别和解释
Android 8.1平台SystemUI虚拟导航键加载流程解析
IStatusBarService 的AIDL实现与调用

你可能感兴趣的:(导航栏的部分按键动态显示与隐藏)