From 958bceff4a1155c41beee2f658efbab2151c3027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=91=AB?= Date: Sun, 29 Sep 2019 14:26:09 +0800 Subject: [PATCH] =?UTF-8?q?0.7.0=20+=201.1.2=E7=89=88=E6=9C=AC=E5=90=88?= =?UTF-8?q?=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 32 + build.gradle | 27 + consumer-rules.pro | 0 proguard-rules.pro | 21 + src/main/AndroidManifest.xml | 10 + .../ActivityLifecycleCallbacksImpl.java | 48 ++ .../jessyan/autosize/AutoAdaptStrategy.java | 43 ++ .../java/me/jessyan/autosize/AutoSize.java | 352 ++++++++++ .../me/jessyan/autosize/AutoSizeCompat.java | 326 +++++++++ .../me/jessyan/autosize/AutoSizeConfig.java | 645 ++++++++++++++++++ .../autosize/DefaultAutoAdaptStrategy.java | 76 +++ .../jessyan/autosize/DisplayMetricsInfo.java | 150 ++++ .../me/jessyan/autosize/InitProvider.java | 42 ++ .../autosize/WrapperAutoAdaptStrategy.java | 49 ++ .../autosize/external/ExternalAdaptInfo.java | 66 ++ .../external/ExternalAdaptManager.java | 68 ++ .../autosize/internal/CancelAdapt.java | 9 + .../autosize/internal/CustomAdapt.java | 12 + .../me/jessyan/autosize/onAdaptListener.java | 46 ++ .../me/jessyan/autosize/unit/Subunits.java | 53 ++ .../jessyan/autosize/unit/UnitsManager.java | 213 ++++++ .../jessyan/autosize/utils/AutoSizeUtils.java | 35 + .../me/jessyan/autosize/utils/LogUtils.java | 46 ++ .../jessyan/autosize/utils/Preconditions.java | 159 +++++ .../jessyan/autosize/utils/ScreenUtils.java | 75 ++ 26 files changed, 2604 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build.gradle create mode 100644 consumer-rules.pro create mode 100644 proguard-rules.pro create mode 100644 src/main/AndroidManifest.xml create mode 100644 src/main/java/me/jessyan/autosize/ActivityLifecycleCallbacksImpl.java create mode 100644 src/main/java/me/jessyan/autosize/AutoAdaptStrategy.java create mode 100644 src/main/java/me/jessyan/autosize/AutoSize.java create mode 100644 src/main/java/me/jessyan/autosize/AutoSizeCompat.java create mode 100644 src/main/java/me/jessyan/autosize/AutoSizeConfig.java create mode 100644 src/main/java/me/jessyan/autosize/DefaultAutoAdaptStrategy.java create mode 100644 src/main/java/me/jessyan/autosize/DisplayMetricsInfo.java create mode 100644 src/main/java/me/jessyan/autosize/InitProvider.java create mode 100644 src/main/java/me/jessyan/autosize/WrapperAutoAdaptStrategy.java create mode 100644 src/main/java/me/jessyan/autosize/external/ExternalAdaptInfo.java create mode 100644 src/main/java/me/jessyan/autosize/external/ExternalAdaptManager.java create mode 100644 src/main/java/me/jessyan/autosize/internal/CancelAdapt.java create mode 100644 src/main/java/me/jessyan/autosize/internal/CustomAdapt.java create mode 100644 src/main/java/me/jessyan/autosize/onAdaptListener.java create mode 100644 src/main/java/me/jessyan/autosize/unit/Subunits.java create mode 100644 src/main/java/me/jessyan/autosize/unit/UnitsManager.java create mode 100644 src/main/java/me/jessyan/autosize/utils/AutoSizeUtils.java create mode 100644 src/main/java/me/jessyan/autosize/utils/LogUtils.java create mode 100644 src/main/java/me/jessyan/autosize/utils/Preconditions.java create mode 100644 src/main/java/me/jessyan/autosize/utils/ScreenUtils.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build diff --git a/README.md b/README.md new file mode 100644 index 0000000..140d9fb --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# **AndroidAutoSize** 0.7.0 + 1.1.2 综合版本 + +本项目是解决低版本适配问题 解决 [#32错误](https://github.com/JessYanCoding/AndroidAutoSize/issues/32) + +不包含 + +``` +FragmentManager.FragmentLifecycleCallbacks +``` + +在AutoSize 0.7.0 的基础上 去掉了 fragment 适配 + + +使用 AutoSizeCompat 类,使用以下代码即可解决所有屏幕适配失效的问题 + +``` +@Override +public Resources getResources() { +//如果没有自定义需求用这个方法 +AutoSizeCompat.autoConvertDensityOfGlobal((super.getResources()); +//如果有自定义需求就用这个方法 +AutoSizeCompat.autoConvertDensity((super.getResources(), 667, false); +return super.getResources(); +} +AutoSizeConfig.getInstance().setExcludeFontScale(true); 一行代码即可实现 App 内的字体大小不跟随系统设置中字体大小的改 +``` + + + + + +`注意:` 本项目是LIbrary 请使用 Module 方式导入项目使用 \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ac930e5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + buildToolsVersion "28.0.3" + + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + provided 'com.android.support:appcompat-v7:28.0.0' +} diff --git a/consumer-rules.pro b/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/proguard-rules.pro b/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4f5d3b8 --- /dev/null +++ b/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/src/main/java/me/jessyan/autosize/ActivityLifecycleCallbacksImpl.java b/src/main/java/me/jessyan/autosize/ActivityLifecycleCallbacksImpl.java new file mode 100644 index 0000000..c81a70b --- /dev/null +++ b/src/main/java/me/jessyan/autosize/ActivityLifecycleCallbacksImpl.java @@ -0,0 +1,48 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize; + +import android.app.Activity; +import android.app.Application.ActivityLifecycleCallbacks; +import android.os.Bundle; + +public class ActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks { + private AutoAdaptStrategy mAutoAdaptStrategy; + + public ActivityLifecycleCallbacksImpl(AutoAdaptStrategy autoAdaptStrategy) { + this.setAutoAdaptStrategy(autoAdaptStrategy); + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + if (this.mAutoAdaptStrategy != null) { + this.mAutoAdaptStrategy.applyAdapt(activity,activity); + } + + } + @Override + public void onActivityStarted(Activity activity) { + } + @Override + public void onActivityResumed(Activity activity) { + } + @Override + public void onActivityPaused(Activity activity) { + } + @Override + public void onActivityStopped(Activity activity) { + } + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + } + @Override + public void onActivityDestroyed(Activity activity) { + } + + public void setAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) { + this.mAutoAdaptStrategy = autoAdaptStrategy; + } +} diff --git a/src/main/java/me/jessyan/autosize/AutoAdaptStrategy.java b/src/main/java/me/jessyan/autosize/AutoAdaptStrategy.java new file mode 100644 index 0000000..7216f40 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/AutoAdaptStrategy.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.app.Activity; +import android.app.Application; +import android.support.v4.app.Fragment; +import android.util.DisplayMetrics; + +/** + * ================================================ + * 屏幕适配逻辑策略类, 可通过 {@link AutoSizeConfig#init(Application, boolean, AutoAdaptStrategy)} + * 和 {@link AutoSizeConfig#setAutoAdaptStrategy(AutoAdaptStrategy)} 切换策略 + * + * @see DefaultAutoAdaptStrategy + * Created by JessYan on 2018/8/9 15:13 + * Contact me + * Follow me + * ================================================ + */ +public interface AutoAdaptStrategy { + + /** + * 开始执行屏幕适配逻辑 + * + * @param target 需要屏幕适配的对象 (可能是 {@link Activity} 或者 {@link Fragment}) + * @param activity 需要拿到当前的 {@link Activity} 才能修改 {@link DisplayMetrics#density} + */ + void applyAdapt(Object target, Activity activity); +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/AutoSize.java b/src/main/java/me/jessyan/autosize/AutoSize.java new file mode 100644 index 0000000..77fef7d --- /dev/null +++ b/src/main/java/me/jessyan/autosize/AutoSize.java @@ -0,0 +1,352 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.app.Activity; +import android.app.Application; +import android.app.Dialog; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.net.Uri; +import android.util.DisplayMetrics; +import android.view.View; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import me.jessyan.autosize.external.ExternalAdaptInfo; +import me.jessyan.autosize.external.ExternalAdaptManager; +import me.jessyan.autosize.internal.CancelAdapt; +import me.jessyan.autosize.internal.CustomAdapt; +import me.jessyan.autosize.utils.LogUtils; +import me.jessyan.autosize.utils.Preconditions; + +/** + * ================================================ + * AndroidAutoSize 用于屏幕适配的核心方法都在这里, 核心原理来自于 今日头条官方适配方案 + * 此方案只要应用到 {@link Activity} 上, 这个 {@link Activity} 下的所有 {@link android.support.v4.app.Fragment}、{@link Dialog}、 + * 自定义 {@link View} 都会达到适配的效果, 如果某个页面不想使用适配请让该 {@link Activity} 实现 {@link CancelAdapt} + *

+ * 任何方案都不可能完美, 在成本和收益中做出取舍, 选择出最适合自己的方案即可, 在没有更好的方案出来之前, 只有继续忍耐它的不完美, 或者自己作出改变 + * 既然选择, 就不要抱怨, 感谢 今日头条技术团队 和 张鸿洋 等人对 Android 屏幕适配领域的的贡献 + *

+ * Created by JessYan on 2018/8/8 19:20 + * Contact me + * Follow me + * ================================================ + */ +public final class AutoSize { + private static Map mCache = new ConcurrentHashMap<>(); + + private AutoSize() { + throw new IllegalStateException("you can't instantiate me!"); + } + + /** + * 使用 AndroidAutoSize 初始化时设置的默认适配参数进行适配 (AndroidManifest 的 Meta 属性) + * + * @param activity {@link Activity} + */ + public static void autoConvertDensityOfGlobal(Activity activity) { + if (AutoSizeConfig.getInstance().isBaseOnWidth()) { + autoConvertDensityBaseOnWidth(activity, AutoSizeConfig.getInstance().getDesignWidthInDp()); + } else { + autoConvertDensityBaseOnHeight(activity, AutoSizeConfig.getInstance().getDesignHeightInDp()); + } + } + + /** + * 使用 {@link Activity} 或 {@link android.support.v4.app.Fragment} 的自定义参数进行适配 + * + * @param activity {@link Activity} + * @param customAdapt {@link Activity} 或 {@link android.support.v4.app.Fragment} 需实现 {@link CustomAdapt} + */ + public static void autoConvertDensityOfCustomAdapt(Activity activity, CustomAdapt customAdapt) { + Preconditions.checkNotNull(customAdapt, "customAdapt == null"); + float sizeInDp = customAdapt.getSizeInDp(); + + //如果 CustomAdapt#getSizeInDp() 返回 0, 则使用在 AndroidManifest 上填写的设计图尺寸 + if (sizeInDp <= 0) { + if (customAdapt.isBaseOnWidth()) { + sizeInDp = AutoSizeConfig.getInstance().getDesignWidthInDp(); + } else { + sizeInDp = AutoSizeConfig.getInstance().getDesignHeightInDp(); + } + } + autoConvertDensity(activity, sizeInDp, customAdapt.isBaseOnWidth()); + } + + /** + * 使用外部三方库的 {@link Activity} 或 {@link android.support.v4.app.Fragment} 的自定义适配参数进行适配 + * + * @param activity {@link Activity} + * @param externalAdaptInfo 三方库的 {@link Activity} 或 {@link android.support.v4.app.Fragment} 提供的适配参数, 需要配合 {@link ExternalAdaptManager#addExternalAdaptInfoOfActivity(Class, ExternalAdaptInfo)} + */ + public static void autoConvertDensityOfExternalAdaptInfo(Activity activity, ExternalAdaptInfo externalAdaptInfo) { + Preconditions.checkNotNull(externalAdaptInfo, "externalAdaptInfo == null"); + float sizeInDp = externalAdaptInfo.getSizeInDp(); + + //如果 ExternalAdaptInfo#getSizeInDp() 返回 0, 则使用在 AndroidManifest 上填写的设计图尺寸 + if (sizeInDp <= 0) { + if (externalAdaptInfo.isBaseOnWidth()) { + sizeInDp = AutoSizeConfig.getInstance().getDesignWidthInDp(); + } else { + sizeInDp = AutoSizeConfig.getInstance().getDesignHeightInDp(); + } + } + autoConvertDensity(activity, sizeInDp, externalAdaptInfo.isBaseOnWidth()); + } + + /** + * 以宽度为基准进行适配 + * + * @param activity {@link Activity} + * @param designWidthInDp 设计图的总宽度 + */ + public static void autoConvertDensityBaseOnWidth(Activity activity, float designWidthInDp) { + autoConvertDensity(activity, designWidthInDp, true); + } + + /** + * 以高度为基准进行适配 + * + * @param activity {@link Activity} + * @param designHeightInDp 设计图的总高度 + */ + public static void autoConvertDensityBaseOnHeight(Activity activity, float designHeightInDp) { + autoConvertDensity(activity, designHeightInDp, false); + } + + /** + * 这里是今日头条适配方案的核心代码, 核心在于根据当前设备的实际情况做自动计算并转换 {@link DisplayMetrics#density}、 + * {@link DisplayMetrics#scaledDensity}、{@link DisplayMetrics#densityDpi} 这三个值, 额外增加 {@link DisplayMetrics#xdpi} + * 以支持单位 {@code pt}、{@code in}、{@code mm} + * + * @param activity {@link Activity} + * @param sizeInDp 设计图上的设计尺寸, 单位 dp, 如果 {@param isBaseOnWidth} 设置为 {@code true}, + * {@param sizeInDp} 则应该填写设计图的总宽度, 如果 {@param isBaseOnWidth} 设置为 {@code false}, + * {@param sizeInDp} 则应该填写设计图的总高度 + * @param isBaseOnWidth 是否按照宽度进行等比例适配, {@code true} 为以宽度进行等比例适配, {@code false} 为以高度进行等比例适配 + * @see 今日头条官方适配方案 + */ + public static void autoConvertDensity(Activity activity, float sizeInDp, boolean isBaseOnWidth) { + Preconditions.checkNotNull(activity, "activity == null"); + + float subunitsDesignSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getUnitsManager().getDesignWidth() + : AutoSizeConfig.getInstance().getUnitsManager().getDesignHeight(); + subunitsDesignSize = subunitsDesignSize > 0 ? subunitsDesignSize : sizeInDp; + + int screenSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getScreenWidth() + : AutoSizeConfig.getInstance().getScreenHeight(); + String key = sizeInDp + "|" + subunitsDesignSize + "|" + isBaseOnWidth + "|" + + AutoSizeConfig.getInstance().isUseDeviceSize() + "|" + + AutoSizeConfig.getInstance().getInitScaledDensity() + "|" + + screenSize; + + DisplayMetricsInfo displayMetricsInfo = mCache.get(key); + + float targetDensity = 0; + int targetDensityDpi = 0; + float targetScaledDensity = 0; + float targetXdpi = 0; + int targetScreenWidthDp; + int targetScreenHeightDp; + + if (displayMetricsInfo == null) { + if (isBaseOnWidth) { + targetDensity = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / sizeInDp; + } else { + targetDensity = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / sizeInDp; + } + float scale = AutoSizeConfig.getInstance().isExcludeFontScale() ? 1 : AutoSizeConfig.getInstance(). + getInitScaledDensity() * 1.0f / AutoSizeConfig.getInstance().getInitDensity(); + targetScaledDensity = targetDensity * scale; + targetDensityDpi = (int) (targetDensity * 160); + + targetScreenWidthDp = (int) (AutoSizeConfig.getInstance().getScreenWidth() / targetDensity); + targetScreenHeightDp = (int) (AutoSizeConfig.getInstance().getScreenHeight() / targetDensity); + + if (isBaseOnWidth) { + targetXdpi = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / subunitsDesignSize; + } else { + targetXdpi = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / subunitsDesignSize; + } + + mCache.put(key, new DisplayMetricsInfo(targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi, targetScreenWidthDp, targetScreenHeightDp)); + } else { + targetDensity = displayMetricsInfo.getDensity(); + targetDensityDpi = displayMetricsInfo.getDensityDpi(); + targetScaledDensity = displayMetricsInfo.getScaledDensity(); + targetXdpi = displayMetricsInfo.getXdpi(); + targetScreenWidthDp = displayMetricsInfo.getScreenWidthDp(); + targetScreenHeightDp = displayMetricsInfo.getScreenHeightDp(); + } + + setDensity(activity, targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi); + setScreenSizeDp(activity, targetScreenWidthDp, targetScreenHeightDp); + + LogUtils.d(String.format(Locale.ENGLISH, "The %s has been adapted! \n%s Info: isBaseOnWidth = %s, %s = %f, %s = %f, targetDensity = %f, targetScaledDensity = %f, targetDensityDpi = %d, targetXdpi = %f, targetScreenWidthDp = %d, targetScreenHeightDp = %d" + , activity.getClass().getName(), activity.getClass().getSimpleName(), isBaseOnWidth, isBaseOnWidth ? "designWidthInDp" + : "designHeightInDp", sizeInDp, isBaseOnWidth ? "designWidthInSubunits" : "designHeightInSubunits", subunitsDesignSize + , targetDensity, targetScaledDensity, targetDensityDpi, targetXdpi, targetScreenWidthDp, targetScreenHeightDp)); + } + + /** + * 取消适配 + * + * @param activity {@link Activity} + */ + public static void cancelAdapt(Activity activity) { + float initXdpi = AutoSizeConfig.getInstance().getInitXdpi(); + switch (AutoSizeConfig.getInstance().getUnitsManager().getSupportSubunits()) { + case PT: + initXdpi = initXdpi / 72f; + break; + case MM: + initXdpi = initXdpi / 25.4f; + break; + default: + } + setDensity(activity, AutoSizeConfig.getInstance().getInitDensity() + , AutoSizeConfig.getInstance().getInitDensityDpi() + , AutoSizeConfig.getInstance().getInitScaledDensity() + , initXdpi); + setScreenSizeDp(activity + , AutoSizeConfig.getInstance().getInitScreenWidthDp() + , AutoSizeConfig.getInstance().getInitScreenHeightDp()); + } + + /** + * 当 App 中出现多进程,并且您需要适配所有的进程,就需要在 App 初始化时调用 {@link #initCompatMultiProcess} + * 建议实现自定义 {@link Application} 并在 {@link Application#onCreate()} 中调用 {@link #initCompatMultiProcess} + * + * @param context {@link Context} + */ + public static void initCompatMultiProcess(Context context) { + context.getContentResolver().query(Uri.parse("content://" + context.getPackageName() + ".autosize-init-provider"), null, null, null, null); + } + + /** + * 给几大 {@link DisplayMetrics} 赋值 + * + * @param activity {@link Activity} + * @param density {@link DisplayMetrics#density} + * @param densityDpi {@link DisplayMetrics#densityDpi} + * @param scaledDensity {@link DisplayMetrics#scaledDensity} + * @param xdpi {@link DisplayMetrics#xdpi} + */ + private static void setDensity(Activity activity, float density, int densityDpi, float scaledDensity, float xdpi) { + //兼容 MIUI + DisplayMetrics activityDisplayMetricsOnMIUI = getMetricsOnMiui(activity.getResources()); + DisplayMetrics appDisplayMetricsOnMIUI = getMetricsOnMiui(AutoSizeConfig.getInstance().getApplication().getResources()); + + if (activityDisplayMetricsOnMIUI != null) { + setDensity(activityDisplayMetricsOnMIUI, density, densityDpi, scaledDensity, xdpi); + } else { + DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); + setDensity(activityDisplayMetrics, density, densityDpi, scaledDensity, xdpi); + } + + if (appDisplayMetricsOnMIUI != null) { + setDensity(appDisplayMetricsOnMIUI, density, densityDpi, scaledDensity, xdpi); + } else { + DisplayMetrics appDisplayMetrics = AutoSizeConfig.getInstance().getApplication().getResources().getDisplayMetrics(); + setDensity(appDisplayMetrics, density, densityDpi, scaledDensity, xdpi); + } + } + + /** + * 赋值 + * + * @param displayMetrics {@link DisplayMetrics} + * @param density {@link DisplayMetrics#density} + * @param densityDpi {@link DisplayMetrics#densityDpi} + * @param scaledDensity {@link DisplayMetrics#scaledDensity} + * @param xdpi {@link DisplayMetrics#xdpi} + */ + private static void setDensity(DisplayMetrics displayMetrics, float density, int densityDpi, float scaledDensity, float xdpi) { + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportDP()) { + displayMetrics.density = density; + displayMetrics.densityDpi = densityDpi; + } + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportSP()) { + displayMetrics.scaledDensity = scaledDensity; + } + switch (AutoSizeConfig.getInstance().getUnitsManager().getSupportSubunits()) { + case NONE: + break; + case PT: + displayMetrics.xdpi = xdpi * 72f; + break; + case IN: + displayMetrics.xdpi = xdpi; + break; + case MM: + displayMetrics.xdpi = xdpi * 25.4f; + break; + default: + } + } + + /** + * 给 {@link Configuration} 赋值 + * + * @param activity {@link Activity} + * @param screenWidthDp {@link Configuration#screenWidthDp} + * @param screenHeightDp {@link Configuration#screenHeightDp} + */ + private static void setScreenSizeDp(Activity activity, int screenWidthDp, int screenHeightDp) { + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportDP() && AutoSizeConfig.getInstance().getUnitsManager().isSupportScreenSizeDP()) { + Configuration activityConfiguration = activity.getResources().getConfiguration(); + setScreenSizeDp(activityConfiguration, screenWidthDp, screenHeightDp); + + Configuration appConfiguration = AutoSizeConfig.getInstance().getApplication().getResources().getConfiguration(); + setScreenSizeDp(appConfiguration, screenWidthDp, screenHeightDp); + } + } + + /** + * Configuration赋值 + * + * @param configuration {@link Configuration} + * @param screenWidthDp {@link Configuration#screenWidthDp} + * @param screenHeightDp {@link Configuration#screenHeightDp} + */ + private static void setScreenSizeDp(Configuration configuration, int screenWidthDp, int screenHeightDp) { + configuration.screenWidthDp = screenWidthDp; + configuration.screenHeightDp = screenHeightDp; + } + + /** + * 解决 MIUI 更改框架导致的 MIUI7 + Android5.1.1 上出现的失效问题 (以及极少数基于这部分 MIUI 去掉 ART 然后置入 XPosed 的手机) + * 来源于: https://github.com/Firedamp/Rudeness/blob/master/rudeness-sdk/src/main/java/com/bulong/rudeness/RudenessScreenHelper.java#L61:5 + * + * @param resources {@link Resources} + * @return {@link DisplayMetrics}, 可能为 {@code null} + */ + private static DisplayMetrics getMetricsOnMiui(Resources resources) { + if (AutoSizeConfig.getInstance().isMiui() && AutoSizeConfig.getInstance().getTmpMetricsField() != null) { + try { + return (DisplayMetrics) AutoSizeConfig.getInstance().getTmpMetricsField().get(resources); + } catch (Exception e) { + return null; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/AutoSizeCompat.java b/src/main/java/me/jessyan/autosize/AutoSizeCompat.java new file mode 100644 index 0000000..a83d7fd --- /dev/null +++ b/src/main/java/me/jessyan/autosize/AutoSizeCompat.java @@ -0,0 +1,326 @@ +package me.jessyan.autosize; + +/* + * Copyright 2019 JessYan + * + * 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. + */ + +import android.app.Activity; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.util.DisplayMetrics; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import me.jessyan.autosize.external.ExternalAdaptInfo; +import me.jessyan.autosize.external.ExternalAdaptManager; +import me.jessyan.autosize.internal.CustomAdapt; +import me.jessyan.autosize.utils.Preconditions; + +/** + * ================================================ + * 当遇到本来适配正常的布局突然出现适配失效,适配异常等问题, 重写当前 {@link Activity} 的 {@link Activity#getResources()} 并调用 + * {@link AutoSizeCompat} 的对应方法即可解决问题 + *

+ * Created by JessYan on 2018/8/8 19:20 + * Contact me + * Follow me + * ================================================ + */ +public final class AutoSizeCompat { + private static Map mCache = new ConcurrentHashMap<>(); + + private AutoSizeCompat() { + throw new IllegalStateException("you can't instantiate me!"); + } + + /** + * 使用 AndroidAutoSize 初始化时设置的默认适配参数进行适配 (AndroidManifest 的 Meta 属性) + * + * @param resources {@link Resources} + */ + public static void autoConvertDensityOfGlobal(Resources resources) { + if (AutoSizeConfig.getInstance().isBaseOnWidth()) { + autoConvertDensityBaseOnWidth(resources, AutoSizeConfig.getInstance().getDesignWidthInDp()); + } else { + autoConvertDensityBaseOnHeight(resources, AutoSizeConfig.getInstance().getDesignHeightInDp()); + } + } + + /** + * 使用 {@link Activity} 或 {@link android.support.v4.app.Fragment} 的自定义参数进行适配 + * + * @param resources {@link Resources} + * @param customAdapt {@link Activity} 或 {@link android.support.v4.app.Fragment} 需实现 {@link CustomAdapt} + */ + public static void autoConvertDensityOfCustomAdapt(Resources resources, CustomAdapt customAdapt) { + Preconditions.checkNotNull(customAdapt, "customAdapt == null"); + float sizeInDp = customAdapt.getSizeInDp(); + + //如果 CustomAdapt#getSizeInDp() 返回 0, 则使用在 AndroidManifest 上填写的设计图尺寸 + if (sizeInDp <= 0) { + if (customAdapt.isBaseOnWidth()) { + sizeInDp = AutoSizeConfig.getInstance().getDesignWidthInDp(); + } else { + sizeInDp = AutoSizeConfig.getInstance().getDesignHeightInDp(); + } + } + autoConvertDensity(resources, sizeInDp, customAdapt.isBaseOnWidth()); + } + + /** + * 使用外部三方库的 {@link Activity} 或 {@link android.support.v4.app.Fragment} 的自定义适配参数进行适配 + * + * @param resources {@link Resources} + * @param externalAdaptInfo 三方库的 {@link Activity} 或 {@link android.support.v4.app.Fragment} 提供的适配参数, 需要配合 {@link ExternalAdaptManager#addExternalAdaptInfoOfActivity(Class, ExternalAdaptInfo)} + */ + public static void autoConvertDensityOfExternalAdaptInfo(Resources resources, ExternalAdaptInfo externalAdaptInfo) { + Preconditions.checkNotNull(externalAdaptInfo, "externalAdaptInfo == null"); + float sizeInDp = externalAdaptInfo.getSizeInDp(); + + //如果 ExternalAdaptInfo#getSizeInDp() 返回 0, 则使用在 AndroidManifest 上填写的设计图尺寸 + if (sizeInDp <= 0) { + if (externalAdaptInfo.isBaseOnWidth()) { + sizeInDp = AutoSizeConfig.getInstance().getDesignWidthInDp(); + } else { + sizeInDp = AutoSizeConfig.getInstance().getDesignHeightInDp(); + } + } + autoConvertDensity(resources, sizeInDp, externalAdaptInfo.isBaseOnWidth()); + } + + /** + * 以宽度为基准进行适配 + * + * @param resources {@link Resources} + * @param designWidthInDp 设计图的总宽度 + */ + public static void autoConvertDensityBaseOnWidth(Resources resources, float designWidthInDp) { + autoConvertDensity(resources, designWidthInDp, true); + } + + /** + * 以高度为基准进行适配 + * + * @param resources {@link Resources} + * @param designHeightInDp 设计图的总高度 + */ + public static void autoConvertDensityBaseOnHeight(Resources resources, float designHeightInDp) { + autoConvertDensity(resources, designHeightInDp, false); + } + + /** + * 这里是今日头条适配方案的核心代码, 核心在于根据当前设备的实际情况做自动计算并转换 {@link DisplayMetrics#density}、 + * {@link DisplayMetrics#scaledDensity}、{@link DisplayMetrics#densityDpi} 这三个值, 额外增加 {@link DisplayMetrics#xdpi} + * 以支持单位 {@code pt}、{@code in}、{@code mm} + * + * @param resources {@link Resources} + * @param sizeInDp 设计图上的设计尺寸, 单位 dp, 如果 {@param isBaseOnWidth} 设置为 {@code true}, + * {@param sizeInDp} 则应该填写设计图的总宽度, 如果 {@param isBaseOnWidth} 设置为 {@code false}, + * {@param sizeInDp} 则应该填写设计图的总高度 + * @param isBaseOnWidth 是否按照宽度进行等比例适配, {@code true} 为以宽度进行等比例适配, {@code false} 为以高度进行等比例适配 + * @see 今日头条官方适配方案 + */ + public static void autoConvertDensity(Resources resources, float sizeInDp, boolean isBaseOnWidth) { + Preconditions.checkNotNull(resources, "resources == null"); + + float subunitsDesignSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getUnitsManager().getDesignWidth() + : AutoSizeConfig.getInstance().getUnitsManager().getDesignHeight(); + subunitsDesignSize = subunitsDesignSize > 0 ? subunitsDesignSize : sizeInDp; + + int screenSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getScreenWidth() + : AutoSizeConfig.getInstance().getScreenHeight(); + String key = sizeInDp + "|" + subunitsDesignSize + "|" + isBaseOnWidth + "|" + + AutoSizeConfig.getInstance().isUseDeviceSize() + "|" + + AutoSizeConfig.getInstance().getInitScaledDensity() + "|" + + screenSize; + + DisplayMetricsInfo displayMetricsInfo = mCache.get(key); + + float targetDensity = 0; + int targetDensityDpi = 0; + float targetScaledDensity = 0; + float targetXdpi = 0; + int targetScreenWidthDp; + int targetScreenHeightDp; + + if (displayMetricsInfo == null) { + if (isBaseOnWidth) { + targetDensity = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / sizeInDp; + } else { + targetDensity = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / sizeInDp; + } + float scale = AutoSizeConfig.getInstance().isExcludeFontScale() ? 1 : AutoSizeConfig.getInstance(). + getInitScaledDensity() * 1.0f / AutoSizeConfig.getInstance().getInitDensity(); + targetScaledDensity = targetDensity * scale; + targetDensityDpi = (int) (targetDensity * 160); + + targetScreenWidthDp = (int) (AutoSizeConfig.getInstance().getScreenWidth() / targetDensity); + targetScreenHeightDp = (int) (AutoSizeConfig.getInstance().getScreenHeight() / targetDensity); + + if (isBaseOnWidth) { + targetXdpi = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / subunitsDesignSize; + } else { + targetXdpi = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / subunitsDesignSize; + } + + mCache.put(key, new DisplayMetricsInfo(targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi, targetScreenWidthDp, targetScreenHeightDp)); + } else { + targetDensity = displayMetricsInfo.getDensity(); + targetDensityDpi = displayMetricsInfo.getDensityDpi(); + targetScaledDensity = displayMetricsInfo.getScaledDensity(); + targetXdpi = displayMetricsInfo.getXdpi(); + targetScreenWidthDp = displayMetricsInfo.getScreenWidthDp(); + targetScreenHeightDp = displayMetricsInfo.getScreenHeightDp(); + } + + setDensity(resources, targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi); + setScreenSizeDp(resources, targetScreenWidthDp, targetScreenHeightDp); + } + + /** + * 取消适配 + * + * @param resources {@link Resources} + */ + public static void cancelAdapt(Resources resources) { + float initXdpi = AutoSizeConfig.getInstance().getInitXdpi(); + switch (AutoSizeConfig.getInstance().getUnitsManager().getSupportSubunits()) { + case PT: + initXdpi = initXdpi / 72f; + break; + case MM: + initXdpi = initXdpi / 25.4f; + break; + default: + } + setDensity(resources, AutoSizeConfig.getInstance().getInitDensity() + , AutoSizeConfig.getInstance().getInitDensityDpi() + , AutoSizeConfig.getInstance().getInitScaledDensity() + , initXdpi); + setScreenSizeDp(resources + , AutoSizeConfig.getInstance().getInitScreenWidthDp() + , AutoSizeConfig.getInstance().getInitScreenHeightDp()); + } + + /** + * 给几大 {@link DisplayMetrics} 赋值 + * + * @param resources {@link Resources} + * @param density {@link DisplayMetrics#density} + * @param densityDpi {@link DisplayMetrics#densityDpi} + * @param scaledDensity {@link DisplayMetrics#scaledDensity} + * @param xdpi {@link DisplayMetrics#xdpi} + */ + private static void setDensity(Resources resources, float density, int densityDpi, float scaledDensity, float xdpi) { + //兼容 MIUI + DisplayMetrics activityDisplayMetricsOnMIUI = getMetricsOnMiui(resources); + DisplayMetrics appDisplayMetricsOnMIUI = getMetricsOnMiui(AutoSizeConfig.getInstance().getApplication().getResources()); + + if (activityDisplayMetricsOnMIUI != null) { + setDensity(activityDisplayMetricsOnMIUI, density, densityDpi, scaledDensity, xdpi); + } else { + DisplayMetrics activityDisplayMetrics = resources.getDisplayMetrics(); + setDensity(activityDisplayMetrics, density, densityDpi, scaledDensity, xdpi); + } + + if (appDisplayMetricsOnMIUI != null) { + setDensity(appDisplayMetricsOnMIUI, density, densityDpi, scaledDensity, xdpi); + } else { + DisplayMetrics appDisplayMetrics = AutoSizeConfig.getInstance().getApplication().getResources().getDisplayMetrics(); + setDensity(appDisplayMetrics, density, densityDpi, scaledDensity, xdpi); + } + } + + /** + * 赋值 + * + * @param displayMetrics {@link DisplayMetrics} + * @param density {@link DisplayMetrics#density} + * @param densityDpi {@link DisplayMetrics#densityDpi} + * @param scaledDensity {@link DisplayMetrics#scaledDensity} + * @param xdpi {@link DisplayMetrics#xdpi} + */ + private static void setDensity(DisplayMetrics displayMetrics, float density, int densityDpi, float scaledDensity, float xdpi) { + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportDP()) { + displayMetrics.density = density; + displayMetrics.densityDpi = densityDpi; + } + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportSP()) { + displayMetrics.scaledDensity = scaledDensity; + } + switch (AutoSizeConfig.getInstance().getUnitsManager().getSupportSubunits()) { + case NONE: + break; + case PT: + displayMetrics.xdpi = xdpi * 72f; + break; + case IN: + displayMetrics.xdpi = xdpi; + break; + case MM: + displayMetrics.xdpi = xdpi * 25.4f; + break; + default: + } + } + + /** + * 给 {@link Configuration} 赋值 + * + * @param resources {@link Resources} + * @param screenWidthDp {@link Configuration#screenWidthDp} + * @param screenHeightDp {@link Configuration#screenHeightDp} + */ + private static void setScreenSizeDp(Resources resources, int screenWidthDp, int screenHeightDp) { + if (AutoSizeConfig.getInstance().getUnitsManager().isSupportDP() && AutoSizeConfig.getInstance().getUnitsManager().isSupportScreenSizeDP()) { + Configuration activityConfiguration = resources.getConfiguration(); + setScreenSizeDp(activityConfiguration, screenWidthDp, screenHeightDp); + + Configuration appConfiguration = AutoSizeConfig.getInstance().getApplication().getResources().getConfiguration(); + setScreenSizeDp(appConfiguration, screenWidthDp, screenHeightDp); + } + } + + /** + * Configuration赋值 + * + * @param configuration {@link Configuration} + * @param screenWidthDp {@link Configuration#screenWidthDp} + * @param screenHeightDp {@link Configuration#screenHeightDp} + */ + private static void setScreenSizeDp(Configuration configuration, int screenWidthDp, int screenHeightDp) { + configuration.screenWidthDp = screenWidthDp; + configuration.screenHeightDp = screenHeightDp; + } + + /** + * 解决 MIUI 更改框架导致的 MIUI7 + Android5.1.1 上出现的失效问题 (以及极少数基于这部分 MIUI 去掉 ART 然后置入 XPosed 的手机) + * 来源于: https://github.com/Firedamp/Rudeness/blob/master/rudeness-sdk/src/main/java/com/bulong/rudeness/RudenessScreenHelper.java#L61:5 + * + * @param resources {@link Resources} + * @return {@link DisplayMetrics}, 可能为 {@code null} + */ + private static DisplayMetrics getMetricsOnMiui(Resources resources) { + if (AutoSizeConfig.getInstance().isMiui() && AutoSizeConfig.getInstance().getTmpMetricsField() != null) { + try { + return (DisplayMetrics) AutoSizeConfig.getInstance().getTmpMetricsField().get(resources); + } catch (Exception e) { + return null; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/AutoSizeConfig.java b/src/main/java/me/jessyan/autosize/AutoSizeConfig.java new file mode 100644 index 0000000..d49c825 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/AutoSizeConfig.java @@ -0,0 +1,645 @@ +package me.jessyan.autosize; + +import android.app.Activity; +import android.app.Application; +import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.support.v4.app.Fragment; +import android.util.DisplayMetrics; + +import java.lang.reflect.Field; + +import me.jessyan.autosize.external.ExternalAdaptManager; +import me.jessyan.autosize.unit.UnitsManager; +import me.jessyan.autosize.utils.LogUtils; +import me.jessyan.autosize.utils.Preconditions; +import me.jessyan.autosize.utils.ScreenUtils; + +/** + * ================================================ + * AndroidAutoSize 参数配置类, 给 AndroidAutoSize 配置一些必要的自定义参数 + *

+ * Created by JessYan on 2018/8/8 09:58 + * Contact me + * Follow me + * ================================================ + */ +public final class AutoSizeConfig { + private static volatile AutoSizeConfig sInstance; + private static final String KEY_DESIGN_WIDTH_IN_DP = "design_width_in_dp"; + private static final String KEY_DESIGN_HEIGHT_IN_DP = "design_height_in_dp"; + private Application mApplication; + /** + * 用来管理外部三方库 {@link Activity} 的适配 + */ + private ExternalAdaptManager mExternalAdaptManager = new ExternalAdaptManager(); + /** + * 用来管理 AndroidAutoSize 支持的所有单位, AndroidAutoSize 支持五种单位 (dp、sp、pt、in、mm) + */ + private UnitsManager mUnitsManager = new UnitsManager(); + /** + * 最初的 {@link DisplayMetrics#density} + */ + private float mInitDensity = -1; + /** + * 最初的 {@link DisplayMetrics#densityDpi} + */ + private int mInitDensityDpi; + /** + * 最初的 {@link DisplayMetrics#scaledDensity} + */ + private float mInitScaledDensity; + /** + * 最初的 {@link DisplayMetrics#xdpi} + */ + private float mInitXdpi; + /** + * 最初的 {@link Configuration#screenWidthDp} + */ + private int mInitScreenWidthDp; + /** + * 最初的 {@link Configuration#screenHeightDp} + */ + private int mInitScreenHeightDp; + /** + * 设计图上的总宽度, 单位 dp + */ + private int mDesignWidthInDp; + /** + * 设计图上的总高度, 单位 dp + */ + private int mDesignHeightInDp; + /** + * 设备的屏幕总宽度, 单位 px + */ + private int mScreenWidth; + /** + * 设备的屏幕总高度, 单位 px, 如果 {@link #isUseDeviceSize} 为 {@code false}, 屏幕总高度会减去状态栏的高度 + */ + private int mScreenHeight; + /** + * 状态栏高度, 当 {@link #isUseDeviceSize} 为 {@code false} 时, AndroidAutoSize 会将 {@link #mScreenHeight} 减去状态栏高度 + * AndroidAutoSize 默认使用 {@link ScreenUtils#getStatusBarHeight()} 方法获取状态栏高度 + * AndroidAutoSize 使用者可使用 {@link #setStatusBarHeight(int)} 自行设置状态栏高度 + */ + private int mStatusBarHeight; + /** + * 为了保证在不同高宽比的屏幕上显示效果也能完全一致, 所以本方案适配时是以设计图宽度与设备实际宽度的比例或设计图高度与设备实际高度的比例应用到 + * 每个 View 上 (只能在宽度和高度之中选一个作为基准), 从而使每个 View 的高和宽用同样的比例缩放, 避免在与设计图高宽比不一致的设备上出现适配的 View 高或宽变形的问题 + * {@link #isBaseOnWidth} 为 {@code true} 时代表以宽度等比例缩放, {@code false} 代表以高度等比例缩放 + * {@link #isBaseOnWidth} 为全局配置, 默认为 {@code true}, 每个 {@link Activity} 也可以单独选择使用高或者宽做等比例缩放 + */ + private boolean isBaseOnWidth = true; + /** + * 此字段表示是否使用设备的实际尺寸做适配 + * {@link #isUseDeviceSize} 为 {@code true} 表示屏幕高度 {@link #mScreenHeight} 包含状态栏的高度 + * {@link #isUseDeviceSize} 为 {@code false} 表示 {@link #mScreenHeight} 会减去状态栏的高度, 默认为 {@code true} + */ + private boolean isUseDeviceSize = true; + /** + * {@link #mActivityLifecycleCallbacks} 可用来代替在 BaseActivity 中加入适配代码的传统方式 + * {@link #mActivityLifecycleCallbacks} 这种方案类似于 AOP, 面向接口, 侵入性低, 方便统一管理, 扩展性强, 并且也支持适配三方库的 {@link Activity} + */ + private ActivityLifecycleCallbacksImpl mActivityLifecycleCallbacks; + /** + * 框架具有 热插拔 特性, 支持在项目运行中动态停止和重新启动适配功能 + * + * @see #stop(Activity) + * @see #restart() + */ + private boolean isStop; + /** + * 是否让框架支持自定义 {@link Fragment} 的适配参数, 由于这个需求是比较少见的, 所以须要使用者手动开启 + */ + private boolean isCustomFragment; + /** + * 屏幕方向, {@code true} 为纵向, {@code false} 为横向 + */ + private boolean isVertical; + /** + * 是否屏蔽系统字体大小对 AndroidAutoSize 的影响, 如果为 {@code true}, App 内的字体的大小将不会跟随系统设置中字体大小的改变 + * 如果为 {@code false}, 则会跟随系统设置中字体大小的改变, 默认为 {@code false} + */ + private boolean isExcludeFontScale; + /** + * 是否是 Miui 系统 + */ + private boolean isMiui; + /** + * Miui 系统中的 mTmpMetrics 字段 + */ + private Field mTmpMetricsField; + /** + * 屏幕适配监听器,用于监听屏幕适配时的一些事件 + */ + private onAdaptListener mOnAdaptListener; + + public static AutoSizeConfig getInstance() { + if (sInstance == null) { + synchronized (AutoSizeConfig.class) { + if (sInstance == null) { + sInstance = new AutoSizeConfig(); + } + } + } + return sInstance; + } + + private AutoSizeConfig() { + } + + public Application getApplication() { + Preconditions.checkNotNull(mApplication, "Please call the AutoSizeConfig#init() first"); + return mApplication; + } + + /** + * v0.7.0 以后, 框架会在 APP 启动时自动调用此方法进行初始化, 使用者无需手动初始化, 初始化方法只能调用一次, 否则报错 + * 此方法默认使用以宽度进行等比例适配, 如想使用以高度进行等比例适配, 请调用 {@link #init(Application, boolean)} + * + * @param application {@link Application} + */ + AutoSizeConfig init(Application application) { + return init(application, true, null); + } + + /** + * v0.7.0 以后, 框架会在 APP 启动时自动调用此方法进行初始化, 使用者无需手动初始化, 初始化方法只能调用一次, 否则报错 + * 此方法使用默认的 {@link AutoAdaptStrategy} 策略, 如想使用自定义的 {@link AutoAdaptStrategy} 策略 + * 请调用 {@link #init(Application, boolean, AutoAdaptStrategy)} + * + * @param application {@link Application} + * @param isBaseOnWidth 详情请查看 {@link #isBaseOnWidth} 的注释 + */ + AutoSizeConfig init(Application application, boolean isBaseOnWidth) { + return init(application, isBaseOnWidth, null); + } + + /** + * v0.7.0 以后, 框架会在 APP 启动时自动调用此方法进行初始化, 使用者无需手动初始化, 初始化方法只能调用一次, 否则报错 + * + * @param application {@link Application} + * @param isBaseOnWidth 详情请查看 {@link #isBaseOnWidth} 的注释 + * @param strategy {@link AutoAdaptStrategy}, 传 {@code null} 则使用 {@link DefaultAutoAdaptStrategy} + */ + AutoSizeConfig init(final Application application, boolean isBaseOnWidth, AutoAdaptStrategy strategy) { + Preconditions.checkArgument(mInitDensity == -1, "AutoSizeConfig#init() can only be called once"); + Preconditions.checkNotNull(application, "application == null"); + this.mApplication = application; + this.isBaseOnWidth = isBaseOnWidth; + final DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics(); + final Configuration configuration = Resources.getSystem().getConfiguration(); + + getMetaData(application); + isVertical = application.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + int[] screenSize = ScreenUtils.getScreenSize(application); + mScreenWidth = screenSize[0]; + mScreenHeight = screenSize[1]; + mStatusBarHeight = ScreenUtils.getStatusBarHeight(); + LogUtils.d("designWidthInDp = " + mDesignWidthInDp + ", designHeightInDp = " + mDesignHeightInDp + ", screenWidth = " + mScreenWidth + ", screenHeight = " + mScreenHeight); + + mInitDensity = displayMetrics.density; + mInitDensityDpi = displayMetrics.densityDpi; + mInitScaledDensity = displayMetrics.scaledDensity; + mInitXdpi = displayMetrics.xdpi; + mInitScreenWidthDp = configuration.screenWidthDp; + mInitScreenHeightDp = configuration.screenHeightDp; + application.registerComponentCallbacks(new ComponentCallbacks() { + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (newConfig != null) { + if (newConfig.fontScale > 0) { + mInitScaledDensity = + Resources.getSystem().getDisplayMetrics().scaledDensity; + LogUtils.d("initScaledDensity = " + mInitScaledDensity + " on ConfigurationChanged"); + } + isVertical = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT; + int[] screenSize = ScreenUtils.getScreenSize(application); + mScreenWidth = screenSize[0]; + mScreenHeight = screenSize[1]; + } + } + + @Override + public void onLowMemory() { + + } + }); + LogUtils.d("initDensity = " + mInitDensity + ", initScaledDensity = " + mInitScaledDensity); + mActivityLifecycleCallbacks = new ActivityLifecycleCallbacksImpl(strategy == null ? new WrapperAutoAdaptStrategy(new DefaultAutoAdaptStrategy()) : strategy); + application.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks); + if ("MiuiResources".equals(application.getResources().getClass().getSimpleName()) || "XResources".equals(application.getResources().getClass().getSimpleName())) { + isMiui = true; + try { + mTmpMetricsField = Resources.class.getDeclaredField("mTmpMetrics"); + mTmpMetricsField.setAccessible(true); + } catch (Exception e) { + mTmpMetricsField = null; + } + } + return this; + } + + /** + * 重新开始框架的运行 + * 框架具有 热插拔 特性, 支持在项目运行中动态停止和重新启动适配功能 + */ + public void restart() { + Preconditions.checkNotNull(mActivityLifecycleCallbacks, "Please call the AutoSizeConfig#init() first"); + synchronized (AutoSizeConfig.class) { + if (isStop) { + mApplication.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks); + isStop = false; + } + } + } + + /** + * 停止框架的运行 + * 框架具有 热插拔 特性, 支持在项目运行中动态停止和重新启动适配功能 + */ + public void stop(Activity activity) { + Preconditions.checkNotNull(mActivityLifecycleCallbacks, "Please call the AutoSizeConfig#init() first"); + synchronized (AutoSizeConfig.class) { + if (!isStop) { + mApplication.unregisterActivityLifecycleCallbacks(mActivityLifecycleCallbacks); + AutoSize.cancelAdapt(activity); + isStop = true; + } + } + } + + /** + * 设置屏幕适配逻辑策略类 + * + * @param autoAdaptStrategy {@link AutoAdaptStrategy} + */ + public AutoSizeConfig setAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) { + Preconditions.checkNotNull(autoAdaptStrategy, "autoAdaptStrategy == null"); + Preconditions.checkNotNull(mActivityLifecycleCallbacks, "Please call the AutoSizeConfig#init() first"); + mActivityLifecycleCallbacks.setAutoAdaptStrategy(new WrapperAutoAdaptStrategy(autoAdaptStrategy)); + return this; + } + + /** + * 设置屏幕适配监听器 + * + * @param onAdaptListener {@link onAdaptListener} + */ + public AutoSizeConfig setOnAdaptListener(onAdaptListener onAdaptListener) { + Preconditions.checkNotNull(onAdaptListener, "onAdaptListener == null"); + mOnAdaptListener = onAdaptListener; + return this; + } + + /** + * 是否全局按照宽度进行等比例适配 + * + * @param baseOnWidth {@code true} 为按照宽度, {@code false} 为按照高度 + * @see #isBaseOnWidth 详情请查看这个字段的注释 + */ + public AutoSizeConfig setBaseOnWidth(boolean baseOnWidth) { + isBaseOnWidth = baseOnWidth; + return this; + } + + /** + * 是否使用设备的实际尺寸做适配 + * + * @param useDeviceSize {@code true} 为使用设备的实际尺寸 (包含状态栏), {@code false} 为不使用设备的实际尺寸 (不包含状态栏) + * @see #isUseDeviceSize 详情请查看这个字段的注释 + */ + public AutoSizeConfig setUseDeviceSize(boolean useDeviceSize) { + isUseDeviceSize = useDeviceSize; + return this; + } + + /** + * 是否打印 Log + * + * @param log {@code true} 为打印 + */ + public AutoSizeConfig setLog(boolean log) { + LogUtils.setDebug(log); + return this; + } + + /** + * 是否让框架支持自定义 {@link Fragment} 的适配参数, 由于这个需求是比较少见的, 所以须要使用者手动开启 + * + * @param customFragment {@code true} 为支持 + */ + public AutoSizeConfig setCustomFragment(boolean customFragment) { + isCustomFragment = customFragment; + return this; + } + + /** + * 框架是否已经开启支持自定义 {@link Fragment} 的适配参数 + * + * @return {@code true} 为支持 + */ + public boolean isCustomFragment() { + return isCustomFragment; + } + + /** + * 框架是否已经停止运行 + * + * @return {@code false} 框架正在运行, {@code true} 框架已经停止运行 + */ + public boolean isStop() { + return isStop; + } + + /** + * {@link ExternalAdaptManager} 用来管理外部三方库 {@link Activity} 的适配 + * + * @return {@link #mExternalAdaptManager} + */ + public ExternalAdaptManager getExternalAdaptManager() { + return mExternalAdaptManager; + } + + /** + * {@link UnitsManager} 用来管理 AndroidAutoSize 支持的所有单位, AndroidAutoSize 支持五种单位 (dp、sp、pt、in、mm) + * + * @return {@link #mUnitsManager} + */ + public UnitsManager getUnitsManager() { + return mUnitsManager; + } + + /** + * 返回 {@link #mOnAdaptListener} + * + * @return {@link #mOnAdaptListener} + */ + public onAdaptListener getOnAdaptListener() { + return mOnAdaptListener; + } + + /** + * 返回 {@link #isBaseOnWidth} + * + * @return {@link #isBaseOnWidth} + */ + public boolean isBaseOnWidth() { + return isBaseOnWidth; + } + + /** + * 返回 {@link #isUseDeviceSize} + * + * @return {@link #isUseDeviceSize} + */ + public boolean isUseDeviceSize() { + return isUseDeviceSize; + } + + /** + * 返回 {@link #mScreenWidth} + * + * @return {@link #mScreenWidth} + */ + public int getScreenWidth() { + return mScreenWidth; + } + + /** + * 返回 {@link #mScreenHeight} + * + * @return {@link #mScreenHeight} + */ + public int getScreenHeight() { + return isUseDeviceSize() ? mScreenHeight : mScreenHeight - mStatusBarHeight; + } + + /** + * 获取 {@link #mDesignWidthInDp} + * + * @return {@link #mDesignWidthInDp} + */ + public int getDesignWidthInDp() { + Preconditions.checkArgument(mDesignWidthInDp > 0, "you must set " + KEY_DESIGN_WIDTH_IN_DP + " in your AndroidManifest file"); + return mDesignWidthInDp; + } + + /** + * 获取 {@link #mDesignHeightInDp} + * + * @return {@link #mDesignHeightInDp} + */ + public int getDesignHeightInDp() { + Preconditions.checkArgument(mDesignHeightInDp > 0, "you must set " + KEY_DESIGN_HEIGHT_IN_DP + " in your AndroidManifest file"); + return mDesignHeightInDp; + } + + /** + * 获取 {@link #mInitDensity} + * + * @return {@link #mInitDensity} + */ + public float getInitDensity() { + return mInitDensity; + } + + /** + * 获取 {@link #mInitDensityDpi} + * + * @return {@link #mInitDensityDpi} + */ + public int getInitDensityDpi() { + return mInitDensityDpi; + } + + /** + * 获取 {@link #mInitScaledDensity} + * + * @return {@link #mInitScaledDensity} + */ + public float getInitScaledDensity() { + return mInitScaledDensity; + } + + /** + * 获取 {@link #mInitXdpi} + * + * @return {@link #mInitXdpi} + */ + public float getInitXdpi() { + return mInitXdpi; + } + + /** + * 获取 {@link #mInitScreenWidthDp} + * + * @return {@link #mInitScreenWidthDp} + */ + public int getInitScreenWidthDp() { + return mInitScreenWidthDp; + } + + /** + * 获取 {@link #mInitScreenHeightDp} + * + * @return {@link #mInitScreenHeightDp} + */ + public int getInitScreenHeightDp() { + return mInitScreenHeightDp; + } + + /** + * 获取屏幕方向 + * + * @return {@code true} 为纵向, {@code false} 为横向 + */ + public boolean isVertical() { + return isVertical; + } + + /** + * 返回 {@link #isMiui} + * + * @return {@link #isMiui} + */ + public boolean isMiui() { + return isMiui; + } + + /** + * 返回 {@link #mTmpMetricsField} + * + * @return {@link #mTmpMetricsField} + */ + public Field getTmpMetricsField() { + return mTmpMetricsField; + } + + /** + * 设置屏幕方向 + * + * @param vertical {@code true} 为纵向, {@code false} 为横向 + */ + public AutoSizeConfig setVertical(boolean vertical) { + isVertical = vertical; + return this; + } + + /** + * 是否屏蔽系统字体大小对 AndroidAutoSize 的影响, 如果为 {@code true}, App 内的字体的大小将不会跟随系统设置中字体大小的改变 + * 如果为 {@code false}, 则会跟随系统设置中字体大小的改变, 默认为 {@code false} + * + * @return {@link #isExcludeFontScale} + */ + public boolean isExcludeFontScale() { + return isExcludeFontScale; + } + + /** + * 是否屏蔽系统字体大小对 AndroidAutoSize 的影响, 如果为 {@code true}, App 内的字体的大小将不会跟随系统设置中字体大小的改变 + * 如果为 {@code false}, 则会跟随系统设置中字体大小的改变, 默认为 {@code false} + * + * @param excludeFontScale 是否屏蔽 + */ + public AutoSizeConfig setExcludeFontScale(boolean excludeFontScale) { + isExcludeFontScale = excludeFontScale; + return this; + } + + /** + * 设置屏幕宽度 + * + * @param screenWidth 屏幕宽度 + */ + public AutoSizeConfig setScreenWidth(int screenWidth) { + Preconditions.checkArgument(screenWidth > 0, "screenWidth must be > 0"); + mScreenWidth = screenWidth; + return this; + } + + /** + * 设置屏幕高度 + * + * @param screenHeight 屏幕高度 (需要包含状态栏) + */ + public AutoSizeConfig setScreenHeight(int screenHeight) { + Preconditions.checkArgument(screenHeight > 0, "screenHeight must be > 0"); + mScreenHeight = screenHeight; + return this; + } + + /** + * 设置全局设计图宽度 + * + * @param designWidthInDp 设计图宽度 + */ + public AutoSizeConfig setDesignWidthInDp(int designWidthInDp) { + Preconditions.checkArgument(designWidthInDp > 0, "designWidthInDp must be > 0"); + mDesignWidthInDp = designWidthInDp; + return this; + } + + /** + * 设置全局设计图高度 + * + * @param designHeightInDp 设计图高度 + */ + public AutoSizeConfig setDesignHeightInDp(int designHeightInDp) { + Preconditions.checkArgument(designHeightInDp > 0, "designHeightInDp must be > 0"); + mDesignHeightInDp = designHeightInDp; + return this; + } + + /** + * 设置状态栏高度 + * + * @param statusBarHeight 状态栏高度 + */ + public AutoSizeConfig setStatusBarHeight(int statusBarHeight) { + Preconditions.checkArgument(statusBarHeight > 0, "statusBarHeight must be > 0"); + mStatusBarHeight = statusBarHeight; + return this; + } + + /** + * 获取使用者在 AndroidManifest 中填写的 Meta 信息 + *

+ * Example usage: + *

+     * 
+     * 
+     * 
+ * + * @param context {@link Context} + */ + private void getMetaData(final Context context) { + new Thread(new Runnable() { + @Override + public void run() { + PackageManager packageManager = context.getPackageManager(); + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfo(context + .getPackageName(), PackageManager.GET_META_DATA); + if (applicationInfo != null && applicationInfo.metaData != null) { + if (applicationInfo.metaData.containsKey(KEY_DESIGN_WIDTH_IN_DP)) { + mDesignWidthInDp = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH_IN_DP); + } + if (applicationInfo.metaData.containsKey(KEY_DESIGN_HEIGHT_IN_DP)) { + mDesignHeightInDp = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT_IN_DP); + } + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + }).start(); + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/DefaultAutoAdaptStrategy.java b/src/main/java/me/jessyan/autosize/DefaultAutoAdaptStrategy.java new file mode 100644 index 0000000..81a98e3 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/DefaultAutoAdaptStrategy.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.app.Activity; +import android.app.Application; + +import java.util.Locale; + +import me.jessyan.autosize.external.ExternalAdaptInfo; +import me.jessyan.autosize.internal.CancelAdapt; +import me.jessyan.autosize.internal.CustomAdapt; +import me.jessyan.autosize.utils.LogUtils; + +/** + * ================================================ + * 屏幕适配逻辑策略默认实现类, 可通过 {@link AutoSizeConfig#init(Application, boolean, AutoAdaptStrategy)} + * 和 {@link AutoSizeConfig#setAutoAdaptStrategy(AutoAdaptStrategy)} 切换策略 + * + * @see AutoAdaptStrategy + * Created by JessYan on 2018/8/9 15:57 + * Contact me + * Follow me + * ================================================ + */ +public class DefaultAutoAdaptStrategy implements AutoAdaptStrategy { + @Override + public void applyAdapt(Object target, Activity activity) { + + //检查是否开启了外部三方库的适配模式, 只要不主动调用 ExternalAdaptManager 的方法, 下面的代码就不会执行 + if (AutoSizeConfig.getInstance().getExternalAdaptManager().isRun()) { + if (AutoSizeConfig.getInstance().getExternalAdaptManager().isCancelAdapt(target.getClass())) { + LogUtils.w(String.format(Locale.ENGLISH, "%s canceled the adaptation!", target.getClass().getName())); + AutoSize.cancelAdapt(activity); + return; + } else { + ExternalAdaptInfo info = AutoSizeConfig.getInstance().getExternalAdaptManager() + .getExternalAdaptInfoOfActivity(target.getClass()); + if (info != null) { + LogUtils.d(String.format(Locale.ENGLISH, "%s used %s for adaptation!", target.getClass().getName(), ExternalAdaptInfo.class.getName())); + AutoSize.autoConvertDensityOfExternalAdaptInfo(activity, info); + return; + } + } + } + + //如果 target 实现 CancelAdapt 接口表示放弃适配, 所有的适配效果都将失效 + if (target instanceof CancelAdapt) { + LogUtils.w(String.format(Locale.ENGLISH, "%s canceled the adaptation!", target.getClass().getName())); + AutoSize.cancelAdapt(activity); + return; + } + + //如果 target 实现 CustomAdapt 接口表示该 target 想自定义一些用于适配的参数, 从而改变最终的适配效果 + if (target instanceof CustomAdapt) { + LogUtils.d(String.format(Locale.ENGLISH, "%s implemented by %s!", target.getClass().getName(), CustomAdapt.class.getName())); + AutoSize.autoConvertDensityOfCustomAdapt(activity, (CustomAdapt) target); + } else { + LogUtils.d(String.format(Locale.ENGLISH, "%s used the global configuration.", target.getClass().getName())); + AutoSize.autoConvertDensityOfGlobal(activity); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/DisplayMetricsInfo.java b/src/main/java/me/jessyan/autosize/DisplayMetricsInfo.java new file mode 100644 index 0000000..3617fe9 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/DisplayMetricsInfo.java @@ -0,0 +1,150 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.DisplayMetrics; + +/** + * ================================================ + * {@link DisplayMetrics} 封装类 + *

+ * Created by JessYan on 2018/8/11 16:42 + * Contact me + * Follow me + * ================================================ + */ +public class DisplayMetricsInfo implements Parcelable { + private float density; + private int densityDpi; + private float scaledDensity; + private float xdpi; + private int screenWidthDp; + private int screenHeightDp; + + public DisplayMetricsInfo(float density, int densityDpi, float scaledDensity, float xdpi) { + this.density = density; + this.densityDpi = densityDpi; + this.scaledDensity = scaledDensity; + this.xdpi = xdpi; + } + + public DisplayMetricsInfo(float density, int densityDpi, float scaledDensity, float xdpi, int screenWidthDp, int screenHeightDp) { + this.density = density; + this.densityDpi = densityDpi; + this.scaledDensity = scaledDensity; + this.xdpi = xdpi; + this.screenWidthDp = screenWidthDp; + this.screenHeightDp = screenHeightDp; + } + + public float getDensity() { + return density; + } + + public void setDensity(float density) { + this.density = density; + } + + public int getDensityDpi() { + return densityDpi; + } + + public void setDensityDpi(int densityDpi) { + this.densityDpi = densityDpi; + } + + public float getScaledDensity() { + return scaledDensity; + } + + public void setScaledDensity(float scaledDensity) { + this.scaledDensity = scaledDensity; + } + + public float getXdpi() { + return xdpi; + } + + public void setXdpi(float xdpi) { + this.xdpi = xdpi; + } + + public int getScreenWidthDp() { + return screenWidthDp; + } + + public void setScreenWidthDp(int screenWidthDp) { + this.screenWidthDp = screenWidthDp; + } + + public int getScreenHeightDp() { + return screenHeightDp; + } + + public void setScreenHeightDp(int screenHeightDp) { + this.screenHeightDp = screenHeightDp; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeFloat(this.density); + dest.writeInt(this.densityDpi); + dest.writeFloat(this.scaledDensity); + dest.writeFloat(this.xdpi); + dest.writeInt(this.screenWidthDp); + dest.writeInt(this.screenHeightDp); + } + + protected DisplayMetricsInfo(Parcel in) { + this.density = in.readFloat(); + this.densityDpi = in.readInt(); + this.scaledDensity = in.readFloat(); + this.xdpi = in.readFloat(); + this.screenWidthDp = in.readInt(); + this.screenHeightDp = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public DisplayMetricsInfo createFromParcel(Parcel source) { + return new DisplayMetricsInfo(source); + } + + @Override + public DisplayMetricsInfo[] newArray(int size) { + return new DisplayMetricsInfo[size]; + } + }; + + @Override + public String toString() { + return "DisplayMetricsInfo{" + + "density=" + density + + ", densityDpi=" + densityDpi + + ", scaledDensity=" + scaledDensity + + ", xdpi=" + xdpi + + ", screenWidthDp=" + screenWidthDp + + ", screenHeightDp=" + screenHeightDp + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/InitProvider.java b/src/main/java/me/jessyan/autosize/InitProvider.java new file mode 100644 index 0000000..1f2d395 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/InitProvider.java @@ -0,0 +1,42 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize; + +import android.app.Application; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +public class InitProvider extends ContentProvider { + public InitProvider() { + } + + public boolean onCreate() { + AutoSizeConfig.getInstance().setLog(true).init((Application)this.getContext().getApplicationContext()).setUseDeviceSize(false); + return true; + } + + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + return null; + } + + public String getType(Uri uri) { + return null; + } + + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/src/main/java/me/jessyan/autosize/WrapperAutoAdaptStrategy.java b/src/main/java/me/jessyan/autosize/WrapperAutoAdaptStrategy.java new file mode 100644 index 0000000..4fb0652 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/WrapperAutoAdaptStrategy.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.app.Activity; + +/** + * ================================================ + * {@link AutoAdaptStrategy} 的包装者, 用于给 {@link AutoAdaptStrategy} 的实现类增加一些额外的职责 + *

+ * Created by JessYan on 2018/10/30 15:07 + * Contact me + * Follow me + * ================================================ + */ +public class WrapperAutoAdaptStrategy implements AutoAdaptStrategy { + private final AutoAdaptStrategy mAutoAdaptStrategy; + + public WrapperAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) { + mAutoAdaptStrategy = autoAdaptStrategy; + } + + @Override + public void applyAdapt(Object target, Activity activity) { + onAdaptListener onAdaptListener = AutoSizeConfig.getInstance().getOnAdaptListener(); + if (onAdaptListener != null){ + onAdaptListener.onAdaptBefore(target, activity); + } + if (mAutoAdaptStrategy != null) { + mAutoAdaptStrategy.applyAdapt(target, activity); + } + if (onAdaptListener != null){ + onAdaptListener.onAdaptAfter(target, activity); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/external/ExternalAdaptInfo.java b/src/main/java/me/jessyan/autosize/external/ExternalAdaptInfo.java new file mode 100644 index 0000000..db720c7 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/external/ExternalAdaptInfo.java @@ -0,0 +1,66 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.external; + +import android.os.Parcel; +import android.os.Parcelable; + +public class ExternalAdaptInfo implements Parcelable { + private boolean isBaseOnWidth; + private float sizeInDp; + public static final Creator CREATOR = new Creator() { + public ExternalAdaptInfo createFromParcel(Parcel source) { + return new ExternalAdaptInfo(source); + } + + public ExternalAdaptInfo[] newArray(int size) { + return new ExternalAdaptInfo[size]; + } + }; + + public ExternalAdaptInfo(boolean isBaseOnWidth) { + this.isBaseOnWidth = isBaseOnWidth; + } + + public ExternalAdaptInfo(boolean isBaseOnWidth, float sizeInDp) { + this.isBaseOnWidth = isBaseOnWidth; + this.sizeInDp = sizeInDp; + } + + public boolean isBaseOnWidth() { + return this.isBaseOnWidth; + } + + public void setBaseOnWidth(boolean baseOnWidth) { + this.isBaseOnWidth = baseOnWidth; + } + + public float getSizeInDp() { + return this.sizeInDp; + } + + public void setSizeInDp(float sizeInDp) { + this.sizeInDp = sizeInDp; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeByte((byte)(this.isBaseOnWidth ? 1 : 0)); + dest.writeFloat(this.sizeInDp); + } + + protected ExternalAdaptInfo(Parcel in) { + this.isBaseOnWidth = in.readByte() != 0; + this.sizeInDp = in.readFloat(); + } + + public String toString() { + return "ExternalAdaptInfo{isBaseOnWidth=" + this.isBaseOnWidth + ", sizeInDp=" + this.sizeInDp + '}'; + } +} diff --git a/src/main/java/me/jessyan/autosize/external/ExternalAdaptManager.java b/src/main/java/me/jessyan/autosize/external/ExternalAdaptManager.java new file mode 100644 index 0000000..c2c9dda --- /dev/null +++ b/src/main/java/me/jessyan/autosize/external/ExternalAdaptManager.java @@ -0,0 +1,68 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.external; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import me.jessyan.autosize.utils.Preconditions; + +public class ExternalAdaptManager { + private List mCancelAdaptList; + private Map mExternalAdaptInfos; + private boolean isRun; + + public ExternalAdaptManager() { + } + + public synchronized ExternalAdaptManager addCancelAdaptOfActivity(Class activityClass) { + Preconditions.checkNotNull(activityClass, "activityClass == null"); + if (!this.isRun) { + this.isRun = true; + } + + if (this.mCancelAdaptList == null) { + this.mCancelAdaptList = new ArrayList(); + } + + this.mCancelAdaptList.add(activityClass.getCanonicalName()); + return this; + } + + public synchronized ExternalAdaptManager addExternalAdaptInfoOfActivity(Class activityClass, ExternalAdaptInfo info) { + Preconditions.checkNotNull(activityClass, "activityClass == null"); + if (!this.isRun) { + this.isRun = true; + } + + if (this.mExternalAdaptInfos == null) { + this.mExternalAdaptInfos = new HashMap(16); + } + + this.mExternalAdaptInfos.put(activityClass.getCanonicalName(), info); + return this; + } + + public synchronized boolean isCancelAdapt(Class activityClass) { + Preconditions.checkNotNull(activityClass, "activityClass == null"); + return this.mCancelAdaptList == null ? false : this.mCancelAdaptList.contains(activityClass.getCanonicalName()); + } + + public synchronized ExternalAdaptInfo getExternalAdaptInfoOfActivity(Class activityClass) { + Preconditions.checkNotNull(activityClass, "activityClass == null"); + return this.mExternalAdaptInfos == null ? null : (ExternalAdaptInfo)this.mExternalAdaptInfos.get(activityClass.getCanonicalName()); + } + + public boolean isRun() { + return this.isRun; + } + + public void setRun(boolean run) { + this.isRun = run; + } +} diff --git a/src/main/java/me/jessyan/autosize/internal/CancelAdapt.java b/src/main/java/me/jessyan/autosize/internal/CancelAdapt.java new file mode 100644 index 0000000..c29837a --- /dev/null +++ b/src/main/java/me/jessyan/autosize/internal/CancelAdapt.java @@ -0,0 +1,9 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.internal; + +public interface CancelAdapt { +} diff --git a/src/main/java/me/jessyan/autosize/internal/CustomAdapt.java b/src/main/java/me/jessyan/autosize/internal/CustomAdapt.java new file mode 100644 index 0000000..6d1f319 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/internal/CustomAdapt.java @@ -0,0 +1,12 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.internal; + +public interface CustomAdapt { + boolean isBaseOnWidth(); + + float getSizeInDp(); +} diff --git a/src/main/java/me/jessyan/autosize/onAdaptListener.java b/src/main/java/me/jessyan/autosize/onAdaptListener.java new file mode 100644 index 0000000..42310eb --- /dev/null +++ b/src/main/java/me/jessyan/autosize/onAdaptListener.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize; + +import android.app.Activity; +import android.support.v4.app.Fragment; + +/** + * ================================================ + * 屏幕适配监听器,用于监听屏幕适配时的一些事件 + *

+ * Created by JessYan on 2018/10/30 16:29 + * Contact me + * Follow me + * ================================================ + */ +public interface onAdaptListener { + /** + * 在屏幕适配前调用 + * + * @param target 需要屏幕适配的对象 (可能是 {@link Activity} 或者 {@link Fragment}) + * @param activity 当前 {@link Activity} + */ + void onAdaptBefore(Object target, Activity activity); + + /** + * 在屏幕适配后调用 + * + * @param target 需要屏幕适配的对象 (可能是 {@link Activity} 或者 {@link Fragment}) + * @param activity 当前 {@link Activity} + */ + void onAdaptAfter(Object target, Activity activity); +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/unit/Subunits.java b/src/main/java/me/jessyan/autosize/unit/Subunits.java new file mode 100644 index 0000000..fb80d99 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/unit/Subunits.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize.unit; + +import android.util.DisplayMetrics; + +/** + * ================================================ + * AndroidAutoSize 支持一些在 Android 系统上比较少见的单位作为副单位, 用于规避修改 {@link DisplayMetrics#density} + * 所造成的对于其他使用 dp 布局的系统控件或三方库控件的不良影响 + *

+ * Created by JessYan on 2018/8/28 10:27 + * Contact me + * Follow me + * ================================================ + */ +public enum Subunits { + /** + * 不使用副单位 + */ + NONE, + /** + * 单位 pt + * + * @see android.util.TypedValue#COMPLEX_UNIT_PT + */ + PT, + /** + * 单位 in + * + * @see android.util.TypedValue#COMPLEX_UNIT_IN + */ + IN, + /** + * 单位 mm + * + * @see android.util.TypedValue#COMPLEX_UNIT_MM + */ + MM +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/unit/UnitsManager.java b/src/main/java/me/jessyan/autosize/unit/UnitsManager.java new file mode 100644 index 0000000..c48f010 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/unit/UnitsManager.java @@ -0,0 +1,213 @@ +/* + * Copyright 2018 JessYan + * + * 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 me.jessyan.autosize.unit; + +import android.util.DisplayMetrics; + +import me.jessyan.autosize.utils.Preconditions; + +/** + * ================================================ + * 管理 AndroidAutoSize 支持的所有单位, AndroidAutoSize 支持五种单位 (dp、sp、pt、in、mm) + * 其中 dp、sp 这两个是比较常见的单位, 作为 AndroidAutoSize 的主单位, 默认被 AndroidAutoSize 支持 + * pt、in、mm 这三个是比较少见的单位, 只可以选择其中的一个, 作为 AndroidAutoSize 的副单位, 与 dp、sp 一起被 AndroidAutoSize 支持 + * 副单位是用于规避修改 {@link DisplayMetrics#density} 所造成的对于其他使用 dp 布局的系统控件或三方库控件的不良影响 + * 您选择什么单位, 就在 layout 文件中用什么单位布局 + *

+ * 两个主单位和一个副单位, 可以随时使用下面的方法关闭和重新开启对它们的支持 + * 如果您想完全规避修改 {@link DisplayMetrics#density} 所造成的对于其他使用 dp 布局的系统控件或三方库控件的不良影响 + * 那请调用 {@link #setSupportDP}、{@link #setSupportSP} 都设置为 {@code false}, 停止对两个主单位的支持 (如果开启 sp, 对其他三方库控件影响不大, 也可以不关闭对 sp 的支持) + * 并调用 {@link #setSupportSubunits} 从三个冷门单位中选择一个作为副单位 (三个单位的效果都是一样的, 按自己的喜好选择, 比如我就喜欢 mm, 翻译为中文是妹妹的意思) + * 然后在 layout 文件中只使用这个副单位进行布局, 这样就可以完全规避修改 {@link DisplayMetrics#density} 所造成的问题 + * 因为 dp、sp 这两个单位在其他系统控件或三方库控件中都非常常见, 但三个冷门单位却非常少见 + *

+ * Created by JessYan on 2018/8/28 10:21 + * Contact me + * Follow me + * ================================================ + */ +public class UnitsManager { + /** + * 设计图上的总宽度, 建议单位为 px, 当使用者想将旧项目从主单位过渡到副单位, 或从副单位过渡到主单位时使用 + * 因为在使用主单位时, 建议在 AndroidManifest 中填写设计图的 dp 尺寸, 比如 360 * 640 + * 而副单位有一个特性是可以直接在 AndroidManifest 中填写设计图的 px 尺寸, 比如 1080 * 1920 + * 但在 AndroidManifest 中却只能填写一套设计图尺寸, 并且已经填写了主单位的设计图尺寸 + * 所以当项目中同时存在副单位和主单位, 并且副单位的设计图尺寸与主单位的设计图尺寸不同时, 就需要在 {@link UnitsManager} 中保存副单位的设计图尺寸 + */ + private float mDesignWidth; + /** + * 设计图上的总高度, 建议单位为 px, 当使用者想将旧项目从主单位过渡到副单位, 或从副单位过渡到主单位时使用 + * 因为在使用主单位时, 建议在 AndroidManifest 中填写设计图的 dp 尺寸, 比如 360 * 640 + * 而副单位有一个特性是可以直接在 AndroidManifest 中填写设计图的 px 尺寸, 比如 1080 * 1920 + * 但在 AndroidManifest 中却只能填写一套设计图尺寸, 并且已经填写了主单位的设计图尺寸 + * 所以当项目中同时存在副单位和主单位, 并且副单位的设计图尺寸与主单位的设计图尺寸不同时, 就需要在 {@link UnitsManager} 中保存副单位的设计图尺寸 + */ + private float mDesignHeight; + /** + * 是否支持 dp 单位, 默认支持 + */ + private boolean isSupportDP = true; + /** + * 是否支持 sp 单位, 默认支持 + */ + private boolean isSupportSP = true; + /** + * 是否支持副单位, 以什么为副单位? 默认不支持 + */ + private Subunits mSupportSubunits = Subunits.NONE; + /** + * 是否支持 ScreenSizeDp 修改, 默认不支持 + */ + private boolean isSupportScreenSizeDP = false; + + /** + * 设置设计图尺寸 + * + * @param designWidth 设计图上的总宽度, 建议单位为 px + * @param designHeight 设计图上的总高度, 建议单位为 px + * @return {@link UnitsManager} + * @see #mDesignWidth 详情请查看这个字段的注释 + * @see #mDesignHeight 详情请查看这个字段的注释 + */ + public UnitsManager setDesignSize(float designWidth, float designHeight) { + setDesignWidth(designWidth); + setDesignHeight(designHeight); + return this; + } + + /** + * 返回 {@link #mDesignWidth} + * + * @return {@link #mDesignWidth} + */ + public float getDesignWidth() { + return mDesignWidth; + } + + /** + * 设置设计图上的总宽度, 建议单位为 px + * + * @param designWidth 设计图上的总宽度, 建议单位为 px + * @return {@link UnitsManager} + * @see #mDesignWidth 详情请查看这个字段的注释 + */ + public UnitsManager setDesignWidth(float designWidth) { + Preconditions.checkArgument(designWidth > 0, "designWidth must be > 0"); + mDesignWidth = designWidth; + return this; + } + + /** + * 返回 {@link #mDesignHeight} + * + * @return {@link #mDesignHeight} + */ + public float getDesignHeight() { + return mDesignHeight; + } + + /** + * 设置设计图上的总高度, 建议单位为 px + * + * @param designHeight 设计图上的总高度, 建议单位为 px + * @return {@link UnitsManager} + * @see #mDesignHeight 详情请查看这个字段的注释 + */ + public UnitsManager setDesignHeight(float designHeight) { + Preconditions.checkArgument(designHeight > 0, "designHeight must be > 0"); + mDesignHeight = designHeight; + return this; + } + + /** + * 是否支持 dp 单位, 默认支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @return {@code true} 为支持, {@code false} 为不支持 + */ + public boolean isSupportDP() { + return isSupportDP; + } + + /** + * 是否让 AndroidAutoSize 支持 dp 单位, 默认支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @param supportDP {@code true} 为支持, {@code false} 为不支持 + */ + public UnitsManager setSupportDP(boolean supportDP) { + isSupportDP = supportDP; + return this; + } + + /** + * 是否支持 sp 单位, 默认支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @return {@code true} 为支持, {@code false} 为不支持 + */ + public boolean isSupportSP() { + return isSupportSP; + } + + /** + * 是否让 AndroidAutoSize 支持 sp 单位, 默认支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @param supportSP {@code true} 为支持, {@code false} 为不支持 + */ + public UnitsManager setSupportSP(boolean supportSP) { + isSupportSP = supportSP; + return this; + } + + /** + * AndroidAutoSize 以什么单位为副单位, 默认为 {@link Subunits#NONE}, 即不支持副单位, 详情请看类文件的注释 {@link UnitsManager} + * + * @return {@link Subunits} + */ + public Subunits getSupportSubunits() { + return mSupportSubunits; + } + + /** + * 是否支持 ScreenSizeDp 修改, 默认不支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @return {@code true} 为支持, {@code false} 为不支持 + */ + public boolean isSupportScreenSizeDP() { + return isSupportScreenSizeDP; + } + + /** + * 是否让 AndroidAutoSize 支持 ScreenSizeDp 修改, 默认不支持, 详情请看类文件的注释 {@link UnitsManager} + * + * @param supportScreenSizeDP {@code true} 为支持, {@code false} 为不支持 + */ + public UnitsManager setSupportScreenSizeDP(boolean supportScreenSizeDP) { + isSupportScreenSizeDP = supportScreenSizeDP; + return this; + } + + /** + * 让 AndroidAutoSize 以什么单位为副单位, 在 pt、in、mm 这三个冷门单位中选择一个即可, 三个效果都是一样的 + * 按自己的喜好选择, 比如我就喜欢 mm, 翻译为中文是妹妹的意思 + * 默认为 {@link Subunits#NONE}, 即不支持副单位, 详情请看类文件的注释 {@link UnitsManager} + * + * @param supportSubunits {@link Subunits} + */ + public UnitsManager setSupportSubunits(Subunits supportSubunits) { + mSupportSubunits = Preconditions.checkNotNull(supportSubunits, + "The supportSubunits can not be null, use Subunits.NONE instead"); + return this; + } +} \ No newline at end of file diff --git a/src/main/java/me/jessyan/autosize/utils/AutoSizeUtils.java b/src/main/java/me/jessyan/autosize/utils/AutoSizeUtils.java new file mode 100644 index 0000000..8ebec25 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/utils/AutoSizeUtils.java @@ -0,0 +1,35 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.utils; + +import android.content.Context; +import android.util.TypedValue; + +public class AutoSizeUtils { + private AutoSizeUtils() { + throw new IllegalStateException("you can't instantiate me!"); + } + + public static int dp2px(Context context, float value) { + return (int)(TypedValue.applyDimension(1, value, context.getResources().getDisplayMetrics()) + 0.5F); + } + + public static int sp2px(Context context, float value) { + return (int)(TypedValue.applyDimension(2, value, context.getResources().getDisplayMetrics()) + 0.5F); + } + + public static int pt2px(Context context, float value) { + return (int)(TypedValue.applyDimension(3, value, context.getResources().getDisplayMetrics()) + 0.5F); + } + + public static int in2px(Context context, float value) { + return (int)(TypedValue.applyDimension(4, value, context.getResources().getDisplayMetrics()) + 0.5F); + } + + public static int mm2px(Context context, float value) { + return (int)(TypedValue.applyDimension(5, value, context.getResources().getDisplayMetrics()) + 0.5F); + } +} diff --git a/src/main/java/me/jessyan/autosize/utils/LogUtils.java b/src/main/java/me/jessyan/autosize/utils/LogUtils.java new file mode 100644 index 0000000..a5ec0df --- /dev/null +++ b/src/main/java/me/jessyan/autosize/utils/LogUtils.java @@ -0,0 +1,46 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.utils; + +import android.util.Log; + +public class LogUtils { + private static final String TAG = "AndroidAutoSize"; + private static boolean debug; + + private LogUtils() { + throw new IllegalStateException("you can't instantiate me!"); + } + + public static boolean isDebug() { + return debug; + } + + public static void setDebug(boolean debug) { + LogUtils.debug = debug; + } + + public static void d(String message) { + if (debug) { + Log.d("AndroidAutoSize", message); + } + + } + + public static void w(String message) { + if (debug) { + Log.w("AndroidAutoSize", message); + } + + } + + public static void e(String message) { + if (debug) { + Log.e("AndroidAutoSize", message); + } + + } +} diff --git a/src/main/java/me/jessyan/autosize/utils/Preconditions.java b/src/main/java/me/jessyan/autosize/utils/Preconditions.java new file mode 100644 index 0000000..3d92e07 --- /dev/null +++ b/src/main/java/me/jessyan/autosize/utils/Preconditions.java @@ -0,0 +1,159 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.utils; + +public final class Preconditions { + private Preconditions() { + throw new IllegalStateException("you can't instantiate me!"); + } + + public static void checkArgument(boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } + + public static void checkArgument(boolean expression, Object errorMessage) { + if (!expression) { + throw new IllegalArgumentException(String.valueOf(errorMessage)); + } + } + + public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { + if (!expression) { + throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs)); + } + } + + public static void checkState(boolean expression) { + if (!expression) { + throw new IllegalStateException(); + } + } + + public static void checkState(boolean expression, Object errorMessage) { + if (!expression) { + throw new IllegalStateException(String.valueOf(errorMessage)); + } + } + + public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) { + if (!expression) { + throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs)); + } + } + + public static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } else { + return reference; + } + } + + public static T checkNotNull(T reference, Object errorMessage) { + if (reference == null) { + throw new NullPointerException(String.valueOf(errorMessage)); + } else { + return reference; + } + } + + public static T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs) { + if (reference == null) { + throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs)); + } else { + return reference; + } + } + + public static int checkElementIndex(int index, int size) { + return checkElementIndex(index, size, "index"); + } + + public static int checkElementIndex(int index, int size, String desc) { + if (index >= 0 && index < size) { + return index; + } else { + throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); + } + } + + private static String badElementIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException((new StringBuilder(26)).append("negative size: ").append(size).toString()); + } else { + return format("%s (%s) must be less than size (%s)", desc, index, size); + } + } + + public static int checkPositionIndex(int index, int size) { + return checkPositionIndex(index, size, "index"); + } + + public static int checkPositionIndex(int index, int size, String desc) { + if (index >= 0 && index <= size) { + return index; + } else { + throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); + } + } + + private static String badPositionIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException((new StringBuilder(26)).append("negative size: ").append(size).toString()); + } else { + return format("%s (%s) must not be greater than size (%s)", desc, index, size); + } + } + + public static void checkPositionIndexes(int start, int end, int size) { + if (start < 0 || end < start || end > size) { + throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); + } + } + + private static String badPositionIndexes(int start, int end, int size) { + return start >= 0 && start <= size ? (end >= 0 && end <= size ? format("end index (%s) must not be less than start index (%s)", end, start) : badPositionIndex(end, size, "end index")) : badPositionIndex(start, size, "start index"); + } + + static String format(String template, Object... args) { + template = String.valueOf(template); + StringBuilder builder = new StringBuilder(template.length() + 16 * args.length); + int templateStart = 0; + + int i; + int placeholderStart; + for(i = 0; i < args.length; templateStart = placeholderStart + 2) { + placeholderStart = template.indexOf("%s", templateStart); + if (placeholderStart == -1) { + break; + } + + builder.append(template.substring(templateStart, placeholderStart)); + builder.append(args[i++]); + } + + builder.append(template.substring(templateStart)); + if (i < args.length) { + builder.append(" ["); + builder.append(args[i++]); + + while(i < args.length) { + builder.append(", "); + builder.append(args[i++]); + } + + builder.append(']'); + } + + return builder.toString(); + } +} diff --git a/src/main/java/me/jessyan/autosize/utils/ScreenUtils.java b/src/main/java/me/jessyan/autosize/utils/ScreenUtils.java new file mode 100644 index 0000000..93f1b9a --- /dev/null +++ b/src/main/java/me/jessyan/autosize/utils/ScreenUtils.java @@ -0,0 +1,75 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package me.jessyan.autosize.utils; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.graphics.Point; +import android.os.Build.VERSION; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +public class ScreenUtils { + public ScreenUtils() { + } + + public static int getStatusBarHeight() { + int result = 0; + + try { + int resourceId = Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = Resources.getSystem().getDimensionPixelSize(resourceId); + } + } catch (NotFoundException var2) { + var2.printStackTrace(); + } + + return result; + } + + public static int[] getScreenSize(Context context) { + int[] size = new int[2]; + WindowManager w = (WindowManager)context.getSystemService("window"); + Display d = w.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + d.getMetrics(metrics); + int widthPixels = metrics.widthPixels; + int heightPixels = metrics.heightPixels; + if (VERSION.SDK_INT >= 14 && VERSION.SDK_INT < 17) { + try { + widthPixels = (Integer)Display.class.getMethod("getRawWidth").invoke(d); + heightPixels = (Integer)Display.class.getMethod("getRawHeight").invoke(d); + } catch (Exception var9) { + } + } + + if (VERSION.SDK_INT >= 17) { + try { + Point realSize = new Point(); + Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize); + widthPixels = realSize.x; + heightPixels = realSize.y; + } catch (Exception var8) { + } + } + + size[0] = widthPixels; + size[1] = heightPixels; + return size; + } + + public static int getHeightOfNavigationBar(Context context) { + Display d = ((WindowManager)context.getSystemService("window")).getDefaultDisplay(); + int realHeight = getScreenSize(context)[1]; + DisplayMetrics displayMetrics = new DisplayMetrics(); + d.getMetrics(displayMetrics); + int displayHeight = displayMetrics.heightPixels; + return realHeight - displayHeight; + } +}