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

Android 12
使用 Material You 打造的全新系统界面,富有表现力、活力和个性。使用重新设计的微件、AppSearch、游戏模式和新的编解码器扩展您的应用。支持隐私信息中心和大致位置等新的保护功能。使用富媒体内容插入功能、更简便的模糊处理功能、经过改进的原生调试功能等提高工作效率.
-----------------------------正文-------------------------------
平台: RK3588 + Android 12
本文用于记录一些基于RK3588 Android12 的客制化修改内容
Launcher & 导航栏
12带来的一个巨大的变化之一就是导航栏从SystemUI整合到了Launcher3QuickStep

众所周知, 曾经的SystemUI才是导航栏的拥有者, 把导航栏交给Launcher这意味着, 以后的Launcher, 不是你想动就能动的了.
要替换Launcher的就好好考虑清楚了.
从布局上看, 位于底部, 占满宽度:
packages/apps/Launcher3/quickstep/res/layout/taskbar.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source ProjectLicensed 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed 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 andlimitations under the License.
-->
<com.android.launcher3.taskbar.TaskbarDragLayerxmlns: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.TaskbarViewandroid: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.TaskbarScrimViewandroid:id="@+id/taskbar_scrim"android:layout_width="match_parent"android:layout_height="match_parent"/><FrameLayoutandroid:id="@+id/navbuttons_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="bottom"><FrameLayoutandroid: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"/><LinearLayoutandroid: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"/><FrameLayoutandroid: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.StashedHandleViewandroid: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 keyguardboolean 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 keyguardint 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 buttonsView 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*/@BinderThreadpublic 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 connectif (!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 boundmHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);} else {// Retry after exponential backoff timeoutretryConnectionWithBackoff();}}
替换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">
-
+ <!--AnsonCode remove appicons--><!-- Hotseat (We use the screen as the position of the item in the hotseat) --><!-- Mail Calendar Gallery Store Internet Camera -->
- <resolve
+ <!--resolvelauncher:container="-101"launcher:screen="0"launcher:x="0"
@@ -61,9 +61,9 @@<favoritelauncher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" /><favorite launcher:uri="http://www.example.com/" />
- </resolve>
+ </resolve-->- <!-- Resolve camera intent if GoogleCamera is not available e.g. on emulator -->
+ <!-- Resolve camera intent if GoogleCamera is not available e.g. on emulator ><resolvelauncher:container="-101"launcher:screen="5"
@@ -71,6 +71,6 @@launcher:y="0" ><favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" /><favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
- </resolve>
+ </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 videomVideoAnimation = 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
//....<PreferenceCategoryandroid:key="device_detail_category"android:selectable="false"android:title="@string/my_device_info_device_details_category_title"><Preferenceandroid:key="screen_info"android:order="19"android:title="屏幕信息"android:summary="分辨率1920x1080 DPI 240"/><!-- SIM status --><Preferenceandroid: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.
#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags>
# 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);}
}
参考
- Android进程管理1—进程优先级adj
相关文章:
Android 12 客制化修改初探-Launcher/Settings/Bootanimation
Android 12 使用 Material You 打造的全新系统界面,富有表现力、活力和个性。使用重新设计的微件、AppSearch、游戏模式和新的编解码器扩展您的应用。支持隐私信息中心和大致位置等新的保护功能。使用富媒体内容插入功能、更简便的模糊处理功能、经过改进的原生调试…...
【JavaEE初阶】 HTML基础详解
文章目录 🎋什么是HTML?🍀HTML 结构🚩认识标签🚩HTML 文件基本结构🚩快速生成代码框架 🎄HTML 常见标签🚩注释标签🚩标题标签: h1-h6🚩段落标签: pǶ…...
C# Socket通信从入门到精通(10)——如何检测两台电脑之间的网络是否通畅
前言: 我们在完成了socket通信程序开发以后,并且IP地址也设置好以后,可以先通过一些手段来测试两台电脑之间的网络是否通畅,如果确认了网络通畅以后,我们再测试我们编写的Socket程序。 1、同时按下键盘的windows键+"R"键,如下图: 下面两张图是两种键盘的情…...
python科研绘图:P-P图与Q-Q图
目录 什么是P-P图与Q-Q图 分位数 百分位数 Q-Q图步骤与原理 Shapiro-Wilk检验 绘制Q-Q图 绘制P-P图 什么是P-P图与Q-Q图 P-P图和Q-Q图都是用于检验样本的概率分布是否服从某种理论分布。 P-P图的原理是检验实际累积概率分布与理论累积概率分布是否吻合。若吻合…...
浅尝:iOS的CoreGraphics和Flutter的Canvas
iOS的CoreGraphic 基本就是创建一个自定义的UIView,然后重写drawRect方法,在此方法里使用UIGraphicsGetCurrentContext()来绘制目标图形和样式 #import <UIKit/UIKit.h>interface MyGraphicView : UIView endimplementation MyGraphicView// Onl…...
网络安全黑客技术自学
前言 一、什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域,都有攻与防…...
【文件读取/包含】任意文件读取漏洞 afr_3
1.1漏洞描述 漏洞名称任意文件读取漏洞 afr_3漏洞类型文件读取/包含漏洞等级⭐⭐⭐⭐⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.环境搭建 1.创建docker-compose.yml文件 version: 3.2 servi…...
第四章:单例模式与final
系列文章目录 文章目录 系列文章目录前言一、单例模式二、final 关键字总结 前言 单例模式与final关键字。 一、单例模式 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。就像是经典的棋谱,不同的棋局,我…...
深入Android S(12.0) 探索 Android Framework 之 SystemServer 进程启动详解
深入学习 Android Framework 第三:深入Android S(12.0) 探索 Android Framework 之 SystemServer 进程启动详解 文章目录 深入学习 Android Framework前言一、Android 系统的启动流程1. 流程图2. 启动流程概述 二、源码详解1. 时序图2. 源代码1、ZygoteInit # main…...
搜维尔科技:【软件篇】TechViz是一款专为工程设计的专业级3D可视化软件
在沉浸式房间内深入研究您自己的 3D 数据 沉浸式房间是一个交互式虚拟现实空间,其中每个表面(墙壁、地板和天花板)都充当投影屏幕,创造高度沉浸式的体验。这就像您的 3D 模型有一个窗口,您可以在其中从不同角度走动、…...
android Handler
一、Handler的作用 1、Handler的作用是在andorid中实现线程间的通信。我们常说的说的,子线程处理逻辑,主线程更新UI是上述情况的一个子集。 二、源码分析 1、Handler源码 源码地址:http://androidxref.com/7.1.1_r6/xref/frameworks/base/co…...
【Ubuntu·系统·的Linux环境变量配置方法最全】
文章目录 概要读取环境变量的方法小技巧 概要 在Linux环境中,配置环境变量是一种常见的操作,用于指定系统或用户环境中可执行程序的搜索路径。 读取环境变量的方法 在Linux中,可以使用以下两个命令来读取环境变量: export 命令…...
Django之模板层
【1】模板之变量 在Django模板中要想使用变量关键是使用点语法。 获取值的语法是:{{ 变量名 }} Python中所有的数据类型包括函数,类等都可以调用 【2】模板之过滤器 过滤器语法 {{ obj | filter_name:param }} obj:变量名字&…...
社区论坛小程序系统源码+自定义设置+活动奖励 自带流量主 带完整的搭建教程
大家好啊,又到了罗峰来给大家分享好用的源码的时间了。今天罗峰要给大家分享的是一款社区论坛小程序系统。社区论坛已经成为人们交流、学习、分享的重要平台。然而,传统的社区论坛往往功能单一、缺乏个性化设置,无法满足用户多样化的需求。而…...
2023亚太杯数学建模C题思路解析
文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…...
acme在同一台服务器上设置多个Ali_key实现自动ssl申请和续期
在同一台服务器上设置多个Ali_key,您可以按照以下步骤进行操作: 首先,确保您已经安装了acme.sh工具。如果没有安装,请先安装acme.sh,您可以使用以下命令安装acme.sh: curl https://get.acme.sh | sh安装完…...
乐观锁与悲观锁
乐观锁 乐观锁是一种并发控制的机制,其核心思想是假设多个事务之间的冲突是不太可能发生的,因此在事务处理之前不会加锁,而是在事务提交的时候再检查是否有冲突。如果发现冲突,就会回滚事务,重新尝试。 实现乐观锁的方…...
【算法】堆排序
算法-堆排序 前置知识 堆(即将更新) 思路 我们现在有一个序列,怎么对它排序? 这是一个非常经典的问题,这里我们使用一个借助数据结构的算法——堆排序解决。 这里有一个序列,要对它升序排序 4 7 3 6 5 …...
51单片机应用从零开始(三)
51单片机应用从零开始(一)-CSDN博客 51单片机应用从零开始(二)-CSDN博客 详解 KEIL C51 软件的使用建立工程-CSDN博客 详解 KEIL C51 软件的使用设置工程编绎与连接程序-CSDN博客 目录 1. 用单片机控制第一个灯亮 2. 认识单片…...
如何在 Nginx Proxy Manager(NPM)上部署静态网站
前言 众所周知,我们在之前介绍过 Nginx Proxy Manager(以下简称 NPM) 这个反向代理的神器,对于一些 Docker 搭建的 Web 项目,NPM 能够很轻松地给他们做反向代理。 然而对于一些静态网站,小伙伴们可能不知道怎么用 NP…...
Android 11开发避坑:为什么你的App获取的Wifi MAC地址总是变?手把手教你配置固定MAC
Android 11开发实战:彻底解决Wifi MAC地址随机化问题最近在开发一个设备管理系统时,遇到了一个棘手的问题:我们的App在Android 11设备上获取的Wifi MAC地址每次都不一样,导致基于MAC地址的设备识别功能完全失效。经过一周的深入研…...
UOS系统下WPS卸载不干净?手把手教你用命令行精准清理(附dpkg/apt组合拳)
UOS系统下WPS卸载不干净?手把手教你用命令行精准清理 在UOS系统日常使用中,WPS Office作为常用办公软件,有时因版本更新或功能调整需要彻底卸载。但不少用户发现,通过图形界面或简单命令卸载后,系统中仍残留配置文件、…...
2026 新视角:化妆品开发的底层逻辑,做好一款产品,从选对原料开始
在化妆品研发链条中,配方架构、生产工艺、包装设计固然重要,但决定一款产品上限的,永远是原料。一款稳定、安全、表现优异的护肤成品,离不开纯净、达标、批次一致的优质原料。对于品牌方、配方师、代工企业而言,原料不…...
WPF虚拟桌宠组件:可嵌入、高性能、工程化UI生命体
1. 这不是“桌面宠物”,而是一个可嵌入的WPF UI组件化生命体你可能在Windows XP时代见过那只晃着尾巴、偶尔打哈欠的3D小猫,也可能在Win10系统托盘里点开过一个会眨眼的像素狐狸——但那些是独立进程、是系统级小工具、是“看一眼就关掉”的轻量娱乐。而…...
从RD、CS到WK:一文讲透SAR主流成像算法的演进与选型实战
从RD、CS到WK:SAR成像算法选型实战指南 当无人机掠过灾区上空,或卫星扫描地球表面时,合成孔径雷达(SAR)正通过电磁波穿透云层和黑暗,将地面信息转化为高分辨率图像。而决定图像质量的关键,在于工…...
基于雷达与光敏传感器的低功耗智能窗防设备设计与实现
1. 项目概述:一个基于雷达与光敏的智能窗防设备几年前,我因为一次短暂的出差,家里空置了几天,回来后就一直琢磨着怎么给家里的窗户加点“动静”。市面上的智能安防摄像头固然好,但要么需要复杂的布线,要么云…...
HarmonyOS 6学习:解决图片放大后无法移动至边缘的matrix4矩阵变换技巧
从"卡在中间"到"自由拖拽":一次完整的图片缩放平移边界问题攻关在HarmonyOS 6应用开发中,我最近遇到了一个看似简单却让人头疼的图片查看器问题:用户双指放大图片后,想要拖动查看边缘细节,却发现图…...
CentOS 8.5最小化安装后,这5个必做的安全与效率优化设置(附一键脚本)
CentOS 8.5最小化安装后的5个必做安全与效率优化刚完成CentOS 8.5最小化安装的系统就像一张白纸——干净但缺乏生产力。作为运维老手,我见过太多人跳过基础优化直接部署应用,结果在后续使用中频繁遇到权限混乱、软件安装慢、SSH爆破等问题。本文将分享我…...
【大模型聚合平台深度评测:阿里云百炼 vs 腾讯云 ADP,企业如何选型?】
大模型聚合平台深度评测:阿里云百炼 vs 腾讯云 ADP,企业如何选型? 随着大模型技术的快速发展,越来越多的企业开始将 AI 能力融入到业务流程中。然而,面对市场上众多的大模型产品,企业往往面临着 “选择困难…...
网安学习第24天 PHP安全——PHP反序列化
一、序列化与反序列化 1、序列化serialize() 序列化是什么?序列化就是把程序中的对象、数组、结构体等复杂数据,转换成可以存储或传输的格式。 简单说: 把“内存里的对象”变成“字符串/字节流”。 例如 PHP 中有一个对象: $u…...
