1

I have an activity, in which the user is sent to device settings if the GPS is off to turn it on, and when the user is back from settings, then the device is asking for location permission.

So the first GPS dialog is done via AlertDialog builder, here is my full code:

      public class Okoli extends AppCompatActivity implements LocationListener {

    private final static int ALL_PERMISSIONS_RESULT = 101;
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1;
    private static final long MIN_TIME_BW_UPDATES = 90000; //1.5 mins

    LocationManager locationManager;
    Location loc;
    ArrayList<String> permissions = new ArrayList<>();
    ArrayList<String> permissionsToRequest= new ArrayList<>();
    ArrayList<String> permissionsRejected = new ArrayList<>();
    boolean isGPS = false;
    boolean isNetwork = false;
    boolean canGetLocation = true;

    ArrayList<Actors> actorsList;
    ActorAdapterDist adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if(getSupportActionBar() != null){
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeButtonEnabled(true);
            getSupportActionBar().setTitle((Html.fromHtml("<font color=\"#c6c6c6\">V okolí (vzdušná čiara)</font>")));
            getSupportActionBar().setHomeAsUpIndicator(R.drawable.back);
        }

        setContentView(R.layout.okoli_fragment);

        actorsList = new ArrayList<>();
        adapter = new ActorAdapterDist(this, R.layout.okoli_item, actorsList);
        TextView listTitle = findViewById(R.id.booklist_title1);
        listTitle.setText("Čakám na signál GPS");

        getIntent().setAction("created");
        String MY_PREFS_NAME = "resumecheck";
        SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
        editor.putInt("idName", 2);
        editor.apply();

        ListView lv = findViewById(R.id.listViewx);   lv.setAdapter(adapter);

        locationManager = (LocationManager) this.getSystemService(Service.LOCATION_SERVICE);
        assert locationManager != null;
        isGPS = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        isNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
        permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
        permissionsToRequest = findUnAskedPermissions(permissions);

        if (!isGPS && !isNetwork) {

            showSettingsAlert(getString(R.string.askgps),  new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                    if (dialog != null) {
                        dialog.dismiss();  dialog = null;
                    }
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(intent);
                }
            });
            getLastLocation();
        } else {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (permissionsToRequest.size() > 0) {
                    requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]),
                            ALL_PERMISSIONS_RESULT);
                    canGetLocation = false;
                }
            }

            getLocation();
        }

    }

    @Override
    public void onLocationChanged(Location location) {updateUI(location);}

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {}

    @Override
    public void onProviderEnabled(String s) {
        getLocation();
    }

    @Override
    public void onProviderDisabled(String s) {
        if (locationManager != null) {
            locationManager.removeUpdates(this);
        }
    }

    private void getLocation() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);


        try {
            if (canGetLocation) {

                if (isGPS) {
                    locationManager.requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        if (loc != null) {updateUI(loc);}
                    }

                } else if (isNetwork) {
                    // from Network Provider
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (loc != null) {updateUI(loc);}
                    }

                } else {
                    loc.setLatitude(0);
                    loc.setLongitude(0);
                    updateUI(loc);
                }

            } else {
                Toast.makeText(this, R.string.nolocation,
                        Toast.LENGTH_LONG).show();
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private void getLastLocation() {
        try {
            Criteria criteria = new Criteria();
            String provider = locationManager.getBestProvider(criteria, false);

            if(provider==null) {    showSettingsAlert(getString(R.string.askgps),  new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(intent);
                }
            });}

            else {

                Location location = locationManager.getLastKnownLocation(provider);
                if (location != null) {updateUI(location);}

            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private ArrayList findUnAskedPermissions(ArrayList<String> wanted) {
        ArrayList<String> result = new ArrayList<>();

        for (String perm : wanted) {
            if (!hasPermission(perm)) {
                result.add(perm);
            }
        }

        return result;
    }

    private boolean hasPermission(String permission) {
        if (canAskPermission()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return (this.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
            }
        }
        return true;
    }

    private boolean canAskPermission() {
        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {


        switch (requestCode) {
            case ALL_PERMISSIONS_RESULT:

                for (String perms : permissionsToRequest) {
                    if (!hasPermission(perms)) {
                        permissionsRejected.add(perms);
                    }
                }

                if (permissionsRejected.size() > 0) {//Log.e("rejected", "onRequestPermissionsResult");

                 String MY_PREFS_NAME = "resumecheck";
                    SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
                    editor.putInt("idName", 2);
                    editor.apply();


                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {


                            editor.putInt("idName", 1);
                            editor.apply();

                            showMessageOKCancel(getString(R.string.denied),
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                                requestPermissions(permissionsRejected.toArray(
                                                        new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
                                            }
                                        }
                                    });
                            return;
                        }
                    }
                } else {
                    // Log.e("ON", "No rejected permissions.");
                    String MY_PREFS_NAME = "resumecheck";
                    SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
                    editor.putInt("idName", 2);
                    editor.apply();



                    canGetLocation = true;
                    getLocation();
                }
                break;
        }
    }

    public void showSettingsAlert(String message, DialogInterface.OnClickListener okListener) {

        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog_Alert);
        builder.setTitle(R.string.nogps);
        builder.setMessage(message);
        builder.setPositiveButton(R.string.ano, okListener);
        builder.setNegativeButton(R.string.nie, null);
        builder.create();
        builder.show();

    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {

        new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog_Alert)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton(R.string.cancel, null)
                .create()
                .show();
    }

    public void updateUI(Location loc) {
        double Act1=loc.getLatitude();
        double Act2=loc.getLongitude();
        adapter.clear();adapter.notifyDataSetChanged();

        TextView listTitle = findViewById(R.id.booklist_title1);
        ListView lv = findViewById(R.id.listViewx);

        if (Act1 > 0.0) { listTitle.setVisibility(View.GONE);lv.setVisibility(View.VISIBLE);GetContacts task = new GetContacts (Act1, Act2);
            task.execute();
            //  new GetContacts().execute(Act1,Act2);
        } else {
            listTitle.setVisibility(View.VISIBLE);listTitle.setText("Čakám na signál GPS");lv.setVisibility(View.GONE);
        }
    }

    ProgressDialog dialog;

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (locationManager != null) {
            locationManager.removeUpdates(this);
        }
        if (dialog != null) {
            dialog.dismiss();
            dialog = null;
        }

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (dialog != null) {
            dialog.dismiss();
            dialog = null;
        }
    }

    class GetContacts extends AsyncTask<Double, Void, Boolean> {


        private Double act1;
        private Double act2;

        GetContacts(double act1, double act2) {
            this.act1 = act1;
            this.act2 = act2;
        }


        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            dialog = new ProgressDialog(Okoli.this);
            dialog.setMessage("Načítavam");
            dialog.setTitle("Pripájam sa k serveru");
            dialog.show();
            dialog.setCancelable(false);
dialog.dismiss();
            dialog=null;
        }

        @Override
        protected Boolean doInBackground(Double... args) {
            HttpHandler sh = new HttpHandler();
            String url = "https://www.myweb.sk";
            String jsonStr = sh.makeServiceCall(url);

            int pocet =0;

            if (jsonStr != null) {
                try {JSONObject jsonObj = new JSONObject(jsonStr);
                    JSONArray actors = jsonObj.getJSONArray("result");

                    double myDistx;
                    //Log.e("pocet",String.format("value = %d", actors.length()));

                    for (int i = 0; i < actors.length(); i++) {
                        JSONObject c = actors.getJSONObject(i);

                        Actors actor = new Actors();
                        double g1 = Double.parseDouble(c.getString("gps1"));
                        double g2 = Double.parseDouble(c.getString("gps2"));

                        myDistx = calculateDistance(act1, act2, g1, g2);

                        if (myDistx <= 50) {
                            actor.setLetter("x");
                            actor.setNazov(c.getString("nazov"));
                            actor.setThumb(c.getString("thumb"));
                            actor.setPerex(c.getString("perex"));
                            actor.setTyp(c.getString("typ"));
                            actor.setPlace(c.getString("place"));
                            actor.setGps1(c.getString("gps1"));
                            actor.setGps2(c.getString("gps2"));
                            actor.setExterier(c.getString("adresar"));

                            actor.setDist(myDistx);

                            actorsList.add(actor);
                            pocet++;
                        }
                    }

                    if (pocet == 0) {
                        runOnUiThread(new Runnable() {
                            public void run() {

                                Toast.makeText(Okoli.this.getApplicationContext(), R.string.nothing_around, Toast.LENGTH_LONG).show();
                            }
                        });

                    }

                    Collections.sort(actorsList, new Comparator<Actors>() {
                        @Override
                        public int compare(Actors lhs, Actors rhs) {
                            return lhs.getDist().compareTo(rhs.getDist());
                        }
                    });



                }  catch (final JSONException e) {
                    Okoli.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(Okoli.this.getApplicationContext(),
                                    "Chyba dát: " + e.getMessage(),
                                    Toast.LENGTH_LONG).show();
                        }
                    }); }

                return true;

            } else {
                Okoli.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(Okoli.this.getApplicationContext(),
                                "Chyba internetového pripojenia.",
                                Toast.LENGTH_LONG).show();
                    }
                });
                return false;
            }
        }

        final static double AVERAGE_RADIUS_OF_EARTH = 6371;
        double calculateDistance(double userLat, double userLng, double venueLat, double venueLng) {

            double latDistance = Math.toRadians(userLat - venueLat);
            double lngDistance = Math.toRadians(userLng - venueLng);

            double a = (Math.sin(latDistance / 2) * Math.sin(latDistance / 2)) +
                    (Math.cos(Math.toRadians(userLat))) *
                            (Math.cos(Math.toRadians(venueLat))) *
                            (Math.sin(lngDistance / 2)) *
                            (Math.sin(lngDistance / 2));

            double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

            return (AVERAGE_RADIUS_OF_EARTH * c);
        }

        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            if (dialog != null && dialog.isShowing()) {
                dialog.dismiss();  dialog = null;
            }
            //dialog.dismiss();
            adapter.notifyDataSetChanged();
        }


    }


    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                onBackPressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onResume() { //restart activity after back from GPS settings
        super.onResume();
        adapter.clear();
        adapter.notifyDataSetChanged();

        if (dialog != null) {
            dialog.dismiss();
            dialog = null;
        }



        String action = getIntent().getAction();
        // Prevent endless loop by adding a unique action, don't restart if action is present
        if(action == null || !action.equals("created")) {


            String MY_PREFS_NAME = "resumecheck";
            SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);

                int idName = prefs.getInt("idName", 0); //0 is the default value.


            if(idName == 2) {
                Intent intent = new Intent(this, Okoli.class);
                startActivity(intent);
                finish();
            } else {
                SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
                editor.putInt("idName", 1);
                editor.apply(); }



        }
        // Remove the unique action so the next time onResume is called it will restart
        else
            getIntent().setAction(null);


    }
}

However it is working fine, but the console gives me an error

android.view.WindowLeaked: Activity has leaked window DecorView@11bd862[] that was originally added here
                 at android.view.ViewRootImpl.<init>(ViewRootImpl.java:576)
                 at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:363)
                 at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:128)
                 at android.app.Dialog.show(Dialog.java:454)
                 at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:1006)
                 at **.showSettingsAlert(Okoli.java:298)
                 at Okoli.onCreate(Okoli.java:95)**
                 at android.app.Activity.performCreate(Activity.java:7372)
                 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1218)
                 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3147)
                 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302)
                 at android.app.ActivityThread.-wrap12(Unknown Source:0)
                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891)
                 at android.os.Handler.dispatchMessage(Handler.java:108)
                 at android.os.Looper.loop(Looper.java:166)
                 at android.app.ActivityThread.main(ActivityThread.java:7425)
                 at java.lang.reflect.Method.invoke(Native Method)
                 at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

So the lines 95 and 298 are pointing to showSettingsAlert.

I tried to dismiss dialog onDestroy, onPause, onpostExecute also onResume, but the error is still there. It is showing exactly, when I press the back arrow from device GPS settings and the permission alert is showing next.

Can you please advice, where and how to dismiss that alert window to avoid leaking?

Darksymphony
  • 2,155
  • 30
  • 54
  • Possible duplicate of [Activity has leaked window that was originally added](https://stackoverflow.com/questions/2850573/activity-has-leaked-window-that-was-originally-added) – Ehsan Mashhadi Aug 10 '18 at 07:19
  • Possible duplicate of [Activity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44f72ff0 that was originally added here](https://stackoverflow.com/questions/11957409/activity-has-leaked-window-com-android-internal-policy-impl-phonewindowdecorvie) – Khemraj Sharma Aug 10 '18 at 07:19
  • did not find a solution for my case there – Darksymphony Aug 10 '18 at 07:56

2 Answers2

0

you should make dialog is null all the place after dismiss the dialog

     if (dialog != null) 
     {
     dialog.dismiss();
     dialog = null;
     }

so your onDestroy should be

@Override
public void onDestroy() {
super.onDestroy();
if (dialog != null) {
    dialog.dismiss();
    dialog = null;
}
}

Change your showSettingsAlert method like this

public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("GPS is not Enabled!");
alertDialog.setMessage("Do you want to turn on GPS?");
alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        startActivity(intent);
    }
});

alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int which) {
        dialog.cancel();
    }
});

alertDialog.show();
}
sasikumar
  • 12,540
  • 3
  • 28
  • 48
  • my onDestroy looks exactly like you posted, but still have the error – Darksymphony Aug 10 '18 at 07:21
  • all the place you should make null after dismmis the dialog – sasikumar Aug 10 '18 at 07:23
  • hm, just added everywhere dialog = null; after each dismiss, did not help – Darksymphony Aug 10 '18 at 07:26
  • again you get same exception? can you post your full activity code? – sasikumar Aug 10 '18 at 07:29
  • yes, the same exception as before. I added the full code in my original question. – Darksymphony Aug 10 '18 at 07:30
  • change your showSettingsAlert method like this above see my edited answer – sasikumar Aug 10 '18 at 07:35
  • Ok, I updated the code, now the alert is only white background, but when returning back from GPs, android.view.WindowLeaked exception again - pointing to line alertDialog.show(); – Darksymphony Aug 10 '18 at 07:44
  • 1
    SO I found out, the issue is in the last part - if(action == null || !action.equals("created")) {... Intent intent = new Intent(this, Okoli.class); startActivity(intent);finish(); When I remove this part, it has no more errors! But then after returning from GPS settings the activity is not restarted and the items are not showing because the activity needs restarted to show the items according the gps. – Darksymphony Aug 10 '18 at 08:51
0

Ok I think I've found the issue in onResume. I had startActivity and then finish, so probably first should be finish and then startActivity.

But for now I updated the onResume like this:

      if (Okoli.isFromSetting){

    if (dialog != null) {
        dialog.dismiss();
        dialog = null;
    }

        startActivity(getIntent());
        Okoli.isFromSetting=false;

so I am using isFromSetting true in the dialog and checking it's state to avoid infinity loop restart of the activity.

But I think the issue was resolved by removing finish() and keeping only startActivity.

Seems it is working now without any errors or exceptions.

Darksymphony
  • 2,155
  • 30
  • 54