解決小米,魅族手機打開懸浮窗口問題

當開啓一個懸浮窗口時,發現三星,華爲都能夠開啓,無論系統爲android4.4.4、android5.1.1還是android6.0,但是當用小米手機或者魅族的時候發現打不開了,檢查manifest中的android.permission.SYSTEM_ALERT_WINDOW權限,我也加了啊,但是就是不好使,這個權限也不是android6.0中的敏感權限,所以android6.0動態申請權限是行不通的,這個問題找了好久,發現很難通過代碼去打開懸浮窗,沒轍之後想到,調到應用的設置界面去吧,引導用戶手動的去打開。下面是三星和小米手機的運行效果,魅族的和小米的效果差不多就沒貼動圖了。

三星Galaxy (android6.0)手機上運行的效果:



小米5(android6.0)上運行效果:




首先添加權限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Build.MANUFACTURER這個可以獲取手機的型號,可以分辨是小米還是魅族

    public void open(View v){
        //開啓懸浮框前先請求權限
        if("Xiaomi".equals(Build.MANUFACTURER)){//小米手機
            requestPermission();
        }else if("Meizu".equals(Build.MANUFACTURER)){//魅族手機
            requestPermission();
        }else {//其他手機
            CallFloatBoxView.showFloatBox(this);
        }
    }

 /**
     * 請求用戶給予懸浮窗的權限
     */
    public void requestPermission() {
        if(isFloatWindowOpAllowed(this)){//已經開啓
            CallFloatBoxView.showFloatBox(this);
        }else {
            openSetting();
        }
    }

    /**
     * 打開權限設置界面
     */
    public void openSetting() {
        try {
            Intent localIntent = new Intent(
                    "miui.intent.action.APP_PERM_EDITOR");
            localIntent.setClassName("com.miui.securitycenter",
                            "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            localIntent.putExtra("extra_pkgname", getPackageName());
            startActivityForResult(localIntent,11);

        } catch (ActivityNotFoundException localActivityNotFoundException) {
            Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", getPackageName(), null);
            intent1.setData(uri);
            startActivityForResult(intent1,11);
        }

    }

完整的類如下:

package com.cool.hello.widget;

import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.cool.hello.R;

import java.lang.reflect.Method;

public class WatchBoardViewActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_watch_board_view);


    }

    public void open(View v){
        //開啓懸浮框前先請求權限
        if("Xiaomi".equals(Build.MANUFACTURER)){//小米手機
            requestPermission();
        }else if("Meizu".equals(Build.MANUFACTURER)){//魅族手機
            requestPermission();
        }else {//其他手機
            CallFloatBoxView.showFloatBox(this);
        }
    }

    public void close(View v){
        CallFloatBoxView.hideFloatBox();
    }

    /**
     * 請求用戶給予懸浮窗的權限
     */
    public void requestPermission() {
        if(isFloatWindowOpAllowed(this)){//已經開啓
            CallFloatBoxView.showFloatBox(this);
        }else {
            openSetting();
        }
    }

    /**
     * 打開權限設置界面
     */
    public void openSetting() {
        try {
            Intent localIntent = new Intent(
                    "miui.intent.action.APP_PERM_EDITOR");
            localIntent.setClassName("com.miui.securitycenter",
                            "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            localIntent.putExtra("extra_pkgname", getPackageName());
            startActivityForResult(localIntent,11);

        } catch (ActivityNotFoundException localActivityNotFoundException) {
            Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", getPackageName(), null);
            intent1.setData(uri);
            startActivityForResult(intent1,11);
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == 11){
            if(isFloatWindowOpAllowed(this)){//已經開啓
                CallFloatBoxView.showFloatBox(this);
            }else {
                Toast.makeText(this,"開啓懸浮窗失敗",Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * 判斷懸浮窗權限
     *
     * @param context
     * @return
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean isFloatWindowOpAllowed(Context context) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= 19) {
            return checkOp(context, 24);  // AppOpsManager.OP_SYSTEM_ALERT_WINDOW
        } else {
            if ((context.getApplicationInfo().flags & 1 << 27) == 1 << 27) {
                return true;
            } else {
                return false;
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean checkOp(Context context, int op) {
        final int version = Build.VERSION.SDK_INT;

        if (version >= 19) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {

                Class<?> spClazz = Class.forName(manager.getClass().getName());
                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
                int property = (Integer) method.invoke(manager, op,
                        Binder.getCallingUid(), context.getPackageName());
                Log.e("399"," property: " + property);

                if (AppOpsManager.MODE_ALLOWED == property) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.e("399","Below API 19 cannot invoke!");
        }
        return false;
    }

}

懸浮窗:CallFloatBoxView.java

package com.cool.hello.widget;

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;

import com.cool.hello.R;

/**
 * Created by cool on 2016/8/25.
 */
public class CallFloatBoxView {
    private static Context mContext;
    private static View mView;
    private static Boolean isShown = false;
    private static WindowManager wm;

    public static void showFloatBox(Context context) {
        if (isShown) {
            return;
        }
        isShown = true;

        mContext = context;
        wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();

        int type;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            type = WindowManager.LayoutParams.TYPE_TOAST;
        } else {
            type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        params.type = type;
        params.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

        params.format = PixelFormat.TRANSLUCENT;
        params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        params.gravity = Gravity.CENTER;
        params.x = context.getResources().getDisplayMetrics().widthPixels;
        params.y = 0;
        ImageView imageView = new ImageView(mContext);
        imageView.setImageResource(R.drawable.sese);
        mView = imageView;
        mView.setOnTouchListener(new View.OnTouchListener() {
            float lastX, lastY;
            int oldOffsetX, oldOffsetY;
            int tag = 0;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                final int action = event.getAction();
                float x = event.getX();
                float y = event.getY();
                if (tag == 0) {
                    oldOffsetX = params.x;
                    oldOffsetY = params.y;
                }
                if (action == MotionEvent.ACTION_DOWN) {
                    lastX = x;
                    lastY = y;
                } else if (action == MotionEvent.ACTION_MOVE) {
                    // 減小偏移量,防止過度抖動
                    params.x += (int) (x - lastX) / 3;
                    params.y += (int) (y - lastY) / 3;
                    tag = 1;
                    if (mView != null)
                        wm.updateViewLayout(mView, params);
                } else if (action == MotionEvent.ACTION_UP) {
                    int newOffsetX = params.x;
                    int newOffsetY = params.y;
                    if (Math.abs(oldOffsetX - newOffsetX) <= 20 && Math.abs(oldOffsetY - newOffsetY) <= 20) {

                    } else {
                        tag = 0;
                    }
                }
                return true;
            }
        });
        wm.addView(mView, params);
    }

    public static void hideFloatBox() {
        if (isShown && null != mView) {
            wm.removeView(mView);
            isShown = false;
            mView = null;
        }
    }
}


最後非常感謝這篇博文:http://blog.csdn.net/cankingapp/article/details/51569576






發佈了45 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章