使用 Material You 打造的全新系统界面,富有表现力、活力和个性。使用重新设计的微件、AppSearch、游戏模式和新的编解码器扩展您的应用。支持隐私信息中心和大致位置等新的保护功能。使用富媒体内容插入功能、更简便的模糊处理功能、经过改进的原生调试功能等提高工作效率.
-----------------------------正文-------------------------------
平台: RK3588 + Android 12
本文用于记录一些基于RK3588 Android12 的客制化修改内容
12带来的一个巨大的变化之一就是导航栏从SystemUI整合到了Launcher3QuickStep
众所周知, 曾经的SystemUI才是导航栏的拥有者, 把导航栏交给Launcher这意味着, 以后的Launcher, 不是你想动就能动的了.
要替换Launcher的就好好考虑清楚了.
从布局上看, 位于底部, 占满宽度:
packages/apps/Launcher3/quickstep/res/layout/taskbar.xml
<com.android.launcher3.taskbar.TaskbarDragLayer
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/taskbar_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false">
<com.android.launcher3.taskbar.TaskbarView
android:id="@+id/taskbar_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:forceHasOverlappingRendering="false"
android:layout_gravity="bottom"
android:clipChildren="false" />
<com.android.launcher3.taskbar.TaskbarScrimView
android:id="@+id/taskbar_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/navbuttons_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<FrameLayout
android:id="@+id/start_contextual_buttons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
android:paddingTop="@dimen/taskbar_contextual_padding_top"
android:gravity="center_vertical"
android:layout_gravity="start"/>
<LinearLayout
android:id="@+id/end_nav_buttons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
android:layout_marginEnd="@dimen/taskbar_contextual_button_margin"
android:gravity="center_vertical"
android:layout_gravity="end"/>
<FrameLayout
android:id="@+id/end_contextual_buttons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
android:paddingTop="@dimen/taskbar_contextual_padding_top"
android:gravity="center_vertical"
android:layout_gravity="end"/>
FrameLayout>
<com.android.launcher3.taskbar.StashedHandleView
android:id="@+id/stashed_handle"
tools:comment1="The actual size and shape will be set as a ViewOutlineProvider at runtime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/taskbar_stashed_handle_dark_color"
android:clipToOutline="true"
android:layout_gravity="bottom"/>
com.android.launcher3.taskbar.TaskbarDragLayer>
end_nav_buttons 里包含了3个功能键, 动态增加按键控件
packages/apps/Launcher3/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
TaskbarNavButtonController navButtonController) {
mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mNavButtonContainer, mControllers.navButtonController, R.id.back);
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
flags -> {
// Show only if not disabled, and if not on the keyguard or otherwise only when
// the bouncer or a lockscreen app is showing above the keyguard
boolean showingOnKeyguard = (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
(flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
(flags & FLAG_KEYGUARD_OCCLUDED) != 0;
return (flags & FLAG_DISABLE_BACK) == 0
&& ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
}));
boolean isRtl = Utilities.isRtl(mContext.getResources());
mPropertyHolders.add(new StatePropertyHolder(
mBackButton, flags -> (flags & FLAG_IME_VISIBLE) != 0, View.ROTATION,
isRtl ? 90 : -90, 0));
// Translate back button to be at end/start of other buttons for keyguard
int navButtonSize = mContext.getResources().getDimensionPixelSize(
R.dimen.taskbar_nav_buttons_size);
mPropertyHolders.add(new StatePropertyHolder(
mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
|| (flags & FLAG_KEYGUARD_VISIBLE) != 0,
VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
// home and recents buttons
View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
navButtonController, R.id.home);
mPropertyHolders.add(new StatePropertyHolder(homeButton,
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
(flags & FLAG_DISABLE_HOME) == 0));
View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
navContainer, navButtonController, R.id.recent_apps);
mPropertyHolders.add(new StatePropertyHolder(recentsButton,
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
(flags & FLAG_DISABLE_RECENTS) == 0));
按键的点击处理:
packages/apps/Launcher3/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
public void onButtonClick(@TaskbarButton int buttonType) {
switch (buttonType) {
case BUTTON_BACK:
executeBack();
break;
case BUTTON_HOME:
navigateHome();
break;
case BUTTON_RECENTS:
navigateToOverview();
break;
case BUTTON_IME_SWITCH:
showIMESwitcher();
break;
case BUTTON_A11Y:
notifyA11yClick(false /* longClick */);
break;
}
}
private void navigateHome() {
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
private void navigateToOverview() {
if (mScreenPinned) {
return;
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
}
private void executeBack() {
mSystemUiProxy.onBackPressed();
}
packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
/**
* Adds a command to be executed next, after all pending tasks are completed
*/
@BinderThread
public void addCommand(int type) {
CommandInfo cmd = new CommandInfo(type);
MAIN_EXECUTOR.execute(() -> addCommand(cmd));
}
在Launcher3QuickStep存在以下服务:
packages/apps/Launcher3/quickstep/AndroidManifest.xml
<service android:name="com.android.quickstep.TouchInteractionService"
android:permission="android.permission.STATUS_BAR_SERVICE"
android:directBootAware="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
intent-filter>
service>
导航栏离不开SystemUI, 该服务由SystemUI绑定:
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
private void internalConnectToCurrentUser() {
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
if (!isEnabled()) {
Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
try {
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
UserHandle.of(getCurrentUserId()));
} catch (SecurityException e) {
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
if (mBound) {
// Ensure that connection has been established even if it thinks it is bound
mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
} else {
// Retry after exponential backoff timeout
retryConnectionWithBackoff();
}
}
替换Launcher
前面提过, 要替换Launcher需要考虑的比以前更多的, 首先, Launcher3QuickStep不能删除, 在设置中依然可以选择默认的Launcher,(这和现在某些国内的手机厂商不一样).
Settings > Apps > Default Apps > Home app
Launcher3QuickStep 默认桌面图标
去掉所有的桌面图标
packages/apps/Launcher3/res/xml/default_workspace_6x5.xml
diff --git a/packages/apps/Launcher3/res/xml/default_workspace_6x5.xml b/packages/apps/Launcher3/res/xml/default_workspace_6x5.xml
index b078cfd7f8..4300258cc4 100644
--- a/packages/apps/Launcher3/res/xml/default_workspace_6x5.xml
+++ b/packages/apps/Launcher3/res/xml/default_workspace_6x5.xml
@@ -15,10 +15,10 @@
-->
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
-
+
- <resolve
+
+
favorites>
修改动画文件检测路径:
frameworks/base/cmds/bootanimation/BootAnimation.cpp
static const char OEM_BOOTANIMATION_FILE[] = "/cache/bootanimation.zip";
static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
static const char PRODUCT_BOOTANIMATION_FILE[] = "/data/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/odm/media/shutdownanimation.zip";
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
一个小插曲: /data/bootanimation.zip 开机时读取不到. 开完机后, 调试过程中通过命令启动动画, 又可以正常读取, 很是怪异.
启动命令:
setprop ctl.start bootanim
/data/local/bootanimation.ts开机视频读取正常, 于是尝试把检测开机.zip动画的函数放到视频检测里:
void BootAnimation::checkVideoFile() {
// add for boot video
mVideoAnimation = false;
if (access(SYSTEM_BOOTVIDEO_FILE, R_OK) == 0) {
mVideoFile = (char*)SYSTEM_BOOTVIDEO_FILE;
}
if (access(DATA_BOOTVIDEO_FILE, R_OK) == 0) {
mVideoFile = (char*)DATA_BOOTVIDEO_FILE;
}
//增加一行用于检测开机 ZIP 动画.
findBootAnimationFile();
std::string bootVideoEnable = android::base::GetProperty("persist.sys.bootvideo.enable", "false");
std::string showTime = android::base::GetProperty("persist.sys.bootvideo.showtime", "-1");
ALOGD("checkVideoFile()-->bootvideo.enable=%s, showtime=%s", bootVideoEnable.c_str(), showTime.c_str());
if (mVideoFile != NULL && !strcmp(bootVideoEnable.c_str(), "true") && (atoi(showTime.c_str()) != 0)) {
mVideoAnimation = true;
ALOGD("mVideoAnimation = true");
} else {
ALOGD("bootvideo:No boot video animation,EXIT_VIDEO_NAME:%s,bootvideo.showtime:%s\n",
bootVideoEnable.c_str(), showTime.c_str());
}
// add end
}
PS: 未解
首先可以编写一个简单的Activity
new Thread(){
public void run(){
while(true){
//print....
sleep(1);
}
}
}
实际测试会发现, 当Activity切到后台后, sleep的实际时间被拉长了, 线程优先级降下来了.
可以尝试修改保证Activity的线程优先级:
frameworks/base/services/core/java/com/android/server/am/ProcessStateRecord.java
void setCurrentSchedulingGroup(int curSchedGroup) {
//增加代码,
//比如修改为前台APP:
//curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
mCurSchedGroup = curSchedGroup;
mApp.getWindowProcessController().setCurrentSchedulingGroup(curSchedGroup);
}
packages/apps/Settings/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
public void onActivityCreated(Bundle icicle) {
super.onActivityCreated(icicle);
//......
PreferenceCategory cat = (PreferenceCategory)getPreferenceScreen().findPreference("debug_debugging_category");
cat.removePreference(cat.findPreference("enable_adb"));
}
单独写出来是因为刚开始写成了:
getPreferenceScreen().findPreference("enable_adb");
正确的方式, 是先找到对应的PreferenceCategory, 在调用findPreference
packages/apps/Settings/res/xml/my_device_info.xml
//....
<PreferenceCategory
android:key="device_detail_category"
android:selectable="false"
android:title="@string/my_device_info_device_details_category_title">
<Preference
android:key="screen_info"
android:order="19"
android:title="屏幕信息"
android:summary="分辨率1920x1080 DPI 240"/>
<Preference
android:key="sim_status"
android:order="18"
android:title="@string/sim_status_title"
settings:keywords="@string/keywords_sim_status"
android:summary="@string/summary_placeholder"
settings:enableCopying="true"/>
//...
packages/apps/Settings/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
private void initHeader() {
//.....
//增加代码
androidx.preference.PreferenceCategory cat = (androidx.preference.PreferenceCategory)getPreferenceScreen().findPreference("device_detail_category");
android.hardware.display.DisplayManager displayMgr = (android.hardware.display.DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE);
android.view.Display[] displays = displayMgr.getDisplays();
int x = 0;
int y = 0;
int dpi = 0;
if(displays != null && displays.length > 0){
android.graphics.Point rSize = new android.graphics.Point();
displays[0].getRealSize(rSize);
android.util.DisplayMetrics dmOut = new android.util.DisplayMetrics();
displays[0].getMetrics(dmOut);
x = rSize.x;
y = rSize.y;
dpi = dmOut.densityDpi;
}
cat.findPreference("screen_info").setSummary("分辨率 " + x + "x" + y + " DPI " + dpi);
}
系统存储分区
device/rockchip/common/scripts/fstab_tools/fstab.in
# Android fstab file.
#
# The filesystem that contains the filesystem checker binary (typically /system) cannot
# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK
${_block_prefix}system /system ext4 ro,barrier=1 ${_flags_vbmeta},first_stage_mount${_flags_avbpubkey}
${_block_prefix}vendor /vendor ext4 ro,barrier=1 ${_flags},first_stage_mount
${_block_prefix}odm /odm ext4 ro,barrier=1 ${_flags},first_stage_mount
/dev/block/by-name/boot /boot emmc defaults ${_flags_chained}first_stage_mount
/dev/block/by-name/cache /cache ext4 noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard wait,check
/dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,discard,sync wait,formattable,first_stage_mount,check
/dev/block/by-name/misc /misc emmc defaults defaults
/devices/platform/*usb* auto vfat defaults voldmanaged=usb:auto
# For sata
/devices/platform/*.sata* auto vfat defaults voldmanaged=sata:auto
# For pcie ssd
/devices/platform/*.pcie* auto vfat defaults voldmanaged=pcie:auto
/dev/block/zram0 none swap defaults zramsize=50%
# For sdmmc
/devices/platform/${_sdmmc_device}/mmc_host* auto auto defaults voldmanaged=sdcard1:auto
# Full disk encryption has less effect on rk3326, so default to enable this.
/dev/block/by-name/userdata /data f2fs noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065 latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,reservedsize=128M,checkpoint=fs
# for ext4
#/dev/block/by-name/userdata /data ext4 discard,noatime,nosuid,nodev,noauto_da_alloc,data=ordered,user_xattr,barrier=1 latemount,wait,formattable,check,fileencryption=software,quota,reservedsize=128M,checkpoint=block
默认关闭USB调试
默认persist.sys.usb.config的属性值去掉adb
如果打开了ro.debuggable, 以下代码会重新加回去.
system/core/init/property_service.cpp
static void update_sys_usb_config() {
bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
std::string config = android::base::GetProperty("persist.sys.usb.config", "");
// b/150130503, add (config == "none") condition here to prevent appending
// ",adb" if "none" is explicitly defined in default prop.
if (config.empty() || config == "none") {
InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
} else if (is_debuggable && config.find("adb") == std::string::npos &&
config.length() + 4 < PROP_VALUE_MAX) {
config.append(",adb");
InitPropertySet("persist.sys.usb.config", config);
}
}