Skip to content

Commit

Permalink
Add additional permission checks for the other paths that turn on CDR…
Browse files Browse the repository at this point in the history
… logging to improve the UX and prevent crashes
  • Loading branch information
christianrowlands committed Oct 16, 2024
1 parent 66085f2 commit c5c4de6
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
public class DashboardFragment extends AServiceDataFragment implements LocationListener, IConnectionStateListener,
ILoggingChangeListener, SharedPreferences.OnSharedPreferenceChangeListener
{
private static final int ACCESS_REQUIRED_PERMISSION_REQUEST_ID = 20;
private static final int ACCESS_OPTIONAL_PERMISSION_REQUEST_ID = 21;
public static final int ACCESS_REQUIRED_PERMISSION_REQUEST_ID = 20;
public static final int ACCESS_OPTIONAL_PERMISSION_REQUEST_ID = 21;
private static final int ACCESS_BLUETOOTH_PERMISSION_REQUEST_ID = 22;

private final DecimalFormat locationFormat = new DecimalFormat("###.#####");
Expand Down Expand Up @@ -381,7 +381,7 @@ private void showCdrPermissionRationaleAndRequestPermissions()
alertBuilder.setCancelable(true);
alertBuilder.setTitle(getString(R.string.cdr_required_permissions_rationale_title));
alertBuilder.setMessage(getText(R.string.cdr_required_permissions_rationale));
alertBuilder.setPositiveButton(android.R.string.ok, (dialog, which) -> requestRequiredCdrPermissions());
alertBuilder.setPositiveButton(R.string.request, (dialog, which) -> requestRequiredCdrPermissions());

AlertDialog permissionsExplanationDialog = alertBuilder.create();
permissionsExplanationDialog.show();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package com.craxiom.networksurvey.fragments;

import static com.craxiom.networksurvey.constants.CdrPermissions.CDR_OPTIONAL_PERMISSIONS;
import static com.craxiom.networksurvey.constants.CdrPermissions.CDR_REQUIRED_PERMISSIONS;
import static com.craxiom.networksurvey.fragments.DashboardFragment.ACCESS_OPTIONAL_PERMISSION_REQUEST_ID;
import static com.craxiom.networksurvey.fragments.DashboardFragment.ACCESS_REQUIRED_PERMISSION_REQUEST_ID;

import android.content.Context;
import android.content.RestrictionsManager;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.InputType;

import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.DropDownPreference;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
Expand Down Expand Up @@ -72,6 +82,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
int defaultValue = -1;
if (key == null) return;

switch (key)
{
Expand Down Expand Up @@ -113,6 +124,15 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
case NetworkSurveyConstants.PROPERTY_DEVICE_STATUS_SCAN_INTERVAL_SECONDS:
defaultValue = NetworkSurveyConstants.DEFAULT_DEVICE_STATUS_SCAN_INTERVAL_SECONDS;
break;

case NetworkSurveyConstants.PROPERTY_AUTO_START_CDR_LOGGING:
final boolean autostartCdr = sharedPreferences.getBoolean(key, false);
if (autostartCdr)
{
// Verify the app has the necessary permissions to start CDR logging
showCdrPermissionRationaleAndRequestPermissions();
}
break;
}

if (defaultValue != -1)
Expand Down Expand Up @@ -367,4 +387,108 @@ private void setAppInstanceId()

SettingsUtils.setAppInstanceId(context, appInstanceIdPreference);
}

/**
* Check to see if we should show the rationale for any of the CDR permissions. If so, then display a dialog that
* explains what permissions we need for this app to work properly.
* <p>
* If we should not show the rationale, then just request the permissions.
*/
private void showCdrPermissionRationaleAndRequestPermissions()
{
final FragmentActivity activity = getActivity();
if (activity == null) return;

final Context context = getContext();
if (context == null) return;

if (missingAnyPermissions(CDR_REQUIRED_PERMISSIONS))
{
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setCancelable(true);
alertBuilder.setTitle(getString(R.string.cdr_required_permissions_rationale_title));
alertBuilder.setMessage(getText(R.string.cdr_required_permissions_rationale));
alertBuilder.setPositiveButton(R.string.request, (dialog, which) -> requestRequiredCdrPermissions());

AlertDialog permissionsExplanationDialog = alertBuilder.create();
permissionsExplanationDialog.show();

// Revert the cdr autostart preference if the permissions have not been granted
final SwitchPreferenceCompat preference = getPreferenceScreen().findPreference(NetworkSurveyConstants.PROPERTY_AUTO_START_CDR_LOGGING);
if (preference != null) preference.setChecked(false);
getPreferenceManager().getSharedPreferences()
.edit()
.putBoolean(NetworkSurveyConstants.PROPERTY_AUTO_START_CDR_LOGGING, false)
.apply();

return;
}

if (missingAnyPermissions(CDR_OPTIONAL_PERMISSIONS))
{
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setCancelable(true);
alertBuilder.setTitle(getString(R.string.cdr_optional_permissions_rationale_title));
alertBuilder.setMessage(getText(R.string.cdr_optional_permissions_rationale));
alertBuilder.setPositiveButton(R.string.request, (dialog, which) -> requestOptionalCdrPermissions());
alertBuilder.setNegativeButton(R.string.ignore, (dialog, which) -> {

});

AlertDialog permissionsExplanationDialog = alertBuilder.create();
permissionsExplanationDialog.show();
}
}

/**
* @return True if any of the permissions have been denied. False if all the permissions
* have been granted.
*/
private boolean missingAnyPermissions(String[] permissions)
{
final Context context = getContext();
if (context == null) return true;
for (String permission : permissions)
{
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED)
{
Timber.i("Missing the permission: %s", permission);
return true;
}
}

return false;
}

/**
* Request the permissions needed for this app if any of them have not yet been granted. If all of the permissions
* are already granted then don't request anything.
*/
private void requestRequiredCdrPermissions()
{
if (missingAnyPermissions(CDR_REQUIRED_PERMISSIONS))
{
FragmentActivity activity = getActivity();
if (activity != null)
{
ActivityCompat.requestPermissions(activity, CDR_REQUIRED_PERMISSIONS, ACCESS_REQUIRED_PERMISSION_REQUEST_ID);
}
}
}

/**
* Request the optional permissions for this app if any of them have not yet been granted. If all of the permissions
* are already granted then don't request anything.
*/
private void requestOptionalCdrPermissions()
{
if (missingAnyPermissions(CDR_OPTIONAL_PERMISSIONS))
{
FragmentActivity activity = getActivity();
if (activity != null)
{
ActivityCompat.requestPermissions(activity, CDR_OPTIONAL_PERMISSIONS, ACCESS_OPTIONAL_PERMISSION_REQUEST_ID);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,15 @@ public void startCdrEvents()
{
if (surveyService == null) return;

if (ActivityCompat.checkSelfPermission(surveyService, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED)
{
// Not notifying the user here because if the user toggled this via the UI then we already checked this
// permission. The way we can reach this point without the permission is if CDR was turned on via MDM
// control, in which case a user notification is not necessary.
Timber.e("Unable to get the READ_PHONE_STATE permission. CDR logging won't work.");
return;
}

synchronized (activeSubscriptionInfoListLock)
{
if (cdrStarted.getAndSet(true)) return;
Expand Down
2 changes: 1 addition & 1 deletion networksurvey/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
\n\n4. <b>Notifications</b>: This permission allows NS to add a notification so you know when a survey is running in the background.
\n\nThere is a known bug where this permission dialog keep showing, but the permission request dialog does not
show up after hitting OK. You can work around this by uninstalling and reinstalling the app and approving all
the permission the first time, or opening the Android settings and manually approving the required permissions.</string>
the permissions the first time, or opening the Android settings and manually approving the required permissions.</string>

<string name="cdr_optional_permissions_rationale_title">CDR Optional Permissions</string>
<string name="cdr_optional_permissions_rationale">In addition to the required permissions that were listed in a different dialog, CDR logging has an optional permission.
Expand Down

0 comments on commit c5c4de6

Please sign in to comment.