package com.ydl.ydlcommon.utils import android.app.Activity import android.content.Context import android.content.pm.ActivityInfo import android.content.res.Configuration import android.content.res.Resources import android.content.res.TypedArray import android.graphics.Rect import android.os.Build import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.FrameLayout import java.lang.reflect.Field /** * Created by haorui on 2019/6/11. * Des:Android系统相关帮助类 */ class AndroidSystemHelper { companion object { //====================修复Android 8.0 崩溃,Only fullscreen activities can request orientation==================== fun fixAndroidOrientationBug(activity: Activity) { if (!isAllowSetOrientation(activity)) { val result = resetOrientation(activity) Log.i(this.javaClass.simpleName, "onCreate resetOrientation when Oreo, result = " + result); } } /** * 反射调用ActivityInfo#isTranslucentOrFloating() * 判断当前Activity是否透明or悬浮 */ fun isTranslucentOrFloating(activity: Activity): Boolean { var isTranslucentOrFloating = false try { val styleableRes = Class.forName("com.android.internal.R\$styleable").getField("Window").get(null) as IntArray val ta = activity.obtainStyledAttributes(styleableRes) val m = ActivityInfo::class.java.getMethod("isTranslucentOrFloating", TypedArray::class.java) m.isAccessible = true isTranslucentOrFloating = m.invoke(null, ta) as Boolean m.isAccessible = false } catch (e: Exception) { e.printStackTrace() } return isTranslucentOrFloating } /** * 重置屏幕方向 */ fun resetOrientation(activity: Activity): Boolean { try { //设置方向为改为SCREEN_ORIENTATION_UNSPECIFIED:未指定类型 val field = Activity::class.java.getDeclaredField("mActivityInfo") field.isAccessible = true val o = field.get(activity) as ActivityInfo o.screenOrientation = -1 field.isAccessible = false return true } catch (e: Exception) { e.printStackTrace() } return false } /** * 是否允许设置屏幕方向 */ fun isAllowSetOrientation(activity: Activity): Boolean { return if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating( activity ) ) { Log.i(this.javaClass.simpleName, "avoid calling setRequestedOrientation when Oreo.") false; } else { true } } //====================解决 InputMethodManager 导致的内存泄漏问题==================== fun fixInputMethodManagerLeak(activity: Activity) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { return } val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val arr = arrayOf("mCurRootView", "mServedView", "mNextServedView") var f: Field? var obj_get: Any? for (i in arr.indices) { val param = arr[i] try { f = imm.javaClass.getDeclaredField(param) if (f!!.isAccessible === false) { f!!.isAccessible = true } // author: sodino mail:sodino@qq.com obj_get = f!!.get(imm) if (obj_get != null && obj_get is View) { val v_get = obj_get as View? if (v_get!!.context === activity) { // 被InputMethodManager持有引用的context是想要目标销毁的 f.set(imm, null) // 置空,破坏掉path to gc节点 } else { // 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了 break } } } catch (t: Throwable) { t.printStackTrace() } } } //====================解决 修改系统字体大小后 H5页面大小比例不正常现象==================== fun fixResourcesScale(res: Resources): Resources { val config = Configuration() config.setToDefaults() res.updateConfiguration(config, res.displayMetrics) return res } fun fixAndroidBug5497Workaround(activity: Activity){ AndroidBug5497Workaround.assistActivity( activity ) } } //================== 解决全屏模式下,“adjustResize”失效问题(Android系统Bug)====================== /** * Des: 解决全屏模式下,“adjustResize”失效问题(Android系统Bug) * 链接地址:https://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible/19494006#19494006 */ class AndroidBug5497Workaround private constructor(private val activity: Activity) { private val mChildOfContent: View private var usableHeightPrevious: Int = 0 private val frameLayoutParams: FrameLayout.LayoutParams private var contentHeight: Int = 0 private var isfirst = true private val statusBarHeight: Int init { //获取状态栏的高度 val resourceId = activity.resources.getIdentifier("status_bar_height", "dimen", "android") statusBarHeight = activity.resources.getDimensionPixelSize(resourceId) val content = activity.findViewById<View>(android.R.id.content) as FrameLayout mChildOfContent = content.getChildAt(0) //界面出现变动都会调用这个监听事件 mChildOfContent.viewTreeObserver.addOnGlobalLayoutListener { if (isfirst) { contentHeight = mChildOfContent.height//兼容华为等机型 isfirst = false } possiblyResizeChildOfContent() } frameLayoutParams = mChildOfContent.layoutParams as FrameLayout.LayoutParams } //重新调整跟布局的高度 private fun possiblyResizeChildOfContent() { val usableHeightNow = computeUsableHeight() //当前可见高度和上一次可见高度不一致 布局变动 if (usableHeightNow != usableHeightPrevious) { //int usableHeightSansKeyboard2 = mChildOfContent.getHeight();//兼容华为等机型 val usableHeightSansKeyboard = mChildOfContent.rootView.height val heightDifference = usableHeightSansKeyboard - usableHeightNow if (heightDifference > usableHeightSansKeyboard / 4) { // keyboard probably just became visible if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + statusBarHeight } else { frameLayoutParams.height = usableHeightSansKeyboard - heightDifference } } else { frameLayoutParams.height = contentHeight } mChildOfContent.requestLayout() usableHeightPrevious = usableHeightNow } } /** * 计算mChildOfContent可见高度 ** @return */ private fun computeUsableHeight(): Int { val r = Rect() mChildOfContent.getWindowVisibleDisplayFrame(r) return r.bottom - r.top } companion object { fun assistActivity(activity: Activity) { AndroidBug5497Workaround(activity) } } } }