Android 8.0懸濁窓の変動と使い方

31858 ワード

Android 8.0浮上窓変動
問題の説明:
プロジェクト開発中に懸濁窓が使用されていたが、最近Android Oシステムにportingしたところ、懸濁窓が正常に使用できないことがわかり、運行エラーが発生した.
  android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@447a6748 is not valid; is your activity running?

または
  android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootlmpl$W@40ec8528 -- permission denied for this window

 
ソリューション:
Android 8.0は、多くの新しい特性と機能を提供するほか、システムとAPIの動作をさまざまに変更しています.中にはAndroid 8.0向けのアプリもあります.公式文書の説明は以下の通りです.
これらの動作変更は、Oプラットフォームまたはそれ以上のプラットフォームバージョンのアプリケーションに特化して適用されます.Android 8.0以上のプラットフォームバージョンでコンパイルまたはtargetSdkValersonをAndroid 8.0以降に設定したアプリケーション開発者は、これらの動作を正しくサポートするためにアプリケーションを変更する必要があります.(該当する場合).アラームウィンドウSYSTEM_ALERT_WINDOW権限を使用するアプリケーションは、他のアプリケーションやシステムウィンドウの上にアラームウィンドウを表示するために以下のウィンドウタイプを使用できません.・TYPE_PHONE・TYPE_PRIORITY_PHONE・TYPE_SYSTEM_ALERT・TYPE_SYSTEM_OVERLAY・TYPE_SYSTEM_ERROR
逆に、アプリケーションはTYPE_という名前を使用する必要があります.APPLICATION_OVERLaYの新しいウィンドウタイプ.TYPE_の使用APPLICATION_MOVERLaYウィンドウタイプアプリケーションのアラートウィンドウを表示する場合は、新しいウィンドウタイプの次の特性を覚えておいてください.
・適用されるアラームウィンドウは、ステータスバーや入力方式などのキーシステムウィンドウの下に常に表示される.
・TYPE_を移動して使用できるシステムAPPLICATION_MOVERLaYウィンドウタイプのウィンドウまたはそのサイズを調整して画面表示効果を改善する.・通知バーを開くと、ユーザーは設定にアクセスしてTYPE_の使用をアプリケーションの表示をブロックできます.APPLICATION_MOVERLaYウィンドウタイプ表示のアラームウィンドウ.
            ……
 
したがって、Android 8.0以降のプラットフォームバージョンについてコンパイルしたり、targetSdkVersionをAndroid 8.0以上のバージョンに設定したりするアプリケーション開発は、設定を区別すればよい.
……
if(Build.VERSION.SDK_INT>=26){//8.0新特性mWindowParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLaY;}else{     mWindowParams.type= WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;}
……
また、権限の問題にも注意する必要があります.
Android 4であればxの場合、
AndroidManifest.xmlに権限を追加するには、次の手順に従います.

android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />

Android 6(API 23)以上の場合は、以下のコードを追加して要求権限を付与する必要があります.
//    
if (Build.VERSION.SDK_INT >= 23) {
    if(!Settings.canDrawOverlays(getApplicationContext())) {
        //  Activity     
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));
        startActivity(intent);
        return;
    } else {
        //  6.0      
    }
} else {
    //  6.0      、
}

または、
//    
if (Build.VERSION.SDK_INT >= 23) {
    if(!Settings.canDrawOverlays(getApplicationContext())) {
        //  Activity     
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent,10);
        return;
    } else {
        //  6.0      
    }
} else {
    //  6.0      
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 10) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (!Settings.canDrawOverlays(this)) {
                // SYSTEM_ALERT_WINDOW permission not granted...
                Toast.makeText(LoginActivity.this,"not granted",Toast.LENGTH_SHORT);
            }
        }
    }
}

サスペンション窓の使用方法の補足
package ......;

import android.app.Service;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import java.lang.reflect.Field;

/**
 * Created by zhongxiang.huang on 2017/6/23.
 *
 */

public class FloatWindow implements View.OnTouchListener {

    private Context mContext;
    private WindowManager.LayoutParams mWindowParams;
    private WindowManager mWindowManager;

    private View mFloatLayout;
    private float mInViewX;
    private float mInViewY;
    private float mDownInScreenX;
    private float mDownInScreenY;
    private float mInScreenX;
    private float mInScreenY;

    public FloatWindow(Service context) {
        this.mContext = context;
        initFloatWindow();
    }

    private void initFloatWindow(){
        LayoutInflater inflater = LayoutInflater.from(mContext);
        if(inflater == null)
            return;
        mFloatLayout = (View) inflater.inflate(R.layout.layout_float, null);
        mFloatLayout.setOnTouchListener(this);

        mWindowParams = new WindowManager.LayoutParams();
        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        if (Build.VERSION.SDK_INT >= 26) {//8.0   
            mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }else{
            mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        }
        mWindowParams.format = PixelFormat.RGBA_8888;
        mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        mWindowParams.gravity = Gravity.START | Gravity.TOP;
        mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        return floatLayoutTouch(motionEvent);
    }

    private boolean floatLayoutTouch(MotionEvent motionEvent){

        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //     View   ,   View      
                mInViewX = motionEvent.getX();
                mInViewY = motionEvent.getY();
                //          ,          
                mDownInScreenX = motionEvent.getRawX();
                mDownInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext);
                mInScreenX = motionEvent.getRawX();
                mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext);
                break;
            case MotionEvent.ACTION_MOVE:
                //           
                mInScreenX = motionEvent.getRawX();
                mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext);
                mWindowParams.x = (int) (mInScreenX- mInViewX);
                mWindowParams.y = (int) (mInScreenY - mInViewY);
                //                 
                mWindowManager.updateViewLayout(mFloatLayout, mWindowParams);
                break;
            case MotionEvent.ACTION_UP:
                //          ,xDownInScreen xInScreen  , yDownInScreen yInScreen  ,          。
                if (mDownInScreenX  == mInScreenX && mDownInScreenY == mInScreenY){

                }
                break;
        }
        return true;
    }

    public void showFloatWindow(){
        if (mFloatLayout.getParent() == null){
            DisplayMetrics metrics = new DisplayMetrics();
            //      ,         
            mWindowManager.getDefaultDisplay().getMetrics(metrics);
            mWindowParams.x = metrics.widthPixels;
            mWindowParams.y = metrics.heightPixels/2 - getSysBarHeight(mContext);
            mWindowManager.addView(mFloatLayout, mWindowParams);
        }
    }

    public void hideFloatWindow(){
        if (mFloatLayout.getParent() != null)
            mWindowManager.removeView(mFloatLayout);
    }

    public void setFloatLayoutAlpha(boolean alpha){
        if (alpha)
            mFloatLayout.setAlpha((float) 0.5);
        else
            mFloatLayout.setAlpha(1);
    }

    //          
    public static int getSysBarHeight(Context contex) {
        Class> c;
        Object obj;
        Field field;
        int x;
        int sbar = 0;
        try {
            c = Class.forName("com.android.internal.R$dimen");
            obj = c.newInstance();
            field = c.getField("status_bar_height");
            x = Integer.parseInt(field.get(obj).toString());
            sbar = contex.getResources().getDimensionPixelSize(x);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return sbar;
    }

}