前言
在系统定制化中,有些客户要添加全局的返回键,或者底部导航栏去掉了,所以要加返回键,首先我们确定的是这个返回键要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