首次启动时的Android运行时权限

时间:2017-06-16 14:47:20

标签: android permissions

当我第一次启动Android应用程序时,它会触发一个询问位置权限的对话框。问题是在我有机会按下允许或拒绝之前onRequestPermissionsResult已被触发。因此,应用程序在第一次启动时没有权限,并且未设置Geofences。当然,当我重新启动应用程序时,所有权限都被授予,Geofences就像他们应该的那样工作。我如何在第一次启动时解决这个问题?

public class MainActivity extends BaseActivity implements OnRetailerClickListener, NetworkListener, GoogleApiClient.ConnectionCallbacks {

    public final int REQUEST_LOCATION_PERMISSION = 2222;
    private GoogleApiClient googleApiClient;
    private ViewPager mViewPager;
    private PagerAdapter mPagerAdapter;
    private OnBackPressedListener onBackPressedListener;
    private List<Geofence> geofenceList;
    private Intent intent;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* Setup custom toolbar for viewpager layout */
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("Overview");
        setSupportActionBar(toolbar);

        /* Setup TabLayout for viewpager tabs */
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_products));
        tabLayout.addTab(tabLayout.newTab().setText(R.string.tab_map));
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        /* register to the geofence observer */
        AppClassWiring.geofenceDao().registerObserver(this);

        /* build up GoogleApiClient and connect, used to set the geofences */
        googleApiClient = new GoogleApiClient
                .Builder(this)
                .addConnectionCallbacks(this)
                .addApi(LocationServices.API).build();
        googleApiClient.connect();

        /* create a viewpager for the fragments */
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
        mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());
        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount()); // all fragments are kept in memory because there are only 3
        initViewPagerListeners(mViewPager, tabLayout);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(!DeviceUtils.checkBluetooth())
            askBluetooth();
    }

    /**
     * The OnClickListener in the fragment will trigger this method.
     * This way the app can switch to the correct page in the viewpager
     *
     * @param retailer object received from fragment
     */
    @Override
    public void onRetailerClick(Retailer retailer) {
        mViewPager.setCurrentItem(PagerAdapter.FRAGMENT_MAP, true);
        mPagerAdapter.getItemForPosition(1).onRetailerClick(retailer);
    }

    /**
     * Init the ViewPagerListeners, used to add an onPageChangeLister for the TabLayout
     * also closes the keyboard when changing pages
     *
     * @param viewPager instance of the used viewpager
     * @param tabLayout instance of the used TabLayout above
     */
    private void initViewPagerListeners(final ViewPager viewPager, TabLayout tabLayout) {
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                DeviceUtils.hideKeyboard(MainActivity.this);
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
                DeviceUtils.hideKeyboard(MainActivity.this);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });
    }

    /**
     * Builder method to build up a Geofencingrequest with the retrieved backend data
     *
     * @param geofences to provide the data, required for a geofence to be built. This can be:
     *                  an Id, Latitude, Longitude, Radius, ExpirationDuration and TransitionTypes
     * @return a new instance of a GeofencingRequest
     */
    private GeofencingRequest buildGeofenceRequest(List<Geofence> geofences) {
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
        builder.addGeofences(geofences);
        return builder.build();
    }

    @Override
    public void onConnectionSuspended(int i) {
        Toast.makeText(this, "Could not connect with the Google API", Toast.LENGTH_LONG).show();
    }

    private void askBluetooth() {
        new AlertDialog.Builder(this)
                .setTitle("Enable bluetooth")
                .setMessage("Bluetooth should be enabled, Turn bluetooth on?")
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        DeviceUtils.setBluetoothOn(true);
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        DeviceUtils.setBluetoothOn(false);
                    }
                })
                .setIcon(android.R.drawable.stat_sys_data_bluetooth)
                .show();
    }

    /**
     * When the GoogleApiClient is connected,
     * the user is able to get all the geofences from the backend
     *
     * @param bundle null
     */
    @Override
    public void onConnected(@Nullable Bundle bundle) {
        /* Trigger the network call to get all geofences.
        The results can be shared with other classes that also listen to it */
        AppClassWiring.geofenceDao().getAllGeofences();
    }

    /**
     * Observable method that listens to the incoming results of the network call for geofences
     *
     * @param pointList recieved geofence/point objects from the API.
     *                  Used to build up a GeofencingRequest. After building the GeofencingRequest,
     *                  the data is provided to the GoogleApiClient to setup the geofences ready to trigger
     */
    @Override
    public void onResult(Object pointList) {
        List<Point> points = (List<Point>) pointList;
        geofenceList = new ArrayList<>();
        for (int i = 0; i < points.size(); i++) {
            geofenceList.add(new Geofence.Builder()
                    .setRequestId(points.get(i).getRetailer())
                    .setCircularRegion(
                            points.get(i).getValidLat(),
                            points.get(i).getValidLong(),
                            points.get(i).getValidRadius())
                    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
                            | Geofence.GEOFENCE_TRANSITION_EXIT)
                    .setExpirationDuration(Geofence.NEVER_EXPIRE)
                    .build());
        }
        intent = new Intent(this, GeoFencingService.class);
        // Permission check
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
        } else {
            LocationServices.GeofencingApi.addGeofences(
                    googleApiClient,
                    buildGeofenceRequest(geofenceList),
                    PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            );
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_LOCATION_PERMISSION: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        LocationServices.GeofencingApi.addGeofences(
                                googleApiClient,
                                buildGeofenceRequest(geofenceList),
                                PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                    }
                }
            }
        }
    }

    /**
     * @param error provides the error that was thrown by the retrofit call.
     */
    @Override
    public void onError(NetworkException error) {
        Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        /* unregister from the geofence observer */
        AppClassWiring.geofenceDao().unregisterObserver(this);
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }


}

2 个答案:

答案 0 :(得分:1)

  

问题是onRequestPermissionsResult在我有机会按下或拒绝之前已经被触发。

唯一的方法是,如果您已经授予了权限,那么对话框就不会出现。或者,如果您决定自己致电onRequestPermissionsResult(),那将非常奇怪。

答案 1 :(得分:0)

在onCreate()方法中使用此方法:

requestStoragePermission();

并在onCreate()方法之外定义此方法:

 private void requestStoragePermission() {
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        return;
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        return;
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
        return;
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
        return;


    ActivityCompat.requestPermissions(this, new String[]
            {
                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    android.Manifest.permission.CAMERA,
                    android.Manifest.permission.READ_PHONE_STATE,
            }, STORAGE_PERMISSION_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    //Checking the request code of our request
    if (requestCode == STORAGE_PERMISSION_CODE) {
        //If permission is granted
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //Displaying a toast
        } else {
            //Displaying another toast if permission is not granted
            Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show();
        }
    }
}