如何在棉花糖设备中检查屏幕覆盖检测到的权限

Posted

技术标签:

【中文标题】如何在棉花糖设备中检查屏幕覆盖检测到的权限【英文标题】:How to check screen overlay detected permission in Marshmallow Devices 【发布时间】:2017-05-23 09:11:44 【问题描述】:

我有一个应用程序,在检测到用户的位置后,该应用程序会显示附近的银行、餐馆等。早些时候一切正常,但在最近对我的 Moto X Play 设备进行更新后,该应用程序要求“检测到屏幕覆盖”,然后就崩溃了.我不知道如何在我的应用程序中包含此权限。这是我的代码

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.ads.AdView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import in.protechlabz.www.yavatmalindicatorserver.R;

/**
 * Created by Nikesh on 03/01/2017.
 */

public class NearbyMainActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener 
    private GoogleMap mMap;
    double latitude;
    double longitude;
    private int PROXIMITY_RADIUS = 10000;
    GoogleApiClient mGoogleApiClient;
    Location mLastLocation;
    Marker mCurrLocationMarker;
    LocationRequest mLocationRequest;
    private int listItemSelector;
    private String[] choosePlace = new String[] "hospital","bank","atm","restaurant","gas_station","school","post_office"
            ,"police","pharmacy","airport","gym","movie_theater","courthouse","bakery","bar","cafe"
            ,"car_repair","library","dentist";
    private AdView mAdView9;
    public final static int PERM_REQUEST_CODE_DRAW_OVERLAYS = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.show_places);

        /* Admob related important code*/
        mAdView9 = (AdView) findViewById(R.id.adView9);
        com.google.android.gms.ads.AdRequest adRequest = new com.google.android.gms.ads.AdRequest.Builder().build();
        mAdView9.loadAd(adRequest);

        // Extract information from intent for listItemSelector
        Bundle extras = getIntent().getExtras();
        if (extras != null) 
            listItemSelector = extras.getInt("PlacesKey");
        

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            checkLocationPermission();
        

        //Check if Google Play Services Available or not
        if (!CheckGooglePlayServices()) 
            Log.d("onCreate", "Finishing test case since Google Play Services are not available");
            finish();
        
        else 
            Log.d("onCreate","Google Play Services available.");
        

        MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map1);
        mapFragment.getMapAsync(this);
    

    @Override
    protected void onStop() 
        super.onStop();
        mGoogleApiClient.disconnect();
    


    private boolean CheckGooglePlayServices() 
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        int result = googleAPI.isGooglePlayServicesAvailable(this);
        if(result != ConnectionResult.SUCCESS) 
            if(googleAPI.isUserResolvableError(result)) 
                googleAPI.getErrorDialog(this, result,
                        0).show();
            
            return false;
        
        return true;
    

    @Override
    public void onMapReady(GoogleMap googleMap) 
        mMap = googleMap;
        mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);

        //Initialize Google Play Services
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            if (ContextCompat.checkSelfPermission(this,
                    android.Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) 
                buildGoogleApiClient();
                mMap.setMyLocationEnabled(true);
            
        
        else 
            buildGoogleApiClient();
            mMap.setMyLocationEnabled(true);
        
    

    protected synchronized void buildGoogleApiClient() 
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    

    @Override
    public void onConnected(Bundle bundle) 
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        Log.d("Errors","In On Connected Method");
        if (ContextCompat.checkSelfPermission(this,
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) 
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            Log.d("Errors","Requesting Location Services");
        
    

    private String getUrl(double latitude, double longitude, String nearbyPlace) 

        StringBuilder googlePlacesUrl = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
        googlePlacesUrl.append("location=" + latitude + "," + longitude);
        googlePlacesUrl.append("&radius=" + PROXIMITY_RADIUS);
        googlePlacesUrl.append("&type=" + nearbyPlace);
        googlePlacesUrl.append("&sensor=true");
        googlePlacesUrl.append("&key=" + "AIzaSyChSLh_uZYL87wFeoNqo7OtupWzFMqYXB0");
        Log.d("getUrl", googlePlacesUrl.toString());
        return (googlePlacesUrl.toString());
    

    @Override
    public void onConnectionSuspended(int i) 

    

    @Override
    public void onLocationChanged(Location location) 
        Log.d("onLocationChanged", "entered");

        mLastLocation = location;
        if (mCurrLocationMarker != null) 
            mCurrLocationMarker.remove();
        

        //Place current location marker
        latitude = location.getLatitude();
        longitude = location.getLongitude();
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mMap.addMarker(markerOptions);

        //move map camera
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        mMap.animateCamera(CameraUpdateFactory.zoomTo(15));
        //Toast.makeText(NearbyMainActivity.this,"Your Current Location", Toast.LENGTH_LONG).show();

        Log.d("onLocationChanged", String.format("latitude:%.3f longitude:%.3f",latitude,longitude));

        //stop location updates
        if (mGoogleApiClient != null) 
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            Log.d("onLocationChanged", "Removing Location Updates");
        
        Log.d("onLocationChanged", "Exit");
        buttonsReplacedMethod();

    

    private void buttonsReplacedMethod() 

        mMap.clear();
        String url = getUrl(latitude, longitude, choosePlace[listItemSelector]);
        Log.d("Location Value",choosePlace[listItemSelector]);
        Object[] DataTransfer = new Object[2];
        DataTransfer[0] = mMap;
        DataTransfer[1] = url;
        Log.d("onClick", url);
        GetNearbyPlacesData getNearbyPlacesData = new GetNearbyPlacesData();
        getNearbyPlacesData.execute(DataTransfer);
        Toast.makeText(NearbyMainActivity.this,"Nearby " + choosePlace[listItemSelector] + "s", Toast.LENGTH_LONG).show();

    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 

    

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
    public boolean checkLocationPermission()
        if (ContextCompat.checkSelfPermission(this,
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) 

            // Asking user if explanation is needed
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    android.Manifest.permission.ACCESS_FINE_LOCATION)) 

                //Prompt the user once explanation has been shown
                ActivityCompat.requestPermissions(this,
                        new String[]android.Manifest.permission.ACCESS_FINE_LOCATION,
                        MY_PERMISSIONS_REQUEST_LOCATION);


             else 
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[]android.Manifest.permission.ACCESS_FINE_LOCATION,
                        MY_PERMISSIONS_REQUEST_LOCATION);
            
            return false;
         else 
            return true;
        
    

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) 
        switch (requestCode) 
            case MY_PERMISSIONS_REQUEST_LOCATION: 
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) 

                    // permission was granted. Do the
                    // contacts-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            android.Manifest.permission.ACCESS_FINE_LOCATION)
                            == PackageManager.PERMISSION_GRANTED) 

                        if (mGoogleApiClient == null) 
                            buildGoogleApiClient();
                        
                        mMap.setMyLocationEnabled(true);
                    
                 else 

                    // Permission denied, Disable the functionality that depends on this permission.
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                
                return;
            
        
    

我现在不知道该怎么办。该应用程序在 Marshmallow 之前的设备中运行良好。但对于 Marshmallow 用户来说,这是一个非常令人沮丧的情况。请帮忙

这是我添加的内容并出现空对象引用错误

public void permissionToDrawOverlays() 
        if (android.os.Build.VERSION.SDK_INT >= 23)    //Android M Or Over
            if (!Settings.canDrawOverlays(this)) 
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, PERM_REQUEST_CODE_DRAW_OVERLAYS);
            
        
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if (requestCode == PERM_REQUEST_CODE_DRAW_OVERLAYS) 
            if (android.os.Build.VERSION.SDK_INT >= 23)    //Android M Or Over
                if (!Settings.canDrawOverlays(this)) 
                    // ADD UI FOR USER TO KNOW THAT UI for SYSTEM_ALERT_WINDOW permission was not granted earlier...
                
            
        
    

我在 onCreate 方法中调用了这个方法一次,下一次在 onLocationChanged 方法中调用了这个方法

【问题讨论】:

【参考方案1】:

您可以使用Settings.canDrawOverlays()检查Application是否有权限,并使用ACTION_MANAGE_OVERLAY_PERMISSION将应用程序引导到设置屏幕以进一步打开或关闭。

添加清单

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

示例代码

public void checkDrawOverlayPermission(Context context) 
    // check if we already  have permission to draw over other apps
    if (Settings.canDrawOverlays(context)) 
        // code
     else 
        // if not construct intent to request permission
        final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        // request permission via start activity for result
        startActivityForResult(intent, REQUEST_CODE);
    

onActivityResult里面再次检查权限

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    // check if received result code
    // is equal our requested code for draw permission
    if (requestCode == REQUEST_CODE) 
        // if so check once again if we have permission
         if (Settings.canDrawOverlays(this)) 
        // continue here - permission was granted

    
    

【讨论】:

您能否确切地建议我应该在哪里请求许可,因为我已经尝试过许可并且我在尝试调用虚拟方法 'void com.google.android.空对象引用上的 gms.common.api.GoogleApiClient.disconnect()' 勾选不Nullif(mGoogleApiClient != null) mGoogleApiClient.disconnect(); 在上述情况之后我没有收到错误但它不起作用我的意思是它只是说权限被拒绝并返回 你在manifest中添加了&lt;uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/&gt; 已添加权限仍然 toast 消息显示权限被拒绝并且没有任何反应【参考方案2】:

当您在检测到用户位置后显示所有数据时,您可以在 onLocationChanged() 中检查屏幕检测权限,如果用户授予权限,则进行进一步操作

【讨论】:

在 onLocationChanged 检查权限后出现此错误尝试在空对象引用上调用虚拟方法 'void com.google.android.gms.common.api.GoogleApiClient.disconnect()'跨度>

以上是关于如何在棉花糖设备中检查屏幕覆盖检测到的权限的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式关闭棉花糖设备中特定应用程序的打盹模式

如何在android中获得相机的权限。(特别是棉花糖)

Android棉花糖请求权限?

检测到屏幕覆盖 - 如何在屏幕覆盖应用程序中处理此问题

如何在棉花糖中首次启动应用程序时获取位置访问权限

如何在棉花糖上强制打瞌睡?