Android實(shí)現(xiàn)懸浮窗效果
本文實(shí)例為大家分享了Android實(shí)現(xiàn)懸浮窗效果的具體代碼,供大家參考,具體內(nèi)容如下
一、權(quán)限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
二、懸浮窗其實(shí)就是 WindowManager.addView(view,layoutParams),直接上代碼
1、單例創(chuàng)建FloatWindowManager
/** ? 懸浮Manager */ public class FloatWindowManager { ? ? private volatile static FloatWindowManager mInstance; ? ? private WindowManager mWindowManager; ? ? private Context mContext; ? ? private WindowManager.LayoutParams mLayoutParams; ? ? private int layoutY; ? ? private int layoutX; ? ? private ValueAnimator animator; ? ? private TextView textView; ? ? ? ? public static synchronized FloatWindowManager getInstance() { ? ? ? ? if (mInstance == null) { ? ? ? ? ? ? synchronized (FloatWindowManager.class) { ? ? ? ? ? ? ? ? if (mInstance == null) { ? ? ? ? ? ? ? ? ? ? mInstance = new FloatWindowManager(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return mInstance; ? ? } ? ? ? public FloatWindowManager initManager(Context context) { ? ? ? ? mContext = context; ? ? ? ? mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); ? ? ? ? showWindow(); ? ? ? ? return this; ? ? } ? ? ? ? /** ? ? ?* 是否有懸浮框權(quán)限 ? ? ?* ? ? ?* @return ? ? ?*/ ? ? public boolean requestPermission(Context context) { ? ? ? ? return SettingsCompat.canDrawOverlays(context, true, false); ? ? } ? ? ? /** ? ? ?* 加載 懸浮窗 ? 沒(méi)有內(nèi)容 ? ? ?*/ ? ? private synchronized void showWindow() { ? ? ? ? textView = new TextView(mContext); ? ? ? ? textView.setText("此為懸浮窗口View"); ? ? ? ? textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp2px(mContext, 15)); ? ? ? ? mLayoutParams = new WindowManager.LayoutParams(); ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ? ? ? ? ? ? mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; ? ? ? ? } else { ? ? ? ? ? ? mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; ? ? ? ? } ? ? ? ? mLayoutParams.format = PixelFormat.RGBA_8888; //窗口透明 ? ? ? ? mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; //窗口位置 ? ? ? ? mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; ? ? ? ? DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); ? ? ? ? layoutY = displayMetrics.heightPixels / 2; ? ? ? ? layoutX = displayMetrics.widthPixels - textView.getMeasuredWidth(); ? ? ? ? mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; ? ? ? ? mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; ? ? ? ? mLayoutParams.x = layoutX; ? ? ? ? mLayoutParams.y = layoutY; ? ? ? ? setListener(); ? ? } ? ? ? public void showFloatWindow(){ ? ? ? ? mWindowManager.addView(textView, mLayoutParams); ? ? } ? ? ? /** ? ? ?* 設(shè)置 懸浮窗 view 滑動(dòng)事件 ? ? ?*/ ? ? private void setListener() { ? ? ? ? if (textView != null) { ? ? ? ? ? ? textView.setOnTouchListener(new View.OnTouchListener() { ? ? ? ? ? ? ? ? private int moveX; ? //動(dòng)畫(huà)平移距離 ? ? ? ? ? ? ? ? int startX, startY; ?//起始點(diǎn) ? ? ? ? ? ? ? ? boolean isMove; ?//是否在移動(dòng) ? ? ? ? ? ? ? ? long startTime; ? ? ? ? ? ? ? ? int finalMoveX; ?//最后通過(guò)動(dòng)畫(huà)將mView的X軸坐標(biāo)移動(dòng)到finalMoveX ? ? ? ? ? ? ? ? boolean downMove = false; ? ? ? ? ? ? ? ? ? @Override ? ? ? ? ? ? ? ? public boolean onTouch(View v, MotionEvent event) { ? ? ? ? ? ? ? ? ? ? switch (event.getAction()) { ? ? ? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_DOWN: ? ? ? ? ? ? ? ? ? ? ? ? ? ? startX = (int) event.getX(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? startY = (int) event.getY(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? startTime = System.currentTimeMillis(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? isMove = false; ? ? ? ? ? ? ? ? ? ? ? ? ? ? downMove = false; ? ? ? ? ? ? ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_MOVE: ? ? ? ? ? ? ? ? ? ? ? ? ? ? //當(dāng)移動(dòng)距離大于2時(shí)候,刷新界面。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (Math.abs(startX - event.getX()) > 2 || Math.abs(startY - event.getY()) > 2) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? downMove = true; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mLayoutParams.x = (int) (event.getRawX() - startX); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mLayoutParams.y = (int) (event.getRawY() - startY); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateViewLayout(); ? //更新mView 的位置 ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_UP: ? ? ? ? ? ? ? ? ? ? ? ? ? ? long curTime = System.currentTimeMillis(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? isMove = curTime - startTime > 100; ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (isMove){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //判斷mView是在Window中的位置,以中間為界 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (mLayoutParams.x + textView.getMeasuredWidth() / 2 >= mWindowManager.getDefaultDisplay().getWidth() / 2) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? finalMoveX = mWindowManager.getDefaultDisplay().getWidth() - textView.getMeasuredWidth(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? finalMoveX = 0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //使用動(dòng)畫(huà)移動(dòng)mView ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animator = ValueAnimator.ofInt(mLayoutParams.x, finalMoveX).setDuration(Math.abs(mLayoutParams.x - finalMoveX)); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animator.addUpdateListener((ValueAnimator animation) -> { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (animation != null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? moveX = (int) animation.getAnimatedValue(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mLayoutParams.x = (int) animation.getAnimatedValue(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateViewLayout(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animator.start(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return isMove; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }); ? ? ? ? } ? ? } ? ? ? ? /** ? ? ?* 刷新 circle view 位置 ? ? ?*/ ? ? private void updateViewLayout() { ? ? ? ? if (null != textView && null != mLayoutParams && mWindowManager != null) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? mWindowManager.updateViewLayout(textView, mLayoutParams); ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? ? /** ? ? ?* 根據(jù)手機(jī)的分辨率從 dp 的單位 轉(zhuǎn)成為 px(像素) ? ? ?*/ ? ? public static int dp2px(Context context, float dpValue) { ? ? ? ? if (context != null) { ? ? ? ? ? ? final float scale = context.getResources().getDisplayMetrics().density; ? ? ? ? ? ? return (int) (dpValue * scale + 0.5f); ? ? ? ? } ? ? ? ? return (int) dpValue; ? ? }
2、SettingsCompat 動(dòng)態(tài)權(quán)限判斷(適配大部分廠商)
public class SettingsCompat { ? ? ? private static final int OP_WRITE_SETTINGS = 23; ? ? private static final int OP_SYSTEM_ALERT_WINDOW = 24; ? ? ? /** ? ? ?* 檢查懸浮窗權(quán)限 ?當(dāng)沒(méi)有權(quán)限,跳轉(zhuǎn)到權(quán)限設(shè)置界面 ? ? ?* ? ? ?* @param context ? ? ? ? ?上下文 ? ? ?* @param isShowDialog ? ? 沒(méi)有權(quán)限,是否彈框提示跳轉(zhuǎn)到權(quán)限設(shè)置界面 ? ? ?* @param isShowPermission 是否跳轉(zhuǎn)權(quán)限開(kāi)啟界面 ? ? ?* @return true 有權(quán)限 ? false 沒(méi)有權(quán)限(跳轉(zhuǎn)權(quán)限界面、權(quán)限失敗 提示用戶手動(dòng)設(shè)置權(quán)限) ? ? ?* @by 騰訊云直播 懸浮框判斷邏輯 ? ? ?*/ ? ? public static boolean canDrawOverlays(Context context, boolean isShowDialog, boolean isShowPermission) { ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ? ? ? ? ? ? if (!Settings.canDrawOverlays(context)) { ? ? ? ? ? ? ? ? if (isShowDialog) { ? ? ? ? ? ? ? ? ? ? //去授權(quán) ? ? ? ? ? ? ? ? ? ? SettingsCompat.manageDrawOverlays(context); ? ? ? ? ? ? ? ? } else if (isShowPermission) { ? ? ? ? ? ? ? ? ? ? manageDrawOverlays(context); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? ? ? return true; ? ? ? ? } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { ? ? ? ? ? ? if (checkOp(context, OP_SYSTEM_ALERT_WINDOW)) { ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? if (isShowPermission) ? ? ? ? ? ? ? ? ? ? startFloatWindowPermissionErrorToast(context); ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? } else { ? ? ? ? ? ? return true; ? ? ? ? } ? ? } ? ? ? ? /** ? ? ?* 打開(kāi) 懸浮窗 授權(quán)界面 ? ? ?* ? ? ?* @param context ? ? ?*/ ? ? public static void manageDrawOverlays(Context context) { ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); ? ? ? ? ? ? ? ? intent.setData(Uri.parse("package:" + context.getPackageName())); ? ? ? ? ? ? ? ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ? ? ? ? ? ? ? ? context.startActivity(intent); ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? startFloatWindowPermissionErrorToast(context); ? ? ? ? ? ? } ? ? ? ? } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { ? ? ? ? ? ? if (!manageDrawOverlaysForRom(context)) { ? ? ? ? ? ? ? ? startFloatWindowPermissionErrorToast(context); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? /** ? ? ?* 權(quán)限設(shè)置 失敗提示。 ? ? ?* ? ? ?* @param context ? ? ?*/ ? ? public static void startFloatWindowPermissionErrorToast(Context context) { ? ? ? ? if (context != null) ? ? ? ? ? ? Toast.makeText(context, "進(jìn)入設(shè)置頁(yè)面失敗,請(qǐng)手動(dòng)開(kāi)啟懸浮窗權(quán)限", Toast.LENGTH_SHORT).show(); ? ? } ? ? ? private static boolean manageDrawOverlaysForRom(Context context) { ? ? ? ? if (RomUtil.isMiui()) { ? ? ? ? ? ? return manageDrawOverlaysForMiui(context); ? ? ? ? } ? ? ? ? if (RomUtil.isEmui()) { ? ? ? ? ? ? return manageDrawOverlaysForEmui(context); ? ? ? ? } ? ? ? ? if (RomUtil.isFlyme()) { ? ? ? ? ? ? return manageDrawOverlaysForFlyme(context); ? ? ? ? } ? ? ? ? if (RomUtil.isOppo()) { ? ? ? ? ? ? return manageDrawOverlaysForOppo(context); ? ? ? ? } ? ? ? ? if (RomUtil.isVivo()) { ? ? ? ? ? ? return manageDrawOverlaysForVivo(context); ? ? ? ? } ? ? ? ? if (RomUtil.isQiku()) { ? ? ? ? ? ? return manageDrawOverlaysForQihu(context); ? ? ? ? } ? ? ? ? if (RomUtil.isSmartisan()) { ? ? ? ? ? ? return manageDrawOverlaysForSmartisan(context); ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? ? private static boolean checkOp(Context context, int op) { ? ? ? ? AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); ? ? ? ? try { ? ? ? ? ? ? Method method = AppOpsManager.class.getDeclaredMethod("checkOp", int.class, int.class, String.class); ? ? ? ? ? ? return AppOpsManager.MODE_ALLOWED == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName()); ? ? ? ? } catch (Exception e) { ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? // 可設(shè)置Android 4.3/4.4的授權(quán)狀態(tài) ? ? private static boolean setMode(Context context, int op, boolean allowed) { ? ? ? ? if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? ? AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); ? ? ? ? try { ? ? ? ? ? ? Method method = AppOpsManager.class.getDeclaredMethod("setMode", int.class, int.class, String.class, int.class); ? ? ? ? ? ? method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName(), allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); ? ? ? ? ? ? return true; ? ? ? ? } catch (Exception e) { ? ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? /** ? ? ?* 跳轉(zhuǎn)界面 ? ? ?* ? ? ?* @param context ? ? ?* @param intent ? ? ?* @return ? ? ?*/ ? ? private static boolean startSafely(Context context, Intent intent) { ? ? ? ? List<ResolveInfo> resolveInfos = null; ? ? ? ? try { ? ? ? ? ? ? resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); ? ? ? ? ? ? if (resolveInfos != null && resolveInfos.size() > 0) { ? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ? ? ? ? ? ? ? ? context.startActivity(intent); ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? ? // 小米 ? ? private static boolean manageDrawOverlaysForMiui(Context context) { ? ? ? ? Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR"); ? ? ? ? intent.putExtra("extra_pkgname", context.getPackageName()); ? ? ? ? intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? // miui v5 的支持的android版本最高 4.x ? ? ? ? // http://www.romzj.com/list/search?keyword=MIUI%20V5#search_result ? ? ? ? if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { ? ? ? ? ? ? Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); ? ? ? ? ? ? intent1.setData(Uri.fromParts("package", context.getPackageName(), null)); ? ? ? ? ? ? return startSafely(context, intent1); ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? private final static String HUAWEI_PACKAGE = "com.huawei.systemmanager"; ? ? ? // 華為 ? ? private static boolean manageDrawOverlaysForEmui(Context context) { ? ? ? ? Intent intent = new Intent(); ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ? ? ? ? ? ? intent.setClassName(HUAWEI_PACKAGE, "com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity"); ? ? ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? // Huawei Honor P6|4.4.4|3.0 ? ? ? ? intent.setClassName(HUAWEI_PACKAGE, "com.huawei.notificationmanager.ui.NotificationManagmentActivity"); ? ? ? ? intent.putExtra("showTabsNumber", 1); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? intent.setClassName(HUAWEI_PACKAGE, "com.huawei.permissionmanager.ui.MainActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? return false; ? ? } ? ? ? // VIVO ? ? private static boolean manageDrawOverlaysForVivo(Context context) { ? ? ? ? // 不支持直接到達(dá)懸浮窗設(shè)置頁(yè),只能到 i管家 首頁(yè) ? ? ? ? Intent intent = new Intent("com.iqoo.secure"); ? ? ? ? intent.setClassName("com.iqoo.secure", "com.iqoo.secure.MainActivity"); ? ? ? ? // com.iqoo.secure.ui.phoneoptimize.SoftwareManagerActivity ? ? ? ? // com.iqoo.secure.ui.phoneoptimize.FloatWindowManager ? ? ? ? return startSafely(context, intent); ? ? } ? ? ? // OPPO ? ? private static boolean manageDrawOverlaysForOppo(Context context) { ? ? ? ? Intent intent = new Intent(); ? ? ? ? intent.putExtra("packageName", context.getPackageName()); ? ? ? ? // OPPO A53|5.1.1|2.1 ? ? ? ? intent.setAction("com.oppo.safe"); ? ? ? ? intent.setClassName("com.oppo.safe", "com.oppo.safe.permission.floatwindow.FloatWindowListActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? // OPPO R7s|4.4.4|2.1 ? ? ? ? intent.setAction("com.color.safecenter"); ? ? ? ? intent.setClassName("com.color.safecenter", "com.color.safecenter.permission.floatwindow.FloatWindowListActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? intent.setAction("com.coloros.safecenter"); ? ? ? ? intent.setClassName("com.coloros.safecenter", "com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity"); ? ? ? ? return startSafely(context, intent); ? ? } ? ? ? // 魅族 ? ? private static boolean manageDrawOverlaysForFlyme(Context context) { ? ? ? ? Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC"); ? ? ? ? intent.setClassName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity"); ? ? ? ? intent.putExtra("packageName", context.getPackageName()); ? ? ? ? return startSafely(context, intent); ? ? } ? ? ? // 360 ? ? private static boolean manageDrawOverlaysForQihu(Context context) { ? ? ? ? Intent intent = new Intent(); ? ? ? ? intent.setClassName("com.android.settings", "com.android.settings.Settings$OverlaySettingsActivity"); ? ? ? ? if (startSafely(context, intent)) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? intent.setClassName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity"); ? ? ? ? return startSafely(context, intent); ? ? } ? ? ? // 錘子 ? ? private static boolean manageDrawOverlaysForSmartisan(Context context) { ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ? ? ? ? ? ? // 錘子 堅(jiān)果|5.1.1|2.5.3 ? ? ? ? ? ? Intent intent = new Intent("com.smartisanos.security.action.SWITCHED_PERMISSIONS_NEW"); ? ? ? ? ? ? intent.setClassName("com.smartisanos.security", "com.smartisanos.security.SwitchedPermissions"); ? ? ? ? ? ? intent.putExtra("index", 17); // 不同版本會(huì)不一樣 ? ? ? ? ? ? return startSafely(context, intent); ? ? ? ? } else { ? ? ? ? ? ? // 錘子 堅(jiān)果|4.4.4|2.1.2 ? ? ? ? ? ? Intent intent = new Intent("com.smartisanos.security.action.SWITCHED_PERMISSIONS"); ? ? ? ? ? ? intent.setClassName("com.smartisanos.security", "com.smartisanos.security.SwitchedPermissions"); ? ? ? ? ? ? intent.putExtra("permission", new String[]{Manifest.permission.SYSTEM_ALERT_WINDOW}); ? ? ? ? ? ? ? // ? ? ? ?Intent intent = new Intent("com.smartisanos.security.action.MAIN"); ? ? ? ? ? ? // ? ? ? ?intent.setClassName("com.smartisanos.security", "com.smartisanos.security.MainActivity"); ? ? ? ? ? ? return startSafely(context, intent); ? ? ? ? } ? ? } ? }
3、廠商 RomUtil
public class RomUtil { ? ? private static final String TAG = "RomUtil"; ? ? ? public static final String ROM_MIUI = "MIUI"; ? ? public static final String ROM_EMUI = "EMUI"; ? ? public static final String ROM_FLYME = "FLYME"; ? ? public static final String ROM_OPPO = "OPPO"; ? ? public static final String ROM_SMARTISAN = "SMARTISAN"; ? ? ? public static final String ROM_VIVO = "VIVO"; ? ? public static final String ROM_QIKU = "QIKU"; ? ? ? public static final String ROM_LENOVO = "LENOVO"; ? ? public static final String ROM_SAMSUNG = "SAMSUNG"; ? ? ? private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name"; ? ? private static final String KEY_VERSION_EMUI = "ro.build.version.emui"; ? ? private static final String KEY_VERSION_OPPO = "ro.build.version.opporom"; ? ? private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version"; ? ? private static final String KEY_VERSION_VIVO = "ro.vivo.os.version"; ? ? private static final String KEY_VERSION_GIONEE = "ro.gn.sv.version"; ? ? private static final String KEY_VERSION_LENOVO = "ro.lenovo.lvp.version"; ? ? private static final String KEY_VERSION_FLYME = "ro.build.display.id"; ? ? ? ? private static final String KEY_EMUI_VERSION_CODE = "ro.build.hw_emui_api_level"; ? ? ? private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code"; ? ? private static final String KEY_MIUI_HANDY_MODE_SF = "ro.miui.has_handy_mode_sf"; ? ? private static final String KEY_MIUI_REAL_BLUR = "ro.miui.has_real_blur"; ? ? ? private static final String KEY_FLYME_PUBLISHED = "ro.flyme.published"; ? ? private static final String KEY_FLYME_FLYME = "ro.meizu.setupwizard.flyme"; ? ? ? private static final String KEY_FLYME_ICON_FALG = "persist.sys.use.flyme.icon"; ? ? private static final String KEY_FLYME_SETUP_FALG = "ro.meizu.setupwizard.flyme"; ? ? private static final String KEY_FLYME_PUBLISH_FALG = "ro.flyme.published"; ? ? ? private static final String KEY_VIVO_OS_NAME = "ro.vivo.os.name"; ? ? private static final String KEY_VIVO_OS_VERSION = "ro.vivo.os.version"; ? ? private static final String KEY_VIVO_ROM_VERSION = "ro.vivo.rom.version"; ? ? ? public static boolean isEmui() { ? ? ? ? return check(ROM_EMUI); ? ? } ? ? ? public static boolean isMiui() { ? ? ? ? return check(ROM_MIUI); ? ? } ? ? ? public static boolean isVivo() { ? ? ? ? return check(ROM_VIVO); ? ? } ? ? ? public static boolean isOppo() { ? ? ? ? return check(ROM_OPPO); ? ? } ? ? ? public static boolean isFlyme() { ? ? ? ? return check(ROM_FLYME); ? ? } ? ? ? public static boolean isQiku() { ? ? ? ? return check(ROM_QIKU) || check("360"); ? ? } ? ? ? public static boolean isSmartisan() { ? ? ? ? return check(ROM_SMARTISAN); ? ? } ? ? ? private static String sName; ? ? ? public static String getName() { ? ? ? ? if (sName == null) { ? ? ? ? ? ? check(""); ? ? ? ? } ? ? ? ? return sName; ? ? } ? ? ? private static String sVersion; ? ? ? public static String getVersion() { ? ? ? ? if (sVersion == null) { ? ? ? ? ? ? check(""); ? ? ? ? } ? ? ? ? return sVersion; ? ? } ? ? ? public static boolean check(String rom) { ? ? ? ? if (sName != null) { ? ? ? ? ? ? return sName.equals(rom); ? ? ? ? } ? ? ? ? ? if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) { ? ? ? ? ? ? sName = ROM_MIUI; ? ? ? ? } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) { ? ? ? ? ? ? sName = ROM_EMUI; ? ? ? ? } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) { ? ? ? ? ? ? sName = ROM_OPPO; ? ? ? ? } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) { ? ? ? ? ? ? sName = ROM_VIVO; ? ? ? ? } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) { ? ? ? ? ? ? sName = ROM_SMARTISAN; ? ? ? ? } else { ? ? ? ? ? ? sVersion = Build.DISPLAY; ? ? ? ? ? ? if (sVersion.toUpperCase().contains(ROM_FLYME)) { ? ? ? ? ? ? ? ? sName = ROM_FLYME; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? sVersion = Build.UNKNOWN; ? ? ? ? ? ? ? ? sName = Build.MANUFACTURER.toUpperCase(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return sName.equals(rom); ? ? } ? ? ? public static String getProp(String name) { ? ? ? ? String line = null; ? ? ? ? BufferedReader input = null; ? ? ? ? try { ? ? ? ? ? ? Process p = Runtime.getRuntime().exec("getprop " + name); ? ? ? ? ? ? input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); ? ? ? ? ? ? line = input.readLine(); ? ? ? ? ? ? input.close(); ? ? ? ? } catch (IOException ex) { ? ? ? ? ? ? Log.e(TAG, "Unable to read prop " + name, ex); ? ? ? ? ? ? return null; ? ? ? ? } finally { ? ? ? ? ? ? if (input != null) { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? input.close(); ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return line; ? ? } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 使用Android實(shí)現(xiàn)跨頁(yè)面懸浮窗效果
- Android懸浮窗的實(shí)現(xiàn)步驟
- Android開(kāi)發(fā)懸浮窗踩坑解決
- Android 無(wú)障礙全局懸浮窗實(shí)現(xiàn)示例
- Android應(yīng)用內(nèi)懸浮窗Activity的簡(jiǎn)單實(shí)現(xiàn)
- Android超簡(jiǎn)單懸浮窗使用教程
- Android實(shí)現(xiàn)懸浮窗的簡(jiǎn)單方法實(shí)例
- Android創(chuàng)建懸浮窗的完整步驟
- Android 懸浮窗開(kāi)發(fā)示例((動(dòng)態(tài)權(quán)限請(qǐng)求 | 前臺(tái)服務(wù)和通知 | 懸浮窗創(chuàng)建 )
相關(guān)文章
Android圖片加載框架Coil的詳細(xì)使用總結(jié)
Coil是Android上的一個(gè)全新的圖片加載框架,它的全名叫做coroutine image loader,即協(xié)程圖片加載庫(kù),下面這篇文章主要給大家介紹了關(guān)于Android圖片加載框架Coil詳細(xì)使用的相關(guān)資料,需要的朋友可以參考下2022-07-07Android自定義實(shí)現(xiàn)可滑動(dòng)按鈕
這篇文章主要為大家詳細(xì)介紹了Android自定義實(shí)現(xiàn)可滑動(dòng)的按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Retrofit2.0添加Header的方法總結(jié)(推薦)
這篇文章主要介紹了Retrofit2.0添加Header的方法總結(jié)(推薦),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09Android實(shí)現(xiàn)關(guān)機(jī)后數(shù)據(jù)不會(huì)丟失問(wèn)題
這篇文章主要介紹了Android實(shí)現(xiàn)關(guān)機(jī)后數(shù)據(jù)不會(huì)丟失問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10Android實(shí)現(xiàn)可點(diǎn)擊的幸運(yùn)大轉(zhuǎn)盤
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)可點(diǎn)擊的幸運(yùn)大轉(zhuǎn)盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02Android開(kāi)發(fā)自學(xué)筆記(二):工程文件剖析
這篇文章主要介紹了Android開(kāi)發(fā)自學(xué)筆記(二):工程文件剖析,本文講解了AndroidManifest.xml、src文件夾、res文件夾等文件的作用,需要的朋友可以參考下2015-04-04Android Studio / IDEA kotlin 顯示 var 真實(shí)類型操作
這篇文章主要介紹了Android Studio / IDEA kotlin 顯示 var 真實(shí)類型操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08Android之沉浸式狀態(tài)欄的實(shí)現(xiàn)方法、狀態(tài)欄透明
本篇文章主要介紹了Android之沉浸式狀態(tài)欄的實(shí)現(xiàn)方法、狀態(tài)欄透明,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-02-02