Android 12 客制化修改初探-Launcher/Settings/Bootanimation

Android 12 客制化修改初探-Launcher/Settings/Bootanimation_第1张图片
Android 12

    使用 Material You 打造的全新系统界面,富有表现力、活力和个性。使用重新设计的微件、AppSearch、游戏模式和新的编解码器扩展您的应用。支持隐私信息中心和大致位置等新的保护功能。使用富媒体内容插入功能、更简便的模糊处理功能、经过改进的原生调试功能等提高工作效率.


-----------------------------正文-------------------------------

平台: RK3588 + Android 12
本文用于记录一些基于RK3588 Android12 的客制化修改内容


Launcher & 导航栏

12带来的一个巨大的变化之一就是导航栏从SystemUI整合到了Launcher3QuickStep
Android 12 客制化修改初探-Launcher/Settings/Bootanimation_第2张图片
众所周知, 曾经的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
Android 12 客制化修改初探-Launcher/Settings/Bootanimation_第3张图片
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>

Bootanimation

修改动画文件检测路径:

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: 未解

  • ZIP动画文件检测需要放在checkVideoFile
  • /cache/bootanimation.zip 死活读不到.

Activity/Service 保持高优先级运行

首先可以编写一个简单的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);
    }

Settings

  • 去除Usb调试开关

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);
    }
}

参考

  1. Android进程管理1—进程优先级adj

你可能感兴趣的:(android,android,Launcher,Settings,开机动画,SystemUI)