RK系列之Android7.1 SystemUI 添加全局返回键悬浮窗

前言

在系统定制化中,有些客户要添加全局的返回键,或者底部导航栏去掉了,所以要加返回键,首先我们确定的是这个返回键要Window级别的,才能不被其他应用缩遮盖,也就是我们说的悬浮窗,他就是系统级别的,接下来我们直接上代码就明了了。
目录:
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\tv\TvStatusBar.java

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.tv;

import android.content.ComponentName;
import android.graphics.Rect;
import android.os.IBinder;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;

import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.tv.pip.PipManager;

import com.android.systemui.ArcMenu;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.os.SystemProperties;
import android.widget.ImageView;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.hardware.input.InputManager;
import com.android.systemui.R;
import android.view.WindowManager;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.KeyEvent;
import android.os.SystemClock;
import android.view.ViewGroup.LayoutParams;
import android.util.Log;
import android.content.res.Resources;

/**
 * Status bar implementation for "large screen" products that mostly present no on-screen nav
 */

public class TvStatusBar extends BaseStatusBar {

    /* add by keily on 11/22/19. BEGIN ********************************************************* */
    @Override
    public void start() {
        super.start();
        putComponent(TvStatusBar.class, this);
		

        if (SystemProperties.getBoolean("persist.sys.floated_back.enable", false)) {
            addFloatView(true);
        }
    }

   
    private long mDownTime;

   
    private void sendEvent(int code) {
        mDownTime = SystemClock.uptimeMillis() - 100;
        sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime, code);
        sendEvent(KeyEvent.ACTION_UP, 0, SystemClock.uptimeMillis(), code);
    }

    private void sendEvent(int action, int flags, long when, int code) {
        final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
        final KeyEvent ev = new KeyEvent(
                mDownTime,
                when,
                action,
                code,
                repeatCount,
                0,
                KeyCharacterMap.VIRTUAL_KEYBOARD,
                0,
                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);
        InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
    }
   
    GestureDetector mGestureDetector;
    private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;
    private int mStartX, mStartY, mStopX, mStopY;
    private boolean isMove;
    private ImageView mFloatView;
    private WindowManager.LayoutParams mFloatViewLayoutParams;
    DisplayMetrics mDisplayMetrics = new DisplayMetrics();

    private void addFloatView(boolean istrue) {
        Log.i(TAG, "addFloatView......");

//        mDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
//                .getDefaultDisplay();
        mDisplay.getMetrics(mDisplayMetrics);
        Log.d(TAG, "widthPixels = " + mDisplayMetrics.widthPixels);
        Log.d(TAG, "heightPixels = " + mDisplayMetrics.heightPixels);
        
        mFloatView = new ImageView(mContext);
        mFloatView.setImageResource(R.drawable.ic_float_back);
        mFloatView.setBackgroundResource(R.drawable.bg_icon_white);
        mWindowManager.addView(mFloatView, getFloatViewLayoutParams());
        mGestureDetector = new GestureDetector(mContext, new MyOnGestureListener());
        mFloatView.setOnTouchListener(new FloatingListener());
        
    }

    

    private WindowManager.LayoutParams getFloatViewLayoutParams() {
        mFloatViewLayoutParams = new WindowManager.LayoutParams(
                mContext.getResources().getDimensionPixelSize(R.dimen.float_back_button_size),
                mContext.getResources().getDimensionPixelSize(R.dimen.float_back_button_size),
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                PixelFormat.TRANSLUCENT);
                
        // this will allow the navbar to run in an overlay on devices that support this
        if (ActivityManager.isHighEndGfx()) {
            mFloatViewLayoutParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
        mFloatViewLayoutParams.windowAnimations = 0;
        mFloatViewLayoutParams.x = 10;
//        lp.y = 10;
        mFloatViewLayoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
        mFloatViewLayoutParams.setTitle("FloatView");
        return mFloatViewLayoutParams;
    }
    

    private class FloatingListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View view, MotionEvent event) {
            int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    mFloatView.setPressed(true);
                    mDownTime = SystemClock.uptimeMillis();
                    isMove = false;
                    mTouchStartX = (int) event.getRawX();
                    mTouchStartY = (int) event.getRawY();
                    mStartX = (int) event.getX();
                    mStartY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    mFloatView.setPressed(true);
                    mTouchCurrentX = (int) event.getRawX();
                    mTouchCurrentY = (int) event.getRawY();
                    mFloatViewLayoutParams.x += mTouchCurrentX - mTouchStartX;
                    mFloatViewLayoutParams.y += mTouchCurrentY - mTouchStartY;
                    mWindowManager.updateViewLayout(mFloatView, mFloatViewLayoutParams);

                    mTouchStartX = mTouchCurrentX;
                    mTouchStartY = mTouchCurrentY;
                    break;
                case MotionEvent.ACTION_CANCEL:
                    mFloatView.setPressed(false);
                    break;
                case MotionEvent.ACTION_UP:
                    mFloatView.setPressed(false);
                    mStopX = (int) event.getX();
                    mStopY = (int) event.getY();

                    // --- to move button scale screen start ---
                    float endX = event.getRawX();
                    float endY = event.getRawY();
                    if (endX < mDisplayMetrics.widthPixels / 2) {
                        endX = 0 + 10;
                    } else {
                        endX = mDisplayMetrics.widthPixels - mFloatView.getWidth();
                    }
                    mFloatViewLayoutParams.x = (int) endX;
                    mWindowManager.updateViewLayout(mFloatView, mFloatViewLayoutParams);
                    // --- to move button scale screen  end  ---

                    if (Math.abs(mStartX - mStopX) >= 30 || Math.abs(mStartY - mStopY) >= 30) {
                        isMove = true;
                    }
                    break;
            }
            return mGestureDetector.onTouchEvent(event);
        }

    }

    class MyOnGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
		public boolean onSingleTapUp(MotionEvent e) {
			if (!isMove) {
				sendEvent(KeyEvent.KEYCODE_BACK);
			}
		
			return false;
		}
    }

    /* add by keily on 11/22/19. END   ********************************************************* */



    @Override
    public void setIcon(String slot, StatusBarIcon icon) {
    }

    @Override
    public void removeIcon(String slot) {
    }

    @Override
    public void addNotification(StatusBarNotification notification, RankingMap ranking,
            NotificationData.Entry entry) {
    }

    @Override
    protected void updateNotificationRanking(RankingMap ranking) {
    }

    @Override
    public void removeNotification(String key, RankingMap ranking) {
    }

    @Override
    public void disable(int state1, int state2, boolean animate) {
    }

    @Override
    public void animateExpandNotificationsPanel() {
    }

    @Override
    public void animateCollapsePanels(int flags) {
    }

    @Override
    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
    }

    @Override
    public void topAppWindowChanged(boolean visible) {
    }

    @Override
    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
            boolean showImeSwitcher) {
    }

    @Override // CommandQueue
    public void setWindowState(int window, int state) {
    }

    @Override // CommandQueue
    public void buzzBeepBlinked() {
    }

    @Override // CommandQueue
    public void notificationLightOff() {
    }

    @Override // CommandQueue
    public void notificationLightPulse(int argb, int onMillis, int offMillis) {
    }

    @Override
    protected void setAreThereNotifications() {
    }

    @Override
    protected void updateNotifications() {
    }

    @Override
    public boolean shouldDisableNavbarGestures() {
        return true;
    }

    public View getStatusBarView() {
        return null;
    }

    @Override
    protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
    }

    @Override
    public void maybeEscalateHeadsUp() {
    }

    @Override
    public boolean isPanelFullyCollapsed() {
        return false;
    }

    @Override
    protected int getMaxKeyguardNotifications(boolean recompute) {
        return 0;
    }

    @Override
    public void animateExpandSettingsPanel(String subPanel) {
    }

    @Override
    protected void createAndAddWindows() {
    }

    @Override
    protected void refreshLayout(int layoutDirection) {
    }

    @Override
    public void onActivated(ActivatableNotificationView view) {
    }

    @Override
    public void onActivationReset(ActivatableNotificationView view) {
    }

    @Override
    public void showScreenPinningRequest(int taskId) {
    }

    @Override
    public void appTransitionPending() {
    }

    @Override
    public void appTransitionCancelled() {
    }

    @Override
    public void appTransitionStarting(long startTime, long duration) {
    }

    @Override
    public void appTransitionFinished() {
    }

    @Override
    public void onCameraLaunchGestureDetected(int source) {
    }

    @Override
    public void showTvPictureInPictureMenu() {
        PipManager.getInstance().showTvPictureInPictureMenu();
    }

    @Override
    protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldPeek,
            boolean alertAgain) {
    }

    @Override
    protected void setHeadsUpUser(int newUserId) {
    }

    protected boolean isSnoozedPackage(StatusBarNotification sbn) {
        return false;
    }

    @Override
    public void addQsTile(ComponentName tile) {
    }

    @Override
    public void remQsTile(ComponentName tile) {
    }

    @Override
    public void clickTile(ComponentName tile) {
    }

   /* @Override
    public void start() {
        super.start();
        putComponent(TvStatusBar.class, this);
    }*/

    @Override
    public void handleSystemNavigationKey(int arg1) {
        // Not implemented
    }
}

上面贴出来的代码是实现的代码,TvStatusBar这个类是在RK3128 Android7.1上面SystemUI默认启动的状态栏,他跟Android4.4上面PhoneStatusBar其实是继承同一个基类BaseStatusBar,区别在于他没有下拉状态栏以及底部导航栏,正常情况系统默认的是PhoneStatusBar,而由于原厂给到的源码是RK平台定制的,他们用TvStatusBar替代了PhoneStatusBar。
至于TvStatusBar是哪里加载的,这里我也贴一下目录,后续流程你也可以跟踪下,很简单的。
目录:
U:\workspace\Keily\RK3128_7.1\rk3128-20191016\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\SystemBars.java

  private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
		
        String clsName = mContext.getString(R.string.config_statusBarComponent);
        if ("box".equals(SystemProperties.get("ro.target.product", "tablet"))){
        //默认进入到这里
            clsName = "com.android.systemui.statusbar.tv.TvStatusBar";
			//com.android.systemui.statusbar.phone.PhoneStatusBar
        }
        //可以在这里写死,切换到PhoneStatusBar
		//clsName = "com.android.systemui.statusbar.phone.PhoneStatusBar";
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }
        Class<?> cls = null;
        try {
            cls = mContext.getClassLoader().loadClass(clsName);
        } catch (Throwable t) {
            throw andLog("Error loading status bar component: " + clsName, t);
        }
        try {
            mStatusBar = (BaseStatusBar) cls.newInstance();
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }

QQ交流:3151365988
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 7.1 的源码中,您可以通过修改 fstab 文件或 init.rc 文件来添加一个可被电脑识别的分区。具体来说,您可以按照以下步骤进行操作: 1. 确定您要挂载的分区的设备节点名称,例如 `/dev/sdb1`。 2. 打开设备的 fstab 文件,例如 `/vendor/etc/fstab.rk3288`,在其中添加一行类似于以下内容的条目: `/dev/block/sdb1 /mnt/usb_storage vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0002,dmask=0002,allow_utime=0020,codepage=936,iocharset=utf8,shortname=mixed,utf8,errors=remount-ro 0 0` 这个条目的意思是将 `/dev/block/sdb1` 这个设备节点挂载到 `/mnt/usb_storage` 这个挂载点,使用 vfat 文件系统,具有一系列选项,例如读写权限、字符集等。 3. 如果您想要在设备启动时自动挂载该分区,可以修改设备的 init.rc 文件。具体来说,您可以在文件中添加以下内容: ``` mount /dev/block/sdb1 /mnt/usb_storage vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0002,dmask=0002,allow_utime=0020,codepage=936,iocharset=utf8,shortname=mixed,utf8,errors=remount-ro ``` 这个命令的意思是在设备启动时将 `/dev/block/sdb1` 挂载到 `/mnt/usb_storage`,使用 vfat 文件系统,具有一系列选项。 请注意,上述操作可能需要 root 权限才能执行,同时修改系统文件可能会导致系统不稳定或无法正常启动,请谨慎操作,并备份好您的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值