Android 系统适配无源码app
Android系统,无源码apk分辨率适配
demo1:某个应用的字体大小和UI显示,不适配当前设备的屏幕dpi
先来看一个问题:app启动,onResume中是否可以测量宽高?
如果是activity 启动后第一次进入onResume 生命周期,那么获取到的View的宽高是错误的;
如果是从其他activity回到当前activity而执行的onResume方法,那么就能够获取到View的宽高
为什么?
先找到系统调用 onResume 的地方,read f*** source code
./frameworks/base/core/java/android/app/ActivityThread.java
handleResumeActivity() {
//...
r = performResumeActivity(token, clearHide, reason);//调用 onResume()
//...
wm.addView(decor, l);// WindowManager添加Decor(decor是DecorView)
//...
}
可以看到View的添加是要在执行完onResume()之后的,所以我们调整某个应用的字体大小和UI显示最好是在它之前
frameworks/base/core/java/android/app/Activity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
mRestoredFromBundle = savedInstanceState != null;
mCalled = true;
//add text
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(1);
if (runningTasks != null && !runningTasks.isEmpty()) {
ComponentName topActivity = runningTasks.get(0).topActivity;
String packageName = topActivity.getPackageName();
if ("com.android.deskclock".equals(packageName)) {
Resources resources = getResources();
if (resources != null) {
Configuration configuration = resources.getConfiguration();
//适配字体
if(configuration != null){
if(configuration.fontScale != 1.5f){
configuration.fontScale = 1.5f;
resources.updateConfiguration(configuration,resources.getDisplayMetrics());
}
}
if (configuration != null) {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int densityDpi = displayMetrics.densityDpi;
// 适配 dpi
if (densityDpi != 240) {
configuration.densityDpi = 240;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
}
}
}
}
//add text
}
Android 11 系统修改第三方应用的DPI
onResume中是否可以测量宽高
无源码app修改在Launcher3上显示的app图标
1.系统层修改,可以让系统内所有显示该app图标的地方都改了
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
parseBaseApk(){
...
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp =
parser.getAttributeBooleanValue(null, "coreApp", false);
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
if (result.isError()) {
return result;
}
return input.success(pkg);
} finally {
manifestArray.recycle();
}
...
}
-> parseBaseApkTags() -> parseBaseApplication() -> parseBaseAppBasicFlags(){
...
// Resource ID
.setBanner(resId(R.styleable.AndroidManifestApplication_banner, sa))
.setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
.setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))// app应用图标,熟悉的AndroidManifest
.setLogo(resId(R.styleable.AndroidManifestApplication_logo, sa))
.setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
.setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
.setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
// Strings
.setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
...
.setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
//因为它是链式调用,不方便在上面添加拦截函数,最后替换
//add text
String packageName = pkg.getPackageName();
if(packageName != null && packageName.equals("com.android.settings")){
pkg.setIconRes(com.android.internal.R.drawable.perm_group_camera);//ic_battery
}
//add text
}
./frameworks/base/core/res/res/values/symbols.xml:: <java-symbol type="drawable" name="perm_group_camera" />
Android 11.0 PackageManagerService(二)APK扫描过程
2.Launcher3层面修改,在Launcher3层面修改界面上面显示的icon被修改了,setting和系统安装应用界面等还是原来的图
packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
|| mDisplay == DISPLAY_TASKBAR;
int flags = useTheme ? FLAG_THEMED : 0;
if (mHideBadge) {
flags |= FLAG_NO_BADGE;
}
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
mDotParams.appColor = iconDrawable.getIconColor();
mDotParams.dotColor = getContext().getResources()
.getColor(android.R.color.system_accent3_200, getContext().getTheme());
//add text
String pkg = info.getIntent().getComponent().getPackageName();
String cls = info.getIntent().getComponent().getClassName();
if("com.android.text".equals(pkg)){
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.BS_player);
setIcon(new FastBitmapDrawable(bitmap));
}else{
setIcon(iconDrawable);
}
//add text
applyLabel(info);
}